mirror of
https://github.com/rancher/os.git
synced 2025-07-16 08:05:51 +00:00
Add bootstrap phase to handle udev and auto-format
This commit is contained in:
parent
0e77cde9c0
commit
91dd56e595
@ -1,225 +1,12 @@
|
||||
package sysinit
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"syscall"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
dockerClient "github.com/fsouza/go-dockerclient"
|
||||
"github.com/rancherio/os/config"
|
||||
"github.com/rancherio/os/docker"
|
||||
initPkg "github.com/rancherio/os/init"
|
||||
"github.com/rancherio/os/util"
|
||||
)
|
||||
|
||||
func Main() {
|
||||
if err := sysInit(); err != nil {
|
||||
if err := initPkg.SysInit(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func importImage(client *dockerClient.Client, name, fileName string) error {
|
||||
file, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
log.Debugf("Importing image for %s", fileName)
|
||||
repo, tag := dockerClient.ParseRepositoryTag(name)
|
||||
return client.ImportImage(dockerClient.ImportImageOptions{
|
||||
Source: "-",
|
||||
Repository: repo,
|
||||
Tag: tag,
|
||||
InputStream: file,
|
||||
})
|
||||
}
|
||||
|
||||
func hasImage(name string) bool {
|
||||
stamp := path.Join(initPkg.STATE, name)
|
||||
if _, err := os.Stat(stamp); os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func findImages(cfg *config.Config) ([]string, error) {
|
||||
log.Debugf("Looking for images at %s", config.IMAGES_PATH)
|
||||
|
||||
result := []string{}
|
||||
|
||||
dir, err := os.Open(config.IMAGES_PATH)
|
||||
if os.IsNotExist(err) {
|
||||
log.Debugf("Not loading images, %s does not exist")
|
||||
return result, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer dir.Close()
|
||||
|
||||
files, err := dir.Readdirnames(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, fileName := range files {
|
||||
if ok, _ := path.Match(config.IMAGES_PATTERN, fileName); ok {
|
||||
log.Debugf("Found %s", fileName)
|
||||
result = append(result, fileName)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func loadImages(cfg *config.Config) error {
|
||||
images, err := findImages(cfg)
|
||||
if err != nil || len(images) == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := docker.NewSystemClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, image := range images {
|
||||
if hasImage(image) {
|
||||
continue
|
||||
}
|
||||
|
||||
inputFileName := path.Join(config.IMAGES_PATH, image)
|
||||
input, err := os.Open(inputFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer input.Close()
|
||||
|
||||
log.Infof("Loading images from %s", inputFileName)
|
||||
err = client.LoadImage(dockerClient.LoadImageOptions{
|
||||
InputStream: input,
|
||||
})
|
||||
log.Infof("Done loading images from %s", inputFileName)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runContainersFrom(startFrom string, cfg *config.Config, containerConfigs []config.ContainerConfig) error {
|
||||
foundStart := false
|
||||
|
||||
for i, containerConfig := range containerConfigs {
|
||||
container := docker.NewContainer(config.DOCKER_SYSTEM_HOST, &containerConfig)
|
||||
|
||||
if util.Contains(cfg.Disable, containerConfig.Id) {
|
||||
log.Infof("%s is disabled : %v", containerConfig.Id, cfg.Disable)
|
||||
continue
|
||||
}
|
||||
|
||||
//if containerConfig.Id == config.CONSOLE_CONTAINER {
|
||||
// if util.IsRunningInTty() {
|
||||
// container.Config.Tty = true
|
||||
// container.Config.AttachStdin = true
|
||||
// container.Config.AttachStdout = true
|
||||
// container.Config.AttachStderr = true
|
||||
// }
|
||||
//}
|
||||
|
||||
if foundStart || startFrom == "" {
|
||||
log.Infof("Running [%d/%d] %s", i+1, len(containerConfigs), containerConfig.Id)
|
||||
container.StartAndWait()
|
||||
|
||||
if container.Err != nil {
|
||||
log.Errorf("Failed to run %v: %v", containerConfig.Id, container.Err)
|
||||
}
|
||||
|
||||
if containerConfig.ReloadConfig {
|
||||
log.Info("Reloading configuration")
|
||||
err := cfg.Reload()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return runContainersFrom(containerConfig.Id, cfg, cfg.SystemContainers)
|
||||
}
|
||||
} else if startFrom == containerConfig.Id {
|
||||
foundStart = true
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runContainers(cfg *config.Config) error {
|
||||
containerConfigs := cfg.SystemContainers
|
||||
if cfg.Rescue {
|
||||
log.Debug("Running rescue container")
|
||||
containerConfigs = []config.ContainerConfig{*cfg.RescueContainer}
|
||||
}
|
||||
|
||||
return runContainersFrom("", cfg, containerConfigs)
|
||||
}
|
||||
|
||||
func tailConsole(cfg *config.Config) error {
|
||||
if !cfg.Console.Tail {
|
||||
return nil
|
||||
}
|
||||
|
||||
client, err := docker.NewSystemClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, container := range cfg.SystemContainers {
|
||||
if container.Id != config.CONSOLE_CONTAINER {
|
||||
continue
|
||||
}
|
||||
|
||||
c := docker.NewContainer(config.DOCKER_SYSTEM_HOST, &container).Lookup()
|
||||
if c.Err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Infof("Tailing console : %s", c.Name)
|
||||
return client.Logs(dockerClient.LogsOptions{
|
||||
Container: c.Name,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
Follow: true,
|
||||
OutputStream: os.Stdout,
|
||||
ErrorStream: os.Stderr,
|
||||
})
|
||||
}
|
||||
|
||||
log.Error("Console not found")
|
||||
return nil
|
||||
}
|
||||
|
||||
func sysInit() error {
|
||||
cfg, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
initFuncs := []config.InitFunc{
|
||||
loadImages,
|
||||
runContainers,
|
||||
func(cfg *config.Config) error {
|
||||
syscall.Sync()
|
||||
return nil
|
||||
},
|
||||
tailConsole,
|
||||
}
|
||||
|
||||
return config.RunInitFuncs(cfg, initFuncs)
|
||||
}
|
||||
|
129
init/bootstrap.go
Normal file
129
init/bootstrap.go
Normal file
@ -0,0 +1,129 @@
|
||||
package init
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/rancherio/os/config"
|
||||
"github.com/rancherio/os/util"
|
||||
)
|
||||
|
||||
func runBootstrapContainers(cfg *config.Config) error {
|
||||
if len(cfg.State.Autoformat) == 0 || util.ResolveDevice(cfg.State.Dev) != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var format string
|
||||
|
||||
outer:
|
||||
for _, dev := range cfg.State.Autoformat {
|
||||
log.Infof("Checking %s to auto-format", dev)
|
||||
if _, err := os.Stat(dev); os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
f, err := os.Open(dev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
buffer := make([]byte, 1048576, 1048576)
|
||||
c, err := f.Read(buffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c != 1048576 {
|
||||
log.Infof("%s not right size", dev)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, b := range buffer {
|
||||
if b != 0 {
|
||||
log.Infof("%s not empty", dev)
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
|
||||
format = dev
|
||||
break
|
||||
}
|
||||
|
||||
if format != "" {
|
||||
log.Infof("Auto formatting : %s", format)
|
||||
return runContainersFrom("", cfg, append([]config.ContainerConfig{
|
||||
{
|
||||
Id: "auto-format",
|
||||
Cmd: "--name auto-format " +
|
||||
"--rm " +
|
||||
"--net=none " +
|
||||
"--privileged " +
|
||||
"autoformat " +
|
||||
format,
|
||||
},
|
||||
}, cfg.BootstrapContainers...))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoformat(cfg *config.Config) error {
|
||||
return runContainersFrom("", cfg, cfg.BootstrapContainers)
|
||||
}
|
||||
|
||||
func startDocker(cfg *config.Config) (chan interface{}, error) {
|
||||
for _, d := range []string{config.DOCKER_SYSTEM_HOST, "/var/run"} {
|
||||
err := os.MkdirAll(d, 0700)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command(cfg.SystemDocker.Args[0], cfg.SystemDocker.Args[1:]...)
|
||||
if cfg.Debug {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := make(chan interface{})
|
||||
go func() {
|
||||
<-c
|
||||
cmd.Process.Signal(syscall.SIGTERM)
|
||||
cmd.Wait()
|
||||
c <- struct{}{}
|
||||
}()
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func stopDocker(c chan interface{}) error {
|
||||
c <- struct{}{}
|
||||
<-c
|
||||
|
||||
return os.RemoveAll(config.DOCKER_SYSTEM_HOME)
|
||||
}
|
||||
|
||||
func bootstrap(cfg *config.Config) error {
|
||||
log.Info("Starting bootstrap")
|
||||
c, err := startDocker(cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
initFuncs := []config.InitFunc{
|
||||
loadImages,
|
||||
runBootstrapContainers,
|
||||
autoformat,
|
||||
}
|
||||
|
||||
defer stopDocker(c)
|
||||
|
||||
return config.RunInitFuncs(cfg, initFuncs)
|
||||
}
|
44
init/init.go
44
init/init.go
@ -27,6 +27,9 @@ var (
|
||||
}
|
||||
postDirs []string = []string{
|
||||
"/var/log",
|
||||
"/var/lib/rancher/state/docker",
|
||||
"/var/lib/rancher/state/home",
|
||||
"/var/lib/rancher/state/opt",
|
||||
}
|
||||
mounts [][]string = [][]string{
|
||||
[]string{"devtmpfs", "/dev", "devtmpfs", ""},
|
||||
@ -58,10 +61,15 @@ var (
|
||||
"/sbin/modprobe": "/busybox",
|
||||
DOCKER: "/docker",
|
||||
SYSINIT: "/init",
|
||||
"/home": "/var/lib/rancher/state/home",
|
||||
"/opt": "/var/lib/rancher/state/opt",
|
||||
}
|
||||
postSymlinks map[string]string = map[string]string{
|
||||
"/var/lib/docker": "/var/lib/rancher/state/docker",
|
||||
}
|
||||
)
|
||||
|
||||
func createSymlinks(cfg *config.Config) error {
|
||||
func createSymlinks(cfg *config.Config, symlinks map[string]string) error {
|
||||
log.Debug("Creating symlinking")
|
||||
for dest, src := range symlinks {
|
||||
if _, err := os.Stat(dest); os.IsNotExist(err) {
|
||||
@ -146,13 +154,28 @@ func setResolvConf(cfg *config.Config) error {
|
||||
|
||||
defer f.Close()
|
||||
|
||||
for _, dns := range cfg.Dns {
|
||||
for _, dns := range cfg.Network.Dns.Nameservers {
|
||||
content := fmt.Sprintf("nameserver %s\n", dns)
|
||||
if _, err = f.Write([]byte(content)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
search := strings.Join(cfg.Network.Dns.Search, " ")
|
||||
if search != "" {
|
||||
content := fmt.Sprintf("search %s\n", search)
|
||||
if _, err = f.Write([]byte(content)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.Network.Dns.Domain != "" {
|
||||
content := fmt.Sprintf("domain %s\n", cfg.Network.Dns.Domain)
|
||||
if _, err = f.Write([]byte(content)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -214,7 +237,7 @@ func execDocker(cfg *config.Config) error {
|
||||
}
|
||||
|
||||
os.Stdin.Close()
|
||||
return syscall.Exec(DOCKER, cfg.SystemDockerArgs, os.Environ())
|
||||
return syscall.Exec(DOCKER, cfg.SystemDocker.Args, os.Environ())
|
||||
}
|
||||
|
||||
func MainInit() {
|
||||
@ -286,19 +309,26 @@ func RunInit() error {
|
||||
return err
|
||||
},
|
||||
mountCgroups,
|
||||
setResolvConf,
|
||||
createSymlinks,
|
||||
func(cfg *config.Config) error {
|
||||
return createSymlinks(cfg, symlinks)
|
||||
},
|
||||
extractModules,
|
||||
loadModules,
|
||||
setResolvConf,
|
||||
bootstrap,
|
||||
mountState,
|
||||
func(cfg *config.Config) error {
|
||||
return cfg.Reload()
|
||||
},
|
||||
setResolvConf,
|
||||
func(cfg *config.Config) error {
|
||||
return createDirs(postDirs...)
|
||||
},
|
||||
func(cfg *config.Config) error {
|
||||
return createMounts(postMounts...)
|
||||
return createSymlinks(cfg, postSymlinks)
|
||||
},
|
||||
func(cfg *config.Config) error {
|
||||
return cfg.Reload()
|
||||
return createMounts(postMounts...)
|
||||
},
|
||||
remountRo,
|
||||
sysInit,
|
||||
|
202
init/sysinit.go
Normal file
202
init/sysinit.go
Normal file
@ -0,0 +1,202 @@
|
||||
package init
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"syscall"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
dockerClient "github.com/fsouza/go-dockerclient"
|
||||
"github.com/rancherio/os/config"
|
||||
"github.com/rancherio/os/docker"
|
||||
"github.com/rancherio/os/util"
|
||||
)
|
||||
|
||||
func importImage(client *dockerClient.Client, name, fileName string) error {
|
||||
file, err := os.Open(fileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
log.Debugf("Importing image for %s", fileName)
|
||||
repo, tag := dockerClient.ParseRepositoryTag(name)
|
||||
return client.ImportImage(dockerClient.ImportImageOptions{
|
||||
Source: "-",
|
||||
Repository: repo,
|
||||
Tag: tag,
|
||||
InputStream: file,
|
||||
})
|
||||
}
|
||||
|
||||
func hasImage(name string) bool {
|
||||
stamp := path.Join(STATE, name)
|
||||
if _, err := os.Stat(stamp); os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func findImages(cfg *config.Config) ([]string, error) {
|
||||
log.Debugf("Looking for images at %s", config.IMAGES_PATH)
|
||||
|
||||
result := []string{}
|
||||
|
||||
dir, err := os.Open(config.IMAGES_PATH)
|
||||
if os.IsNotExist(err) {
|
||||
log.Debugf("Not loading images, %s does not exist")
|
||||
return result, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer dir.Close()
|
||||
|
||||
files, err := dir.Readdirnames(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, fileName := range files {
|
||||
if ok, _ := path.Match(config.IMAGES_PATTERN, fileName); ok {
|
||||
log.Debugf("Found %s", fileName)
|
||||
result = append(result, fileName)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func loadImages(cfg *config.Config) error {
|
||||
images, err := findImages(cfg)
|
||||
if err != nil || len(images) == 0 {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := docker.NewSystemClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, image := range images {
|
||||
if hasImage(image) {
|
||||
continue
|
||||
}
|
||||
|
||||
inputFileName := path.Join(config.IMAGES_PATH, image)
|
||||
input, err := os.Open(inputFileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer input.Close()
|
||||
|
||||
log.Infof("Loading images from %s", inputFileName)
|
||||
err = client.LoadImage(dockerClient.LoadImageOptions{
|
||||
InputStream: input,
|
||||
})
|
||||
log.Infof("Done loading images from %s", inputFileName)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runContainersFrom(startFrom string, cfg *config.Config, containerConfigs []config.ContainerConfig) error {
|
||||
foundStart := false
|
||||
|
||||
for i, containerConfig := range containerConfigs {
|
||||
container := docker.NewContainer(config.DOCKER_SYSTEM_HOST, &containerConfig)
|
||||
|
||||
if util.Contains(cfg.Disable, containerConfig.Id) {
|
||||
log.Infof("%s is disabled : %v", containerConfig.Id, cfg.Disable)
|
||||
continue
|
||||
}
|
||||
|
||||
if foundStart || startFrom == "" {
|
||||
log.Infof("Running [%d/%d] %s", i+1, len(containerConfigs), containerConfig.Id)
|
||||
container.StartAndWait()
|
||||
|
||||
if container.Err != nil {
|
||||
log.Errorf("Failed to run %v: %v", containerConfig.Id, container.Err)
|
||||
}
|
||||
|
||||
if containerConfig.ReloadConfig {
|
||||
log.Info("Reloading configuration")
|
||||
err := cfg.Reload()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return runContainersFrom(containerConfig.Id, cfg, cfg.SystemContainers)
|
||||
}
|
||||
} else if startFrom == containerConfig.Id {
|
||||
foundStart = true
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runContainers(cfg *config.Config) error {
|
||||
return runContainersFrom("", cfg, cfg.SystemContainers)
|
||||
}
|
||||
|
||||
func tailConsole(cfg *config.Config) error {
|
||||
if !cfg.Console.Tail {
|
||||
return nil
|
||||
}
|
||||
|
||||
client, err := docker.NewSystemClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, container := range cfg.SystemContainers {
|
||||
if container.Id != config.CONSOLE_CONTAINER {
|
||||
continue
|
||||
}
|
||||
|
||||
c := docker.NewContainer(config.DOCKER_SYSTEM_HOST, &container).Lookup()
|
||||
if c.Err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Infof("Tailing console : %s", c.Name)
|
||||
return client.Logs(dockerClient.LogsOptions{
|
||||
Container: c.Name,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
Follow: true,
|
||||
OutputStream: os.Stdout,
|
||||
ErrorStream: os.Stderr,
|
||||
})
|
||||
}
|
||||
|
||||
log.Error("Console not found")
|
||||
return nil
|
||||
}
|
||||
|
||||
func SysInit() error {
|
||||
cfg, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
initFuncs := []config.InitFunc{
|
||||
loadImages,
|
||||
runContainers,
|
||||
func(cfg *config.Config) error {
|
||||
syscall.Sync()
|
||||
return nil
|
||||
},
|
||||
tailConsole,
|
||||
}
|
||||
|
||||
return config.RunInitFuncs(cfg, initFuncs)
|
||||
}
|
3
scripts/dockerimages/10-autoformat
Normal file
3
scripts/dockerimages/10-autoformat
Normal file
@ -0,0 +1,3 @@
|
||||
FROM base
|
||||
COPY scripts/dockerimages/scripts/auto-format.sh /usr/sbin/
|
||||
ENTRYPOINT ["/usr/sbin/auto-format.sh"]
|
5
scripts/dockerimages/scripts/auto-format.sh
Executable file
5
scripts/dockerimages/scripts/auto-format.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -n "$1" ]; then
|
||||
exec mkfs.ext4 -L RANCHER_STATE $1
|
||||
fi
|
Loading…
Reference in New Issue
Block a user