parse.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package configuration
  2. import (
  3. "fmt"
  4. "github.com/dotcloud/docker/pkg/libcontainer"
  5. "github.com/dotcloud/docker/utils"
  6. "os/exec"
  7. "path/filepath"
  8. "strconv"
  9. "strings"
  10. )
  11. type Action func(*libcontainer.Container, interface{}, string) error
  12. var actions = map[string]Action{
  13. "cap.add": addCap, // add a cap
  14. "cap.drop": dropCap, // drop a cap
  15. "ns.add": addNamespace, // add a namespace
  16. "ns.drop": dropNamespace, // drop a namespace when cloning
  17. "net.join": joinNetNamespace, // join another containers net namespace
  18. "cgroups.cpu_shares": cpuShares, // set the cpu shares
  19. "cgroups.memory": memory, // set the memory limit
  20. "cgroups.memory_swap": memorySwap, // set the memory swap limit
  21. "cgroups.cpuset.cpus": cpusetCpus, // set the cpus used
  22. "apparmor_profile": apparmorProfile, // set the apparmor profile to apply
  23. "fs.readonly": readonlyFs, // make the rootfs of the container read only
  24. }
  25. func cpusetCpus(container *libcontainer.Container, context interface{}, value string) error {
  26. if container.Cgroups == nil {
  27. return fmt.Errorf("cannot set cgroups when they are disabled")
  28. }
  29. container.Cgroups.CpusetCpus = value
  30. return nil
  31. }
  32. func apparmorProfile(container *libcontainer.Container, context interface{}, value string) error {
  33. container.Context["apparmor_profile"] = value
  34. return nil
  35. }
  36. func cpuShares(container *libcontainer.Container, context interface{}, value string) error {
  37. if container.Cgroups == nil {
  38. return fmt.Errorf("cannot set cgroups when they are disabled")
  39. }
  40. v, err := strconv.ParseInt(value, 10, 0)
  41. if err != nil {
  42. return err
  43. }
  44. container.Cgroups.CpuShares = v
  45. return nil
  46. }
  47. func memory(container *libcontainer.Container, context interface{}, value string) error {
  48. if container.Cgroups == nil {
  49. return fmt.Errorf("cannot set cgroups when they are disabled")
  50. }
  51. v, err := utils.RAMInBytes(value)
  52. if err != nil {
  53. return err
  54. }
  55. container.Cgroups.Memory = v
  56. return nil
  57. }
  58. func memorySwap(container *libcontainer.Container, context interface{}, value string) error {
  59. if container.Cgroups == nil {
  60. return fmt.Errorf("cannot set cgroups when they are disabled")
  61. }
  62. v, err := strconv.ParseInt(value, 0, 64)
  63. if err != nil {
  64. return err
  65. }
  66. container.Cgroups.MemorySwap = v
  67. return nil
  68. }
  69. func addCap(container *libcontainer.Container, context interface{}, value string) error {
  70. c := container.CapabilitiesMask.Get(value)
  71. if c == nil {
  72. return fmt.Errorf("%s is not a valid capability", value)
  73. }
  74. c.Enabled = true
  75. return nil
  76. }
  77. func dropCap(container *libcontainer.Container, context interface{}, value string) error {
  78. c := container.CapabilitiesMask.Get(value)
  79. if c == nil {
  80. return fmt.Errorf("%s is not a valid capability", value)
  81. }
  82. c.Enabled = false
  83. return nil
  84. }
  85. func addNamespace(container *libcontainer.Container, context interface{}, value string) error {
  86. ns := container.Namespaces.Get(value)
  87. if ns == nil {
  88. return fmt.Errorf("%s is not a valid namespace", value[1:])
  89. }
  90. ns.Enabled = true
  91. return nil
  92. }
  93. func dropNamespace(container *libcontainer.Container, context interface{}, value string) error {
  94. ns := container.Namespaces.Get(value)
  95. if ns == nil {
  96. return fmt.Errorf("%s is not a valid namespace", value[1:])
  97. }
  98. ns.Enabled = false
  99. return nil
  100. }
  101. func readonlyFs(container *libcontainer.Container, context interface{}, value string) error {
  102. switch value {
  103. case "1", "true":
  104. container.ReadonlyFs = true
  105. default:
  106. container.ReadonlyFs = false
  107. }
  108. return nil
  109. }
  110. func joinNetNamespace(container *libcontainer.Container, context interface{}, value string) error {
  111. var (
  112. running = context.(map[string]*exec.Cmd)
  113. cmd = running[value]
  114. )
  115. if cmd == nil || cmd.Process == nil {
  116. return fmt.Errorf("%s is not a valid running container to join", value)
  117. }
  118. nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")
  119. container.Networks = append(container.Networks, &libcontainer.Network{
  120. Type: "netns",
  121. Context: libcontainer.Context{
  122. "nspath": nspath,
  123. },
  124. })
  125. return nil
  126. }
  127. func vethMacAddress(container *libcontainer.Container, context interface{}, value string) error {
  128. var veth *libcontainer.Network
  129. for _, network := range container.Networks {
  130. if network.Type == "veth" {
  131. veth = network
  132. break
  133. }
  134. }
  135. if veth == nil {
  136. return fmt.Errorf("not veth configured for container")
  137. }
  138. veth.Context["mac"] = value
  139. return nil
  140. }
  141. // configureCustomOptions takes string commands from the user and allows modification of the
  142. // container's default configuration.
  143. //
  144. // TODO: this can be moved to a general utils or parser in pkg
  145. func ParseConfiguration(container *libcontainer.Container, running map[string]*exec.Cmd, opts []string) error {
  146. for _, opt := range opts {
  147. kv := strings.SplitN(opt, "=", 2)
  148. if len(kv) < 2 {
  149. return fmt.Errorf("invalid format for %s", opt)
  150. }
  151. action, exists := actions[kv[0]]
  152. if !exists {
  153. return fmt.Errorf("%s is not a valid option for the native driver", kv[0])
  154. }
  155. if err := action(container, running, kv[1]); err != nil {
  156. return err
  157. }
  158. }
  159. return nil
  160. }