1
0
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:
Darren Shepherd 2015-03-18 06:21:32 -07:00
parent 0e77cde9c0
commit 91dd56e595
6 changed files with 377 additions and 221 deletions

View File

@ -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
View 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)
}

View File

@ -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
View 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)
}

View File

@ -0,0 +1,3 @@
FROM base
COPY scripts/dockerimages/scripts/auto-format.sh /usr/sbin/
ENTRYPOINT ["/usr/sbin/auto-format.sh"]

View File

@ -0,0 +1,5 @@
#!/bin/bash
if [ -n "$1" ]; then
exec mkfs.ext4 -L RANCHER_STATE $1
fi