2015-02-17 21:31:37 +00:00
|
|
|
package control
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2015-02-18 01:42:26 +00:00
|
|
|
"io"
|
2015-02-17 21:31:37 +00:00
|
|
|
"io/ioutil"
|
2015-02-18 01:42:26 +00:00
|
|
|
"os"
|
2015-02-17 22:32:15 +00:00
|
|
|
"strings"
|
2015-02-17 21:31:37 +00:00
|
|
|
|
|
|
|
log "github.com/Sirupsen/logrus"
|
2015-02-17 22:32:15 +00:00
|
|
|
"gopkg.in/yaml.v2"
|
2015-02-17 21:31:37 +00:00
|
|
|
|
|
|
|
"github.com/codegangsta/cli"
|
|
|
|
"github.com/rancherio/os/config"
|
|
|
|
"github.com/rancherio/os/docker"
|
|
|
|
)
|
|
|
|
|
|
|
|
func configSubcommands() []cli.Command {
|
|
|
|
return []cli.Command{
|
|
|
|
{
|
2015-02-17 22:32:15 +00:00
|
|
|
Name: "get",
|
|
|
|
Usage: "get value",
|
|
|
|
Action: configGet,
|
2015-02-17 21:31:37 +00:00
|
|
|
},
|
2015-02-18 00:00:30 +00:00
|
|
|
{
|
|
|
|
Name: "set",
|
|
|
|
Usage: "set a value",
|
|
|
|
Action: configSet,
|
|
|
|
},
|
2015-02-17 21:31:37 +00:00
|
|
|
{
|
2015-02-18 01:42:26 +00:00
|
|
|
Name: "import",
|
|
|
|
Usage: "import configuration from standard in or a file",
|
|
|
|
Action: configImport,
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "input, i",
|
|
|
|
Usage: "File from which to read",
|
|
|
|
},
|
|
|
|
},
|
2015-02-17 21:31:37 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "export",
|
|
|
|
Usage: "dump full configuration",
|
|
|
|
Flags: []cli.Flag{
|
|
|
|
cli.StringFlag{
|
|
|
|
Name: "output, o",
|
|
|
|
Usage: "File to which to save",
|
|
|
|
},
|
|
|
|
cli.BoolFlag{
|
|
|
|
Name: "full",
|
|
|
|
Usage: "Include full configuration, not just writable fields",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Action: configSave,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-18 00:00:30 +00:00
|
|
|
func getConfigData() (map[interface{}]interface{}, error) {
|
2015-02-17 22:32:15 +00:00
|
|
|
cfg, err := config.LoadConfig()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
content, err := cfg.Dump()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
data := make(map[interface{}]interface{})
|
2015-02-18 00:00:30 +00:00
|
|
|
err = yaml.Unmarshal([]byte(content), data)
|
|
|
|
|
|
|
|
return data, err
|
|
|
|
}
|
|
|
|
|
2015-02-18 01:42:26 +00:00
|
|
|
func configImport(c *cli.Context) {
|
|
|
|
var input io.Reader
|
|
|
|
var err error
|
|
|
|
input = os.Stdin
|
|
|
|
|
|
|
|
inputFile := c.String("input")
|
|
|
|
if inputFile != "" {
|
|
|
|
input, err = os.Open(inputFile)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2015-02-18 00:00:30 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 01:42:26 +00:00
|
|
|
bytes, err := ioutil.ReadAll(input)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2015-02-18 00:00:30 +00:00
|
|
|
|
2015-02-18 01:42:26 +00:00
|
|
|
err = mergeConfig(bytes)
|
2015-02-18 00:00:30 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2015-02-18 01:42:26 +00:00
|
|
|
}
|
2015-02-18 00:00:30 +00:00
|
|
|
|
2015-02-18 01:42:26 +00:00
|
|
|
func mergeConfig(bytes []byte) error {
|
2015-02-18 00:00:30 +00:00
|
|
|
var newConfig config.Config
|
2015-02-18 01:42:26 +00:00
|
|
|
|
|
|
|
err := yaml.Unmarshal(bytes, &newConfig)
|
2015-02-18 00:00:30 +00:00
|
|
|
if err != nil {
|
2015-02-18 01:42:26 +00:00
|
|
|
return err
|
2015-02-18 00:00:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cfg, err := config.LoadConfig()
|
|
|
|
if err != nil {
|
2015-02-18 01:42:26 +00:00
|
|
|
return err
|
2015-02-18 00:00:30 +00:00
|
|
|
}
|
|
|
|
|
2015-02-21 07:34:01 +00:00
|
|
|
_, err = cfg.Merge(newConfig)
|
2015-02-18 00:00:30 +00:00
|
|
|
if err != nil {
|
2015-02-18 01:42:26 +00:00
|
|
|
return err
|
2015-02-18 00:00:30 +00:00
|
|
|
}
|
2015-02-17 22:32:15 +00:00
|
|
|
|
2015-02-18 00:00:30 +00:00
|
|
|
err = cfg.Save()
|
|
|
|
if err != nil {
|
2015-02-18 01:42:26 +00:00
|
|
|
return err
|
2015-02-18 00:00:30 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 01:42:26 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func configSet(c *cli.Context) {
|
|
|
|
key := c.Args().Get(0)
|
|
|
|
value := c.Args().Get(1)
|
|
|
|
if key == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
data, err := getConfigData()
|
|
|
|
getOrSetVal(key, data, value)
|
|
|
|
|
|
|
|
bytes, err := yaml.Marshal(data)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = mergeConfig(bytes)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2015-02-18 00:00:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func configGet(c *cli.Context) {
|
2015-02-17 22:32:15 +00:00
|
|
|
arg := c.Args().Get(0)
|
|
|
|
if arg == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-02-18 00:00:30 +00:00
|
|
|
data, err := getConfigData()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2015-02-17 23:03:56 +00:00
|
|
|
|
2015-02-18 00:00:30 +00:00
|
|
|
val := getOrSetVal(arg, data, nil)
|
2015-02-17 23:03:56 +00:00
|
|
|
|
|
|
|
printYaml := false
|
|
|
|
switch val.(type) {
|
|
|
|
case []interface{}:
|
|
|
|
printYaml = true
|
|
|
|
case map[interface{}]interface{}:
|
|
|
|
printYaml = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if printYaml {
|
|
|
|
bytes, err := yaml.Marshal(val)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
fmt.Println(string(bytes))
|
|
|
|
} else {
|
|
|
|
fmt.Println(val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-18 00:00:30 +00:00
|
|
|
func getOrSetVal(args string, data map[interface{}]interface{}, value interface{}) interface{} {
|
|
|
|
parts := strings.Split(args, ".")
|
|
|
|
|
2015-02-17 22:32:15 +00:00
|
|
|
for i, part := range parts {
|
2015-02-17 23:03:56 +00:00
|
|
|
val, ok := data[part]
|
2015-02-18 00:00:30 +00:00
|
|
|
last := i+1 == len(parts)
|
2015-02-21 06:35:42 +00:00
|
|
|
|
2015-02-18 00:00:30 +00:00
|
|
|
if last && value != nil {
|
|
|
|
if s, ok := value.(string); ok {
|
|
|
|
value = config.DummyMarshall(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
data[part] = value
|
|
|
|
return value
|
|
|
|
}
|
|
|
|
|
2015-02-17 23:03:56 +00:00
|
|
|
if !ok {
|
2015-02-17 22:32:15 +00:00
|
|
|
break
|
|
|
|
}
|
2015-02-17 23:03:56 +00:00
|
|
|
|
2015-02-18 00:00:30 +00:00
|
|
|
if last {
|
2015-02-17 23:03:56 +00:00
|
|
|
return val
|
|
|
|
}
|
|
|
|
|
|
|
|
newData, ok := val.(map[interface{}]interface{})
|
|
|
|
if !ok {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
data = newData
|
2015-02-17 22:32:15 +00:00
|
|
|
}
|
2015-02-17 23:03:56 +00:00
|
|
|
|
|
|
|
return ""
|
2015-02-17 22:32:15 +00:00
|
|
|
}
|
|
|
|
|
2015-02-17 21:31:37 +00:00
|
|
|
func configSave(c *cli.Context) {
|
|
|
|
cfg, err := config.LoadConfig()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:32:15 +00:00
|
|
|
//TODO: why doesn't this work
|
2015-02-17 21:31:37 +00:00
|
|
|
for _, c := range cfg.SystemContainers {
|
|
|
|
container := docker.NewContainer("", &c)
|
|
|
|
if container.Err != nil {
|
|
|
|
log.Fatalf("Failed to parse [%s] : %v", c.Cmd, container.Err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !c.Bool("full") {
|
|
|
|
cfg.ClearReadOnly()
|
|
|
|
}
|
|
|
|
|
|
|
|
content, err := cfg.Dump()
|
|
|
|
|
|
|
|
output := c.String("output")
|
|
|
|
if output == "" {
|
|
|
|
fmt.Println(content)
|
|
|
|
} else {
|
|
|
|
err := ioutil.WriteFile(output, []byte(content), 0400)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|