init.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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/rancher/docker-from-scratch"
  12. "github.com/rancher/os/config"
  13. "github.com/rancher/os/util"
  14. )
  15. const (
  16. STATE string = "/state"
  17. TMPFS_MAGIC int64 = 0x01021994
  18. RAMFS_MAGIC int64 = 0x858458f6
  19. )
  20. var (
  21. mountConfig = dockerlaunch.Config{
  22. CgroupHierarchy: map[string]string{
  23. "cpu": "cpu",
  24. "cpuacct": "cpu",
  25. "net_cls": "net_cls",
  26. "net_prio": "net_cls",
  27. },
  28. }
  29. )
  30. func loadModules(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  31. mounted := map[string]bool{}
  32. f, err := os.Open("/proc/modules")
  33. if err != nil {
  34. return cfg, err
  35. }
  36. defer f.Close()
  37. reader := bufio.NewScanner(f)
  38. for reader.Scan() {
  39. mounted[strings.SplitN(reader.Text(), " ", 2)[0]] = true
  40. }
  41. for _, module := range cfg.Rancher.Modules {
  42. if mounted[module] {
  43. continue
  44. }
  45. log.Debugf("Loading module %s", module)
  46. if err := exec.Command("modprobe", module).Run(); err != nil {
  47. log.Errorf("Could not load module %s, err %v", module, err)
  48. }
  49. }
  50. return cfg, nil
  51. }
  52. func sysInit(c *config.CloudConfig) (*config.CloudConfig, error) {
  53. args := append([]string{config.SYSINIT_BIN}, os.Args[1:]...)
  54. cmd := &exec.Cmd{
  55. Path: config.ROS_BIN,
  56. Args: args,
  57. }
  58. cmd.Stdin = os.Stdin
  59. cmd.Stderr = os.Stderr
  60. cmd.Stdout = os.Stdout
  61. if err := cmd.Start(); err != nil {
  62. return c, err
  63. }
  64. return c, os.Stdin.Close()
  65. }
  66. func MainInit() {
  67. if err := RunInit(); err != nil {
  68. log.Fatal(err)
  69. }
  70. }
  71. func mountConfigured(display, dev, fsType, target string) error {
  72. var err error
  73. if dev == "" {
  74. return nil
  75. }
  76. dev = util.ResolveDevice(dev)
  77. if dev == "" {
  78. return fmt.Errorf("Could not resolve device %q", dev)
  79. }
  80. if fsType == "auto" {
  81. fsType, err = util.GetFsType(dev)
  82. }
  83. if err != nil {
  84. return err
  85. }
  86. log.Debugf("FsType has been set to %s", fsType)
  87. log.Infof("Mounting %s device %s to %s", display, dev, target)
  88. return util.Mount(dev, target, fsType, "")
  89. }
  90. func mountState(cfg *config.CloudConfig) error {
  91. return mountConfigured("state", cfg.Rancher.State.Dev, cfg.Rancher.State.FsType, STATE)
  92. }
  93. func mountOem(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  94. if cfg == nil {
  95. cfg = config.LoadConfig()
  96. }
  97. if err := mountConfigured("oem", cfg.Rancher.State.OemDev, cfg.Rancher.State.OemFsType, config.OEM); err != nil {
  98. log.Debugf("Not mounting OEM: %v", err)
  99. } else {
  100. log.Infof("Mounted OEM: %s", cfg.Rancher.State.OemDev)
  101. }
  102. return cfg, nil
  103. }
  104. func tryMountState(cfg *config.CloudConfig) error {
  105. if mountState(cfg) == nil {
  106. return nil
  107. }
  108. // If we failed to mount lets run bootstrap and try again
  109. if err := bootstrap(cfg); err != nil {
  110. return err
  111. }
  112. return mountState(cfg)
  113. }
  114. func tryMountAndBootstrap(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  115. if isInitrd() {
  116. if err := tryMountState(cfg); !cfg.Rancher.State.Required && err != nil {
  117. return cfg, nil
  118. } else if err != nil {
  119. return cfg, err
  120. }
  121. log.Debugf("Switching to new root at %s %s", STATE, cfg.Rancher.State.Directory)
  122. if err := switchRoot(STATE, cfg.Rancher.State.Directory, cfg.Rancher.RmUsr); err != nil {
  123. return cfg, err
  124. }
  125. }
  126. return mountOem(cfg)
  127. }
  128. func getLaunchConfig(cfg *config.CloudConfig, dockerCfg *config.DockerConfig) (*dockerlaunch.Config, []string) {
  129. var launchConfig dockerlaunch.Config
  130. args := dockerlaunch.ParseConfig(&launchConfig, append(dockerCfg.Args, dockerCfg.ExtraArgs...)...)
  131. launchConfig.DnsConfig.Nameservers = cfg.Rancher.Defaults.Network.Dns.Nameservers
  132. launchConfig.DnsConfig.Search = cfg.Rancher.Defaults.Network.Dns.Search
  133. launchConfig.Environment = dockerCfg.Environment
  134. launchConfig.EmulateSystemd = true
  135. if !cfg.Rancher.Debug {
  136. launchConfig.LogFile = config.SYSTEM_DOCKER_LOG
  137. }
  138. return &launchConfig, args
  139. }
  140. func isInitrd() bool {
  141. var stat syscall.Statfs_t
  142. syscall.Statfs("/", &stat)
  143. return int64(stat.Type) == TMPFS_MAGIC || int64(stat.Type) == RAMFS_MAGIC
  144. }
  145. func RunInit() error {
  146. os.Setenv("PATH", "/sbin:/usr/sbin:/usr/bin")
  147. if isInitrd() {
  148. log.Debug("Booting off an in-memory filesystem")
  149. // Magic setting to tell Docker to do switch_root and not pivot_root
  150. os.Setenv("DOCKER_RAMDISK", "true")
  151. } else {
  152. log.Debug("Booting off a persistent filesystem")
  153. }
  154. initFuncs := []config.CfgFunc{
  155. func(c *config.CloudConfig) (*config.CloudConfig, error) {
  156. return c, dockerlaunch.PrepareFs(&mountConfig)
  157. },
  158. mountOem,
  159. func(_ *config.CloudConfig) (*config.CloudConfig, error) {
  160. cfg := config.LoadConfig()
  161. if cfg.Rancher.Debug {
  162. cfgString, err := config.Export(false, true)
  163. if err != nil {
  164. log.WithFields(log.Fields{"err": err}).Error("Error serializing config")
  165. } else {
  166. log.Debugf("Config: %s", cfgString)
  167. }
  168. }
  169. return cfg, nil
  170. },
  171. loadModules,
  172. tryMountAndBootstrap,
  173. func(_ *config.CloudConfig) (*config.CloudConfig, error) {
  174. return config.LoadConfig(), nil
  175. },
  176. loadModules,
  177. func(c *config.CloudConfig) (*config.CloudConfig, error) {
  178. return c, dockerlaunch.PrepareFs(&mountConfig)
  179. },
  180. initializeSelinux,
  181. sysInit,
  182. }
  183. cfg, err := config.ChainCfgFuncs(nil, initFuncs...)
  184. if err != nil {
  185. return err
  186. }
  187. launchConfig, args := getLaunchConfig(cfg, &cfg.Rancher.SystemDocker)
  188. launchConfig.Fork = !cfg.Rancher.SystemDocker.Exec
  189. log.Info("Launching System Docker")
  190. _, err = dockerlaunch.LaunchDocker(launchConfig, config.SYSTEM_DOCKER_BIN, args...)
  191. if err != nil {
  192. return err
  193. }
  194. return pidOne()
  195. }