mirror of
https://github.com/rancher/os.git
synced 2025-09-04 16:21:07 +00:00
Refactor configuration
This commit is contained in:
@@ -51,7 +51,7 @@ func disable(c *cli.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if changed {
|
if changed {
|
||||||
if err = cfg.Save(); err != nil {
|
if err = cfg.Set("enabled_addons", cfg.EnabledAddons); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ func enable(c *cli.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if changed {
|
if changed {
|
||||||
if err = cfg.Save(); err != nil {
|
if err = cfg.Set("enabled_addons", cfg.EnabledAddons); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,7 +12,6 @@ import (
|
|||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
"github.com/rancherio/os/config"
|
"github.com/rancherio/os/config"
|
||||||
"github.com/rancherio/os/docker"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func configSubcommands() []cli.Command {
|
func configSubcommands() []cli.Command {
|
||||||
@@ -30,7 +29,7 @@ func configSubcommands() []cli.Command {
|
|||||||
{
|
{
|
||||||
Name: "import",
|
Name: "import",
|
||||||
Usage: "import configuration from standard in or a file",
|
Usage: "import configuration from standard in or a file",
|
||||||
Action: configImport,
|
Action: runImport,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "input, i",
|
Name: "input, i",
|
||||||
@@ -40,43 +39,40 @@ func configSubcommands() []cli.Command {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "export",
|
Name: "export",
|
||||||
Usage: "dump full configuration",
|
Usage: "export configuration",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "output, o",
|
Name: "output, o",
|
||||||
Usage: "File to which to save",
|
Usage: "File to which to save",
|
||||||
},
|
},
|
||||||
cli.BoolFlag{
|
cli.BoolFlag{
|
||||||
Name: "full",
|
Name: "private, p",
|
||||||
Usage: "Include full configuration, not just writable fields",
|
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) {
|
func runImport(c *cli.Context) {
|
||||||
cfg, err := config.LoadConfig()
|
var input io.ReadCloser
|
||||||
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
|
|
||||||
var err error
|
var err error
|
||||||
input = os.Stdin
|
input = os.Stdin
|
||||||
|
cfg, err := config.LoadConfig()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
inputFile := c.String("input")
|
inputFile := c.String("input")
|
||||||
if inputFile != "" {
|
if inputFile != "" {
|
||||||
@@ -84,6 +80,7 @@ func configImport(c *cli.Context) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
defer input.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes, err := ioutil.ReadAll(input)
|
bytes, err := ioutil.ReadAll(input)
|
||||||
@@ -91,38 +88,12 @@ func configImport(c *cli.Context) {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mergeConfig(bytes)
|
err = cfg.Import(bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
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) {
|
func configSet(c *cli.Context) {
|
||||||
key := c.Args().Get(0)
|
key := c.Args().Get(0)
|
||||||
value := c.Args().Get(1)
|
value := c.Args().Get(1)
|
||||||
@@ -130,15 +101,12 @@ func configSet(c *cli.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := getConfigData()
|
cfg, err := config.LoadConfig()
|
||||||
getOrSetVal(key, data, value)
|
|
||||||
|
|
||||||
bytes, err := yaml.Marshal(data)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mergeConfig(bytes)
|
err = cfg.Set(key, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -150,12 +118,15 @@ func configGet(c *cli.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := getConfigData()
|
cfg, err := config.LoadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
val := getOrSetVal(arg, data, nil)
|
val, err := cfg.Get(arg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
printYaml := false
|
printYaml := false
|
||||||
switch val.(type) {
|
switch val.(type) {
|
||||||
@@ -183,6 +154,7 @@ func getOrSetVal(args string, data map[interface{}]interface{}, value interface{
|
|||||||
val, ok := data[part]
|
val, ok := data[part]
|
||||||
last := i+1 == len(parts)
|
last := i+1 == len(parts)
|
||||||
|
|
||||||
|
// Reached end, set the value
|
||||||
if last && value != nil {
|
if last && value != nil {
|
||||||
if s, ok := value.(string); ok {
|
if s, ok := value.(string); ok {
|
||||||
value = config.DummyMarshall(s)
|
value = config.DummyMarshall(s)
|
||||||
@@ -192,6 +164,14 @@ func getOrSetVal(args string, data map[interface{}]interface{}, value interface{
|
|||||||
return 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 {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -211,26 +191,29 @@ func getOrSetVal(args string, data map[interface{}]interface{}, value interface{
|
|||||||
return ""
|
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()
|
cfg, err := config.LoadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: why doesn't this work
|
err = cfg.Merge(bytes)
|
||||||
for _, c := range cfg.SystemContainers {
|
if err != nil {
|
||||||
container := docker.NewContainer("", &c)
|
log.Fatal(err)
|
||||||
if container.Err != nil {
|
|
||||||
log.Fatalf("Failed to parse [%s] : %v", c.Cmd, container.Err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !c.Bool("full") {
|
func export(c *cli.Context) {
|
||||||
cfg.ClearReadOnly()
|
content, err := config.Dump(c.Bool("private"), c.Bool("full"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := cfg.Dump()
|
|
||||||
|
|
||||||
output := c.String("output")
|
output := c.String("output")
|
||||||
if output == "" {
|
if output == "" {
|
||||||
fmt.Println(content)
|
fmt.Println(content)
|
||||||
@@ -240,5 +223,4 @@ func configSave(c *cli.Context) {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
350
config/config.go
350
config/config.go
@@ -3,8 +3,6 @@ package config
|
|||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
@@ -12,90 +10,10 @@ import (
|
|||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
func (c *Config) privilegedMerge(newConfig Config) error {
|
||||||
VERSION = "0.0.1"
|
err := c.overlay(newConfig)
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return reboot, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
toAppend := make([]ContainerConfig, 0, 5)
|
toAppend := make([]ContainerConfig, 0, 5)
|
||||||
@@ -115,48 +33,56 @@ func (c *Config) PrivilegedMerge(newConfig Config) (bool, error) {
|
|||||||
|
|
||||||
c.SystemContainers = append(c.SystemContainers, toAppend...)
|
c.SystemContainers = append(c.SystemContainers, toAppend...)
|
||||||
|
|
||||||
return reboot, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Merge(newConfig Config) (bool, error) {
|
func (c *Config) overlay(newConfig Config) error {
|
||||||
//Efficient? Nope, but computers are fast
|
newConfig.clearReadOnly()
|
||||||
newConfig.ClearReadOnly()
|
return util.Convert(&newConfig, c)
|
||||||
content, err := newConfig.Dump()
|
}
|
||||||
if err != nil {
|
|
||||||
return false, err
|
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 newData
|
||||||
return true, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) ClearReadOnly() {
|
func (c *Config) Import(bytes []byte) error {
|
||||||
c.SystemContainers = []ContainerConfig{}
|
data, err := readConfig(bytes, PrivateConfigFile)
|
||||||
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()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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) {
|
func LoadConfig() (*Config, error) {
|
||||||
@@ -172,17 +98,6 @@ func LoadConfig() (*Config, error) {
|
|||||||
return cfg, nil
|
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 {
|
func (c *Config) readArgs() error {
|
||||||
log.Debug("Reading config args")
|
log.Debug("Reading config args")
|
||||||
parts := make([]string, len(os.Args))
|
parts := make([]string, len(os.Args))
|
||||||
@@ -209,32 +124,13 @@ func (c *Config) readArgs() error {
|
|||||||
return c.merge(cmdLineObj)
|
return c.merge(cmdLineObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) merge(values map[string]interface{}) error {
|
func (c *Config) merge(values map[interface{}]interface{}) error {
|
||||||
// Lazy way to assign values to *Config
|
values = clearReadOnly(values)
|
||||||
override, err := yaml.Marshal(values)
|
return util.Convert(values, c)
|
||||||
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) readFile() error {
|
func (c *Config) readFiles() error {
|
||||||
content, err := ioutil.ReadFile(ConfigFile)
|
data, err := readSavedConfig(nil)
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
data := make(map[string]interface{})
|
|
||||||
err = yaml.Unmarshal(content, data)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -259,75 +155,49 @@ func (c *Config) readCmdline() error {
|
|||||||
return c.merge(cmdLineObj)
|
return c.merge(cmdLineObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DummyMarshall(value string) interface{} {
|
func Dump(private, full bool) (string, error) {
|
||||||
if strings.HasPrefix(value, "[") && strings.HasSuffix(value, "]") {
|
files := []string{ConfigFile}
|
||||||
return strings.Split(value[1:len(value)-1], ",")
|
if private {
|
||||||
|
files = append(files, PrivateConfigFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
if value == "true" {
|
var c Config
|
||||||
return true
|
|
||||||
} else if value == "false" {
|
if full {
|
||||||
return false
|
c = *NewConfig()
|
||||||
} else if ok, _ := regexp.MatchString("^[0-9]+$", value); ok {
|
|
||||||
i, err := strconv.Atoi(value)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return i
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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{} {
|
func (c *Config) readGlobals() error {
|
||||||
result := make(map[string]interface{})
|
return util.ShortCircuit(
|
||||||
|
c.readCmdline,
|
||||||
outer:
|
c.readArgs,
|
||||||
for _, part := range strings.Split(cmdLine, " ") {
|
c.mergeAddons,
|
||||||
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) Reload() error {
|
func (c *Config) Reload() error {
|
||||||
return util.ShortCircuit(
|
return util.ShortCircuit(
|
||||||
c.readFile,
|
c.readFiles,
|
||||||
c.readCmdline,
|
c.readGlobals,
|
||||||
c.readArgs,
|
|
||||||
c.mergeAddons,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,8 +205,7 @@ func (c *Config) mergeAddons() error {
|
|||||||
for _, addon := range c.EnabledAddons {
|
for _, addon := range c.EnabledAddons {
|
||||||
if newConfig, ok := c.Addons[addon]; ok {
|
if newConfig, ok := c.Addons[addon]; ok {
|
||||||
log.Debugf("Enabling addon %s", addon)
|
log.Debugf("Enabling addon %s", addon)
|
||||||
_, err := c.PrivilegedMerge(newConfig)
|
if err := c.privilegedMerge(newConfig); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -345,14 +214,53 @@ func (c *Config) mergeAddons() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunInitFuncs(cfg *Config, initFuncs []InitFunc) error {
|
func (c *Config) Get(key string) (interface{}, error) {
|
||||||
for i, initFunc := range initFuncs {
|
data := make(map[interface{}]interface{})
|
||||||
log.Debugf("[%d/%d] Starting", i+1, len(initFuncs))
|
err := util.Convert(c, &data)
|
||||||
if err := initFunc(cfg); err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed [%d/%d] %d%%", i+1, len(initFuncs), ((i + 1) * 100 / len(initFuncs)))
|
return nil, err
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Debugf("[%d/%d] Done %d%%", i+1, len(initFuncs), ((i + 1) * 100 / len(initFuncs)))
|
|
||||||
}
|
}
|
||||||
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()
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import "testing"
|
||||||
"testing"
|
import "reflect"
|
||||||
|
|
||||||
"code.google.com/p/rog-go/deepdiff"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParseCmdline(t *testing.T) {
|
func TestParseCmdline(t *testing.T) {
|
||||||
expected := map[string]interface{}{
|
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")
|
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)
|
ok := reflect.DeepEqual(actual, expected)
|
||||||
if !ok || err != nil {
|
if !ok {
|
||||||
t.Fatal(err)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
116
config/data_funcs.go
Normal file
116
config/data_funcs.go
Normal file
@@ -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
|
||||||
|
}
|
98
config/disk.go
Normal file
98
config/disk.go
Normal file
@@ -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
|
||||||
|
}
|
32
config/init.go
Normal file
32
config/init.go
Normal file
@@ -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
|
||||||
|
}
|
86
config/types.go
Normal file
86
config/types.go
Normal file
@@ -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"`
|
||||||
|
}
|
@@ -277,7 +277,7 @@ func RunInit() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Debug {
|
if cfg.Debug {
|
||||||
cfgString, _ := cfg.Dump()
|
cfgString, _ := config.Dump(false, true)
|
||||||
if cfgString != "" {
|
if cfgString != "" {
|
||||||
log.Debugf("Config: %s", cfgString)
|
log.Debugf("Config: %s", cfgString)
|
||||||
}
|
}
|
||||||
|
10
util/util.go
10
util/util.go
@@ -10,6 +10,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/mount"
|
"github.com/docker/docker/pkg/mount"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -154,3 +155,12 @@ func RandSeq(n int) string {
|
|||||||
}
|
}
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Convert(from, to interface{}) error {
|
||||||
|
bytes, err := yaml.Marshal(from)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return yaml.Unmarshal(bytes, to)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user