parse.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. // GetSupportedActions returns a list of all the avaliable actions supported by the driver
  26. // TODO: this should return a description also
  27. func GetSupportedActions() []string {
  28. var (
  29. i int
  30. out = make([]string, len(actions))
  31. )
  32. for k := range actions {
  33. out[i] = k
  34. i++
  35. }
  36. return out
  37. }
  38. func cpusetCpus(container *libcontainer.Container, context interface{}, value string) error {
  39. if container.Cgroups == nil {
  40. return fmt.Errorf("cannot set cgroups when they are disabled")
  41. }
  42. container.Cgroups.CpusetCpus = value
  43. return nil
  44. }
  45. func apparmorProfile(container *libcontainer.Container, context interface{}, value string) error {
  46. container.Context["apparmor_profile"] = value
  47. return nil
  48. }
  49. func cpuShares(container *libcontainer.Container, context interface{}, value string) error {
  50. if container.Cgroups == nil {
  51. return fmt.Errorf("cannot set cgroups when they are disabled")
  52. }
  53. v, err := strconv.ParseInt(value, 10, 0)
  54. if err != nil {
  55. return err
  56. }
  57. container.Cgroups.CpuShares = v
  58. return nil
  59. }
  60. func memory(container *libcontainer.Container, context interface{}, value string) error {
  61. if container.Cgroups == nil {
  62. return fmt.Errorf("cannot set cgroups when they are disabled")
  63. }
  64. v, err := utils.RAMInBytes(value)
  65. if err != nil {
  66. return err
  67. }
  68. container.Cgroups.Memory = v
  69. return nil
  70. }
  71. func memorySwap(container *libcontainer.Container, context interface{}, value string) error {
  72. if container.Cgroups == nil {
  73. return fmt.Errorf("cannot set cgroups when they are disabled")
  74. }
  75. v, err := strconv.ParseInt(value, 0, 64)
  76. if err != nil {
  77. return err
  78. }
  79. container.Cgroups.MemorySwap = v
  80. return nil
  81. }
  82. func addCap(container *libcontainer.Container, context interface{}, value string) error {
  83. c := container.CapabilitiesMask.Get(value)
  84. if c == nil {
  85. return fmt.Errorf("%s is not a valid capability", value)
  86. }
  87. c.Enabled = true
  88. return nil
  89. }
  90. func dropCap(container *libcontainer.Container, context interface{}, value string) error {
  91. c := container.CapabilitiesMask.Get(value)
  92. if c == nil {
  93. return fmt.Errorf("%s is not a valid capability", value)
  94. }
  95. c.Enabled = false
  96. return nil
  97. }
  98. func addNamespace(container *libcontainer.Container, context interface{}, value string) error {
  99. ns := container.Namespaces.Get(value)
  100. if ns == nil {
  101. return fmt.Errorf("%s is not a valid namespace", value[1:])
  102. }
  103. ns.Enabled = true
  104. return nil
  105. }
  106. func dropNamespace(container *libcontainer.Container, context interface{}, value string) error {
  107. ns := container.Namespaces.Get(value)
  108. if ns == nil {
  109. return fmt.Errorf("%s is not a valid namespace", value[1:])
  110. }
  111. ns.Enabled = false
  112. return nil
  113. }
  114. func readonlyFs(container *libcontainer.Container, context interface{}, value string) error {
  115. switch value {
  116. case "1", "true":
  117. container.ReadonlyFs = true
  118. default:
  119. container.ReadonlyFs = false
  120. }
  121. return nil
  122. }
  123. func joinNetNamespace(container *libcontainer.Container, context interface{}, value string) error {
  124. var (
  125. running = context.(map[string]*exec.Cmd)
  126. cmd = running[value]
  127. )
  128. if cmd == nil || cmd.Process == nil {
  129. return fmt.Errorf("%s is not a valid running container to join", value)
  130. }
  131. nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")
  132. container.Networks = append(container.Networks, &libcontainer.Network{
  133. Type: "netns",
  134. Context: libcontainer.Context{
  135. "nspath": nspath,
  136. },
  137. })
  138. return nil
  139. }
  140. func vethMacAddress(container *libcontainer.Container, context interface{}, value string) error {
  141. var veth *libcontainer.Network
  142. for _, network := range container.Networks {
  143. if network.Type == "veth" {
  144. veth = network
  145. break
  146. }
  147. }
  148. if veth == nil {
  149. return fmt.Errorf("not veth configured for container")
  150. }
  151. veth.Context["mac"] = value
  152. return nil
  153. }
  154. // configureCustomOptions takes string commands from the user and allows modification of the
  155. // container's default configuration.
  156. //
  157. // TODO: this can be moved to a general utils or parser in pkg
  158. func ParseConfiguration(container *libcontainer.Container, running map[string]*exec.Cmd, opts []string) error {
  159. for _, opt := range opts {
  160. kv := strings.SplitN(opt, "=", 2)
  161. if len(kv) < 2 {
  162. return fmt.Errorf("invalid format for %s", opt)
  163. }
  164. action, exists := actions[kv[0]]
  165. if !exists {
  166. return fmt.Errorf("%s is not a valid option for the native driver", kv[0])
  167. }
  168. if err := action(container, running, kv[1]); err != nil {
  169. return err
  170. }
  171. }
  172. return nil
  173. }