ulimit.go 2.8 KB

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