Have working minikube addons command w/ enable, disable, delete. Also

updated docs.
pull/639/head
Aaron Prindle 2016-09-28 17:35:42 -07:00
parent d8e1f20751
commit 2d2b484a22
37 changed files with 1081 additions and 241 deletions

2
.gitignore vendored
View File

@ -26,7 +26,7 @@ _testmain.go
/out
/_gopath
/pkg/minikube/cluster/assets.go
/pkg/minikube/assets/assets.go
/minikube
.DS_Store

View File

@ -59,13 +59,13 @@ else
docker run -w /go/src/$(REPOPATH) -e IN_DOCKER=1 -v $(shell pwd):/go/src/$(REPOPATH) $(BUILD_IMAGE) make out/localkube
endif
out/minikube-darwin-amd64: $(GOPATH)/src/$(ORG) pkg/minikube/cluster/assets.go $(shell $(MINIKUBEFILES))
out/minikube-darwin-amd64: $(GOPATH)/src/$(ORG) pkg/minikube/assets/assets.go $(shell $(MINIKUBEFILES))
CGO_ENABLED=0 GOARCH=amd64 GOOS=darwin go build --installsuffix cgo -ldflags="$(MINIKUBE_LDFLAGS) $(K8S_VERSION_LDFLAGS)" -a -o $(BUILD_DIR)/minikube-darwin-amd64 ./cmd/minikube
out/minikube-linux-amd64: $(GOPATH)/src/$(ORG) pkg/minikube/cluster/assets.go $(shell $(MINIKUBEFILES))
out/minikube-linux-amd64: $(GOPATH)/src/$(ORG) pkg/minikube/assets/assets.go $(shell $(MINIKUBEFILES))
CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build --installsuffix cgo -ldflags="$(MINIKUBE_LDFLAGS) $(K8S_VERSION_LDFLAGS)" -a -o $(BUILD_DIR)/minikube-linux-amd64 ./cmd/minikube
out/minikube-windows-amd64.exe: $(GOPATH)/src/$(ORG) pkg/minikube/cluster/assets.go $(shell $(MINIKUBEFILES))
out/minikube-windows-amd64.exe: $(GOPATH)/src/$(ORG) pkg/minikube/assets/assets.go $(shell $(MINIKUBEFILES))
CGO_ENABLED=0 GOARCH=amd64 GOOS=windows go build --installsuffix cgo -ldflags="$(MINIKUBE_LDFLAGS) $(K8S_VERSION_LDFLAGS)" -a -o $(BUILD_DIR)/minikube-windows-amd64.exe ./cmd/minikube
localkube-image: out/localkube
@ -79,11 +79,11 @@ integration: out/minikube
go test -v $(REPOPATH)/test/integration --tags=integration
.PHONY: test
test: $(GOPATH)/src/$(ORG) pkg/minikube/cluster/assets.go
test: $(GOPATH)/src/$(ORG) pkg/minikube/assets/assets.go
./test.sh
pkg/minikube/cluster/assets.go: out/localkube $(GOPATH)/bin/go-bindata deploy/iso/addon-manager.yaml deploy/addons/dashboard-rc.yaml deploy/addons/dashboard-svc.yaml
$(GOPATH)/bin/go-bindata -nomemcopy -o pkg/minikube/cluster/assets.go -pkg cluster ./out/localkube deploy/iso/addon-manager.yaml deploy/addons/dashboard-rc.yaml deploy/addons/dashboard-svc.yaml
pkg/minikube/assets/assets.go: out/localkube $(GOPATH)/bin/go-bindata deploy/iso/addon-manager.yaml deploy/addons/dashboard-rc.yaml deploy/addons/dashboard-svc.yaml
$(GOPATH)/bin/go-bindata -nomemcopy -o pkg/minikube/assets/assets.go -pkg assets ./out/localkube deploy/iso/addon-manager.yaml deploy/addons/dashboard-rc.yaml deploy/addons/dashboard-svc.yaml
$(GOPATH)/bin/go-bindata: $(GOPATH)/src/$(ORG)
GOBIN=$(GOPATH)/bin go get github.com/jteeuwen/go-bindata/...
@ -103,12 +103,12 @@ checksum:
clean:
rm -rf $(GOPATH)
rm -rf $(BUILD_DIR)
rm -f pkg/minikube/cluster/assets.go
rm -f pkg/minikube/assets/assets.go
.PHONY: gendocs
gendocs: docs/minikube.md
docs/minikube.md: $(GOPATH)/src/$(ORG) $(shell find cmd) $(shell find pkg/minikube/constants) pkg/minikube/cluster/assets.go
docs/minikube.md: $(GOPATH)/src/$(ORG) $(shell find cmd) $(shell find pkg/minikube/constants) pkg/minikube/assets/assets.go
cd $(GOPATH)/src/$(REPOPATH) && go run -ldflags="$(K8S_VERSION_LDFLAGS) $(MINIKUBE_LDFLAGS)" -tags gendocs gen_help_text.go
out/minikube_$(DEB_VERSION).deb: out/minikube-linux-amd64

View File

@ -0,0 +1,30 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"github.com/spf13/cobra"
)
var AddonsCmd = &cobra.Command{
Use: "addons SUBCOMMAND [flags]",
Short: "Modify minikube's kubernetes addons",
Long: `addons modifies minikube addons files using subcommands like "minikube addons enable heapster"`,
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}

View File

