ulimit.go (3189B)
1 package units 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 ) 8 9 // Ulimit is a human friendly version of Rlimit. 10 type Ulimit struct { 11 Name string 12 Hard int64 13 Soft int64 14 } 15 16 // Rlimit specifies the resource limits, such as max open files. 17 type Rlimit struct { 18 Type int `json:"type,omitempty"` 19 Hard uint64 `json:"hard,omitempty"` 20 Soft uint64 `json:"soft,omitempty"` 21 } 22 23 const ( 24 // magic numbers for making the syscall 25 // some of these are defined in the syscall package, but not all. 26 // Also since Windows client doesn't get access to the syscall package, need to 27 // define these here 28 rlimitAs = 9 29 rlimitCore = 4 30 rlimitCPU = 0 31 rlimitData = 2 32 rlimitFsize = 1 33 rlimitLocks = 10 34 rlimitMemlock = 8 35 rlimitMsgqueue = 12 36 rlimitNice = 13 37 rlimitNofile = 7 38 rlimitNproc = 6 39 rlimitRss = 5 40 rlimitRtprio = 14 41 rlimitRttime = 15 42 rlimitSigpending = 11 43 rlimitStack = 3 44 ) 45 46 var ulimitNameMapping = map[string]int{ 47 //"as": rlimitAs, // Disabled since this doesn't seem usable with the way Docker inits a container. 48 "core": rlimitCore, 49 "cpu": rlimitCPU, 50 "data": rlimitData, 51 "fsize": rlimitFsize, 52 "locks": rlimitLocks, 53 "memlock": rlimitMemlock, 54 "msgqueue": rlimitMsgqueue, 55 "nice": rlimitNice, 56 "nofile": rlimitNofile, 57 "nproc": rlimitNproc, 58 "rss": rlimitRss, 59 "rtprio": rlimitRtprio, 60 "rttime": rlimitRttime, 61 "sigpending": rlimitSigpending, 62 "stack": rlimitStack, 63 } 64 65 // ParseUlimit parses and returns a Ulimit from the specified string. 66 func ParseUlimit(val string) (*Ulimit, error) { 67 parts := strings.SplitN(val, "=", 2) 68 if len(parts) != 2 { 69 return nil, fmt.Errorf("invalid ulimit argument: %s", val) 70 } 71 72 if _, exists := ulimitNameMapping[parts[0]]; !exists { 73 return nil, fmt.Errorf("invalid ulimit type: %s", parts[0]) 74 } 75 76 var ( 77 soft int64 78 hard = &soft // default to soft in case no hard was set 79 temp int64 80 err error 81 ) 82 switch limitVals := strings.Split(parts[1], ":"); len(limitVals) { 83 case 2: 84 temp, err = strconv.ParseInt(limitVals[1], 10, 64) 85 if err != nil { 86 return nil, err 87 } 88 hard = &temp 89 fallthrough 90 case 1: 91 soft, err = strconv.ParseInt(limitVals[0], 10, 64) 92 if err != nil { 93 return nil, err 94 } 95 default: 96 return nil, fmt.Errorf("too many limit value arguments - %s, can only have up to two, `soft[:hard]`", parts[1]) 97 } 98 99 if *hard != -1 { 100 if soft == -1 { 101 return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: soft: -1 (unlimited), hard: %d", *hard) 102 } 103 if soft > *hard { 104 return nil, fmt.Errorf("ulimit soft limit must be less than or equal to hard limit: %d > %d", soft, *hard) 105 } 106 } 107 108 return &Ulimit{Name: parts[0], Soft: soft, Hard: *hard}, nil 109 } 110 111 // GetRlimit returns the RLimit corresponding to Ulimit. 112 func (u *Ulimit) GetRlimit() (*Rlimit, error) { 113 t, exists := ulimitNameMapping[u.Name] 114 if !exists { 115 return nil, fmt.Errorf("invalid ulimit name %s", u.Name) 116 } 117 118 return &Rlimit{Type: t, Soft: uint64(u.Soft), Hard: uint64(u.Hard)}, nil 119 } 120 121 func (u *Ulimit) String() string { 122 return fmt.Sprintf("%s=%d:%d", u.Name, u.Soft, u.Hard) 123 }