1
0
mirror of https://github.com/rancher/os.git synced 2025-06-27 15:26:50 +00:00

Refactor configuration to compose syntax

This commit is contained in:
Darren Shepherd 2015-03-29 02:57:15 -07:00
parent 38389b1f8e
commit c7ae14cc13
11 changed files with 535 additions and 344 deletions

View File

@ -8,26 +8,26 @@ import (
"github.com/rancherio/os/docker"
)
func parseContainers(cfg *config.Config) map[string]*docker.Container {
result := map[string]*docker.Container{}
for _, containerConfig := range cfg.SystemContainers {
container := docker.NewContainer(config.DOCKER_SYSTEM_HOST, &containerConfig)
if containerConfig.Id != "" {
result[containerConfig.Id] = container
}
}
return result
}
//func parseContainers(cfg *config.Config) map[string]*docker.Container {
// result := map[string]*docker.Container{}
//
// for _, containerConfig := range cfg.SystemContainers {
// container := docker.NewContainer(config.DOCKER_SYSTEM_HOST, &containerConfig)
// if containerConfig.Id != "" {
// result[containerConfig.Id] = container
// }
// }
//
// return result
//}
func reload(c *cli.Context) {
cfg, err := config.LoadConfig()
_, err := config.LoadConfig()
if err != nil {
log.Fatal(err)
}
containers := parseContainers(cfg)
containers := map[string]*docker.Container{} //parseContainers(cfg)
toStart := make([]*docker.Container, 0, len(c.Args()))
for _, id := range c.Args() {

View File

@ -27,10 +27,10 @@ func Main() {
if err != nil {
log.Fatal(err)
}
applyNetworkConfigs(cfg)
ApplyNetworkConfigs(&cfg.Network)
}
func applyNetworkConfigs(cfg *config.Config) error {
func ApplyNetworkConfigs(netCfg *config.NetworkConfig) error {
links, err := netlink.LinkList()
if err != nil {
return err
@ -41,7 +41,7 @@ func applyNetworkConfigs(cfg *config.Config) error {
linkName := link.Attrs().Name
var match config.InterfaceConfig
for key, netConf := range cfg.Network.Interfaces {
for key, netConf := range netCfg.Interfaces {
if netConf.Match == "" {
netConf.Match = key
}
@ -86,8 +86,8 @@ func applyNetworkConfigs(cfg *config.Config) error {
}
//post run
if cfg.Network.PostRun != nil {
return docker.StartAndWait(config.DOCKER_SYSTEM_HOST, cfg.Network.PostRun)
if netCfg.PostRun != nil {
return docker.StartAndWait(config.DOCKER_SYSTEM_HOST, netCfg.PostRun)
}
return nil
}

View File

@ -5,6 +5,8 @@ import (
"os"
"strings"
"github.com/rancherio/rancher-compose/project"
log "github.com/Sirupsen/logrus"
"github.com/rancherio/os/util"
"gopkg.in/yaml.v2"
@ -16,22 +18,9 @@ func (c *Config) privilegedMerge(newConfig Config) error {
return 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
for k, v := range newConfig.SystemContainers {
c.SystemContainers[k] = v
}
}
if !found {
toAppend = append(toAppend, newContainer)
}
}
c.SystemContainers = append(c.SystemContainers, toAppend...)
return nil
}
@ -42,8 +31,8 @@ func (c *Config) overlay(newConfig Config) error {
}
func (c *Config) clearReadOnly() {
c.BootstrapContainers = make([]ContainerConfig, 0)
c.SystemContainers = make([]ContainerConfig, 0)
c.BootstrapContainers = make(map[string]*project.ServiceConfig, 0)
c.SystemContainers = make(map[string]*project.ServiceConfig, 0)
}
func clearReadOnly(data map[interface{}]interface{}) map[interface{}]interface{} {
@ -103,6 +92,12 @@ func LoadConfig() (*Config, error) {
if cfg.Debug {
log.SetLevel(log.DebugLevel)
if !util.Contains(cfg.UserDocker.Args, "-D") {
cfg.UserDocker.Args = append(cfg.UserDocker.Args, "-D")
}
if !util.Contains(cfg.SystemDocker.Args, "-D") {
cfg.SystemDocker.Args = append(cfg.SystemDocker.Args, "-D")
}
}
return cfg, nil
@ -197,20 +192,11 @@ func Dump(private, full bool) (string, error) {
}
func (c *Config) configureConsole() error {
if !c.Console.Persistent {
return nil
}
for i := range c.SystemContainers {
// Need to modify original object, not the copy
var container *ContainerConfig = &c.SystemContainers[i]
if container.Id != CONSOLE_CONTAINER {
continue
}
if strings.Contains(container.Cmd, "--rm ") {
container.Cmd = strings.Replace(container.Cmd, "--rm ", "", 1)
if console, ok := c.SystemContainers[CONSOLE_CONTAINER]; ok {
if c.Console.Persistent {
console.Labels = append(console.Labels, REMOVE+"=false")
} else {
console.Labels = append(console.Labels, REMOVE+"=true")
}
}
@ -221,7 +207,6 @@ func (c *Config) readGlobals() error {
return util.ShortCircuit(
c.readCmdline,
c.readArgs,
c.mergeAddons,
c.configureConsole,
)
}
@ -233,19 +218,6 @@ func (c *Config) Reload() error {
)
}
func (c *Config) mergeAddons() error {
for _, addon := range c.EnabledAddons {
if newConfig, ok := c.Addons[addon]; ok {
log.Debugf("Enabling addon %s", addon)
if err := c.privilegedMerge(newConfig); err != nil {
return err
}
}
}
return nil
}
func (c *Config) Get(key string) (interface{}, error) {
data := make(map[interface{}]interface{})
err := util.Convert(c, &data)

View File

@ -1,5 +1,9 @@
package config
import (
"github.com/rancherio/rancher-compose/project"
)
func NewConfig() *Config {
return &Config{
Debug: DEBUG,
@ -43,7 +47,7 @@ func NewConfig() *Config {
Nameservers: []string{"8.8.8.8", "8.8.4.4"},
},
Interfaces: map[string]InterfaceConfig{
"eth*": {
"eth0": {
DHCP: true,
},
"lo": {
@ -58,193 +62,238 @@ func NewConfig() *Config {
Url: "https://releases.rancher.com/os/versions.yml",
Image: "rancher/os",
},
BootstrapContainers: []ContainerConfig{
{
Id: "udev",
Cmd: "--name=udev " +
"--net=none " +
"--privileged " +
"--rm " +
"-v=/dev:/host/dev " +
"-v=/lib/modules:/lib/modules:ro " +
"udev",
BootstrapContainers: map[string]*project.ServiceConfig{
"udev": {
Net: "host",
Privileged: true,
Labels: []string{
DETACH + "=false",
},
Volumes: []string{
"/dev:/host/dev",
"/lib/modules:/lib/modules:ro",
"/lib/firmware:/lib/firmware:ro",
},
Image: "udev",
},
},
SystemContainers: []ContainerConfig{
{
Id: "udev",
Cmd: "--name=udev " +
"--net=none " +
"--privileged " +
"--rm " +
"-v=/dev:/host/dev " +
"-v=/lib/modules:/lib/modules:ro " +
"udev",
CreateOnly: true,
SystemContainers: map[string]*project.ServiceConfig{
"udev": {
Image: "udev",
Net: "host",
Privileged: true,
Labels: []string{
DETACH + "=true",
},
{
Id: "system-volumes",
Cmd: "--name=system-volumes " +
"--net=none " +
"--read-only " +
"-v=/etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt " +
"-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",
CreateOnly: true,
Environment: []string{
"DAEMON=true",
},
{
Id: "command-volumes",
Cmd: "--name=command-volumes " +
"--net=none " +
"--read-only " +
"-v=/init:/sbin/halt:ro " +
"-v=/init:/sbin/poweroff:ro " +
"-v=/init:/sbin/reboot:ro " +
"-v=/init:/sbin/shutdown:ro " +
"-v=/init:/sbin/netconf:ro " +
"-v=/init:/usr/bin/cloud-init:ro " +
"-v=/init:/usr/bin/rancherctl:ro " +
"-v=/init:/usr/bin/respawn:ro " +
"-v=/init:/usr/bin/system-docker:ro " +
"-v=/lib/modules:/lib/modules:ro " +
"-v=/usr/bin/docker:/usr/bin/docker:ro " +
"state",
CreateOnly: true,
Volumes: []string{
"/dev:/host/dev",
"/lib/modules:/lib/modules:ro",
"/lib/firmware:/lib/firmware:ro",
},
{
Id: "user-volumes",
Cmd: "--name=user-volumes " +
"--net=none " +
"--read-only " +
"-v=/home:/home " +
"-v=/opt:/opt " +
"state",
CreateOnly: true,
},
{
Id: "docker-volumes",
Cmd: "--name=docker-volumes " +
"--net=none " +
"--read-only " +
"-v=/var/lib/rancher:/var/lib/rancher " +
"-v=/var/lib/docker:/var/lib/docker " +
"-v=/var/lib/system-docker:/var/lib/system-docker " +
"state",
CreateOnly: true,
"system-volumes": {
Image: "state",
Net: "none",
ReadOnly: true,
Privileged: true,
Labels: []string{
CREATE_ONLY + "=true",
},
{
Id: "all-volumes",
Cmd: "--name=all-volumes " +
"--rm " +
"--net=none " +
"--read-only " +
"--volumes-from=docker-volumes " +
"--volumes-from=command-volumes " +
"--volumes-from=user-volumes " +
"--volumes-from=system-volumes " +
"state",
CreateOnly: true,
Volumes: []string{
"/etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt",
"/var/lib/rancher/conf:/var/lib/rancher/conf",
"/lib/modules:/lib/modules:ro",
"/lib/firmware:/lib/firmware:ro",
"/var/run:/var/run",
"/var/log:/var/log",
},
{
Id: "cloud-init-pre",
Cmd: "--name=cloud-init-pre " +
"--rm " +
"--privileged " +
"--net=host " +
"-e CLOUD_INIT_NETWORK=false " +
"--volumes-from=command-volumes " +
"--volumes-from=system-volumes " +
"cloudinit",
ReloadConfig: true,
},
{
Id: "network",
Cmd: "--name=network " +
"--rm " +
"--cap-add=NET_ADMIN " +
"--net=host " +
"--volumes-from=command-volumes " +
"--volumes-from=system-volumes " +
"command-volumes": {
Image: "state",
Net: "none",
ReadOnly: true,
Privileged: true,
Labels: []string{
CREATE_ONLY + "=true",
},
Volumes: []string{
"/init:/sbin/halt:ro",
"/init:/sbin/poweroff:ro",
"/init:/sbin/reboot:ro",
"/init:/sbin/shutdown:ro",
"/init:/sbin/netconf:ro",
"/init:/usr/bin/cloud-init:ro",
"/init:/usr/bin/rancherctl:ro",
"/init:/usr/bin/respawn:ro",
"/init:/usr/bin/system-docker:ro",
"/lib/modules:/lib/modules:ro",
"/usr/bin/docker:/usr/bin/docker:ro",
},
},
"user-volumes": {
Image: "state",
Net: "none",
ReadOnly: true,
Privileged: true,
Labels: []string{
CREATE_ONLY + "=true",
},
Volumes: []string{
"/home:/home",
"/opt:/opt",
},
},
"docker-volumes": {
Image: "state",
Net: "none",
ReadOnly: true,
Privileged: true,
Labels: []string{
CREATE_ONLY + "=true",
},
Volumes: []string{
"/var/lib/rancher:/var/lib/rancher",
"/var/lib/docker:/var/lib/docker",
"/var/lib/system-docker:/var/lib/system-docker",
},
},
"all-volumes": {
Image: "state",
Net: "none",
ReadOnly: true,
Privileged: true,
Labels: []string{
CREATE_ONLY + "=true",
},
VolumesFrom: []string{
"docker-volumes",
"command-volumes",
"user-volumes",
"system-volumes",
},
},
"cloud-init-pre": {
Image: "cloudinit",
Privileged: true,
Net: "host",
Labels: []string{
RELOAD_CONFIG + "=true",
DETACH + "=false",
},
Environment: []string{
"CLOUD_INIT_NETWORK=false",
},
VolumesFrom: []string{
"command-volumes",
"system-volumes",
},
},
"network": {
Image: "network",
CapAdd: []string{
"NET_ADMIN",
},
Net: "host",
Labels: []string{
DETACH + "=false",
},
Links: []string{
"cloud-init-pre",
},
VolumesFrom: []string{
"command-volumes",
"system-volumes",
},
},
"cloud-init": {
Image: "cloudinit",
Privileged: true,
Labels: []string{
RELOAD_CONFIG + "=true",
DETACH + "=false",
},
Net: "host",
Links: []string{
"cloud-init-pre",
"network",
},
{
Id: "cloud-init",
Cmd: "--name=cloud-init " +
"--rm " +
"--privileged " +
"--net=host " +
"--volumes-from=command-volumes " +
"--volumes-from=system-volumes " +
"cloudinit",
ReloadConfig: true,
VolumesFrom: []string{
"command-volumes",
"system-volumes",
},
{
Id: "ntp",
Cmd: "--name=ntp " +
"--rm " +
"-d " +
"--privileged " +
"--net=host " +
"ntp",
},
{
Id: "syslog",
Cmd: "--name=syslog " +
"-d " +
"--rm " +
"--privileged " +
"--net=host " +
"--ipc=host " +
"--pid=host " +
"--volumes-from=system-volumes " +
"syslog",
"ntp": {
Image: "ntp",
Privileged: true,
Net: "host",
Links: []string{
"cloud-init",
"network",
},
{
Id: "userdocker",
Cmd: "--name=userdocker " +
"-d " +
"--rm " +
"--restart=always " +
"--ipc=host " +
"--pid=host " +
"--net=host " +
"--privileged " +
"--volumes-from=all-volumes " +
"userdocker",
},
{
Id: "console",
Cmd: "--name=console " +
"-d " +
"--rm " +
"--privileged " +
"--volumes-from=all-volumes " +
"--restart=always " +
"--ipc=host " +
"--net=host " +
"--pid=host " +
"console",
"syslog": {
Image: "syslog",
Privileged: true,
Net: "host",
Links: []string{
"cloud-init",
"network",
},
VolumesFrom: []string{
"system-volumes",
},
},
"userdocker": {
Image: "userdocker",
Privileged: true,
Pid: "host",
Ipc: "host",
Net: "host",
Links: []string{
"network",
},
VolumesFrom: []string{
"all-volumes",
},
},
"console": {
Image: "console",
Privileged: true,
Links: []string{
"cloud-init",
},
VolumesFrom: []string{
"all-volumes",
},
Restart: "always",
Pid: "host",
Ipc: "host",
Net: "host",
},
},
EnabledAddons: []string{},
Addons: map[string]Config{
"ubuntu-console": {
SystemContainers: []ContainerConfig{
{
Id: "console",
Cmd: "--name=ubuntu-console " +
"-d " +
"--rm " +
"--privileged " +
"--volumes-from=all-volumes " +
"--restart=always " +
"--ipc=host " +
"--net=host " +
"--pid=host " +
"rancher/ubuntuconsole:" + VERSION,
SystemContainers: map[string]*project.ServiceConfig{
"console": {
Image: "rancher/ubuntuconsole:" + VERSION,
Privileged: true,
Labels: []string{
DETACH + "=true",
},
Links: []string{
"cloud-init",
},
VolumesFrom: []string{
"all-volumes",
},
Restart: "always",
Pid: "host",
Ipc: "host",
Net: "host",
},
},
},

View File

@ -1,5 +1,7 @@
package config
import "github.com/rancherio/rancher-compose/project"
const (
CONSOLE_CONTAINER = "console"
DOCKER_BIN = "/usr/bin/docker"
@ -12,6 +14,14 @@ const (
USER_INIT = "/sbin/init-user"
MODULES_ARCHIVE = "/modules.tar"
DEBUG = false
LABEL = "label"
HASH = "io.rancher.os.hash"
ID = "io.rancher.os.id"
DETACH = "io.rancher.os.detach"
REMOVE = "io.rancher.os.remove"
CREATE_ONLY = "io.rancher.os.createonly"
RELOAD_CONFIG = "io.rancher.os.reloadconfig"
)
var (
@ -27,21 +37,22 @@ type ContainerConfig struct {
MigrateVolumes bool `yaml:"migrate_volumes,omitempty"`
ReloadConfig bool `yaml:"reload_config,omitempty"`
CreateOnly bool `yaml:create_only,omitempty`
Service *project.ServiceConfig `yaml:service,omitempty`
}
type Config struct {
Addons map[string]Config `yaml:"addons,omitempty"`
BootstrapContainers []ContainerConfig `yaml:"bootstrap_containers,omitempty"`
BootstrapContainers map[string]*project.ServiceConfig `yaml:"bootstrap_containers,omitempty"`
CloudInit CloudInit `yaml:"cloud_init,omitempty"`
Console ConsoleConfig `yaml:"console,omitempty"`
Debug bool `yaml:"debug,omitempty"`
Disable []string `yaml:"disable,omitempty"`
//Disable []string `yaml:"disable,omitempty"`
EnabledAddons []string `yaml:"enabled_addons,omitempty"`
Modules []string `yaml:"modules,omitempty"`
Network NetworkConfig `yaml:"network,omitempty"`
Ssh SshConfig `yaml:"ssh,omitempty"`
State StateConfig `yaml:"state,omitempty"`
SystemContainers []ContainerConfig `yaml:"system_containers,omitempty"`
SystemContainers map[string]*project.ServiceConfig `yaml:"system_containers,omitempty"`
SystemDocker DockerConfig `yaml:"system_docker,omitempty"`
Upgrade UpgradeConfig `yaml:"upgrade,omitempty"`
UserContainers []ContainerConfig `yaml:"user_containers,omitempty"`

View File

@ -3,6 +3,8 @@ package docker
import (
"time"
log "github.com/Sirupsen/logrus"
dockerClient "github.com/fsouza/go-dockerclient"
"github.com/rancherio/os/config"
)
@ -26,12 +28,16 @@ func NewClient(endpoint string) (*dockerClient.Client, error) {
return nil, err
}
retry := false
for i := 0; i < (MAX_WAIT / INTERVAL); i++ {
_, err = client.Info()
if err == nil {
break
}
retry = true
log.Infof("Waiting for Docker at %s", endpoint)
time.Sleep(INTERVAL * time.Millisecond)
}
@ -39,5 +45,8 @@ func NewClient(endpoint string) (*dockerClient.Client, error) {
return nil, err
}
if retry {
log.Infof("Connected to Docker at %s", endpoint)
}
return client, nil
}

View File

@ -4,6 +4,7 @@ import (
"crypto/sha1"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"os"
"sort"
@ -16,12 +17,8 @@ import (
dockerClient "github.com/fsouza/go-dockerclient"
"github.com/rancherio/os/config"
"github.com/rancherio/os/util"
)
const (
LABEL = "label"
HASH = "io.rancher.os.hash"
ID = "io.rancher.os.id"
"github.com/rancherio/rancher-compose/docker"
"github.com/rancherio/rancher-compose/project"
)
type Container struct {
@ -48,6 +45,10 @@ func getHash(containerCfg *config.ContainerConfig) (string, error) {
w.Write([]byte(containerCfg.Id))
w.Write([]byte(containerCfg.Cmd))
if containerCfg.Service != nil {
//TODO: properly hash
w.Write([]byte(fmt.Sprintf("%v", containerCfg.Service)))
}
if w.Err != nil {
return "", w.Err
@ -61,6 +62,18 @@ func StartAndWait(dockerHost string, containerCfg *config.ContainerConfig) error
return container.Err
}
func NewContainerFromService(dockerHost string, name string, service *project.ServiceConfig) *Container {
c := &Container{
Name: name,
dockerHost: dockerHost,
ContainerCfg: &config.ContainerConfig{
Id: name,
Service: service,
},
}
return c.Parse()
}
func NewContainer(dockerHost string, containerCfg *config.ContainerConfig) *Container {
c := &Container{
dockerHost: dockerHost,
@ -78,7 +91,7 @@ func getByLabel(client *dockerClient.Client, key, value string) (*dockerClient.A
containers, err := client.ListContainers(dockerClient.ListContainersOptions{
All: true,
Filters: map[string][]string{
LABEL: []string{fmt.Sprintf("%s=%s", key, value)},
config.LABEL: []string{fmt.Sprintf("%s=%s", key, value)},
},
})
@ -114,7 +127,7 @@ func (c *Container) Lookup() *Container {
containers, err := client.ListContainers(dockerClient.ListContainersOptions{
All: true,
Filters: map[string][]string{
LABEL: []string{fmt.Sprintf("%s=%s", HASH, hash)},
config.LABEL: []string{fmt.Sprintf("%s=%s", config.HASH, hash)},
},
})
if err != nil {
@ -157,11 +170,23 @@ func (c *Container) Reset() *Container {
return c
}
func (c *Container) Parse() *Container {
if c.Config != nil || c.Err != nil {
return c
func (c *Container) parseService() {
cfg, hostConfig, err := docker.Convert(c.ContainerCfg.Service)
if err != nil {
c.Err = err
return
}
c.Config = cfg
c.HostConfig = hostConfig
c.detach = c.Config.Labels[config.DETACH] != "false"
c.remove = c.Config.Labels[config.REMOVE] != "false"
c.ContainerCfg.CreateOnly = c.Config.Labels[config.CREATE_ONLY] == "true"
c.ContainerCfg.ReloadConfig = c.Config.Labels[config.RELOAD_CONFIG] == "true"
}
func (c *Container) parseCmd() {
flags := flag.NewFlagSet("run", flag.ExitOnError)
flRemove := flags.Bool([]string{"#rm", "-rm"}, false, "")
@ -170,7 +195,8 @@ func (c *Container) Parse() *Container {
args, err := shlex.Split(c.ContainerCfg.Cmd)
if err != nil {
return c.returnErr(err)
c.Err = err
return
}
log.Debugf("Parsing [%s]", strings.Join(args, ","))
@ -179,6 +205,21 @@ func (c *Container) Parse() *Container {
c.Name = *flName
c.detach = *flDetach
c.remove = *flRemove
}
func (c *Container) Parse() *Container {
if c.Config != nil || c.Err != nil {
return c
}
if len(c.ContainerCfg.Cmd) > 0 {
c.parseCmd()
} else if c.ContainerCfg.Service != nil {
c.parseService()
} else {
c.Err = errors.New("Cmd or Service must be set")
return c
}
if c.ContainerCfg.Id == "" {
c.ContainerCfg.Id = c.Name
@ -219,6 +260,7 @@ func (c *Container) Stage() *Container {
OutputStream: os.Stdout,
}, dockerClient.AuthConfiguration{})
} else if err != nil {
log.Errorf("Failed to stage: %s: %v", c.Config.Image, err)
c.Err = err
}
@ -291,7 +333,7 @@ func (c *Container) renameOld(client *dockerClient.Client, opts *dockerClient.Cr
}
var newName string
if label, ok := existing.Config.Labels[HASH]; ok {
if label, ok := existing.Config.Labels[config.HASH]; ok {
newName = fmt.Sprintf("%s-%s", existing.Name, label)
} else {
newName = fmt.Sprintf("%s-unknown-%s", existing.Name, util.RandSeq(12))
@ -316,6 +358,7 @@ func (c *Container) renameOld(client *dockerClient.Client, opts *dockerClient.Cr
func (c *Container) getCreateOpts(client *dockerClient.Client) (*dockerClient.CreateContainerOptions, error) {
bytes, err := json.Marshal(c)
if err != nil {
log.Errorf("Failed to marshall: %v", c)
return nil, err
}
@ -323,6 +366,7 @@ func (c *Container) getCreateOpts(client *dockerClient.Client) (*dockerClient.Cr
err = json.Unmarshal(bytes, &opts)
if err != nil {
log.Errorf("Failed to unmarshall: %s", string(bytes))
return nil, err
}
@ -335,8 +379,8 @@ func (c *Container) getCreateOpts(client *dockerClient.Client) (*dockerClient.Cr
return nil, err
}
opts.Config.Labels[HASH] = hash
opts.Config.Labels[ID] = c.ContainerCfg.Id
opts.Config.Labels[config.HASH] = hash
opts.Config.Labels[config.ID] = c.ContainerCfg.Id
return &opts, nil
}
@ -346,7 +390,7 @@ func appendVolumesFrom(client *dockerClient.Client, containerCfg *config.Contain
return nil
}
container, err := getByLabel(client, ID, containerCfg.Id)
container, err := getByLabel(client, config.ID, containerCfg.Id)
if err != nil || container == nil {
return err
}
@ -360,7 +404,7 @@ func appendVolumesFrom(client *dockerClient.Client, containerCfg *config.Contain
return nil
}
func (c *Container) start(create_only, wait bool) *Container {
func (c *Container) start(createOnly, wait bool) *Container {
c.Lookup()
c.Stage()
@ -378,6 +422,7 @@ func (c *Container) start(create_only, wait bool) *Container {
opts, err := c.getCreateOpts(client)
if err != nil {
log.Errorf("Failed to create container create options: %v", err)
return c.returnErr(err)
}
@ -420,7 +465,7 @@ func (c *Container) start(create_only, wait bool) *Container {
hostConfig = opts.HostConfig
}
if create_only {
if createOnly {
return c
}
@ -439,12 +484,17 @@ func (c *Container) start(create_only, wait bool) *Container {
err = client.StartContainer(c.Container.ID, hostConfig)
if err != nil {
log.Errorf("Error from Docker %s", err)
return c.returnErr(err)
}
}
if !c.detach && wait {
_, c.Err = client.WaitContainer(c.Container.ID)
var exitCode int
exitCode, c.Err = client.WaitContainer(c.Container.ID)
if exitCode != 0 {
c.Err = errors.New(fmt.Sprintf("Container %s exited with code %d", c.Name, exitCode))
}
return c
}

69
docker/factory.go Normal file
View File

@ -0,0 +1,69 @@
package docker
import (
log "github.com/Sirupsen/logrus"
"github.com/rancherio/os/config"
"github.com/rancherio/rancher-compose/project"
)
type ContainerFactory struct {
}
type containerBasedService struct {
name string
project *project.Project
container *Container
serviceConfig *project.ServiceConfig
cfg *config.Config
}
func (c *containerBasedService) Up() error {
container := c.container
containerCfg := c.container.ContainerCfg
if containerCfg.CreateOnly {
container.Create()
c.project.Notify(project.CONTAINER_CREATED, c, map[string]string{
project.CONTAINER_ID: container.Container.ID,
})
} else {
container.StartAndWait()
c.project.Notify(project.CONTAINER_STARTED, c, map[string]string{
project.CONTAINER_ID: container.Container.ID,
})
}
if container.Err != nil {
log.Errorf("Failed to run %v: %v", containerCfg.Id, container.Err)
}
if container.Err == nil && containerCfg.ReloadConfig {
return project.ErrRestart
}
return container.Err
}
func (c *containerBasedService) Config() *project.ServiceConfig {
return c.serviceConfig
}
func (c *containerBasedService) Name() string {
return c.name
}
func (c *ContainerFactory) Create(project *project.Project, name string, serviceConfig *project.ServiceConfig) (project.Service, error) {
container := NewContainerFromService(config.DOCKER_SYSTEM_HOST, name, serviceConfig)
if container.Err != nil {
return nil, container.Err
}
return &containerBasedService{
name: name,
project: project,
container: container,
serviceConfig: serviceConfig,
}, nil
}

View File

@ -8,9 +8,10 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/rancherio/os/config"
"github.com/rancherio/os/util"
"github.com/rancherio/rancher-compose/project"
)
func runBootstrapContainers(cfg *config.Config) error {
func autoformat(cfg *config.Config) error {
if len(cfg.State.Autoformat) == 0 || util.ResolveDevice(cfg.State.Dev) != "" {
return nil
}
@ -54,24 +55,22 @@ outer:
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,
return runServices("autoformat", cfg, map[string]*project.ServiceConfig{
"autoformat": {
Net: "none",
Privileged: true,
Image: "autoformat",
Command: format,
},
}, cfg.BootstrapContainers...))
"udev": cfg.BootstrapContainers["udev"],
})
}
return nil
}
func autoformat(cfg *config.Config) error {
return runContainersFrom("", cfg, cfg.BootstrapContainers)
func runBootstrapContainers(cfg *config.Config) error {
return runServices("bootstrap", cfg, cfg.BootstrapContainers)
}
func startDocker(cfg *config.Config) (chan interface{}, error) {

View File

@ -10,6 +10,8 @@ import (
"github.com/rancherio/os/config"
"github.com/rancherio/os/docker"
"github.com/rancherio/os/util"
"github.com/rancherio/rancher-compose/project"
)
func importImage(client *dockerClient.Client, name, fileName string) error {
@ -107,50 +109,63 @@ func loadImages(cfg *config.Config) error {
return nil
}
func runContainersFrom(startFrom string, cfg *config.Config, containerConfigs []config.ContainerConfig) error {
foundStart := false
func runServices(name string, cfg *config.Config, configs map[string]*project.ServiceConfig) error {
project := project.NewProject(name, &docker.ContainerFactory{})
enabled := make(map[string]bool)
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
for name, serviceConfig := range configs {
if err := project.AddConfig(name, serviceConfig); err != nil {
log.Infof("Failed loading service %s", name)
}
}
if foundStart || startFrom == "" {
if containerConfig.CreateOnly {
log.Infof("Creating [%d/%d] %s", i+1, len(containerConfigs), containerConfig.Id)
container.Create()
} else {
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")
project.ReloadCallback = func() error {
err := cfg.Reload()
if err != nil {
return err
}
return runContainersFrom(containerConfig.Id, cfg, cfg.SystemContainers)
for _, addon := range cfg.EnabledAddons {
if _, ok := enabled[addon]; ok {
continue
}
} else if startFrom == containerConfig.Id {
foundStart = true
if config, ok := cfg.Addons[addon]; ok {
for name, s := range config.SystemContainers {
if err := project.AddConfig(name, s); err != nil {
log.Errorf("Failed to load %s : %v", name, err)
}
}
} else {
bytes, err := util.LoadResource(addon)
if err != nil {
log.Errorf("Failed to load %s : %v", addon, err)
continue
}
err = project.Load(bytes)
if err != nil {
log.Errorf("Failed to load %s : %v", addon, err)
continue
}
}
enabled[addon] = true
}
return nil
}
err := project.ReloadCallback()
if err != nil {
log.Errorf("Failed to reload %s : %v", name, err)
return err
}
return project.Up()
}
func runContainers(cfg *config.Config) error {
return runContainersFrom("", cfg, cfg.SystemContainers)
return runServices("system-init", cfg, cfg.SystemContainers)
}
func tailConsole(cfg *config.Config) error {
@ -163,14 +178,15 @@ func tailConsole(cfg *config.Config) error {
return err
}
for _, container := range cfg.SystemContainers {
if container.Id != config.CONSOLE_CONTAINER {
continue
console, ok := cfg.SystemContainers[config.CONSOLE_CONTAINER]
if !ok {
log.Error("Console not found")
return nil
}
c := docker.NewContainer(config.DOCKER_SYSTEM_HOST, &container).Lookup()
c := docker.NewContainerFromService(config.DOCKER_SYSTEM_HOST, config.CONSOLE_CONTAINER, console)
if c.Err != nil {
continue
return c.Err
}
log.Infof("Tailing console : %s", c.Name)
@ -184,10 +200,6 @@ func tailConsole(cfg *config.Config) error {
})
}
log.Error("Console not found")
return nil
}
func SysInit() error {
cfg, err := config.LoadConfig()
if err != nil {
@ -201,6 +213,10 @@ func SysInit() error {
syscall.Sync()
return nil
},
func(cfg *config.Config) error {
log.Info("RancherOS booted")
return nil
},
tailConsole,
}

View File

@ -4,9 +4,12 @@ import (
"archive/tar"
"fmt"
"io"
"io/ioutil"
"math/rand"
"net/http"
"os"
"path"
"strings"
"syscall"
"github.com/docker/docker/pkg/mount"
@ -182,3 +185,16 @@ func MergeMaps(left, right map[interface{}]interface{}) {
}
}
}
func LoadResource(location string) ([]byte, error) {
if strings.HasPrefix(location, "http:/") || strings.HasPrefix(location, "https:/") {
resp, err := http.Get(location)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
} else {
return ioutil.ReadFile(location)
}
}