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
|
|
|
"regexp"
|
|
|
|
"strconv"
|
|
|
|
"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-02-17 08:18:48 +00:00
|
|
|
const (
|
2015-02-17 21:31:20 +00:00
|
|
|
VERSION = "0.0.1"
|
2015-02-17 08:18:48 +00:00
|
|
|
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"
|
2015-02-17 21:31:20 +00:00
|
|
|
DEBUG = false
|
2015-02-17 08:18:48 +00:00
|
|
|
)
|
|
|
|
|
2015-02-18 00:00:30 +00:00
|
|
|
var (
|
2015-02-19 15:34:38 +00:00
|
|
|
ConfigFile = "/var/lib/rancher/conf/rancher.yml"
|
2015-02-18 00:00:30 +00:00
|
|
|
)
|
|
|
|
|
2015-02-09 04:38:37 +00:00
|
|
|
type InitFunc func(*Config) error
|
|
|
|
|
|
|
|
type ContainerConfig struct {
|
2015-02-19 15:34:38 +00:00
|
|
|
Id string `yaml:"id,omitempty"`
|
|
|
|
Cmd string `yaml:"run,omitempty"`
|
|
|
|
MigrateVolumes bool `yaml:"migrate_volumes,omitempty"`
|
2015-02-09 04:38:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Config struct {
|
2015-02-17 21:31:20 +00:00
|
|
|
Debug bool `yaml:"debug,omitempty"`
|
|
|
|
Disable []string `yaml:"disable,omitempty"`
|
2015-02-18 00:00:30 +00:00
|
|
|
Dns []string `yaml:"dns,flow,omitempty"`
|
2015-02-17 21:31:20 +00:00
|
|
|
Rescue bool `yaml:"rescue,omitempty"`
|
|
|
|
RescueContainer *ContainerConfig `yaml:"rescue_container,omitempty"`
|
|
|
|
State ConfigState `yaml:"state,omitempty"`
|
2015-02-18 01:05:03 +00:00
|
|
|
Userdocker UserDockerInfo `yaml:"userdocker,omitempty"`
|
2015-02-19 20:47:06 +00:00
|
|
|
CloudConfig []string `yaml:"cloud_config,omitempty"`
|
2015-02-17 21:31:20 +00:00
|
|
|
SystemContainers []ContainerConfig `yaml:"system_containers,omitempty"`
|
|
|
|
SystemDockerArgs []string `yaml:"system_docker_args,flow,omitempty"`
|
|
|
|
Modules []string `yaml:"modules,omitempty"`
|
2015-02-17 08:18:48 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 01:05:03 +00:00
|
|
|
type UserDockerInfo struct {
|
2015-02-19 20:47:06 +00:00
|
|
|
UseTLS bool `yaml:"use_tls,omitempty"`
|
|
|
|
TLSServerCert string `yaml:"tls_server_cert"`
|
|
|
|
TLSServerKey string `yaml:"tls_server_key"`
|
|
|
|
TLSCACert string `yaml:"tls_ca_cert"`
|
2015-02-18 01:05:03 +00:00
|
|
|
}
|
|
|
|
|
2015-02-17 08:18:48 +00:00
|
|
|
type ConfigState struct {
|
2015-02-17 21:31:20 +00:00
|
|
|
FsType string `yaml:"fstype"`
|
|
|
|
Dev string `yaml:"dev"`
|
|
|
|
Required bool `yaml:"required"`
|
2015-02-14 16:29:07 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 00:00:30 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
err = yaml.Unmarshal([]byte(content), c)
|
|
|
|
return true, err
|
|
|
|
}
|
|
|
|
|
2015-02-17 21:31:20 +00:00
|
|
|
func (c *Config) ClearReadOnly() {
|
|
|
|
c.SystemContainers = []ContainerConfig{}
|
|
|
|
c.RescueContainer = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) Dump() (string, error) {
|
|
|
|
content, err := yaml.Marshal(c)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
2015-02-14 16:29:07 +00:00
|
|
|
} else {
|
2015-02-17 21:31:20 +00:00
|
|
|
return string(content), err
|
2015-02-14 16:29:07 +00:00
|
|
|
}
|
2015-02-09 04:38:37 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 00:00:30 +00:00
|
|
|
func (c Config) Save() error {
|
|
|
|
c.ClearReadOnly()
|
|
|
|
content, err := c.Dump()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ioutil.WriteFile(ConfigFile, []byte(content), 400)
|
|
|
|
}
|
|
|
|
|
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")
|
|
|
|
cmdLine := strings.Join(os.Args[1:], " ")
|
|
|
|
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-02-14 16:29:07 +00:00
|
|
|
func (c *Config) merge(values map[string]interface{}) error {
|
2015-02-09 04:38:37 +00:00
|
|
|
// Lazy way to assign values to *Config
|
2015-02-17 21:31:20 +00:00
|
|
|
override, err := yaml.Marshal(values)
|
2015-02-14 16:29:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-02-17 21:31:20 +00:00
|
|
|
return yaml.Unmarshal(override, c)
|
2015-02-14 16:29:07 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 00:00:30 +00:00
|
|
|
func (c *Config) readFile() error {
|
|
|
|
content, err := ioutil.ReadFile(ConfigFile)
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
data := make(map[string]interface{})
|
|
|
|
err = yaml.Unmarshal(content, data)
|
|
|
|
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-02-18 00:00:30 +00:00
|
|
|
func DummyMarshall(value string) interface{} {
|
|
|
|
if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") {
|
|
|
|
return strings.Split(value[1:len(value)-1], ",")
|
|
|
|
}
|
|
|
|
|
2015-02-09 04:38:37 +00:00
|
|
|
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[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 {
|
2015-02-18 00:00:30 +00:00
|
|
|
current[key] = DummyMarshall(value)
|
2015-02-09 04:38:37 +00:00
|
|
|
} 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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-14 16:29:07 +00:00
|
|
|
log.Debugf("Input obj %s", result)
|
2015-02-09 04:38:37 +00:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) Reload() error {
|
2015-02-14 16:29:07 +00:00
|
|
|
return util.ShortCircuit(
|
2015-02-18 00:00:30 +00:00
|
|
|
c.readFile,
|
2015-02-14 16:29:07 +00:00
|
|
|
c.readCmdline,
|
|
|
|
c.readArgs,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Config) GetContainerById(id string) *ContainerConfig {
|
|
|
|
for _, c := range c.SystemContainers {
|
|
|
|
if c.Id == id {
|
|
|
|
return &c
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2015-02-09 04:38:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|