2015-02-09 04:38:37 +00:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io/ioutil"
|
2015-02-14 16:29:07 +00:00
|
|
|
"os"
|
2015-02-09 04:38:37 +00:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
log "github.com/Sirupsen/logrus"
|
2015-02-14 16:29:07 +00:00
|
|
|
"github.com/rancherio/os/util"
|
2015-02-17 21:31:20 +00:00
|
|
|
"gopkg.in/yaml.v2"
|
2015-02-09 04:38:37 +00:00
|
|
|
)
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
func (c *Config) privilegedMerge(newConfig Config) error {
|
|
|
|
err := c.overlay(newConfig)
|
2015-02-23 03:57:09 +00:00
|
|
|
if err != nil {
|
2015-03-15 04:27:04 +00:00
|
|
|
return err
|
2015-02-23 03:57:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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...)
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
return nil
|
2015-02-23 03:57:09 +00:00
|
|
|
}
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
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
|
2015-02-18 00:00:30 +00:00
|
|
|
}
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
delete(newData, "system_container")
|
|
|
|
delete(newData, "bootstrap_container")
|
2015-02-20 03:05:43 +00:00
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
return newData
|
2015-02-18 00:00:30 +00:00
|
|
|
}
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
func (c *Config) Import(bytes []byte) error {
|
|
|
|
data, err := readConfig(bytes, PrivateConfigFile)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = saveToDisk(data); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.Reload()
|
2015-02-17 21:31:20 +00:00
|
|
|
}
|
|
|
|
|
2015-03-18 12:38:36 +00:00
|
|
|
// This function only sets "non-empty" values
|
|
|
|
func (c *Config) SetConfig(newConfig *Config) error {
|
|
|
|
bytes, err := yaml.Marshal(newConfig)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.Merge(bytes)
|
|
|
|
}
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
func (c *Config) Merge(bytes []byte) error {
|
|
|
|
data, err := readSavedConfig(bytes)
|
2015-02-17 21:31:20 +00:00
|
|
|
if err != nil {
|
2015-03-15 04:27:04 +00:00
|
|
|
return err
|
2015-02-14 16:29:07 +00:00
|
|
|
}
|
2015-02-09 04:38:37 +00:00
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
err = saveToDisk(data)
|
2015-02-18 00:00:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
return c.Reload()
|
2015-02-18 00:00:30 +00:00
|
|
|
}
|
|
|
|
|
2015-02-09 04:38:37 +00:00
|
|
|
func LoadConfig() (*Config, error) {
|
|
|
|
cfg := NewConfig()
|
|
|
|
if err := cfg.Reload(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if cfg.Debug {
|
|
|
|
log.SetLevel(log.DebugLevel)
|
|
|
|
}
|
|
|
|
|
|
|
|
return cfg, nil
|
|
|
|
}
|
|
|
|
|
2015-02-14 16:29:07 +00:00
|
|
|
func (c *Config) readArgs() error {
|
|
|
|
log.Debug("Reading config args")
|
2015-02-20 03:05:43 +00:00
|
|
|
parts := make([]string, len(os.Args))
|
|
|
|
|
|
|
|
for _, arg := range os.Args[1:] {
|
|
|
|
if strings.HasPrefix(arg, "--") {
|
|
|
|
arg = arg[2:]
|
|
|
|
}
|
|
|
|
|
2015-02-23 19:00:24 +00:00
|
|
|
kv := strings.SplitN(arg, "=", 2)
|
|
|
|
kv[0] = strings.Replace(kv[0], "-", ".", -1)
|
|
|
|
parts = append(parts, strings.Join(kv, "="))
|
2015-02-20 03:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cmdLine := strings.Join(parts, " ")
|
2015-02-14 16:29:07 +00:00
|
|
|
if len(cmdLine) == 0 {
|
|
|
|
return nil
|
2015-02-09 04:38:37 +00:00
|
|
|
}
|
|
|
|
|
2015-02-14 16:29:07 +00:00
|
|
|
log.Debugf("Config Args %s", cmdLine)
|
|
|
|
|
|
|
|
cmdLineObj := parseCmdline(strings.TrimSpace(cmdLine))
|
|
|
|
|
|
|
|
return c.merge(cmdLineObj)
|
|
|
|
}
|
2015-02-09 04:38:37 +00:00
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
func (c *Config) merge(values map[interface{}]interface{}) error {
|
|
|
|
values = clearReadOnly(values)
|
|
|
|
return util.Convert(values, c)
|
2015-02-14 16:29:07 +00:00
|
|
|
}
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
func (c *Config) readFiles() error {
|
|
|
|
data, err := readSavedConfig(nil)
|
2015-02-18 00:00:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.merge(data)
|
|
|
|
}
|
|
|
|
|
2015-02-14 16:29:07 +00:00
|
|
|
func (c *Config) readCmdline() error {
|
|
|
|
log.Debug("Reading config cmdline")
|
|
|
|
cmdLine, err := ioutil.ReadFile("/proc/cmdline")
|
2015-02-09 04:38:37 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-02-14 16:29:07 +00:00
|
|
|
|
|
|
|
if len(cmdLine) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debugf("Config cmdline %s", cmdLine)
|
|
|
|
|
|
|
|
cmdLineObj := parseCmdline(strings.TrimSpace(string(cmdLine)))
|
|
|
|
return c.merge(cmdLineObj)
|
2015-02-09 04:38:37 +00:00
|
|
|
}
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
func Dump(private, full bool) (string, error) {
|
2015-03-18 12:38:36 +00:00
|
|
|
files := []string{CloudConfigFile, ConfigFile}
|
2015-03-15 04:27:04 +00:00
|
|
|
if private {
|
|
|
|
files = append(files, PrivateConfigFile)
|
2015-02-09 04:38:37 +00:00
|
|
|
}
|
|
|
|
|
2015-03-18 12:38:36 +00:00
|
|
|
c := &Config{}
|
2015-02-09 04:38:37 +00:00
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
if full {
|
2015-03-18 12:38:36 +00:00
|
|
|
c = NewConfig()
|
2015-03-15 04:27:04 +00:00
|
|
|
}
|
2015-02-09 04:38:37 +00:00
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
data, err := readConfig(nil, files...)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2015-02-09 04:38:37 +00:00
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
err = c.merge(data)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2015-02-09 04:38:37 +00:00
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
err = c.readGlobals()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
2015-02-09 04:38:37 +00:00
|
|
|
}
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
bytes, err := yaml.Marshal(c)
|
|
|
|
return string(bytes), err
|
2015-02-09 04:38:37 +00:00
|
|
|
}
|
|
|
|
|
2015-03-18 12:38:36 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
func (c *Config) readGlobals() error {
|
2015-02-14 16:29:07 +00:00
|
|
|
return util.ShortCircuit(
|
|
|
|
c.readCmdline,
|
|
|
|
c.readArgs,
|
2015-02-23 03:57:09 +00:00
|
|
|
c.mergeAddons,
|
2015-03-18 12:38:36 +00:00
|
|
|
c.configureConsole,
|
2015-02-14 16:29:07 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
func (c *Config) Reload() error {
|
|
|
|
return util.ShortCircuit(
|
|
|
|
c.readFiles,
|
|
|
|
c.readGlobals,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2015-02-23 03:57:09 +00:00
|
|
|
func (c *Config) mergeAddons() error {
|
|
|
|
for _, addon := range c.EnabledAddons {
|
|
|
|
if newConfig, ok := c.Addons[addon]; ok {
|
|
|
|
log.Debugf("Enabling addon %s", addon)
|
2015-03-15 04:27:04 +00:00
|
|
|
if err := c.privilegedMerge(newConfig); err != nil {
|
2015-02-23 03:57:09 +00:00
|
|
|
return err
|
|
|
|
}
|
2015-02-14 16:29:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2015-02-09 04:38:37 +00:00
|
|
|
}
|
|
|
|
|
2015-03-15 04:27:04 +00:00
|
|
|
func (c *Config) Get(key string) (interface{}, error) {
|
|
|
|
data := make(map[interface{}]interface{})
|
|
|
|
err := util.Convert(c, &data)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2015-02-09 04:38:37 +00:00
|
|
|
}
|
2015-03-15 04:27:04 +00:00
|
|
|
|
|
|
|
return getOrSetVal(key, data, nil), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
2015-02-09 04:38:37 +00:00
|
|
|
}
|