Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
r2d4 committed Sep 2, 2016
1 parent d8502d9 commit 4da0b0e
Show file tree
Hide file tree
Showing 14 changed files with 628 additions and 3 deletions.
125 changes: 125 additions & 0 deletions cmd/minikube/cmd/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package config

import (
"encoding/json"
"io"

"os"

"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/minikube/pkg/minikube/constants"
)

type configFile interface {
io.ReadWriter
}

type setFn func(string, string) error
type MinikubeConfig map[string]interface{}

type Setting struct {
name string
set func(MinikubeConfig, string, string) error
validations []setFn
callbacks []setFn
}

// These are all the settings that are configurable
// and their validation and callback fn run on Set
var settings []Setting = []Setting{
Setting{
name: "vm-driver",
set: SetString,
validations: []setFn{IsValidDriver},
callbacks: []setFn{RequiresRestartMsg},
},
Setting{
name: "cpus",
set: SetInt,
validations: []setFn{IsPositive},
callbacks: []setFn{RequiresRestartMsg},
},
Setting{
name: "disk-size",
set: SetString,
validations: []setFn{IsValidDiskSize},
callbacks: []setFn{RequiresRestartMsg},
},
Setting{
name: "host-only-cidr",
set: SetString,
validations: []setFn{IsValidCIDR},
},
Setting{
name: "memory",
set: SetInt,
validations: []setFn{IsPositive},
callbacks: []setFn{RequiresRestartMsg},
},
Setting{
name: "show-libmachine-logs",
set: SetBool,
},
Setting{
name: "log_dir",
set: SetString,
validations: []setFn{IsValidPath},
},
Setting{
name: "kubernetes-version",
set: SetString,
},
}

var ConfigCmd = &cobra.Command{
Use: "config SUBCOMMAND [flags]",
Short: "Modify minikube config",
Long: `Modify minikube config using subcommands like "minikube config set verbosity 100"`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}

// Reads in the JSON minikube config
func ReadConfig() map[string]interface{} {
f, err := os.Open(constants.ConfigFile)
if err != nil {
if os.IsNotExist(err) {
return make(map[string]interface{})
}
glog.Errorf("Could not open file %s: %s", constants.ConfigFile, err)
}
var m map[string]interface{}
m, err = decode(f)
if err != nil {
glog.Errorf("Could not decode config %s: %s", constants.ConfigFile, err)
}

return m
}

// Writes a minikube config to the JSON file
func WriteConfig(m map[string]interface{}) {
f, err := os.Create(constants.ConfigFile)
if err != nil {
glog.Errorf("Could not open file %s: %s", constants.ConfigFile, err)
}
defer f.Close()
err = encode(f, m)
if err != nil {
glog.Errorf("Error encoding config %s: %s", constants.ConfigFile, err)
}
}

func decode(r io.Reader) (map[string]interface{}, error) {
var data map[string]interface{}
err := json.NewDecoder(r).Decode(&data)
return data, err
}

func encode(w io.Writer, m map[string]interface{}) error {
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
return enc.Encode(m)
}
69 changes: 69 additions & 0 deletions cmd/minikube/cmd/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package config

import (
"bytes"
"reflect"
"testing"
)

type configTestCase struct {
data string
config map[string]interface{}
}

var configTestCases = []configTestCase{
{
data: `{
"memory": 2
}
`,
config: map[string]interface{}{
"memory": 2,
},
},
{
data: `{
"ReminderWaitPeriodInHours": 99,
"cpus": 4,
"disk-size": "20g",
"log_dir": "/etc/hosts",
"show-libmachine-logs": true,
"v": 5,
"vm-driver": "kvm"
}
`,
config: map[string]interface{}{
"vm-driver": "kvm",
"cpus": 4,
"disk-size": "20g",
"v": 5,
"show-libmachine-logs": true,
"log_dir": "/etc/hosts",
"ReminderWaitPeriodInHours": 99,
},
},
}

func TestReadConfig(t *testing.T) {
for _, tt := range configTestCases {
r := bytes.NewBufferString(tt.data)
config, err := decode(r)
if reflect.DeepEqual(config, tt.config) || err != nil {
t.Errorf("Did not read config correctly,\n\n wanted %+v, \n\n got %+v", tt.config, config)
}
}
}