@ -34,11 +34,10 @@ type configFile interface {
}
type setFn func(string, string) error
type MinikubeConfig map[string]interface{}
type Setting struct {
name string
set func(MinikubeConfig, string, string) error
set func(config.MinikubeConfig, string, string) error
validations []setFn
callbacks []setFn
}
@ -109,6 +108,18 @@ var settings = []Setting{
name: config.WantReportErrorPrompt,
set: SetBool,
},
{
name: "dashboard",
set: SetBool,
validations: []setFn{IsValidAddon},
callbacks: []setFn{EnableOrDisableAddon},
},
{
name: "addon-manager",
set: SetBool,
validations: []setFn{IsValidAddon},
callbacks: []setFn{EnableOrDisableAddon},
},
}
var ConfigCmd = &cobra.Command{
@ -129,25 +140,8 @@ func configurableFields() string {
return strings.Join(fields, "\n")
}
// ReadConfig reads in the JSON minikube config
func ReadConfig() (MinikubeConfig, error) {
f, err := os.Open(constants.ConfigFile)
if err != nil {
if os.IsNotExist(err) {
return make(map[string]interface{}), nil
}
return nil, fmt.Errorf("Could not open file %s: %s", constants.ConfigFile, err)
}
m, err := decode(f)
if err != nil {
return nil, fmt.Errorf("Could not decode config %s: %s", constants.ConfigFile, err)
}
return m, nil
}
// WriteConfig writes a minikube config to the JSON file
func WriteConfig(m MinikubeConfig) error {
func WriteConfig(m config.MinikubeConfig) error {
f, err := os.Create(constants.ConfigFile)
if err != nil {
return fmt.Errorf("Could not open file %s: %s", constants.ConfigFile, err)
@ -160,13 +154,7 @@ func WriteConfig(m MinikubeConfig) error {
return nil
}
func decode(r io.Reader) (MinikubeConfig, error) {
var data MinikubeConfig
err := json.NewDecoder(r).Decode(&data)
return data, err
}
func encode(w io.Writer, m MinikubeConfig) error {
func encode(w io.Writer, m config.MinikubeConfig) error {
b, err := json.MarshalIndent(m, "", " ")
if err != nil {
return err

View File

@ -18,7 +18,6 @@ package config
import (
"bytes"
"reflect"
"testing"
)
@ -58,16 +57,6 @@ var configTestCases = []configTestCase{
},
}
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 {

View File

@ -0,0 +1,48 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var addonsDisableCmd = &cobra.Command{
Use: "disable ADDON_NAME",
Short: "Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list ",
Long: "Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list ",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
fmt.Fprintln(os.Stderr, "usage: minikube addons disable ADDON_NAME")
os.Exit(1)
}
addon := args[0]
err := Set(addon, "false")
if err != nil {
fmt.Fprintln(os.Stdout, err)
os.Exit(1)
}
fmt.Fprintln(os.Stdout, fmt.Sprintf("%s was successfully disabled", addon))
},
}
func init() {
AddonsCmd.AddCommand(addonsDisableCmd)
}

View File

@ -0,0 +1,89 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/docker/machine/libmachine/drivers"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/sshutil"
"k8s.io/minikube/pkg/minikube/tests"
)
func TestDisableUnknownAddon(t *testing.T) {
if err := Set("InvalidAddon", "false"); err == nil {
t.Fatalf("Disable did not return error for unknown addon")
}
}
func TestDisableValidAddonNoVM(t *testing.T) {
tempDir := tests.MakeTempDir()
defer os.RemoveAll(tempDir)
addonName := "dashboard"
expected := "false"
if err := Set(addonName, expected); err != nil {
//check that setting was changed in temp dir
conf, _ := ioutil.ReadFile(filepath.Join(tempDir, "config", "config.json"))
strConf := string(conf)
if !strings.Contains(strConf, addonName) {
t.Fatalf("Expected %s, in %s after running disable", addonName, strConf)
}
if !strings.Contains(strConf, expected) {
t.Fatalf("Expected %s, in %s after running disable", expected, strConf)
}
//check that nothing was transferred?
} else {
if err != nil {
t.Fatalf("Disable returned error for known addon")
}
}
}
func TestDeleteAddonViaDriver(t *testing.T) {
s, _ := tests.NewSSHServer()
port, err := s.Start()
if err != nil {
t.Fatalf("Error starting ssh server: %s", err)
}
d := &tests.MockDriver{
Port: port,
BaseDriver: drivers.BaseDriver{
IPAddress: "127.0.0.1",
SSHKeyPath: "",
},
}
dashboard := assets.Addons["dashboard"]
if err := deleteAddonViaDriver(dashboard, d); err != nil {
t.Fatalf("Unexpected error %s deleting addon", err)
}
// check command(s) were run
for _, addon := range dashboard.Assets {
expected, _ := ioutil.ReadFile(addon.GetAssetName())
if _, ok := s.Commands[sshutil.GetDeleteFileCommand(addon)]; !ok {
t.Fatalf("Error: Expected delete addon ssh command to be run: %s.", expected)
}
}
}

View File

@ -0,0 +1,47 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
var addonsEnableCmd = &cobra.Command{
Use: "enable ADDON_NAME",
Short: "Enables the addon w/ADDON_NAME within minikube (example: minikube addons enable dashboard). For a list of available addons use: minikube addons list ",
Long: "Enables the addon w/ADDON_NAME within minikube (example: minikube addons enable dashboard). For a list of available addons use: minikube addons list ",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
fmt.Fprintln(os.Stderr, "usage: minikube addons enable ADDON_NAME")
os.Exit(1)
}
addon := args[0]
err := Set(addon, "true")
if err != nil {
fmt.Fprintln(os.Stdout, err)
}
fmt.Fprintln(os.Stdout, fmt.Sprintf("%s was successfully enabled", addon))
},
}
func init() {
AddonsCmd.AddCommand(addonsEnableCmd)
}

View File

@ -0,0 +1,90 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/docker/machine/libmachine/drivers"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/tests"
)
func TestEnableUnknownAddon(t *testing.T) {
if err := Set("InvalidAddon", "false"); err == nil {
t.Fatalf("Enable did not return error for unknown addon")
}
}
func TestEnableValidAddonNoVM(t *testing.T) {
tempDir := tests.MakeTempDir()
defer os.RemoveAll(tempDir)
addonName := "dashboard"
expected := "true"
if err := Set(addonName, expected); err != nil {
//check that setting was changed in temp dir
conf, _ := ioutil.ReadFile(filepath.Join(tempDir, "config", "config.json"))
strConf := string(conf)
if !strings.Contains(strConf, addonName) {
t.Fatalf("Expected %s, in %s after running enable", addonName, strConf)
}
if !strings.Contains(strConf, expected) {
t.Fatalf("Expected %s, in %s after running enable", expected, strConf)
}
} else {
if err != nil {
t.Fatalf("Enable returned error for known addon")
}
}
}
func TestTransferAddonViaDriver(t *testing.T) {
s, _ := tests.NewSSHServer()
port, err := s.Start()
if err != nil {
t.Fatalf("Error starting ssh server: %s", err)
}
d := &tests.MockDriver{
Port: port,
BaseDriver: drivers.BaseDriver{
IPAddress: "127.0.0.1",
SSHKeyPath: "",
},
}
dashboard := assets.Addons["dashboard"]
if err := transferAddonViaDriver(dashboard, d); err != nil {
t.Fatalf("Unexpected error %s transferring addon", err)
}
// check contents
for _, addon := range dashboard.Assets {
expected, _ := ioutil.ReadFile(addon.GetAssetName())
transferred := s.Transfers.Bytes()
//test that custom addons are transferred properly
if !bytes.Contains(transferred, expected) {
t.Fatalf("Expected transfers to contain addon with content: %s. It was: %s", expected, transferred)
}
}
}

View File

@ -20,6 +20,8 @@ import (
"fmt"
"os"
"k8s.io/minikube/pkg/minikube/config"
"github.com/spf13/cobra"
)
@ -33,7 +35,7 @@ var configGetCmd = &cobra.Command{
os.Exit(1)
}
val, err := get(args[0])
val, err := config.Get(args[0])
if err != nil {
fmt.Fprintln(os.Stdout, err)
}
@ -46,11 +48,3 @@ var configGetCmd = &cobra.Command{
func init() {
ConfigCmd.AddCommand(configGetCmd)
}
func get(name string) (string, error) {
m, err := ReadConfig()
if err != nil {
return "", err
}
return fmt.Sprintf("%v", m[name]), nil
}

View File

@ -0,0 +1,87 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"fmt"
"os"
"text/template"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/constants"
)
var listFormat string
type ListTemplate struct {
AddonName string
AddonStatus string
}
var addonsListCmd = &cobra.Command{
Use: "list",
Short: "Lists all available minikube addons as well as there current status (enabled/disabled)",
Long: "Lists all available minikube addons as well as there current status (enabled/disabled)",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 0 {
fmt.Fprintln(os.Stderr, "usage: minikube addons list")
os.Exit(1)
}
err := list()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
},
}
func init() {
AddonsCmd.Flags().StringVar(&listFormat, "format", constants.DefaultListFormat,
`Go template format string for the addon list output. The format for Go templates can be found here: https://golang.org/pkg/text/template/
For the list of accessible variables for the template, see the struct values here: https://godoc.org/k8s.io/minikube/cmd/minikube/cmd/addon#ListTemplate`)
AddonsCmd.AddCommand(addonsListCmd)
}
func stringFromStatus(addonStatus bool) string {
if addonStatus {
return "enabled"
}
return "disabled"
}
func list() error {
for addonName, addonBundle := range assets.Addons {
addonStatus, err := addonBundle.IsEnabled()
if err != nil {
return err
}
tmpl, err := template.New("list").Parse(listFormat)
if err != nil {
glog.Errorln("Error creating list template:", err)
os.Exit(1)
}
listTmplt := ListTemplate{addonName, stringFromStatus(addonStatus)}
err = tmpl.Execute(os.Stdout, listTmplt)
if err != nil {
glog.Errorln("Error executing list template:", err)
os.Exit(1)
}
}
return nil
}

