diff --git a/cmd/control/addon.go b/cmd/control/addon.go index 82f1d895..600b5e02 100644 --- a/cmd/control/addon.go +++ b/cmd/control/addon.go @@ -51,7 +51,7 @@ func disable(c *cli.Context) { } if changed { - if err = cfg.Save(); err != nil { + if err = cfg.Set("enabled_addons", cfg.EnabledAddons); err != nil { log.Fatal(err) } } @@ -72,7 +72,7 @@ func enable(c *cli.Context) { } if changed { - if err = cfg.Save(); err != nil { + if err = cfg.Set("enabled_addons", cfg.EnabledAddons); err != nil { log.Fatal(err) } } diff --git a/cmd/control/config.go b/cmd/control/config.go index df931b3e..3450e7d2 100644 --- a/cmd/control/config.go +++ b/cmd/control/config.go @@ -12,7 +12,6 @@ import ( "github.com/codegangsta/cli" "github.com/rancherio/os/config" - "github.com/rancherio/os/docker" ) func configSubcommands() []cli.Command { @@ -30,7 +29,7 @@ func configSubcommands() []cli.Command { { Name: "import", Usage: "import configuration from standard in or a file", - Action: configImport, + Action: runImport, Flags: []cli.Flag{ cli.StringFlag{ Name: "input, i", @@ -40,43 +39,40 @@ func configSubcommands() []cli.Command { }, { Name: "export", - Usage: "dump full configuration", + Usage: "export configuration", Flags: []cli.Flag{ cli.StringFlag{ Name: "output, o", Usage: "File to which to save", }, cli.BoolFlag{ - Name: "full", - Usage: "Include full configuration, not just writable fields", + Name: "private, p", + Usage: "Include private information such as keys", + }, + cli.BoolFlag{ + Name: "full, f", + Usage: "Include full configuration, including internal and default settings", }, }, - Action: configSave, + Action: export, + }, + { + Name: "merge", + Usage: "merge configuration from stdin", + Action: merge, }, } } -func getConfigData() (map[interface{}]interface{}, error) { - cfg, err := config.LoadConfig() - if err != nil { - log.Fatal(err) - } - - content, err := cfg.Dump() - if err != nil { - log.Fatal(err) - } - - data := make(map[interface{}]interface{}) - err = yaml.Unmarshal([]byte(content), data) - - return data, err -} - -func configImport(c *cli.Context) { - var input io.Reader +func runImport(c *cli.Context) { + var input io.ReadCloser var err error input = os.Stdin + cfg, err := config.LoadConfig() + + if err != nil { + log.Fatal(err) + } inputFile := c.String("input") if inputFile != "" { @@ -84,6 +80,7 @@ func configImport(c *cli.Context) { if err != nil { log.Fatal(err) } + defer input.Close() } bytes, err := ioutil.ReadAll(input) @@ -91,38 +88,12 @@ func configImport(c *cli.Context) { log.Fatal(err) } - err = mergeConfig(bytes) + err = cfg.Import(bytes) if err != nil { log.Fatal(err) } } -func mergeConfig(bytes []byte) error { - var newConfig config.Config - - err := yaml.Unmarshal(bytes, &newConfig) - if err != nil { - return err - } - - cfg, err := config.LoadConfig() - if err != nil { - return err - } - - _, err = cfg.Merge(newConfig) - if err != nil { - return err - } - - err = cfg.Save() - if err != nil { - return err - } - - return err -} - func configSet(c *cli.Context) { key := c.Args().Get(0) value := c.Args().Get(1) @@ -130,15 +101,12 @@ func configSet(c *cli.Context) { return } - data, err := getConfigData() - getOrSetVal(key, data, value) - - bytes, err := yaml.Marshal(data) + cfg, err := config.LoadConfig() if err != nil { log.Fatal(err) } - err = mergeConfig(bytes) + err = cfg.Set(key, value) if err != nil { log.Fatal(err) } @@ -150,12 +118,15 @@ func configGet(c *cli.Context) { return } - data, err := getConfigData() + cfg, err := config.LoadConfig() if err != nil { log.Fatal(err) } - val := getOrSetVal(arg, data, nil) + val, err := cfg.Get(arg) + if err != nil { + log.Fatal(err) + } printYaml := false switch val.(type) { @@ -183,6 +154,7 @@ func getOrSetVal(args string, data map[interface{}]interface{}, value interface{ val, ok := data[part] last := i+1 == len(parts) + // Reached end, set the value if last && value != nil { if s, ok := value.(string); ok { value = config.DummyMarshall(s) @@ -192,6 +164,14 @@ func getOrSetVal(args string, data map[interface{}]interface{}, value interface{ return value } + // Missing intermediate key, create key + if !last && value != nil && !ok { + newData := map[interface{}]interface{}{} + data[part] = newData + data = newData + continue + } + if !ok { break } @@ -211,26 +191,29 @@ func getOrSetVal(args string, data map[interface{}]interface{}, value interface{ return "" } -func configSave(c *cli.Context) { +func merge(c *cli.Context) { + bytes, err := ioutil.ReadAll(os.Stdin) + if err != nil { + log.Fatal(err) + } + cfg, err := config.LoadConfig() if err != nil { log.Fatal(err) } - //TODO: why doesn't this work - for _, c := range cfg.SystemContainers { - container := docker.NewContainer("", &c) - if container.Err != nil { - log.Fatalf("Failed to parse [%s] : %v", c.Cmd, container.Err) - } + err = cfg.Merge(bytes) + if err != nil { + log.Fatal(err) } +} - if !c.Bool("full") { - cfg.ClearReadOnly() +func export(c *cli.Context) { + content, err := config.Dump(c.Bool("private"), c.Bool("full")) + if err != nil { + log.Fatal(err) } - content, err := cfg.Dump() - output := c.String("output") if output == "" { fmt.Println(content) @@ -240,5 +223,4 @@ func configSave(c *cli.Context) { log.Fatal(err) } } - } diff --git a/config/config.go b/config/config.go index 56254fc7..0c7b72ab 100644 --- a/config/config.go +++ b/config/config.go @@ -3,8 +3,6 @@ package config import ( "io/ioutil" "os" - "regexp" - "strconv" "strings" log "github.com/Sirupsen/logrus" @@ -12,90 +10,10 @@ import ( "gopkg.in/yaml.v2" ) -const ( - VERSION = "0.0.1" - CONSOLE_CONTAINER = "console" - DOCKER_BIN = "/usr/bin/docker" - DOCKER_SYSTEM_HOST = "unix:///var/run/system-docker.sock" - DOCKER_HOST = "unix:///var/run/docker.sock" - IMAGES_PATH = "/" - IMAGES_PATTERN = "images*.tar" - SYS_INIT = "/sbin/init-sys" - USER_INIT = "/sbin/init-user" - MODULES_ARCHIVE = "/modules.tar" - DEBUG = false -) - -var ( - ConfigFile = "/var/lib/rancher/conf/rancher.yml" -) - -type InitFunc func(*Config) error - -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 { - Debug bool `yaml:"debug,omitempty"` - Disable []string `yaml:"disable,omitempty"` - Dns []string `yaml:"dns,flow,omitempty"` - Rescue bool `yaml:"rescue,omitempty"` - RescueContainer *ContainerConfig `yaml:"rescue_container,omitempty"` - State ConfigState `yaml:"state,omitempty"` - Userdocker UserDockerInfo `yaml:"userdocker,omitempty"` - OsUpgradeChannel string `yaml:"os_upgrade_channel,omitempty"` - SystemContainers []ContainerConfig `yaml:"system_containers,omitempty"` - SystemDockerArgs []string `yaml:"system_docker_args,flow,omitempty"` - 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"` - Network NetworkConfig `yaml:"network,omitempty"` -} - -type NetworkConfig struct { - Interfaces []InterfaceConfig `yaml:"interfaces"` - PostRun *ContainerConfig `yaml:"post_run"` -} - -type InterfaceConfig struct { - Match string `yaml:"match"` - DHCP bool `yaml:"dhcp"` - Address string `yaml:"address,omitempty"` - Gateway string `yaml:"gateway,omitempty"` - MTU int `yaml:"mtu,omitempty"` -} - -type UserDockerInfo struct { - UseTLS bool `yaml:"use_tls"` - TLSServerCert string `yaml:"tls_server_cert"` - TLSServerKey string `yaml:"tls_server_key"` - TLSCACert string `yaml:"tls_ca_cert"` -} - -type SshInfo struct { - Keys map[string]string -} - -type ConfigState struct { - FsType string `yaml:"fstype"` - Dev string `yaml:"dev"` - Required bool `yaml:"required"` -} - -type CloudInit struct { - Datasources []string `yaml:"datasources,omitempty"` -} - -func (c *Config) PrivilegedMerge(newConfig Config) (bool, error) { - reboot, err := c.Merge(newConfig) +func (c *Config) privilegedMerge(newConfig Config) error { + err := c.overlay(newConfig) if err != nil { - return reboot, err + return err } toAppend := make([]ContainerConfig, 0, 5) @@ -115,48 +33,56 @@ func (c *Config) PrivilegedMerge(newConfig Config) (bool, error) { c.SystemContainers = append(c.SystemContainers, toAppend...) - return reboot, nil + return nil } -func (c *Config) Merge(newConfig Config) (bool, error) { - //Efficient? Nope, but computers are fast - newConfig.ClearReadOnly() - content, err := newConfig.Dump() - if err != nil { - return false, err +func (c *Config) overlay(newConfig Config) error { + newConfig.clearReadOnly() + return util.Convert(&newConfig, c) +} + +func (c *Config) clearReadOnly() { + c.BootstrapContainers = make([]ContainerConfig, 0) + c.SystemContainers = make([]ContainerConfig, 0) +} + +func clearReadOnly(data map[interface{}]interface{}) map[interface{}]interface{} { + newData := make(map[interface{}]interface{}) + for k, v := range data { + newData[k] = v } - log.Debugf("Input \n%s", string(content)) + delete(newData, "system_container") + delete(newData, "bootstrap_container") - err = yaml.Unmarshal([]byte(content), c) - return true, err + return newData } -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) { - content, err := yaml.Marshal(c) - if err != nil { - return "", err - } else { - return string(content), err - } -} - -func (c Config) Save() error { - c.ClearReadOnly() - content, err := c.Dump() +func (c *Config) Import(bytes []byte) error { + data, err := readConfig(bytes, PrivateConfigFile) if err != nil { return err } - return ioutil.WriteFile(ConfigFile, []byte(content), 400) + if err = saveToDisk(data); err != nil { + return err + } + + return c.Reload() +} + +func (c *Config) Merge(bytes []byte) error { + data, err := readSavedConfig(bytes) + if err != nil { + return err + } + + err = saveToDisk(data) + if err != nil { + return err + } + + return c.Reload() } func LoadConfig() (*Config, error) { @@ -172,17 +98,6 @@ func LoadConfig() (*Config, error) { return cfg, nil } -func FilterGlobalConfig(input []string) []string { - result := make([]string, 0, len(input)) - for _, value := range input { - if !strings.HasPrefix(value, "--rancher") { - result = append(result, value) - } - } - - return result -} - func (c *Config) readArgs() error { log.Debug("Reading config args") parts := make([]string, len(os.Args)) @@ -209,32 +124,13 @@ func (c *Config) readArgs() error { return c.merge(cmdLineObj) } -func (c *Config) merge(values map[string]interface{}) error { - // Lazy way to assign values to *Config - override, err := yaml.Marshal(values) - if err != nil { - return err - } - var newConfig Config - err = yaml.Unmarshal(override, &newConfig) - if err != nil { - return nil - } - - _, err = c.Merge(newConfig) - return err +func (c *Config) merge(values map[interface{}]interface{}) error { + values = clearReadOnly(values) + return util.Convert(values, c) } -func (c *Config) readFile() error { - content, err := ioutil.ReadFile(ConfigFile) - if os.IsNotExist(err) { - return nil - } else if err != nil { - return err - } - - data := make(map[string]interface{}) - err = yaml.Unmarshal(content, data) +func (c *Config) readFiles() error { + data, err := readSavedConfig(nil) if err != nil { return err } @@ -259,75 +155,49 @@ func (c *Config) readCmdline() error { return c.merge(cmdLineObj) } -func DummyMarshall(value string) interface{} { - if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") { - return strings.Split(value[1:len(value)-1], ",") +func Dump(private, full bool) (string, error) { + files := []string{ConfigFile} + if private { + files = append(files, PrivateConfigFile) } - if value == "true" { - return true - } else if value == "false" { - return false - } else if ok, _ := regexp.MatchString("^[0-9]+$", value); ok { - i, err := strconv.Atoi(value) - if err != nil { - panic(err) - } - return i + var c Config + + if full { + c = *NewConfig() } - return value + data, err := readConfig(nil, files...) + if err != nil { + return "", err + } + + err = c.merge(data) + if err != nil { + return "", err + } + + err = c.readGlobals() + if err != nil { + return "", err + } + + bytes, err := yaml.Marshal(c) + return string(bytes), err } -func parseCmdline(cmdLine string) map[string]interface{} { - result := make(map[string]interface{}) - -outer: - for _, part := range strings.Split(cmdLine, " ") { - if !strings.HasPrefix(part, "rancher.") { - continue - } - - var value string - kv := strings.SplitN(part, "=", 2) - - if len(kv) == 1 { - value = "true" - } else { - value = kv[1] - } - - current := result - keys := strings.Split(kv[0], ".")[1:] - for i, key := range keys { - if i == len(keys)-1 { - current[key] = DummyMarshall(value) - } else { - if obj, ok := current[key]; ok { - if newCurrent, ok := obj.(map[string]interface{}); ok { - current = newCurrent - } else { - continue outer - } - } else { - newCurrent := make(map[string]interface{}) - current[key] = newCurrent - current = newCurrent - } - } - } - } - - log.Debugf("Input obj %s", result) - return result +func (c *Config) readGlobals() error { + return util.ShortCircuit( + c.readCmdline, + c.readArgs, + c.mergeAddons, + ) } func (c *Config) Reload() error { return util.ShortCircuit( - c.readFile, - c.readCmdline, - c.readArgs, - c.mergeAddons, + c.readFiles, + c.readGlobals, ) } @@ -335,8 +205,7 @@ 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 { + if err := c.privilegedMerge(newConfig); err != nil { return err } } @@ -345,14 +214,53 @@ func (c *Config) mergeAddons() error { return nil } -func RunInitFuncs(cfg *Config, initFuncs []InitFunc) error { - for i, initFunc := range initFuncs { - log.Debugf("[%d/%d] Starting", i+1, len(initFuncs)) - if err := initFunc(cfg); err != nil { - log.Errorf("Failed [%d/%d] %d%%", i+1, len(initFuncs), ((i + 1) * 100 / len(initFuncs))) - return err - } - log.Debugf("[%d/%d] Done %d%%", i+1, len(initFuncs), ((i + 1) * 100 / len(initFuncs))) +func (c *Config) Get(key string) (interface{}, error) { + data := make(map[interface{}]interface{}) + err := util.Convert(c, &data) + if err != nil { + return nil, err } - return nil + + return getOrSetVal(key, data, nil), nil +} + +//func (c *Config) SetBytes(bytes []byte) error { +// content, err := readConfigFile() +// if err != nil { +// return err +// } +// +// data := make(map[interface{}]interface{}) +// err = yaml.Unmarshal(content, &data) +// if err != nil { +// return err +// } +// +// err = yaml.Unmarshal(bytes, &data) +// if err != nil { +// return err +// } +// +// content, err = yaml.Marshal(data) +// if err != nil { +// return err +// } +// +// return ioutil.WriteFile(ConfigFile, content, 400) +//} + +func (c *Config) Set(key string, value interface{}) error { + data, err := readSavedConfig(nil) + if err != nil { + return err + } + + getOrSetVal(key, data, value) + + err = saveToDisk(data) + if err != nil { + return err + } + + return c.Reload() } diff --git a/config/config_test.go b/config/config_test.go index 5f4ce005..c19a346a 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1,10 +1,7 @@ package config -import ( - "testing" - - "code.google.com/p/rog-go/deepdiff" -) +import "testing" +import "reflect" func TestParseCmdline(t *testing.T) { expected := map[string]interface{}{ @@ -23,8 +20,76 @@ func TestParseCmdline(t *testing.T) { actual := parseCmdline("a b rancher.rescue rancher.keyArray=[1,2] rancher.key1=value1 c rancher.key2=value2 rancher.obj1.key3=3value rancher.obj1.obj2.key4 rancher.key5=5") - ok, err := deepdiff.DeepDiff(actual, expected) - if !ok || err != nil { - t.Fatal(err) + ok := reflect.DeepEqual(actual, expected) + if !ok { + t.Fatalf("%v != %v", actual, expected) + } +} + +func TestGet(t *testing.T) { + data := map[interface{}]interface{}{ + "key": "value", + "key2": map[interface{}]interface{}{ + "subkey": "subvalue", + "subnum": 42, + }, + } + + tests := map[string]interface{}{ + "key": "value", + "key2.subkey": "subvalue", + "key2.subnum": 42, + "key2.subkey2": "", + "foo": "", + } + + for k, v := range tests { + if getOrSetVal(k, data, nil) != v { + t.Fatalf("Expected %v, got %v, for key %s", v, getOrSetVal(k, data, nil), k) + } + } +} + +func TestSet(t *testing.T) { + data := map[interface{}]interface{}{ + "key": "value", + "key2": map[interface{}]interface{}{ + "subkey": "subvalue", + "subnum": 42, + }, + } + + expected := map[interface{}]interface{}{ + "key": "value2", + "key2": map[interface{}]interface{}{ + "subkey": "subvalue2", + "subkey2": "value", + "subkey3": 43, + "subnum": 42, + }, + "key3": map[interface{}]interface{}{ + "subkey3": 44, + }, + "key4": "value4", + } + + tests := map[string]interface{}{ + "key": "value2", + "key2.subkey": "subvalue2", + "key2.subkey2": "value", + "key2.subkey3": 43, + "key3.subkey3": 44, + "key4": "value4", + } + + for k, v := range tests { + getOrSetVal(k, data, v) + if getOrSetVal(k, data, nil) != v { + t.Fatalf("Expected %v, got %v, for key %s", v, getOrSetVal(k, data, nil), k) + } + } + + if !reflect.DeepEqual(data, expected) { + t.Fatalf("Expected %v, got %v", expected, data) } } diff --git a/config/data_funcs.go b/config/data_funcs.go new file mode 100644 index 00000000..8c0171b1 --- /dev/null +++ b/config/data_funcs.go @@ -0,0 +1,116 @@ +package config + +import ( + log "github.com/Sirupsen/logrus" + + "regexp" + "strconv" + "strings" +) + +func getOrSetVal(args string, data map[interface{}]interface{}, value interface{}) interface{} { + parts := strings.Split(args, ".") + + for i, part := range parts { + val, ok := data[part] + last := i+1 == len(parts) + + // Reached end, set the value + if last && value != nil { + if s, ok := value.(string); ok { + value = DummyMarshall(s) + } + + data[part] = value + return value + } + + // Missing intermediate key, create key + if !last && value != nil && !ok { + newData := map[interface{}]interface{}{} + data[part] = newData + data = newData + continue + } + + if !ok { + break + } + + if last { + return val + } + + newData, ok := val.(map[interface{}]interface{}) + if !ok { + break + } + + data = newData + } + + return "" +} + +func DummyMarshall(value string) interface{} { + if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") { + return strings.Split(value[1:len(value)-1], ",") + } + + if value == "true" { + return true + } else if value == "false" { + return false + } else if ok, _ := regexp.MatchString("^[0-9]+$", value); ok { + i, err := strconv.Atoi(value) + if err != nil { + panic(err) + } + return i + } + + return value +} + +func parseCmdline(cmdLine string) map[interface{}]interface{} { + result := make(map[interface{}]interface{}) + +outer: + for _, part := range strings.Split(cmdLine, " ") { + if !strings.HasPrefix(part, "rancher.") { + continue + } + + var value string + kv := strings.SplitN(part, "=", 2) + + if len(kv) == 1 { + value = "true" + } else { + value = kv[1] + } + + current := result + keys := strings.Split(kv[0], ".")[1:] + for i, key := range keys { + if i == len(keys)-1 { + current[key] = DummyMarshall(value) + } else { + if obj, ok := current[key]; ok { + if newCurrent, ok := obj.(map[interface{}]interface{}); ok { + current = newCurrent + } else { + continue outer + } + } else { + newCurrent := make(map[interface{}]interface{}) + current[key] = newCurrent + current = newCurrent + } + } + } + } + + log.Debugf("Input obj %v", result) + return result +} diff --git a/config/disk.go b/config/disk.go new file mode 100644 index 00000000..d67b8116 --- /dev/null +++ b/config/disk.go @@ -0,0 +1,98 @@ +package config + +import ( + "io/ioutil" + "os" + + "github.com/rancherio/os/util" + "gopkg.in/yaml.v2" +) + +func writeToFile(data interface{}, filename string) error { + content, err := yaml.Marshal(data) + if err != nil { + return err + } + + return ioutil.WriteFile(filename, content, 400) +} + +func saveToDisk(data map[interface{}]interface{}) error { + config := make(map[interface{}]interface{}) + private := make(map[interface{}]interface{}) + + for k, v := range data { + if k == "ssh" { + private[k] = v + } else if k == "userdocker" { + var userDockerConfig UserDockerConfig + var userDockerConfigPrivate UserDockerConfig + err := util.Convert(v, &userDockerConfig) + if err != nil { + return err + } + + userDockerConfigPrivate.TLSCACert = userDockerConfig.TLSCACert + userDockerConfigPrivate.TLSServerKey = userDockerConfig.TLSServerKey + userDockerConfigPrivate.TLSServerCert = userDockerConfig.TLSServerCert + + userDockerConfig.TLSCACert = "" + userDockerConfig.TLSServerKey = "" + userDockerConfig.TLSServerCert = "" + + config[k] = userDockerConfig + private[k] = userDockerConfigPrivate + } else { + config[k] = v + } + } + + err := writeToFile(config, ConfigFile) + if err != nil { + return err + } + + return writeToFile(private, PrivateConfigFile) +} + +func readSavedConfig(bytes []byte) (map[interface{}]interface{}, error) { + return readConfig(bytes, ConfigFile, PrivateConfigFile) +} + +func readConfig(bytes []byte, files ...string) (map[interface{}]interface{}, error) { + data := make(map[interface{}]interface{}) + for _, conf := range files { + content, err := readConfigFile(conf) + if err != nil { + return nil, err + } + + err = yaml.Unmarshal(content, &data) + if err != nil { + return nil, err + } + } + + if bytes != nil && len(bytes) > 0 { + if err := yaml.Unmarshal(bytes, &data); err != nil { + return nil, err + } + } + + return data, nil +} + +func readConfigFile(file string) ([]byte, error) { + content, err := ioutil.ReadFile(file) + + if err != nil { + if os.IsNotExist(err) { + err = nil + content = []byte{} + } else { + return nil, err + } + } + + return content, err +} diff --git a/config/init.go b/config/init.go new file mode 100644 index 00000000..c24c546e --- /dev/null +++ b/config/init.go @@ -0,0 +1,32 @@ +package config + +import ( + "strings" + + log "github.com/Sirupsen/logrus" +) + +type InitFunc func(*Config) error + +func RunInitFuncs(cfg *Config, initFuncs []InitFunc) error { + for i, initFunc := range initFuncs { + log.Debugf("[%d/%d] Starting", i+1, len(initFuncs)) + if err := initFunc(cfg); err != nil { + log.Errorf("Failed [%d/%d] %d%%", i+1, len(initFuncs), ((i + 1) * 100 / len(initFuncs))) + return err + } + log.Debugf("[%d/%d] Done %d%%", i+1, len(initFuncs), ((i + 1) * 100 / len(initFuncs))) + } + return nil +} + +func FilterGlobalConfig(input []string) []string { + result := make([]string, 0, len(input)) + for _, value := range input { + if !strings.HasPrefix(value, "--rancher") { + result = append(result, value) + } + } + + return result +} diff --git a/config/types.go b/config/types.go new file mode 100644 index 00000000..79c3fb39 --- /dev/null +++ b/config/types.go @@ -0,0 +1,86 @@ +package config + +const ( + VERSION = "0.0.1" + CONSOLE_CONTAINER = "console" + DOCKER_BIN = "/usr/bin/docker" + DOCKER_SYSTEM_HOST = "unix:///var/run/system-docker.sock" + DOCKER_HOST = "unix:///var/run/docker.sock" + IMAGES_PATH = "/" + IMAGES_PATTERN = "images*.tar" + SYS_INIT = "/sbin/init-sys" + USER_INIT = "/sbin/init-user" + MODULES_ARCHIVE = "/modules.tar" + DEBUG = false +) + +var ( + ConfigFile = "/var/lib/rancher/conf/rancher.yml" + PrivateConfigFile = "/var/lib/rancher/conf/rancher-private.yml" +) + +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 { + Debug bool `yaml:"debug,omitempty"` + Disable []string `yaml:"disable,omitempty"` + Dns []string `yaml:"dns,flow,omitempty"` + //Rescue bool `yaml:"rescue,omitempty"` + //RescueContainer *ContainerConfig `yaml:"rescue_container,omitempty"` + State ConfigState `yaml:"state,omitempty"` + Userdocker UserDockerConfig `yaml:"userdocker,omitempty"` + UpgradeConfig UpgradeConfig `yaml:"upgrade,omitempty"` + BootstrapContainers []ContainerConfig `yaml:"bootstrap_containers,omitempty"` + SystemContainers []ContainerConfig `yaml:"system_containers,omitempty"` + UserContainers []ContainerConfig `yaml:"user_containers,omitempty"` + SystemDockerArgs []string `yaml:"system_docker_args,flow,omitempty"` + Modules []string `yaml:"modules,omitempty"` + CloudInit CloudInit `yaml:"cloud_init,omitempty"` + SshConfig SshConfig `yaml:"ssh,omitempty"` + EnabledAddons []string `yaml:"enabled_addons,omitempty"` + Addons map[string]Config `yaml:"addons,omitempty"` + Network NetworkConfig `yaml:"network,omitempty"` +} + +type UpgradeConfig struct { + Url string `yaml:"url,omitempty"` +} + +type NetworkConfig struct { + Interfaces []InterfaceConfig `yaml:"interfaces,omitempty"` + PostRun *ContainerConfig `yaml:"post_run,omitempty"` +} + +type InterfaceConfig struct { + Match string `yaml:"match,omitempty"` + DHCP bool `yaml:"dhcp,omitempty"` + Address string `yaml:"address,omitempty"` + Gateway string `yaml:"gateway,omitempty"` + MTU int `yaml:"mtu,omitempty"` +} + +type UserDockerConfig struct { + UseTLS bool `yaml:"use_tls,omitempty"` + TLSServerCert string `yaml:"tls_server_cert,omitempty"` + TLSServerKey string `yaml:"tls_server_key,omitempty"` + TLSCACert string `yaml:"tls_ca_cert,omitempty"` +} + +type SshConfig struct { + Keys map[string]string `yaml:"keys,omitempty"` +} + +type ConfigState struct { + FsType string `yaml:"fstype,omitempty"` + Dev string `yaml:"dev,omitempty"` + Required bool `yaml:"required,omitempty"` +} + +type CloudInit struct { + Datasources []string `yaml:"datasources,omitempty"` +} diff --git a/init/init.go b/init/init.go index 1decdc17..38d5df7c 100644 --- a/init/init.go +++ b/init/init.go @@ -277,7 +277,7 @@ func RunInit() error { } if cfg.Debug { - cfgString, _ := cfg.Dump() + cfgString, _ := config.Dump(false, true) if cfgString != "" { log.Debugf("Config: %s", cfgString) } diff --git a/util/util.go b/util/util.go index 7ff379be..2d859307 100644 --- a/util/util.go +++ b/util/util.go @@ -10,6 +10,7 @@ import ( "syscall" "github.com/docker/docker/pkg/mount" + "gopkg.in/yaml.v2" ) var ( @@ -154,3 +155,12 @@ func RandSeq(n int) string { } return string(b) } + +func Convert(from, to interface{}) error { + bytes, err := yaml.Marshal(from) + if err != nil { + return err + } + + return yaml.Unmarshal(bytes, to) +}