sysinit.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package sysinit
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "os/exec"
  7. "path"
  8. "path/filepath"
  9. "strings"
  10. "syscall"
  11. "github.com/rancher/os/cmd/control"
  12. "github.com/rancher/os/config"
  13. "github.com/rancher/os/pkg/compose"
  14. "github.com/rancher/os/pkg/docker"
  15. "github.com/rancher/os/pkg/log"
  16. "github.com/docker/engine-api/types"
  17. "github.com/docker/libcompose/project/options"
  18. "golang.org/x/net/context"
  19. )
  20. const (
  21. systemImagesPreloadDirectory = "/var/lib/rancher/preload/system-docker"
  22. systemImagesLoadStamp = "/var/lib/rancher/.sysimages_%s_loaded.done"
  23. )
  24. func hasImage(name string) bool {
  25. stamp := path.Join(config.StateDir, name)
  26. if _, err := os.Stat(stamp); os.IsNotExist(err) {
  27. return false
  28. }
  29. return true
  30. }
  31. func getImagesArchive(bootstrap bool) string {
  32. var archive string
  33. if bootstrap {
  34. archive = path.Join(config.ImagesPath, config.InitImages)
  35. } else {
  36. archive = path.Join(config.ImagesPath, config.SystemImages)
  37. }
  38. return archive
  39. }
  40. func LoadBootstrapImages(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  41. return loadImages(cfg, true)
  42. }
  43. func LoadSystemImages(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  44. stamp := fmt.Sprintf(systemImagesLoadStamp, strings.Replace(config.Version, ".", "_", -1))
  45. if _, err := os.Stat(stamp); os.IsNotExist(err) {
  46. os.Create(stamp)
  47. return loadImages(cfg, false)
  48. }
  49. log.Infof("Skipped loading system images because %s exists", systemImagesLoadStamp)
  50. return cfg, nil
  51. }
  52. func loadImages(cfg *config.CloudConfig, bootstrap bool) (*config.CloudConfig, error) {
  53. archive := getImagesArchive(bootstrap)
  54. client, err := docker.NewSystemClient()
  55. if err != nil {
  56. return cfg, err
  57. }
  58. if !hasImage(filepath.Base(archive)) {
  59. if _, err := os.Stat(archive); os.IsNotExist(err) {
  60. log.Fatalf("FATAL: Could not load images from %s (file not found)", archive)
  61. }
  62. // client.ImageLoad is an asynchronous operation
  63. // To ensure the order of execution, use cmd instead of it
  64. log.Infof("Loading images from %s", archive)
  65. cmd := exec.Command("/usr/bin/system-docker", "load", "-q", "-i", archive)
  66. if out, err := cmd.CombinedOutput(); err != nil {
  67. log.Fatalf("FATAL: Error loading images from %s (%v)\n%s ", archive, err, out)
  68. }
  69. log.Infof("Done loading images from %s", archive)
  70. }
  71. dockerImages, _ := client.ImageList(context.Background(), types.ImageListOptions{})
  72. for _, dimg := range dockerImages {
  73. log.Debugf("Loaded a docker image: %s", dimg.RepoTags)
  74. }
  75. return cfg, nil
  76. }
  77. func SysInit() error {
  78. cfg := config.LoadConfig()
  79. if err := control.PreloadImages(docker.NewSystemClient, systemImagesPreloadDirectory); err != nil {
  80. log.Errorf("Failed to preload System Docker images: %v", err)
  81. }
  82. _, err := config.ChainCfgFuncs(cfg,
  83. config.CfgFuncs{
  84. {"loadSystemImages", LoadSystemImages},
  85. {"start project", func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  86. p, err := compose.GetProject(cfg, false, true)
  87. if err != nil {
  88. return cfg, err
  89. }
  90. return cfg, p.Up(context.Background(), options.Up{
  91. Create: options.Create{
  92. NoRecreate: true,
  93. },
  94. Log: cfg.Rancher.Log,
  95. })
  96. }},
  97. {"sync", func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  98. syscall.Sync()
  99. return cfg, nil
  100. }},
  101. {"banner", func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
  102. log.Infof("RancherOS %s started", config.Version)
  103. return cfg, nil
  104. }}})
  105. return err
  106. }
  107. func loadServicesCache() {
  108. // this code make sure the open-vm-tools, modem-manager... services can be started correct when there is no network
  109. // make sure the cache directory exist
  110. if err := os.MkdirAll("/var/lib/rancher/cache/", os.ModeDir|0755); err != nil {
  111. log.Errorf("Create service cache diretory error: %v", err)
  112. }
  113. // move os-services cache file
  114. if _, err := os.Stat("/usr/share/ros/services-cache"); err == nil {
  115. files, err := ioutil.ReadDir("/usr/share/ros/services-cache/")
  116. if err != nil {
  117. log.Errorf("Read file error: %v", err)
  118. }
  119. for _, f := range files {
  120. err := os.Rename("/usr/share/ros/services-cache/"+f.Name(), "/var/lib/rancher/cache/"+f.Name())
  121. if err != nil {
  122. log.Errorf("Rename file error: %v", err)
  123. }
  124. }
  125. if err := os.Remove("/usr/share/ros/services-cache"); err != nil {
  126. log.Errorf("Remove file error: %v", err)
  127. }
  128. }
  129. }
  130. func RunSysInit(c *config.CloudConfig) (*config.CloudConfig, error) {
  131. loadServicesCache()
  132. args := append([]string{config.SysInitBin}, os.Args[1:]...)
  133. cmd := &exec.Cmd{
  134. Path: config.RosBin,
  135. Args: args,
  136. }
  137. cmd.Stdin = os.Stdin
  138. cmd.Stderr = os.Stderr
  139. cmd.Stdout = os.Stdout
  140. if err := cmd.Start(); err != nil {
  141. return c, err
  142. }
  143. return c, os.Stdin.Close()
  144. }