init.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. package lxc
  2. import (
  3. "encoding/json"
  4. "flag"
  5. "fmt"
  6. "io/ioutil"
  7. "log"
  8. "net"
  9. "os"
  10. "os/exec"
  11. "runtime"
  12. "strings"
  13. "syscall"
  14. "github.com/docker/docker/reexec"
  15. "github.com/docker/libcontainer/netlink"
  16. )
  17. // Args provided to the init function for a driver
  18. type InitArgs struct {
  19. User string
  20. Gateway string
  21. Ip string
  22. WorkDir string
  23. Privileged bool
  24. Env []string
  25. Args []string
  26. Mtu int
  27. Console string
  28. Pipe int
  29. Root string
  30. CapAdd string
  31. CapDrop string
  32. }
  33. func init() {
  34. // like always lxc requires a hack to get this to work
  35. reexec.Register("/.dockerinit", dockerInititalizer)
  36. }
  37. func dockerInititalizer() {
  38. initializer()
  39. }
  40. // initializer is the lxc driver's init function that is run inside the namespace to setup
  41. // additional configurations
  42. func initializer() {
  43. runtime.LockOSThread()
  44. args := getArgs()
  45. if err := setupNamespace(args); err != nil {
  46. log.Fatal(err)
  47. }
  48. }
  49. func setupNamespace(args *InitArgs) error {
  50. if err := setupEnv(args); err != nil {
  51. return err
  52. }
  53. if err := setupHostname(args); err != nil {
  54. return err
  55. }
  56. if err := setupNetworking(args); err != nil {
  57. return err
  58. }
  59. if err := finalizeNamespace(args); err != nil {
  60. return err
  61. }
  62. path, err := exec.LookPath(args.Args[0])
  63. if err != nil {
  64. log.Printf("Unable to locate %v", args.Args[0])
  65. os.Exit(127)
  66. }
  67. if err := syscall.Exec(path, args.Args, os.Environ()); err != nil {
  68. return fmt.Errorf("dockerinit unable to execute %s - %s", path, err)
  69. }
  70. return nil
  71. }
  72. func getArgs() *InitArgs {
  73. var (
  74. // Get cmdline arguments
  75. user = flag.String("u", "", "username or uid")
  76. gateway = flag.String("g", "", "gateway address")
  77. ip = flag.String("i", "", "ip address")
  78. workDir = flag.String("w", "", "workdir")
  79. privileged = flag.Bool("privileged", false, "privileged mode")
  80. mtu = flag.Int("mtu", 1500, "interface mtu")
  81. capAdd = flag.String("cap-add", "", "capabilities to add")
  82. capDrop = flag.String("cap-drop", "", "capabilities to drop")
  83. )
  84. flag.Parse()
  85. return &InitArgs{
  86. User: *user,
  87. Gateway: *gateway,
  88. Ip: *ip,
  89. WorkDir: *workDir,
  90. Privileged: *privileged,
  91. Args: flag.Args(),
  92. Mtu: *mtu,
  93. CapAdd: *capAdd,
  94. CapDrop: *capDrop,
  95. }
  96. }
  97. // Clear environment pollution introduced by lxc-start
  98. func setupEnv(args *InitArgs) error {
  99. // Get env
  100. var env []string
  101. content, err := ioutil.ReadFile(".dockerenv")
  102. if err != nil {
  103. return fmt.Errorf("Unable to load environment variables: %v", err)
  104. }
  105. if err := json.Unmarshal(content, &env); err != nil {
  106. return fmt.Errorf("Unable to unmarshal environment variables: %v", err)
  107. }
  108. // Propagate the plugin-specific container env variable
  109. env = append(env, "container="+os.Getenv("container"))
  110. args.Env = env
  111. os.Clearenv()
  112. for _, kv := range args.Env {
  113. parts := strings.SplitN(kv, "=", 2)
  114. if len(parts) == 1 {
  115. parts = append(parts, "")
  116. }
  117. os.Setenv(parts[0], parts[1])
  118. }
  119. return nil
  120. }
  121. func setupHostname(args *InitArgs) error {
  122. hostname := getEnv(args, "HOSTNAME")
  123. if hostname == "" {
  124. return nil
  125. }
  126. return setHostname(hostname)
  127. }
  128. // Setup networking
  129. func setupNetworking(args *InitArgs) error {
  130. if args.Ip != "" {
  131. // eth0
  132. iface, err := net.InterfaceByName("eth0")
  133. if err != nil {
  134. return fmt.Errorf("Unable to set up networking: %v", err)
  135. }
  136. ip, ipNet, err := net.ParseCIDR(args.Ip)
  137. if err != nil {
  138. return fmt.Errorf("Unable to set up networking: %v", err)
  139. }
  140. if err := netlink.NetworkLinkAddIp(iface, ip, ipNet); err != nil {
  141. return fmt.Errorf("Unable to set up networking: %v", err)
  142. }
  143. if err := netlink.NetworkSetMTU(iface, args.Mtu); err != nil {
  144. return fmt.Errorf("Unable to set MTU: %v", err)
  145. }
  146. if err := netlink.NetworkLinkUp(iface); err != nil {
  147. return fmt.Errorf("Unable to set up networking: %v", err)
  148. }
  149. // loopback
  150. iface, err = net.InterfaceByName("lo")
  151. if err != nil {
  152. return fmt.Errorf("Unable to set up networking: %v", err)
  153. }
  154. if err := netlink.NetworkLinkUp(iface); err != nil {
  155. return fmt.Errorf("Unable to set up networking: %v", err)
  156. }
  157. }
  158. if args.Gateway != "" {
  159. gw := net.ParseIP(args.Gateway)
  160. if gw == nil {
  161. return fmt.Errorf("Unable to set up networking, %s is not a valid gateway IP", args.Gateway)
  162. }
  163. if err := netlink.AddDefaultGw(gw.String(), "eth0"); err != nil {
  164. return fmt.Errorf("Unable to set up networking: %v", err)
  165. }
  166. }
  167. return nil
  168. }
  169. // Setup working directory
  170. func setupWorkingDirectory(args *InitArgs) error {
  171. if args.WorkDir == "" {
  172. return nil
  173. }
  174. if err := syscall.Chdir(args.WorkDir); err != nil {
  175. return fmt.Errorf("Unable to change dir to %v: %v", args.WorkDir, err)
  176. }
  177. return nil
  178. }
  179. func getEnv(args *InitArgs, key string) string {
  180. for _, kv := range args.Env {
  181. parts := strings.SplitN(kv, "=", 2)
  182. if parts[0] == key && len(parts) == 2 {
  183. return parts[1]
  184. }
  185. }
  186. return ""
  187. }