1
0
mirror of https://github.com/rancher/os.git synced 2025-04-28 19:34:45 +00:00
os/pkg/sysinit/sysinit.go
2018-12-12 11:28:45 +08:00

172 lines
4.6 KiB
Go

package sysinit
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"syscall"
"github.com/rancher/os/cmd/control"
"github.com/rancher/os/config"
"github.com/rancher/os/pkg/compose"
"github.com/rancher/os/pkg/docker"
"github.com/rancher/os/pkg/log"
"github.com/docker/engine-api/types"
"github.com/docker/libcompose/project/options"
"golang.org/x/net/context"
)
const (
systemImagesPreloadDirectory = "/var/lib/rancher/preload/system-docker"
systemImagesLoadStamp = "/var/lib/rancher/.sysimages_%s_loaded.done"
)
func hasImage(name string) bool {
stamp := path.Join(config.StateDir, name)
if _, err := os.Stat(stamp); os.IsNotExist(err) {
return false
}
return true
}
func getImagesArchive(bootstrap bool) string {
var archive string
if bootstrap {
archive = path.Join(config.ImagesPath, config.InitImages)
} else {
archive = path.Join(config.ImagesPath, config.SystemImages)
}
return archive
}
func LoadBootstrapImages(cfg *config.CloudConfig) (*config.CloudConfig, error) {
return loadImages(cfg, true)
}
func LoadSystemImages(cfg *config.CloudConfig) (*config.CloudConfig, error) {
stamp := fmt.Sprintf(systemImagesLoadStamp, strings.Replace(config.Version, ".", "_", -1))
if _, err := os.Stat(stamp); os.IsNotExist(err) {
os.Create(stamp)
return loadImages(cfg, false)
}
log.Infof("Skipped loading system images because %s exists", systemImagesLoadStamp)
return cfg, nil
}
func loadImages(cfg *config.CloudConfig, bootstrap bool) (*config.CloudConfig, error) {
archive := getImagesArchive(bootstrap)
client, err := docker.NewSystemClient()
if err != nil {
return cfg, err
}
if !hasImage(filepath.Base(archive)) {
if _, err := os.Stat(archive); os.IsNotExist(err) {
log.Fatalf("FATAL: Could not load images from %s (file not found)", archive)
}
// client.ImageLoad is an asynchronous operation
// To ensure the order of execution, use cmd instead of it
log.Infof("Loading images from %s", archive)
cmd := exec.Command("/usr/bin/system-docker", "load", "-q", "-i", archive)
if out, err := cmd.CombinedOutput(); err != nil {
log.Fatalf("FATAL: Error loading images from %s (%v)\n%s ", archive, err, out)
}
log.Infof("Done loading images from %s", archive)
}
dockerImages, _ := client.ImageList(context.Background(), types.ImageListOptions{})
for _, dimg := range dockerImages {
log.Debugf("Loaded a docker image: %s", dimg.RepoTags)
}
return cfg, nil
}
func SysInit() error {
cfg := config.LoadConfig()
if err := control.PreloadImages(docker.NewSystemClient, systemImagesPreloadDirectory); err != nil {
log.Errorf("Failed to preload System Docker images: %v", err)
}
_, err := config.ChainCfgFuncs(cfg,
config.CfgFuncs{
{"loadSystemImages", LoadSystemImages},
{"start project", func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
p, err := compose.GetProject(cfg, false, true)
if err != nil {
return cfg, err
}
return cfg, p.Up(context.Background(), options.Up{
Create: options.Create{
NoRecreate: true,
},
Log: cfg.Rancher.Log,
})
}},
{"sync", func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
syscall.Sync()
return cfg, nil
}},
{"banner", func(cfg *config.CloudConfig) (*config.CloudConfig, error) {
log.Infof("RancherOS %s started", config.Version)
return cfg, nil
}}})
return err
}
func loadServicesCache() {
// this code make sure the open-vm-tools, modem-manager... services can be started correct when there is no network
// make sure the cache directory exist
if err := os.MkdirAll("/var/lib/rancher/cache/", os.ModeDir|0755); err != nil {
log.Errorf("Create service cache diretory error: %v", err)
}
// move os-services cache file
if _, err := os.Stat("/usr/share/ros/services-cache"); err == nil {
files, err := ioutil.ReadDir("/usr/share/ros/services-cache/")
if err != nil {
log.Errorf("Read file error: %v", err)
}
for _, f := range files {
err := os.Rename("/usr/share/ros/services-cache/"+f.Name(), "/var/lib/rancher/cache/"+f.Name())
if err != nil {
log.Errorf("Rename file error: %v", err)
}
}
if err := os.Remove("/usr/share/ros/services-cache"); err != nil {
log.Errorf("Remove file error: %v", err)
}
}
}
func RunSysInit(c *config.CloudConfig) (*config.CloudConfig, error) {
loadServicesCache()
args := append([]string{config.SysInitBin}, os.Args[1:]...)
cmd := &exec.Cmd{
Path: config.RosBin,
Args: args,
}
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
if err := cmd.Start(); err != nil {
return c, err
}
return c, os.Stdin.Close()
}