View File

@ -20,6 +20,8 @@ import (
"fmt"
"os"
pkgConfig "k8s.io/minikube/pkg/minikube/config"
"github.com/spf13/cobra"
)
@ -57,7 +59,7 @@ func Set(name string, value string) error {
}
// Set the value
config, err := ReadConfig()
config, err := pkgConfig.ReadConfig()
if err != nil {
return err
}

View File

@ -20,6 +20,8 @@ import (
"fmt"
"os"
pkgConfig "k8s.io/minikube/pkg/minikube/config"
"github.com/spf13/cobra"
)
@ -44,7 +46,7 @@ func init() {
}
func unset(name string) error {
m, err := ReadConfig()
m, err := pkgConfig.ReadConfig()
if err != nil {
return err
}

View File

@ -19,6 +19,15 @@ package config
import (
"fmt"
"strconv"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/drivers"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/sshutil"
)
// Runs all the validation or callback functions and collects errors
@ -47,12 +56,12 @@ func findSetting(name string) (Setting, error) {
// Set Functions
func SetString(m MinikubeConfig, name string, val string) error {
func SetString(m config.MinikubeConfig, name string, val string) error {
m[name] = val
return nil
}
func SetInt(m MinikubeConfig, name string, val string) error {
func SetInt(m config.MinikubeConfig, name string, val string) error {
i, err := strconv.Atoi(val)
if err != nil {
return err
@ -61,7 +70,7 @@ func SetInt(m MinikubeConfig, name string, val string) error {
return nil
}
func SetBool(m MinikubeConfig, name string, val string) error {
func SetBool(m config.MinikubeConfig, name string, val string) error {
b, err := strconv.ParseBool(val)
if err != nil {
return err
@ -69,3 +78,51 @@ func SetBool(m MinikubeConfig, name string, val string) error {
m[name] = b
return nil
}
func EnableOrDisableAddon(name string, val string) error {
enable, err := strconv.ParseBool(val)
if err != nil {
errors.Wrapf(err, "error attempted to parse enabled/disable value addon %s", name)
}
api := libmachine.NewClient(constants.Minipath, constants.MakeMiniPath("certs"))
defer api.Close()
cluster.EnsureMinikubeRunningOrExit(api, 0)
addon, _ := assets.Addons[name] // validation done prior
if err != nil {
return err
}
host, err := cluster.CheckIfApiExistsAndLoad(api)
if enable {
if err = transferAddonViaDriver(addon, host.Driver); err != nil {
return errors.Wrapf(err, "Error transferring addon %s to VM", name)
}
} else {
if err = deleteAddonViaDriver(addon, host.Driver); err != nil {
return errors.Wrapf(err, "Error deleteing addon %s from VM", name)
}
}
return nil
}
func deleteAddonViaDriver(addon *assets.Addon, d drivers.Driver) error {
client, err := sshutil.NewSSHClient(d)
if err != nil {
return err
}
if err := sshutil.DeleteAddon(addon, client); err != nil {
return err
}
return nil
}
func transferAddonViaDriver(addon *assets.Addon, d drivers.Driver) error {
client, err := sshutil.NewSSHClient(d)
if err != nil {
return err
}
if err := sshutil.TransferAddon(addon, client); err != nil {
return err
}
return nil
}

View File

@ -16,9 +16,13 @@ limitations under the License.
package config
import "testing"
import (
"testing"
var minikubeConfig = MinikubeConfig{
pkgConfig "k8s.io/minikube/pkg/minikube/config"
)
var minikubeConfig = pkgConfig.MinikubeConfig{
"vm-driver": "kvm",
"cpus": 12,
"show-libmachine-logs": true,

View File

@ -23,6 +23,8 @@ import (
"strconv"
units "github.com/docker/go-units"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/constants"
)
@ -74,3 +76,10 @@ func IsValidPath(name string, path string) error {
}
return nil
}
func IsValidAddon(name string, val string) error {
if _, ok := assets.Addons[name]; ok {
return nil
}
return errors.Errorf("Cannot enable/disable invalid addon %s", name)
}

View File

@ -44,7 +44,7 @@ var dashboardCmd = &cobra.Command{
api := libmachine.NewClient(constants.Minipath, constants.MakeMiniPath("certs"))
defer api.Close()
cluster.EnsureMinikubeRunningOrExit(api)
cluster.EnsureMinikubeRunningOrExit(api, 1)
namespace := "kube-system"
service := "kubernetes-dashboard"

View File

@ -112,6 +112,7 @@ func setFlagsUsingViper() {
func init() {
RootCmd.PersistentFlags().Bool(showLibmachineLogs, false, "Whether or not to show logs from libmachine.")
RootCmd.AddCommand(configCmd.ConfigCmd)
RootCmd.AddCommand(configCmd.AddonsCmd)
pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
viper.BindPFlags(RootCmd.PersistentFlags())
cobra.OnInitialize(initConfig)

View File

@ -55,7 +55,7 @@ var serviceCmd = &cobra.Command{
api := libmachine.NewClient(constants.Minipath, constants.MakeMiniPath("certs"))
defer api.Close()
cluster.EnsureMinikubeRunningOrExit(api)
cluster.EnsureMinikubeRunningOrExit(api, 1)
if err := util.RetryAfter(20, func() error { return CheckService(namespace, service) }, 6*time.Second); err != nil {
fmt.Fprintln(os.Stderr, "Could not find finalized endpoint being pointed to by %s: %s", service, err)
cmdUtil.MaybeReportErrorAndExit(err)

View File

@ -75,6 +75,6 @@ var statusCmd = &cobra.Command{
func init() {
statusCmd.Flags().StringVar(&statusFormat, "format", constants.DefaultStatusFormat,
`Go template format string for the status output. The format for Go templates can be found here: https://golang.org/pkg/text/template/
For the list accessible variables for the template, see the struct values here:https://godoc.org/k8s.io/minikube/cmd/minikube/cmd#Status`)
For the list accessible variables for the template, see the struct values here: https://godoc.org/k8s.io/minikube/cmd/minikube/cmd#Status`)
RootCmd.AddCommand(statusCmd)
}

View File

@ -21,6 +21,7 @@ Minikube is a CLI tool that provisions and manages single-node Kubernetes cluste
```
### SEE ALSO
* [minikube addons](minikube_addons.md) - Modify minikube's kubernetes addons
* [minikube config](minikube_config.md) - Modify minikube config
* [minikube dashboard](minikube_dashboard.md) - Opens/displays the kubernetes dashboard URL for your local cluster
* [minikube delete](minikube_delete.md) - Deletes a local kubernetes cluster.

39
docs/minikube_addons.md Normal file
View File

@ -0,0 +1,39 @@
## minikube addons
Modify minikube's kubernetes addons
### Synopsis
addons modifies minikube addons files using subcommands like "minikube addons enable heapster"
```
minikube addons SUBCOMMAND [flags]
```
### Options
```
--format string Go template format string for the addon list output. The format for Go templates can be found here: https://golang.org/pkg/text/template/
For the list of accessible variables for the template, see the struct values here: https://godoc.org/k8s.io/minikube/cmd/minikube/cmd/addon#ListTemplate (default "- {{.AddonName}}: {{.AddonStatus}}\n")
```
### Options inherited from parent commands
```
--alsologtostderr log to standard error as well as files
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
--log_dir string If non-empty, write log files in this directory
--logtostderr log to standard error instead of files
--show-libmachine-logs Whether or not to show logs from libmachine.
--stderrthreshold severity logs at or above this threshold go to stderr (default 2)
-v, --v Level log level for V logs
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```
### SEE ALSO
* [minikube](minikube.md) - Minikube is a tool for managing local Kubernetes clusters.
* [minikube addons disable](minikube_addons_disable.md) - Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list
* [minikube addons enable](minikube_addons_enable.md) - Enables the addon w/ADDON_NAME within minikube (example: minikube addons enable dashboard). For a list of available addons use: minikube addons list
* [minikube addons list](minikube_addons_list.md) - Lists all available minikube addons as well as there current status (enabled/disabled)

View File

@ -0,0 +1,29 @@
## minikube addons disable
Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list
### Synopsis
Disables the addon w/ADDON_NAME within minikube (example: minikube addons disable dashboard). For a list of available addons use: minikube addons list
```
minikube addons disable ADDON_NAME
```
### Options inherited from parent commands
```
--alsologtostderr log to standard error as well as files
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
--log_dir string If non-empty, write log files in this directory
--logtostderr log to standard error instead of files
--show-libmachine-logs Whether or not to show logs from libmachine.
--stderrthreshold severity logs at or above this threshold go to stderr (default 2)
-v, --v Level log level for V logs
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```
### SEE ALSO
* [minikube addons](minikube_addons.md) - Modify minikube's kubernetes addons

View File

@ -0,0 +1,29 @@
## minikube addons enable
Enables the addon w/ADDON_NAME within minikube (example: minikube addons enable dashboard). For a list of available addons use: minikube addons list
### Synopsis
Enables the addon w/ADDON_NAME within minikube (example: minikube addons enable dashboard). For a list of available addons use: minikube addons list
```
minikube addons enable ADDON_NAME
```
### Options inherited from parent commands
```
--alsologtostderr log to standard error as well as files
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
--log_dir string If non-empty, write log files in this directory
--logtostderr log to standard error instead of files
--show-libmachine-logs Whether or not to show logs from libmachine.
--stderrthreshold severity logs at or above this threshold go to stderr (default 2)
-v, --v Level log level for V logs
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```
### SEE ALSO
* [minikube addons](minikube_addons.md) - Modify minikube's kubernetes addons

View File

@ -0,0 +1,29 @@
## minikube addons list
Lists all available minikube addons as well as there current status (enabled/disabled)
### Synopsis
Lists all available minikube addons as well as there current status (enabled/disabled)
```
minikube addons list
```
### Options inherited from parent commands
```
--alsologtostderr log to standard error as well as files
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
--log_dir string If non-empty, write log files in this directory
--logtostderr log to standard error instead of files
--show-libmachine-logs Whether or not to show logs from libmachine.
--stderrthreshold severity logs at or above this threshold go to stderr (default 2)
-v, --v Level log level for V logs
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```
### SEE ALSO
* [minikube addons](minikube_addons.md) - Modify minikube's kubernetes addons

View File

@ -21,6 +21,8 @@ Configurable fields:
* ReminderWaitPeriodInHours
* WantReportError
* WantReportErrorPrompt
* dashboard
* addon-manager
```
minikube config SUBCOMMAND [flags]

View File

@ -15,7 +15,7 @@ minikube status
```
--format string Go template format string for the status output. The format for Go templates can be found here: https://golang.org/pkg/text/template/
For the list accessible variables for the template, see the struct values here:https://godoc.org/k8s.io/minikube/cmd/minikube/cmd#Status (default "minikubeVM: {{.MinikubeStatus}}\nlocalkube: {{.LocalkubeStatus}}\n")
For the list accessible variables for the template, see the struct values here: https://godoc.org/k8s.io/minikube/cmd/minikube/cmd#Status (default "minikubeVM: {{.MinikubeStatus}}\nlocalkube: {{.LocalkubeStatus}}\n")
```
### Options inherited from parent commands

View File

@ -0,0 +1,97 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package assets
import (
"os"
"path/filepath"
"strconv"
"github.com/golang/glog"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
)
type Addon struct {
Assets []*MemoryAsset
enabled bool
addonName string
}
func NewAddon(assets []*MemoryAsset, enabled bool, addonName string) *Addon {
a := &Addon{
Assets: assets,
enabled: enabled,
addonName: addonName,
}
return a
}
func (a *Addon) IsEnabled() (bool, error) {
addonStatusText, err := config.Get(a.addonName)
if err == nil {
addonStatus, err := strconv.ParseBool(addonStatusText)
if err != nil {
return false, err
}
return addonStatus, nil
}
return a.enabled, nil
}
var Addons = map[string]*Addon{
"addon-manager": NewAddon([]*MemoryAsset{
NewMemoryAsset(
"deploy/iso/addon-manager.yaml",
"/etc/kubernetes/manifests/",
"addon-manager.yaml",
"0640"),
}, true, "addon-manager"),
"dashboard": NewAddon([]*MemoryAsset{
NewMemoryAsset(
"deploy/addons/dashboard-rc.yaml",
constants.AddonsPath,
"dashboard-rc.yaml",
"0640"),
NewMemoryAsset(
"deploy/addons/dashboard-svc.yaml",
constants.AddonsPath,
"dashboard-svc.yaml",
"0640"),
}, true, "dashboard"),
}
func AddMinikubeAddonsDirToAssets(assetList *[]CopyableFile) {
// loop over .minikube/addons and add them to assets
searchDir := constants.MakeMiniPath("addons")
err := filepath.Walk(searchDir, func(addonFile string, f os.FileInfo, err error) error {
isDir, err := util.IsDirectory(addonFile)
if err == nil && !isDir {
f, err := NewFileAsset(addonFile, constants.AddonsPath, filepath.Base(addonFile), "0640")
if err == nil {
*assetList = append(*assetList, f)
}
} else if err != nil {
glog.Infoln("Error encountered while walking .minikube/addons: ", err)
}
return nil
})
if err != nil {
glog.Infoln("Error encountered while walking .minikube/addons: ", err)
}
}

View File

@ -0,0 +1,137 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package assets
import (
"bytes"
"io"
"os"
"github.com/pkg/errors"
)
type CopyableFile interface {
io.Reader
GetLength() int
GetAssetName() string
GetTargetDir() string
GetTargetName() string
GetPermissions() string
}
type BaseAsset struct {
data []byte
reader io.Reader
Length int
AssetName string
TargetDir string
TargetName string
Permissions string
}
func (b *BaseAsset) GetAssetName() string {
return b.AssetName
}
func (b *BaseAsset) GetTargetDir() string {
return b.TargetDir
}
func (b *BaseAsset) GetTargetName() string {
return b.TargetName
}
func (b *BaseAsset) GetPermissions() string {
return b.Permissions
}
type FileAsset struct {
BaseAsset
}
func NewFileAsset(assetName, targetDir, targetName, permissions string) (*FileAsset, error) {
f := &FileAsset{
BaseAsset{
AssetName: assetName,
TargetDir: targetDir,
TargetName: targetName,
Permissions: permissions,
},
}
file, err := os.Open(f.AssetName)
if err != nil {
return nil, errors.Wrapf(err, "Error opening file asset: %s", f.AssetName)
}
f.reader = file
return f, nil
}
func (f *FileAsset) GetLength() int {
file, err := os.Open(f.AssetName)
defer file.Close()
if err != nil {
return 0
}
fi, err := file.Stat()
if err != nil {
return 0
}
return int(fi.Size())
}
func (f *FileAsset) Read(p []byte) (int, error) {
if f.reader == nil {
return 0, errors.New("Error attempting FileAsset.Read, FileAsset.reader uninitialized")
}
return f.reader.Read(p)
}
type MemoryAsset struct {
BaseAsset
}
func NewMemoryAsset(assetName, targetDir, targetName, permissions string) *MemoryAsset {
m := &MemoryAsset{
BaseAsset{
AssetName: assetName,
TargetDir: targetDir,
TargetName: targetName,
Permissions: permissions,
},
}
m.loadData()
return m
}
func (m *MemoryAsset) loadData() error {
contents, err := Asset(m.AssetName)
if err != nil {
return err
}
m.data = contents
m.Length = len(contents)
m.reader = bytes.NewReader(m.data)
return nil
}
func (m *MemoryAsset) GetLength() int {
return m.Length
}
func (m *MemoryAsset) Read(p []byte) (int, error) {
return m.reader.Read(p)
}

View File

@ -23,7 +23,6 @@ import (
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
@ -44,6 +43,7 @@ import (
kubeApi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/sshutil"
"k8s.io/minikube/pkg/util"
@ -151,7 +151,7 @@ func GetHostStatus(api libmachine.API) (string, error) {
// GetLocalkubeStatus gets the status of localkube from the host VM.
func GetLocalkubeStatus(api libmachine.API) (string, error) {
host, err := checkIfApiExistsAndLoad(api)
host, err := CheckIfApiExistsAndLoad(api)
if err != nil {
return "", err
}
@ -215,136 +215,6 @@ func StartCluster(h sshAble, kubernetesConfig KubernetesConfig) error {
return nil
}
type CopyableFile interface {
io.Reader
GetLength() int
GetAssetName() string
GetTargetDir() string
GetTargetName() string
GetPermissions() string
}
type BaseAsset struct {
data []byte
reader io.Reader
Length int
AssetName string
TargetDir string
TargetName string
Permissions string
}
func (b *BaseAsset) GetAssetName() string {
return b.AssetName
}
func (b *BaseAsset) GetTargetDir() string {
return b.TargetDir
}
func (b *BaseAsset) GetTargetName() string {
return b.TargetName
}
func (b *BaseAsset) GetPermissions() string {
return b.Permissions
}
type FileAsset struct {
BaseAsset
}
func NewFileAsset(assetName, targetDir, targetName, permissions string) (*FileAsset, error) {
f := &FileAsset{
BaseAsset{
AssetName: assetName,
TargetDir: targetDir,
TargetName: targetName,
Permissions: permissions,
},
}
file, err := os.Open(f.AssetName)
if err != nil {
return nil, errors.Wrapf(err, "Error opening file asset: %s", f.AssetName)
}
f.reader = file
return f, nil
}
func (f *FileAsset) GetLength() int {
file, err := os.Open(f.AssetName)
defer file.Close()
if err != nil {
return 0
}
fi, err := file.Stat()
if err != nil {
return 0
}
return int(fi.Size())
}
func (f *FileAsset) Read(p []byte) (int, error) {
if f.reader == nil {
return 0, errors.New("Error attempting FileAsset.Read, FileAsset.reader uninitialized")
}
return f.reader.Read(p)
}
type MemoryAsset struct {
BaseAsset
}
func NewMemoryAsset(assetName, targetDir, targetName, permissions string) *MemoryAsset {
m := &MemoryAsset{
BaseAsset{
AssetName: assetName,
TargetDir: targetDir,
TargetName: targetName,
Permissions: permissions,
},
}
m.loadData()
return m
}
func (m *MemoryAsset) loadData() error {
contents, err := Asset(m.AssetName)
if err != nil {
return err
}
m.data = contents
m.Length = len(contents)
m.reader = bytes.NewReader(m.data)
return nil
}
func (m *MemoryAsset) GetLength() int {
return m.Length
}
func (m *MemoryAsset) Read(p []byte) (int, error) {
return m.reader.Read(p)
}
var memoryAssets = []CopyableFile{
NewMemoryAsset(
"deploy/iso/addon-manager.yaml",
"/etc/kubernetes/manifests/",
"addon-manager.yaml",
"0640"),
NewMemoryAsset(
"deploy/addons/dashboard-rc.yaml",
"/etc/kubernetes/addons/",
"dashboard-rc.yaml",
"0640"),
NewMemoryAsset(
"deploy/addons/dashboard-svc.yaml",
"/etc/kubernetes/addons/",
"dashboard-svc.yaml",
"0640"),
}
func UpdateCluster(h sshAble, d drivers.Driver, config KubernetesConfig) error {
client, err := sshutil.NewSSHClient(d)
if err != nil {
@ -362,17 +232,23 @@ func UpdateCluster(h sshAble, d drivers.Driver, config KubernetesConfig) error {
return errors.Wrap(err, "Error updating localkube from asset")
}
}
fileAssets := []CopyableFile{}
addMinikubeAddonsDirToAssets(&fileAssets)
fileAssets := []assets.CopyableFile{}
assets.AddMinikubeAddonsDirToAssets(&fileAssets)
// merge files to copy
var copyableFiles []CopyableFile
copyableFiles = append(copyableFiles, memoryAssets...)
var copyableFiles []assets.CopyableFile
for _, addonBundle := range assets.Addons {
if isEnabled, err := addonBundle.IsEnabled(); err == nil && isEnabled {
for _, addon := range addonBundle.Assets {
copyableFiles = append(copyableFiles, addon)
}
} else if err != nil {
return err
}
}
copyableFiles = append(copyableFiles, fileAssets...)
// transfer files to vm
for _, copyableFile := range copyableFiles {
if err := sshutil.Transfer(copyableFile, copyableFile.GetLength(),
copyableFile.GetTargetDir(), copyableFile.GetTargetName(),
copyableFile.GetPermissions(), client); err != nil {
if err := sshutil.TransferFile(copyableFile, client); err != nil {
return err
}
}
@ -588,7 +464,7 @@ func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
// GetHostDockerEnv gets the necessary docker env variables to allow the use of docker through minikube's vm
func GetHostDockerEnv(api libmachine.API) (map[string]string, error) {
host, err := checkIfApiExistsAndLoad(api)
host, err := CheckIfApiExistsAndLoad(api)
if err != nil {
return nil, errors.Wrap(err, "Error checking that api exists and loading it")
}
@ -611,7 +487,7 @@ func GetHostDockerEnv(api libmachine.API) (map[string]string, error) {
// GetHostLogs gets the localkube logs of the host VM.
func GetHostLogs(api libmachine.API) (string, error) {
host, err := checkIfApiExistsAndLoad(api)
host, err := CheckIfApiExistsAndLoad(api)
if err != nil {
return "", errors.Wrap(err, "Error checking that api exists and loading it")
}
@ -622,7 +498,7 @@ func GetHostLogs(api libmachine.API) (string, error) {
return s, nil
}
func checkIfApiExistsAndLoad(api libmachine.API) (*host.Host, error) {
func CheckIfApiExistsAndLoad(api libmachine.API) (*host.Host, error) {
exists, err := api.Exists(constants.MachineName)
if err != nil {
return nil, errors.Wrapf(err, "Error checking that api exists for: ", constants.MachineName)
@ -639,7 +515,7 @@ func checkIfApiExistsAndLoad(api libmachine.API) (*host.Host, error) {
}
func CreateSSHShell(api libmachine.API, args []string) error {
host, err := checkIfApiExistsAndLoad(api)
host, err := CheckIfApiExistsAndLoad(api)
if err != nil {
return errors.Wrap(err, "Error checking if api exist and loading it")
}
@ -661,7 +537,7 @@ func CreateSSHShell(api libmachine.API, args []string) error {
}
func GetServiceURL(api libmachine.API, namespace, service string) (string, error) {
host, err := checkIfApiExistsAndLoad(api)
host, err := CheckIfApiExistsAndLoad(api)
if err != nil {
return "", errors.Wrap(err, "Error checking if api exist and loading it")
}
@ -745,7 +621,7 @@ func GetKubernetesEndpointsWithNamespace(namespace string) (endpointGetter, erro
// EnsureMinikubeRunningOrExit checks that minikube has a status available and that
// that the status is `Running`, otherwise it will exit
func EnsureMinikubeRunningOrExit(api libmachine.API) {
func EnsureMinikubeRunningOrExit(api libmachine.API, exitStatus int) {
s, err := GetHostStatus(api)
if err != nil {
glog.Errorln("Error getting machine status:", err)
@ -753,26 +629,6 @@ func EnsureMinikubeRunningOrExit(api libmachine.API) {
}
if s != state.Running.String() {
fmt.Fprintln(os.Stdout, "minikube is not currently running so the service cannot be accessed")
os.Exit(1)
}
}
func addMinikubeAddonsDirToAssets(assetList *[]CopyableFile) {
// loop over .minikube/addons and add them to assets
searchDir := constants.MakeMiniPath("addons")
err := filepath.Walk(searchDir, func(addonFile string, f os.FileInfo, err error) error {
isDir, err := util.IsDirectory(addonFile)
if err == nil && !isDir {
f, err := NewFileAsset(addonFile, "/etc/kubernetes/addons", filepath.Base(addonFile), "0640")
if err == nil {
*assetList = append(*assetList, f)
}
} else if err != nil {
glog.Infoln("Error encountered while walking .minikube/addons: ", err)
}
return nil
})
if err != nil {
glog.Infoln("Error encountered while walking .minikube/addons: ", err)
os.Exit(exitStatus)
}
}

View File

@ -35,6 +35,7 @@ import (
"github.com/docker/machine/libmachine/state"
"github.com/pkg/errors"
"k8s.io/kubernetes/pkg/api"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/tests"
)
@ -568,16 +569,21 @@ func TestUpdateDefault(t *testing.T) {
}
transferred := s.Transfers.Bytes()
//test that kube-add memoryAssets are transferred properly
for _, a := range memoryAssets {
contents, _ := Asset(a.GetAssetName())
if !bytes.Contains(transferred, contents) {
t.Fatalf("File not copied. Expected transfers to contain: %s. It was: %s", contents, transferred)
for _, addonBundle := range assets.Addons {
if isEnabled, err := addonBundle.IsEnabled(); err == nil && isEnabled {
for _, addon := range addonBundle.Assets {
contents, _ := assets.Asset(addon.GetAssetName())
if !bytes.Contains(transferred, contents) {
t.Fatalf("File not copied. Expected transfers to contain: %s. It was: %s", contents, transferred)
}
}
} else if err != nil {
t.Fatalf("File not copied. Unexpected error while attempting to check transferred addons: %s", err)
}
}
//test that localkube is transferred properly
contents, _ := Asset("out/localkube")
contents, _ := assets.Asset("out/localkube")
if !bytes.Contains(transferred, contents) {
t.Fatalf("File not copied. Expected transfers to contain: %s. It was: %s", contents, transferred)
}

View File

@ -28,13 +28,14 @@ import (
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/sshutil"
"k8s.io/minikube/pkg/util"
)
func updateLocalkubeFromAsset(client *ssh.Client) error {
contents, err := Asset("out/localkube")
contents, err := assets.Asset("out/localkube")
if err != nil {
return errors.Wrap(err, "Error loading asset out/localkube")
}

View File

@ -16,9 +16,68 @@ limitations under the License.
package config
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"k8s.io/minikube/pkg/minikube/constants"
)
const (
WantUpdateNotification = "WantUpdateNotification"
ReminderWaitPeriodInHours = "ReminderWaitPeriodInHours"
WantReportError = "WantReportError"
WantReportErrorPrompt = "WantReportErrorPrompt"
)
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
}
func Get(name string) (string, error) {
m, err := ReadConfig()
if err != nil {
return "", err
}
if val, ok := m[name]; ok {
return fmt.Sprintf("%v", val), nil
} else {
return "", errors.New("specified key could not be found in config")
}
}
// ReadConfig reads in the JSON minikube config
func ReadConfig() (MinikubeConfig, error) {
f, err := os.Open(constants.ConfigFile)
if err != nil {
if os.IsNotExist(err) {
return make(map[string]interface{}), nil
}
return nil, fmt.Errorf("Could not open file %s: %s", constants.ConfigFile, err)
}
m, err := decode(f)
if err != nil {
return nil, fmt.Errorf("Could not decode config %s: %s", constants.ConfigFile, err)
}
return m, nil
}
func decode(r io.Reader) (MinikubeConfig, error) {
var data MinikubeConfig
err := json.NewDecoder(r).Decode(&data)
return data, err
}

View File

@ -0,0 +1,69 @@
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
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)
}
}
}

View File

@ -65,6 +65,7 @@ const (
DefaultVMDriver = "virtualbox"
DefaultStatusFormat = "minikubeVM: {{.MinikubeStatus}}\n" +
"localkube: {{.LocalkubeStatus}}\n"
DefaultListFormat = "- {{.AddonName}}: {{.AddonStatus}}\n"
GithubMinikubeReleasesURL = "https://storage.googleapis.com/minikube/releases.json"
KubernetesVersionGCSURL = "https://storage.googleapis.com/minikube/k8s_releases.json"
)
@ -87,3 +88,5 @@ var LocalkubeLinuxFilename = "localkube-linux-amd64"
const DockerAPIVersion = "1.23"
const ReportingURL = "https://clouderrorreporting.googleapis.com/v1beta1/projects/k8s-minikube/events:report?key=AIzaSyACUwzG0dEPcl-eOgpDKnyKoUFgHdfoFuA"
const AddonsPath = "/etc/kubernetes/addons"

View File

@ -28,6 +28,7 @@ import (
machinessh "github.com/docker/machine/libmachine/ssh"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
"k8s.io/minikube/pkg/minikube/assets"
)
// SSHSession provides methods for running commands on a host.
@ -61,6 +62,42 @@ func NewSSHClient(d drivers.Driver) (*ssh.Client, error) {
return client, nil
}
func DeleteAddon(a *assets.Addon, client *ssh.Client) error {
var err error
if enabled, err := a.IsEnabled(); err != nil {
return errors.Wrapf(err, "error attempting to transfer addon")
} else if enabled {
return errors.Errorf("Error, attempted to removed enabled addon")
}
for _, f := range a.Assets {
if err := DeleteFile(f, client); err != nil {
err = errors.Wrap(err, "")
}
}
return err
}
func TransferAddon(a *assets.Addon, client *ssh.Client) error {
var err error
if enabled, err := a.IsEnabled(); err != nil {
return errors.Wrapf(err, "error attempting to transfer addon")
} else if !enabled {
return errors.Errorf("Error, attempted to transfer disabled addon")
}
for _, f := range a.Assets {
if err := TransferFile(f, client); err != nil {
errors.Wrap(err, "")
}
}
return err
}
func TransferFile(f assets.CopyableFile, client *ssh.Client) error {
return Transfer(f, f.GetLength(),
f.GetTargetDir(), f.GetTargetName(),
f.GetPermissions(), client)
}
// Transfer uses an SSH session to copy a file to the remote machine.
func Transfer(reader io.Reader, readerLen int, remotedir, filename string, perm string, c *ssh.Client) error {
// Delete the old file first. This makes sure permissions get reset.
@ -137,3 +174,11 @@ func newSSHHost(d drivers.Driver) (*sshHost, error) {
Username: d.GetSSHUsername(),
}, nil
}
func DeleteFile(f assets.CopyableFile, client *ssh.Client) error {
return RunCommand(client, GetDeleteFileCommand(f))
}
func GetDeleteFileCommand(f assets.CopyableFile) string {
return fmt.Sprintf("sudo rm %s", filepath.Join(f.GetTargetDir(), f.GetTargetName()))
}

View File

@ -37,7 +37,8 @@ type SSHServer struct {
Connected bool
Transfers *bytes.Buffer
HadASessionRequested bool
CommandToOutput map[string]string
// CommandsToOutput can be used to mock what the SSHServer returns for a given command
CommandToOutput map[string]string
}
// NewSSHServer returns a NewSSHServer instance, ready for use.