From 3620db959f3d3b7e96d482e162a181d3427e87da Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Sun, 22 Feb 2015 20:57:09 -0700 Subject: [PATCH] Support reloading config during system containers start up --- cmd/sysinit/sysinit.go | 54 +++++++++++++++++++++++++++++------------- config/config.go | 54 ++++++++++++++++++++++++++++++++++++++---- config/default.go | 40 +++++++++++++++++++++++++++++++ docker/container.go | 18 +++++++------- 4 files changed, 135 insertions(+), 31 deletions(-) diff --git a/cmd/sysinit/sysinit.go b/cmd/sysinit/sysinit.go index b3ff9ba6..0453e54b 100644 --- a/cmd/sysinit/sysinit.go +++ b/cmd/sysinit/sysinit.go @@ -115,12 +115,8 @@ func loadImages(cfg *config.Config) error { return nil } -func runContainers(cfg *config.Config) error { - containerConfigs := cfg.SystemContainers - if cfg.Rescue { - log.Debug("Running rescue container") - containerConfigs = []config.ContainerConfig{*cfg.RescueContainer} - } +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) @@ -130,26 +126,50 @@ func runContainers(cfg *config.Config) error { 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 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) } - } - log.Infof("Running [%d/%d] %s", i+1, len(containerConfigs), containerConfig.Id) - container.StartAndWait() + if containerConfig.ReloadConfig { + log.Info("Reloading configuration") + err := cfg.Reload() + if err != nil { + return err + } - if container.Err != nil { - log.Errorf("Failed to run %v: %v", containerConfig.Id, container.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 launchConsole(cfg *config.Config) error { if !util.IsRunningInTty() { return nil diff --git a/config/config.go b/config/config.go index 30f41a40..3981d70c 100644 --- a/config/config.go +++ b/config/config.go @@ -36,6 +36,7 @@ type ContainerConfig struct { Id string `yaml:"id,omitempty"` Cmd string `yaml:"run,omitempty"` MigrateVolumes bool `yaml:"migrate_volumes,omitempty"` + ReloadConfig bool `yaml:"reload_config,omitempty"` } type Config struct { @@ -52,6 +53,8 @@ type Config struct { Modules []string `yaml:"modules,omitempty"` CloudInit CloudInit `yaml:"cloud_init"` SshInfo SshInfo `yaml:"ssh"` + EnabledAddons []string `yaml:"enabledAddons,omitempty"` + Addons map[string]Config `yaml:"addons,omitempty"` } type UserDockerInfo struct { @@ -75,6 +78,32 @@ type CloudInit struct { Datasources []string `yaml:"datasources"` } +func (c *Config) PrivilegedMerge(newConfig Config) (bool, error) { + reboot, err := c.Merge(newConfig) + if err != nil { + return reboot, err + } + + toAppend := make([]ContainerConfig, 0, 5) + + for _, newContainer := range newConfig.SystemContainers { + found := false + for i, existingContainer := range c.SystemContainers { + if existingContainer.Id != "" && newContainer.Id == existingContainer.Id { + found = true + c.SystemContainers[i] = newContainer + } + } + if !found { + toAppend = append(toAppend, newContainer) + } + } + + c.SystemContainers = append(c.SystemContainers, toAppend...) + + return reboot, nil +} + func (c *Config) Merge(newConfig Config) (bool, error) { //Efficient? Nope, but computers are fast newConfig.ClearReadOnly() @@ -92,6 +121,9 @@ func (c *Config) Merge(newConfig Config) (bool, error) { func (c *Config) ClearReadOnly() { c.SystemContainers = []ContainerConfig{} c.RescueContainer = nil + c.Rescue = false + c.Debug = false + c.Addons = map[string]Config{} } func (c *Config) Dump() (string, error) { @@ -157,7 +189,14 @@ func (c *Config) merge(values map[string]interface{}) error { if err != nil { return err } - return yaml.Unmarshal(override, c) + var newConfig Config + err = yaml.Unmarshal(override, &newConfig) + if err != nil { + return nil + } + + _, err = c.Merge(newConfig) + return err } func (c *Config) readFile() error { @@ -262,13 +301,18 @@ func (c *Config) Reload() error { c.readFile, c.readCmdline, c.readArgs, + c.mergeAddons, ) } -func (c *Config) GetContainerById(id string) *ContainerConfig { - for _, c := range c.SystemContainers { - if c.Id == id { - return &c +func (c *Config) mergeAddons() error { + for _, addon := range c.EnabledAddons { + if newConfig, ok := c.Addons[addon]; ok { + log.Debugf("Enabling addon %s", addon) + _, err := c.PrivilegedMerge(newConfig) + if err != nil { + return err + } } } diff --git a/config/default.go b/config/default.go index 0760ad28..9b5061b4 100644 --- a/config/default.go +++ b/config/default.go @@ -19,15 +19,18 @@ func NewConfig() *Config { }, SystemContainers: []ContainerConfig{ { + Id: "system-volumes", Cmd: "--name=system-volumes " + "--net=none " + "--read-only " + "-v=/var/lib/rancher/conf:/var/lib/rancher/conf " + "-v=/lib/modules:/lib/modules:ro " + "-v=/var/run:/var/run " + + "-v=/var/log:/var/log " + "state", }, { + Id: "command-volumes", Cmd: "--name=command-volumes " + "--net=none " + "--read-only " + @@ -44,6 +47,7 @@ func NewConfig() *Config { "state", }, { + Id: "user-volumes", Cmd: "--name=user-volumes " + "--net=none " + "--read-only " + @@ -52,6 +56,7 @@ func NewConfig() *Config { "state", }, { + Id: "udev", Cmd: "--name=udev " + "--net=none " + "--privileged " + @@ -61,13 +66,16 @@ func NewConfig() *Config { "udev", }, { + Id: "cloud-init", Cmd: "--name=cloud-init " + "--rm " + "--net=host " + "--volumes-from=command-volumes " + "cloudinit", + ReloadConfig: true, }, { + Id: "network", Cmd: "--name=network " + "--cap-add=NET_ADMIN " + "--net=host " + @@ -75,6 +83,7 @@ func NewConfig() *Config { "network", }, { + Id: "ntp", Cmd: "--name=ntp " + "--rm " + "-d " + @@ -83,14 +92,19 @@ func NewConfig() *Config { "ntp", }, { + Id: "syslog", Cmd: "--name=syslog " + "-d " + "--rm " + "--privileged " + "--net=host " + + "--ipc=host " + + "--pid=host " + + "--volumes-from=system-volumes " + "syslog", }, { + Id: "userdocker", Cmd: "--name=userdocker " + "-d " + "--rm " + @@ -106,6 +120,7 @@ func NewConfig() *Config { "userdocker", }, { + Id: "console", Cmd: "--name=console " + "-d " + "--rm " + @@ -113,13 +128,37 @@ func NewConfig() *Config { "--volumes-from=command-volumes " + "--volumes-from=user-volumes " + "--volumes-from=system-volumes " + + "--restart=always " + "--ipc=host " + "--net=host " + "--pid=host " + "console", }, }, + EnabledAddons: []string{}, + Addons: map[string]Config{ + "ubuntu-console": { + SystemContainers: []ContainerConfig{ + { + Id: "console", + Cmd: "--name=ubuntu-console " + + "-d " + + "--rm " + + "--privileged " + + "--volumes-from=command-volumes " + + "--volumes-from=user-volumes " + + "--volumes-from=system-volumes " + + "--restart=always " + + "--ipc=host " + + "--net=host " + + "--pid=host " + + "rancher/ubuntuconsole", + }, + }, + }, + }, RescueContainer: &ContainerConfig{ + Id: "console", Cmd: "--name=rescue " + "-d " + "--rm " + @@ -127,6 +166,7 @@ func NewConfig() *Config { "--volumes-from=console-volumes " + "--volumes-from=user-volumes " + "--volumes-from=system-volumes " + + "--restart=always " + "--ipc=host " + "--net=host " + "--pid=host " + diff --git a/docker/container.go b/docker/container.go index 4e9ea9fb..1649ea97 100644 --- a/docker/container.go +++ b/docker/container.go @@ -34,7 +34,7 @@ type Container struct { HostConfig *runconfig.HostConfig dockerHost string Container *dockerClient.Container - containerCfg *config.ContainerConfig + ContainerCfg *config.ContainerConfig } type ByCreated []dockerClient.APIContainers @@ -65,7 +65,7 @@ func StartAndWait(dockerHost string, containerCfg *config.ContainerConfig) error func NewContainer(dockerHost string, containerCfg *config.ContainerConfig) *Container { c := &Container{ dockerHost: dockerHost, - containerCfg: containerCfg, + ContainerCfg: containerCfg, } return c.Parse() } @@ -102,7 +102,7 @@ func (c *Container) Lookup() *Container { return c } - hash, err := getHash(c.containerCfg) + hash, err := getHash(c.ContainerCfg) if err != nil { return c.returnErr(err) } @@ -169,7 +169,7 @@ func (c *Container) Parse() *Container { flDetach := flags.Bool([]string{"d", "-detach"}, false, "") flName := flags.String([]string{"#name", "-name"}, "", "") - args, err := shlex.Split(c.containerCfg.Cmd) + args, err := shlex.Split(c.ContainerCfg.Cmd) if err != nil { return c.returnErr(err) } @@ -181,8 +181,8 @@ func (c *Container) Parse() *Container { c.detach = *flDetach c.remove = *flRemove - if c.containerCfg.Id == "" { - c.containerCfg.Id = c.Name + if c.ContainerCfg.Id == "" { + c.ContainerCfg.Id = c.Name } return c @@ -327,13 +327,13 @@ func (c *Container) getCreateOpts(client *dockerClient.Client) (*dockerClient.Cr opts.Config.Labels = make(map[string]string) } - hash, err := getHash(c.containerCfg) + hash, err := getHash(c.ContainerCfg) if err != nil { return nil, err } opts.Config.Labels[HASH] = hash - opts.Config.Labels[ID] = c.containerCfg.Id + opts.Config.Labels[ID] = c.ContainerCfg.Id return &opts, nil } @@ -398,7 +398,7 @@ func (c *Container) start(wait bool) *Container { return c.returnErr(err) } - err := appendVolumesFrom(client, c.containerCfg, opts) + err := appendVolumesFrom(client, c.ContainerCfg, opts) if err != nil { return c.returnErr(err) }