init.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. // +build linux
  2. package init
  3. import (
  4. "bufio"
  5. "fmt"
  6. "os"
  7. "os/exec"
  8. "strings"
  9. "syscall"
  10. log "github.com/Sirupsen/logrus"
  11. "github.com/docker/docker/pkg/mount"
  12. "github.com/rancher/docker-from-scratch"
  13. "github.com/rancher/os/config"
  14. "github.com/rancher/os/util"
  15. "github.com/rancher/os/util/network"
  16. )
  17. const (
  18. STATE string = "/state"
  19. BOOT2DOCKER_MAGIC string = "boot2docker, please format-me"
  20. TMPFS_MAGIC int64 = 0x01021994
  21. RAMFS_MAGIC int64 = 0x858458f6
  22. )
  23. var (
  24. mountConfig = dockerlaunch.Config{
  25. CgroupHierarchy: map[string]string{
  26. "cpu": "cpu",
  27. "cpuacct": "cpu",
  28. "net_cls": "net_cls",
  29. "net_prio": "net_cls",
  30. },
  31. }
  32. )
  33. func loadModules(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  34. mounted := map[string]bool{}
  35. f, err := os.Open("/proc/modules")
  36. if err != nil {
  37. return cfg, err
  38. }
  39. defer f.Close()
  40. reader := bufio.NewScanner(f)
  41. for reader.Scan() {
  42. mounted[strings.SplitN(reader.Text(), " ", 2)[0]] = true
  43. }
  44. for _, module := range cfg.Rancher.Modules {
  45. if mounted[module] {
  46. continue
  47. }
  48. log.Debugf("Loading module %s", module)
  49. if err := exec.Command("modprobe", module).Run(); err != nil {
  50. log.Errorf("Could not load module %s, err %v", module, err)
  51. }
  52. }
  53. return cfg, nil
  54. }
  55. func sysInit(c *config.CloudConfig) (*config.CloudConfig, error) {
  56. args := append([]string{config.SYSINIT_BIN}, os.Args[1:]...)
  57. cmd := &exec.Cmd{
  58. Path: config.ROS_BIN,
  59. Args: args,
  60. }
  61. cmd.Stdin = os.Stdin
  62. cmd.Stderr = os.Stderr
  63. cmd.Stdout = os.Stdout
  64. if err := cmd.Start(); err != nil {
  65. return c, err
  66. }
  67. return c, os.Stdin.Close()
  68. }
  69. func MainInit() {
  70. if err := RunInit(); err != nil {
  71. log.Fatal(err)
  72. }
  73. }
  74. func mountConfigured(display, dev, fsType, target string) error {
  75. var err error
  76. if dev == "" {
  77. return nil
  78. }
  79. dev = util.ResolveDevice(dev)
  80. if dev == "" {
  81. return fmt.Errorf("Could not resolve device %q", dev)
  82. }
  83. if fsType == "auto" {
  84. fsType, err = util.GetFsType(dev)
  85. }
  86. if err != nil {
  87. return err
  88. }
  89. log.Debugf("FsType has been set to %s", fsType)
  90. log.Infof("Mounting %s device %s to %s", display, dev, target)
  91. return util.Mount(dev, target, fsType, "")
  92. }
  93. func mountState(cfg *config.CloudConfig) error {
  94. return mountConfigured("state", cfg.Rancher.State.Dev, cfg.Rancher.State.FsType, STATE)
  95. }
  96. func mountOem(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  97. if cfg == nil {
  98. cfg = config.LoadConfig()
  99. }
  100. if err := mountConfigured("oem", cfg.Rancher.State.OemDev, cfg.Rancher.State.OemFsType, config.OEM); err != nil {
  101. log.Debugf("Not mounting OEM: %v", err)
  102. } else {
  103. log.Infof("Mounted OEM: %s", cfg.Rancher.State.OemDev)
  104. }
  105. return cfg, nil
  106. }
  107. func tryMountState(cfg *config.CloudConfig) error {
  108. if mountState(cfg) == nil {
  109. return nil
  110. }
  111. // If we failed to mount lets run bootstrap and try again
  112. if err := bootstrap(cfg); err != nil {
  113. return err
  114. }
  115. return mountState(cfg)
  116. }
  117. func tryMountAndBootstrap(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  118. if !isInitrd() || cfg.Rancher.State.Dev == "" {
  119. return cfg, nil
  120. }
  121. if err := tryMountState(cfg); !cfg.Rancher.State.Required && err != nil {
  122. return cfg, nil
  123. } else if err != nil {
  124. return cfg, err
  125. }
  126. log.Debugf("Switching to new root at %s %s", STATE, cfg.Rancher.State.Directory)
  127. if err := switchRoot(STATE, cfg.Rancher.State.Directory, cfg.Rancher.RmUsr); err != nil {
  128. return cfg, err
  129. }
  130. return mountOem(cfg)
  131. }
  132. func getLaunchConfig(cfg *config.CloudConfig, dockerCfg *config.DockerConfig) (*dockerlaunch.Config, []string) {
  133. var launchConfig dockerlaunch.Config
  134. args := dockerlaunch.ParseConfig(&launchConfig, dockerCfg.FullArgs()...)
  135. launchConfig.DnsConfig.Nameservers = cfg.Rancher.Defaults.Network.Dns.Nameservers
  136. launchConfig.DnsConfig.Search = cfg.Rancher.Defaults.Network.Dns.Search
  137. launchConfig.Environment = dockerCfg.Environment
  138. if !cfg.Rancher.Debug {
  139. launchConfig.LogFile = config.SYSTEM_DOCKER_LOG
  140. }
  141. return &launchConfig, args
  142. }
  143. func isInitrd() bool {
  144. var stat syscall.Statfs_t
  145. syscall.Statfs("/", &stat)
  146. return int64(stat.Type) == TMPFS_MAGIC || int64(stat.Type) == RAMFS_MAGIC
  147. }
  148. func setupSharedRoot(c *config.CloudConfig) (*config.CloudConfig, error) {
  149. if c.Rancher.NoSharedRoot {
  150. return c, nil
  151. }
  152. if isInitrd() {
  153. for _, i := range []string{"/mnt", "/media", "/var/lib/system-docker"} {
  154. if err := os.MkdirAll(i, 0755); err != nil {
  155. return c, err
  156. }
  157. if err := mount.Mount("tmpfs", i, "tmpfs", "rw"); err != nil {
  158. return c, err
  159. }
  160. if err := mount.MakeShared(i); err != nil {
  161. return c, err
  162. }
  163. }
  164. return c, nil
  165. }
  166. return c, mount.MakeShared("/")
  167. }
  168. func RunInit() error {
  169. os.Setenv("PATH", "/sbin:/usr/sbin:/usr/bin")
  170. if isInitrd() {
  171. log.Debug("Booting off an in-memory filesystem")
  172. // Magic setting to tell Docker to do switch_root and not pivot_root
  173. os.Setenv("DOCKER_RAMDISK", "true")
  174. } else {
  175. log.Debug("Booting off a persistent filesystem")
  176. }
  177. boot2DockerEnvironment := false
  178. initFuncs := []config.CfgFunc{
  179. func(c *config.CloudConfig) (*config.CloudConfig, error) {
  180. return c, dockerlaunch.PrepareFs(&mountConfig)
  181. },
  182. mountOem,
  183. func(_ *config.CloudConfig) (*config.CloudConfig, error) {
  184. cfg := config.LoadConfig()
  185. if cfg.Rancher.Debug {
  186. cfgString, err := config.Export(false, true)
  187. if err != nil {
  188. log.WithFields(log.Fields{"err": err}).Error("Error serializing config")
  189. } else {
  190. log.Debugf("Config: %s", cfgString)
  191. }
  192. }
  193. return cfg, nil
  194. },
  195. loadModules,
  196. func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  197. if util.ResolveDevice("LABEL=B2D_STATE") != "" {
  198. boot2DockerEnvironment = true
  199. cfg.Rancher.State.Dev = "LABEL=B2D_STATE"
  200. return cfg, nil
  201. }
  202. devices := []string{"/dev/sda", "/dev/vda"}
  203. data := make([]byte, len(BOOT2DOCKER_MAGIC))
  204. for _, device := range devices {
  205. f, err := os.Open(device)
  206. if err == nil {
  207. defer f.Close()
  208. _, err = f.Read(data)
  209. if err == nil && string(data) == BOOT2DOCKER_MAGIC {
  210. boot2DockerEnvironment = true
  211. cfg.Rancher.State.Dev = "LABEL=B2D_STATE"
  212. cfg.Rancher.State.Autoformat = []string{device}
  213. break
  214. }
  215. }
  216. }
  217. return cfg, nil
  218. },
  219. tryMountAndBootstrap,
  220. func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  221. if boot2DockerEnvironment {
  222. if err := config.Set("rancher.state.dev", cfg.Rancher.State.Dev); err != nil {
  223. log.Errorf("Failed to update rancher.state.dev: %v", err)
  224. }
  225. if err := config.Set("rancher.state.autoformat", cfg.Rancher.State.Autoformat); err != nil {
  226. log.Errorf("Failed to update rancher.state.autoformat: %v", err)
  227. }
  228. }
  229. return config.LoadConfig(), nil
  230. },
  231. loadModules,
  232. func(c *config.CloudConfig) (*config.CloudConfig, error) {
  233. return c, dockerlaunch.PrepareFs(&mountConfig)
  234. },
  235. func(c *config.CloudConfig) (*config.CloudConfig, error) {
  236. network.SetProxyEnvironmentVariables(c)
  237. return c, nil
  238. },
  239. initializeSelinux,
  240. setupSharedRoot,
  241. sysInit,
  242. }
  243. cfg, err := config.ChainCfgFuncs(nil, initFuncs...)
  244. if err != nil {
  245. return err
  246. }
  247. launchConfig, args := getLaunchConfig(cfg, &cfg.Rancher.SystemDocker)
  248. launchConfig.Fork = !cfg.Rancher.SystemDocker.Exec
  249. log.Info("Launching System Docker")
  250. _, err = dockerlaunch.LaunchDocker(launchConfig, config.SYSTEM_DOCKER_BIN, args...)
  251. if err != nil {
  252. return err
  253. }
  254. return pidOne()
  255. }