func TestWriteConfig(t *testing.T) {
var b bytes.Buffer
for _, tt := range configTestCases {
err := encode(&b, tt.config)
if err != nil {
t.Errorf("Error encoding: %s", err)
}
if b.String() != tt.data {
t.Errorf("Did not write config correctly, \n\n expected:\n %+v \n\n actual:\n %+v", tt.data, b.String())
}
b.Reset()
}
}
33 changes: 33 additions & 0 deletions cmd/minikube/cmd/config/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package config

import (
"fmt"
"github.com/spf13/cobra"
"os"
)

var configGetCmd = &cobra.Command{
Use: "get PROPERTY_NAME",
Short: "Gets the value of PROPERTY_NAME from the minikube config file",
Long: "Returns the value of PROPERTY_NAME from the minikube config file. Can be overwritten by flags or environmental variables.",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
fmt.Fprintln(os.Stderr, "Please specify a PROPERTY_NAME")
os.Exit(1)
}

val := get(args[0])
if val != "" {
fmt.Fprintln(os.Stdout, val)
}
},
}

func init() {
ConfigCmd.AddCommand(configGetCmd)
}

func get(name string) string {
m := ReadConfig()
return fmt.Sprintf("%v", m[name])
}
59 changes: 59 additions & 0 deletions cmd/minikube/cmd/config/set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package config

import (
"fmt"
"github.com/spf13/cobra"
"os"
)

var configSetCmd = &cobra.Command{
Use: "set PROPERTY_NAME PROPERTY_VALUE",
Short: "Sets an individual value in a minikube config file",
Long: `Sets the PROPERTY_NAME config value to PROPERTY_VALUE
These values can be overwritten by flags or environment variables.`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
fmt.Fprintln(os.Stderr, "usage: set PROPERTY_NAME PROPERTY")
os.Exit(1)
}
err := set(args[0], args[1])
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
},
}

func init() {
ConfigCmd.AddCommand(configSetCmd)
}

func set(name string, value string) error {
s, err := findSetting(name)
if err != nil {
return err
}
// Validate the new value
err = run(name, value, s.validations)
if err != nil {
return err
}

// Set the value
config := ReadConfig()
err = s.set(config, name, value)
if err != nil {
return err
}

// Write the value
WriteConfig(config)

// Run any callbacks for this property
err = run(name, value, s.callbacks)
if err != nil {
return err
}

return nil
}
10 changes: 10 additions & 0 deletions cmd/minikube/cmd/config/set_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package config

import "testing"

func TestNotFound(t *testing.T) {
err := set("nonexistant", "10")
if err == nil {
t.Fatalf("Set did not return error for unknown property")
}
}
31 changes: 31 additions & 0 deletions cmd/minikube/cmd/config/unset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package config

import (
"fmt"
"os"

"github.com/spf13/cobra"
)

var configUnsetCmd = &cobra.Command{
Use: "unset PROPERTY_NAME",
Short: "unsets an individual value in a minikube config file",
Long: "unsets PROPERTY_NAME from the minikube config file. Can be overwritten by flags or environmental variables",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
fmt.Fprintf(os.Stdout, "usage: minikube config unset PROPERTY_NAME")
os.Exit(1)
}
unset(args[0])
},
}

func init() {
ConfigCmd.AddCommand(configUnsetCmd)
}

func unset(name string) {
m := ReadConfig()
delete(m, name)
WriteConfig(m)
}
56 changes: 56 additions & 0 deletions cmd/minikube/cmd/config/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package config

import (
"fmt"
"strconv"
)

// Runs all the validation or callback functions and collects errors
func run(name string, value string, fns []setFn) error {
var errors []error
for _, fn := range fns {
err := fn(name, value)
if err != nil {
errors = append(errors, err)
}
}
if len(errors) > 0 {
return fmt.Errorf("%v", errors)
} else {
return nil
}
}

func findSetting(name string) (Setting, error) {
for _, s := range settings {
if name == s.name {
return s, nil
}
}
return Setting{}, fmt.Errorf("Property name %s not found", name)
}

// Set Functions

func SetString(m MinikubeConfig, name string, val string) error {
m[name] = val
return nil
}

func SetInt(m MinikubeConfig, name string, val string) error {
i, err := strconv.Atoi(val)
if err != nil {
return err
}
m[name] = i
return nil
}

func SetBool(m MinikubeConfig, name string, val string) error {
b, err := strconv.ParseBool(val)
if err != nil {
return err
}
m[name] = b
return nil
}
Loading

0 comments on commit 4da0b0e

Please sign in to comment.