1
0
mirror of https://github.com/rancher/os.git synced 2025-06-21 20:47:04 +00:00
os/config/config.go

359 lines
8.0 KiB
Go
Raw Normal View History

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"`
ReloadConfig bool `yaml:"reload_config,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-23 19:00:24 +00:00
OsUpgradeChannel string `yaml:"os_upgrade_channel,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-20 03:05:43 +00:00
CloudInit CloudInit `yaml:"cloud_init"`
2015-02-21 07:34:38 +00:00
SshInfo SshInfo `yaml:"ssh"`
EnabledAddons []string `yaml:"enabledAddons,omitempty"`
Addons map[string]Config `yaml:"addons,omitempty"`
Network NetworkConfig `yaml:"network,omitempty"`
2015-03-02 23:03:21 +00:00
}
type NetworkConfig struct {
Interfaces []InterfaceConfig `yaml:"interfaces"`
PostRun *ContainerConfig `yaml:"post_run"`
2015-03-02 23:03:21 +00:00
}
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"`
2015-02-17 08:18:48 +00:00
}
2015-02-18 01:05:03 +00:00
type UserDockerInfo struct {
2015-02-20 03:05:43 +00:00
UseTLS bool `yaml:"use_tls"`
2015-02-19 20:47:06 +00:00
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-21 07:34:38 +00:00
type SshInfo struct {
Keys map[string]string
}
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-20 03:05:43 +00:00
type CloudInit struct {
2015-02-23 19:00:24 +00:00
Datasources []string `yaml:"datasources,omitempty"`
2015-02-20 03:05:43 +00:00
}
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
}
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
}
2015-02-20 03:05:43 +00:00
log.Debugf("Input \n%s", string(content))
2015-02-18 00:00:30 +00:00
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
c.Rescue = false
c.Debug = false
c.Addons = map[string]Config{}
2015-02-17 21:31:20 +00:00
}
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-23 19:00:24 +00:00
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
}
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-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
}
var newConfig Config
err = yaml.Unmarshal(override, &newConfig)
if err != nil {
return nil
}
_, err = c.Merge(newConfig)
return err
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
2015-02-21 07:34:38 +00:00
} else if err != nil {
return err
2015-02-18 00:00:30 +00:00
}
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,
c.mergeAddons,
2015-02-14 16:29:07 +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)
_, err := c.PrivilegedMerge(newConfig)
if err != nil {
return err
}
2015-02-14 16:29:07 +00:00
}
}
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
}