2015-03-15 04:27:04 +00:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
2016-04-15 00:04:00 +00:00
|
|
|
yaml "github.com/cloudfoundry-incubator/candiedyaml"
|
2016-11-23 10:49:35 +00:00
|
|
|
"github.com/rancher/os/log"
|
2015-03-15 04:27:04 +00:00
|
|
|
|
|
|
|
"strings"
|
2016-05-31 21:34:04 +00:00
|
|
|
|
|
|
|
"github.com/rancher/os/util"
|
2015-03-15 04:27:04 +00:00
|
|
|
)
|
|
|
|
|
2015-09-23 11:36:28 +00:00
|
|
|
type CfgFunc func(*CloudConfig) (*CloudConfig, error)
|
2017-05-02 23:45:58 +00:00
|
|
|
type CfgFuncData struct {
|
|
|
|
Name string
|
|
|
|
Func CfgFunc
|
|
|
|
}
|
|
|
|
type CfgFuncs []CfgFuncData
|
2015-09-23 11:36:28 +00:00
|
|
|
|
2017-05-02 23:45:58 +00:00
|
|
|
func ChainCfgFuncs(cfg *CloudConfig, cfgFuncs CfgFuncs) (*CloudConfig, error) {
|
|
|
|
len := len(cfgFuncs)
|
|
|
|
for c, d := range cfgFuncs {
|
|
|
|
i := c + 1
|
|
|
|
name := d.Name
|
|
|
|
cfgFunc := d.Func
|
|
|
|
if cfg == nil {
|
|
|
|
log.Infof("[%d/%d] Starting %s WITH NIL cfg", i, len, name)
|
|
|
|
} else {
|
|
|
|
log.Infof("[%d/%d] Starting %s", i, len, name)
|
|
|
|
}
|
2015-09-23 11:36:28 +00:00
|
|
|
var err error
|
|
|
|
if cfg, err = cfgFunc(cfg); err != nil {
|
2017-05-02 23:45:58 +00:00
|
|
|
log.Errorf("Failed [%d/%d] %s: %s", i, len, name, err)
|
2015-09-23 11:36:28 +00:00
|
|
|
return cfg, err
|
|
|
|
}
|
2017-05-02 23:45:58 +00:00
|
|
|
log.Debugf("[%d/%d] Done %s", i, len, name)
|
2015-09-23 11:36:28 +00:00
|
|
|
}
|
|
|
|
return cfg, nil
|
|
|
|
}
|
|
|
|
|
2015-07-29 06:52:15 +00:00
|
|
|
func filterKey(data map[interface{}]interface{}, key []string) (filtered, rest map[interface{}]interface{}) {
|
|
|
|
if len(key) == 0 {
|
|
|
|
return data, map[interface{}]interface{}{}
|
|
|
|
}
|
|
|
|
|
|
|
|
filtered = map[interface{}]interface{}{}
|
|
|
|
rest = util.MapCopy(data)
|
|
|
|
|
|
|
|
k := key[0]
|
|
|
|
if d, ok := data[k]; ok {
|
|
|
|
switch d := d.(type) {
|
|
|
|
|
|
|
|
case map[interface{}]interface{}:
|
|
|
|
f, r := filterKey(d, key[1:])
|
|
|
|
|
|
|
|
if len(f) != 0 {
|
|
|
|
filtered[k] = f
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(r) != 0 {
|
|
|
|
rest[k] = r
|
|
|
|
} else {
|
|
|
|
delete(rest, k)
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
filtered[k] = d
|
|
|
|
delete(rest, k)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-05-31 21:34:04 +00:00
|
|
|
func filterPrivateKeys(data map[interface{}]interface{}) map[interface{}]interface{} {
|
|
|
|
for _, privateKey := range PrivateKeys {
|
|
|
|
_, data = filterKey(data, strings.Split(privateKey, "."))
|
2015-07-29 06:52:15 +00:00
|
|
|
}
|
|
|
|
|
2016-05-31 21:34:04 +00:00
|
|
|
return data
|
2015-07-29 06:52:15 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 11:36:28 +00:00
|
|
|
func getOrSetVal(args string, data map[interface{}]interface{}, value interface{}) (interface{}, map[interface{}]interface{}) {
|
2015-03-15 04:27:04 +00:00
|
|
|
parts := strings.Split(args, ".")
|
|
|
|
|
2015-09-23 11:36:28 +00:00
|
|
|
tData := data
|
|
|
|
if value != nil {
|
|
|
|
tData = util.MapCopy(data)
|
|
|
|
}
|
|
|
|
t := tData
|
2015-03-15 04:27:04 +00:00
|
|
|
for i, part := range parts {
|
2015-09-23 11:36:28 +00:00
|
|
|
val, ok := t[part]
|
2015-03-15 04:27:04 +00:00
|
|
|
last := i+1 == len(parts)
|
|
|
|
|
|
|
|
// Reached end, set the value
|
|
|
|
if last && value != nil {
|
|
|
|
if s, ok := value.(string); ok {
|
2016-04-15 00:04:00 +00:00
|
|
|
value = unmarshalOrReturnString(s)
|
2015-03-15 04:27:04 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 11:36:28 +00:00
|
|
|
t[part] = value
|
|
|
|
return value, tData
|
2015-03-15 04:27:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Missing intermediate key, create key
|
|
|
|
if !last && value != nil && !ok {
|
|
|
|
newData := map[interface{}]interface{}{}
|
2015-09-23 11:36:28 +00:00
|
|
|
t[part] = newData
|
|
|
|
t = newData
|
2015-03-15 04:27:04 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
if last {
|
2015-09-23 11:36:28 +00:00
|
|
|
return val, tData
|
2015-03-15 04:27:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
newData, ok := val.(map[interface{}]interface{})
|
|
|
|
if !ok {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2015-09-23 11:36:28 +00:00
|
|
|
t = newData
|
2015-03-15 04:27:04 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 11:36:28 +00:00
|
|
|
return "", tData
|
2015-03-15 04:27:04 +00:00
|
|
|
}
|
|
|
|
|
2017-01-05 00:34:40 +00:00
|
|
|
// Replace newlines, colons, and question marks with random strings
|
2016-09-18 23:35:32 +00:00
|
|
|
// This is done to avoid YAML treating these as special characters
|
|
|
|
var (
|
2017-01-05 00:34:40 +00:00
|
|
|
newlineMagicString = "9XsJcx6dR5EERYCC"
|
|
|
|
colonMagicString = "V0Rc21pIVknMm2rr"
|
|
|
|
questionMarkMagicString = "FoPL6JLMAaJqKMJT"
|
2016-09-18 23:35:32 +00:00
|
|
|
)
|
2016-04-05 17:00:12 +00:00
|
|
|
|
2016-04-15 00:04:00 +00:00
|
|
|
func reverseReplacement(result interface{}) interface{} {
|
|
|
|
switch val := result.(type) {
|
|
|
|
case map[interface{}]interface{}:
|
|
|
|
for k, v := range val {
|
|
|
|
val[k] = reverseReplacement(v)
|
2016-04-05 17:00:12 +00:00
|
|
|
}
|
2016-04-15 00:04:00 +00:00
|
|
|
return val
|
|
|
|
case []interface{}:
|
|
|
|
for i, item := range val {
|
|
|
|
val[i] = reverseReplacement(item)
|
|
|
|
}
|
|
|
|
return val
|
|
|
|
case string:
|
2016-09-18 23:35:32 +00:00
|
|
|
val = strings.Replace(val, newlineMagicString, "\n", -1)
|
|
|
|
val = strings.Replace(val, colonMagicString, ":", -1)
|
2017-01-05 00:34:40 +00:00
|
|
|
val = strings.Replace(val, questionMarkMagicString, "?", -1)
|
2016-09-18 23:35:32 +00:00
|
|
|
return val
|
2016-04-05 17:00:12 +00:00
|
|
|
}
|
|
|
|
|
2016-04-15 00:04:00 +00:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func unmarshalOrReturnString(value string) (result interface{}) {
|
2016-09-18 23:35:32 +00:00
|
|
|
value = strings.Replace(value, "\n", newlineMagicString, -1)
|
|
|
|
value = strings.Replace(value, ":", colonMagicString, -1)
|
2017-01-05 00:34:40 +00:00
|
|
|
value = strings.Replace(value, "?", questionMarkMagicString, -1)
|
2016-04-15 00:04:00 +00:00
|
|
|
if err := yaml.Unmarshal([]byte(value), &result); err != nil {
|
|
|
|
result = value
|
|
|
|
}
|
|
|
|
result = reverseReplacement(result)
|
|
|
|
return
|
2015-03-15 04:27:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func parseCmdline(cmdLine string) map[interface{}]interface{} {
|
|
|
|
result := make(map[interface{}]interface{})
|
|
|
|
|
|
|
|
outer:
|
|
|
|
for _, part := range strings.Split(cmdLine, " ") {
|
2016-12-02 01:16:42 +00:00
|
|
|
if strings.HasPrefix(part, "cc.") {
|
|
|
|
part = part[3:]
|
|
|
|
} else if !strings.HasPrefix(part, "rancher.") {
|
2015-03-15 04:27:04 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
var value string
|
|
|
|
kv := strings.SplitN(part, "=", 2)
|
|
|
|
|
|
|
|
if len(kv) == 1 {
|
|
|
|
value = "true"
|
|
|
|
} else {
|
|
|
|
value = kv[1]
|
|
|
|
}
|
|
|
|
|
|
|
|
current := result
|
2015-07-29 06:52:15 +00:00
|
|
|
keys := strings.Split(kv[0], ".")
|
2015-03-15 04:27:04 +00:00
|
|
|
for i, key := range keys {
|
|
|
|
if i == len(keys)-1 {
|
2016-04-15 00:04:00 +00:00
|
|
|
current[key] = unmarshalOrReturnString(value)
|
2015-03-15 04:27:04 +00:00
|
|
|
} 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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|