Merge pull request #6440 from tstromberg/addons-on-startup
Add addon enablement to startpull/6454/head
commit
e206b25da5
|
|
@ -102,9 +102,9 @@ var printAddonsList = func() {
|
|||
|
||||
for _, addonName := range addonNames {
|
||||
addonBundle := assets.Addons[addonName]
|
||||
addonStatus, err := addonBundle.IsEnabled()
|
||||
addonStatus, err := addonBundle.IsEnabled(pName)
|
||||
if err != nil {
|
||||
exit.WithError("Error getting addons status", err)
|
||||
out.WarningT("Unable to get addon status for {{.name}}: {{.error}}", out.V{"name": addonName, "error": err})
|
||||
}
|
||||
tData = append(tData, []string{addonName, pName, fmt.Sprintf("%s %s", stringFromStatus(addonStatus), iconFromStatus(addonStatus))})
|
||||
}
|
||||
|
|
@ -114,12 +114,11 @@ var printAddonsList = func() {
|
|||
|
||||
v, _, err := config.ListProfiles()
|
||||
if err != nil {
|
||||
glog.Infof("error getting list of porfiles: %v", err)
|
||||
glog.Errorf("list profiles returned error: %v", err)
|
||||
}
|
||||
if len(v) > 1 {
|
||||
out.T(out.Tip, "To see addons list for other profiles use: `minikube addons -p name list`")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var printAddonsJSON = func() {
|
||||
|
|
@ -135,9 +134,10 @@ var printAddonsJSON = func() {
|
|||
for _, addonName := range addonNames {
|
||||
addonBundle := assets.Addons[addonName]
|
||||
|
||||
addonStatus, err := addonBundle.IsEnabled()
|
||||
addonStatus, err := addonBundle.IsEnabled(pName)
|
||||
if err != nil {
|
||||
exit.WithError("Error getting addons status", err)
|
||||
glog.Errorf("Unable to get addon status for %s: %v", addonName, err)
|
||||
continue
|
||||
}
|
||||
|
||||
addonsMap[addonName] = map[string]interface{}{
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ var addonsDisableCmd = &cobra.Command{
|
|||
if err != nil {
|
||||
exit.WithError("disable failed", err)
|
||||
}
|
||||
out.SuccessT(`"{{.minikube_addon}}" was successfully disabled`, out.V{"minikube_addon": addon})
|
||||
out.T(out.AddonDisable, `"The '{{.minikube_addon}}' addon is disabled`, out.V{"minikube_addon": addon})
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,13 +33,12 @@ var addonsEnableCmd = &cobra.Command{
|
|||
if len(args) != 1 {
|
||||
exit.UsageT("usage: minikube addons enable ADDON_NAME")
|
||||
}
|
||||
|
||||
addon := args[0]
|
||||
err := addons.Set(addon, "true", viper.GetString(config.MachineProfile))
|
||||
if err != nil {
|
||||
exit.WithError("enable failed", err)
|
||||
}
|
||||
out.SuccessT("{{.addonName}} was successfully enabled", out.V{"addonName": addon})
|
||||
out.T(out.AddonEnable, "The '{{.addonName}}' addon is enabled", out.V{"addonName": addon})
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,10 @@ import (
|
|||
"github.com/pkg/browser"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"k8s.io/minikube/pkg/minikube/assets"
|
||||
"k8s.io/minikube/pkg/minikube/cluster"
|
||||
pkg_config "k8s.io/minikube/pkg/minikube/config"
|
||||
"k8s.io/minikube/pkg/minikube/exit"
|
||||
"k8s.io/minikube/pkg/minikube/machine"
|
||||
"k8s.io/minikube/pkg/minikube/out"
|
||||
|
|
@ -66,7 +68,8 @@ var addonsOpenCmd = &cobra.Command{
|
|||
}
|
||||
defer api.Close()
|
||||
|
||||
if !cluster.IsMinikubeRunning(api) {
|
||||
profileName := viper.GetString(pkg_config.MachineProfile)
|
||||
if !cluster.IsHostRunning(api, profileName) {
|
||||
os.Exit(1)
|
||||
}
|
||||
addon, ok := assets.Addons[addonName] // validate addon input
|
||||
|
|
@ -75,7 +78,7 @@ var addonsOpenCmd = &cobra.Command{
|
|||
To see the list of available addons run:
|
||||
minikube addons list`, out.V{"name": addonName})
|
||||
}
|
||||
ok, err = addon.IsEnabled()
|
||||
ok, err = addon.IsEnabled(profileName)
|
||||
if err != nil {
|
||||
exit.WithError("IsEnabled failed", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
pkgConfig "k8s.io/minikube/pkg/minikube/config"
|
||||
pkg_config "k8s.io/minikube/pkg/minikube/config"
|
||||
"k8s.io/minikube/pkg/minikube/constants"
|
||||
"k8s.io/minikube/pkg/minikube/exit"
|
||||
"k8s.io/minikube/pkg/minikube/kubeconfig"
|
||||
|
|
@ -78,7 +79,7 @@ var ProfileCmd = &cobra.Command{
|
|||
}
|
||||
cc, err := pkgConfig.Load(profile)
|
||||
// might err when loading older version of cfg file that doesn't have KeepContext field
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
if err != nil && !pkg_config.IsNotExist(err) {
|
||||
out.ErrT(out.Sad, `Error loading profile config: {{.error}}`, out.V{"error": err})
|
||||
}
|
||||
if err == nil {
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ var printProfilesJSON = func() {
|
|||
|
||||
var body = map[string]interface{}{}
|
||||
|
||||
if err == nil || os.IsNotExist(err) {
|
||||
if err == nil || config.IsNotExist(err) {
|
||||
body["valid"] = valid
|
||||
body["invalid"] = invalid
|
||||
jsonString, _ := json.Marshal(body)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ import (
|
|||
pkgaddons "k8s.io/minikube/pkg/addons"
|
||||
"k8s.io/minikube/pkg/minikube/assets"
|
||||
"k8s.io/minikube/pkg/minikube/cluster"
|
||||
"k8s.io/minikube/pkg/minikube/config"
|
||||
pkg_config "k8s.io/minikube/pkg/minikube/config"
|
||||
"k8s.io/minikube/pkg/minikube/exit"
|
||||
"k8s.io/minikube/pkg/minikube/machine"
|
||||
|
|
@ -61,7 +60,7 @@ var dashboardCmd = &cobra.Command{
|
|||
Run: func(cmd *cobra.Command, args []string) {
|
||||
profileName := viper.GetString(pkg_config.MachineProfile)
|
||||
cc, err := pkg_config.Load(profileName)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
if err != nil && !pkg_config.IsNotExist(err) {
|
||||
exit.WithError("Error loading profile config", err)
|
||||
}
|
||||
|
||||
|
|
@ -103,18 +102,18 @@ var dashboardCmd = &cobra.Command{
|
|||
exit.WithCodeT(exit.NoInput, "kubectl not found in PATH, but is required for the dashboard. Installation guide: https://kubernetes.io/docs/tasks/tools/install-kubectl/")
|
||||
}
|
||||
|
||||
if !cluster.IsMinikubeRunning(api) {
|
||||
if !cluster.IsHostRunning(api, profileName) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Check dashboard status before enabling it
|
||||
dashboardAddon := assets.Addons["dashboard"]
|
||||
dashboardStatus, _ := dashboardAddon.IsEnabled()
|
||||
dashboardStatus, _ := dashboardAddon.IsEnabled(profileName)
|
||||
if !dashboardStatus {
|
||||
// Send status messages to stderr for folks re-using this output.
|
||||
out.ErrT(out.Enabling, "Enabling dashboard ...")
|
||||
// Enable the dashboard add-on
|
||||
err = pkgaddons.Set("dashboard", "true", viper.GetString(config.MachineProfile))
|
||||
err = pkgaddons.Set("dashboard", "true", profileName)
|
||||
if err != nil {
|
||||
exit.WithError("Unable to enable dashboard", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ func deleteProfile(profile *pkg_config.Profile) error {
|
|||
}
|
||||
defer api.Close()
|
||||
cc, err := pkg_config.Load(profile.Name)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
if err != nil && !pkg_config.IsNotExist(err) {
|
||||
delErr := profileDeletionErr(profile.Name, fmt.Sprintf("error loading profile config: %v", err))
|
||||
return DeletionError{Err: delErr, Errtype: MissingProfile}
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ func deleteProfile(profile *pkg_config.Profile) error {
|
|||
deleteProfileDirectory(profile.Name)
|
||||
|
||||
if err := pkg_config.DeleteProfile(profile.Name); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if pkg_config.IsNotExist(err) {
|
||||
delErr := profileDeletionErr(profile.Name, fmt.Sprintf("\"%s\" profile does not exist", profile.Name))
|
||||
return DeletionError{Err: delErr, Errtype: MissingProfile}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"k8s.io/minikube/pkg/minikube/config"
|
||||
pkg_config "k8s.io/minikube/pkg/minikube/config"
|
||||
"k8s.io/minikube/pkg/minikube/constants"
|
||||
"k8s.io/minikube/pkg/minikube/exit"
|
||||
"k8s.io/minikube/pkg/minikube/machine"
|
||||
|
|
@ -51,8 +50,8 @@ minikube kubectl -- get pods --namespace kube-system`,
|
|||
}
|
||||
defer api.Close()
|
||||
|
||||
cc, err := pkg_config.Load(viper.GetString(config.MachineProfile))
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
cc, err := config.Load(viper.GetString(config.MachineProfile))
|
||||
if err != nil && !config.IsNotExist(err) {
|
||||
out.ErrLn("Error loading profile config: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ func runPause(cmd *cobra.Command, args []string) {
|
|||
defer api.Close()
|
||||
cc, err := config.Load(cname)
|
||||
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
if err != nil && !config.IsNotExist(err) {
|
||||
exit.WithError("Error loading profile config", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@ import (
|
|||
"github.com/golang/glog"
|
||||
"github.com/pkg/browser"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"k8s.io/minikube/pkg/minikube/cluster"
|
||||
pkg_config "k8s.io/minikube/pkg/minikube/config"
|
||||
"k8s.io/minikube/pkg/minikube/exit"
|
||||
"k8s.io/minikube/pkg/minikube/machine"
|
||||
"k8s.io/minikube/pkg/minikube/out"
|
||||
|
|
@ -71,7 +73,8 @@ var serviceCmd = &cobra.Command{
|
|||
}
|
||||
defer api.Close()
|
||||
|
||||
if !cluster.IsMinikubeRunning(api) {
|
||||
profileName := viper.GetString(pkg_config.MachineProfile)
|
||||
if !cluster.IsHostRunning(api, profileName) {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
"golang.org/x/sync/errgroup"
|
||||
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
|
||||
pkgaddons "k8s.io/minikube/pkg/addons"
|
||||
"k8s.io/minikube/pkg/addons"
|
||||
"k8s.io/minikube/pkg/minikube/bootstrapper"
|
||||
"k8s.io/minikube/pkg/minikube/bootstrapper/bsutil"
|
||||
"k8s.io/minikube/pkg/minikube/bootstrapper/images"
|
||||
|
|
@ -104,7 +104,6 @@ const (
|
|||
imageMirrorCountry = "image-mirror-country"
|
||||
mountString = "mount-string"
|
||||
disableDriverMounts = "disable-driver-mounts"
|
||||
addons = "addons"
|
||||
cacheImages = "cache-images"
|
||||
uuid = "uuid"
|
||||
vpnkitSock = "hyperkit-vpnkit-sock"
|
||||
|
|
@ -172,7 +171,7 @@ func initMinikubeFlags() {
|
|||
startCmd.Flags().String(containerRuntime, "docker", "The container runtime to be used (docker, crio, containerd).")
|
||||
startCmd.Flags().Bool(createMount, false, "This will start the mount daemon and automatically mount files into minikube.")
|
||||
startCmd.Flags().String(mountString, constants.DefaultMountDir+":/minikube-host", "The argument to pass the minikube mount command on start.")
|
||||
startCmd.Flags().StringArrayVar(&addonList, addons, nil, "Enable addons. see `minikube addons list` for a list of valid addon names.")
|
||||
startCmd.Flags().StringArrayVar(&addonList, "addons", nil, "Enable addons. see `minikube addons list` for a list of valid addon names.")
|
||||
startCmd.Flags().String(criSocket, "", "The cri socket path to be used.")
|
||||
startCmd.Flags().String(networkPlugin, "", "The name of the network plugin.")
|
||||
startCmd.Flags().Bool(enableDefaultCNI, false, "Enable the default CNI plugin (/etc/cni/net.d/k8s.conf). Used in conjunction with \"--network-plugin=cni\".")
|
||||
|
|
@ -296,7 +295,7 @@ func runStart(cmd *cobra.Command, args []string) {
|
|||
}
|
||||
|
||||
existing, err := config.Load(viper.GetString(config.MachineProfile))
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
if err != nil && !config.IsNotExist(err) {
|
||||
exit.WithCodeT(exit.Data, "Unable to load config: {{.error}}", out.V{"error": err})
|
||||
}
|
||||
|
||||
|
|
@ -368,8 +367,8 @@ func runStart(cmd *cobra.Command, args []string) {
|
|||
bootstrapCluster(bs, cr, mRunner, mc, preExists, isUpgrade)
|
||||
configureMounts()
|
||||
|
||||
// enable addons with start command
|
||||
enableAddons()
|
||||
// enable addons
|
||||
addons.Start(viper.GetString(config.MachineProfile), addonList)
|
||||
|
||||
if err = cacheAndLoadImagesInConfig(); err != nil {
|
||||
out.T(out.FailureType, "Unable to load cached images from config file.")
|
||||
|
|
@ -408,15 +407,6 @@ func cacheISO(cfg *config.MachineConfig, driverName string) {
|
|||
}
|
||||
}
|
||||
|
||||
func enableAddons() {
|
||||
for _, a := range addonList {
|
||||
err := pkgaddons.Set(a, "true", viper.GetString(config.MachineProfile))
|
||||
if err != nil {
|
||||
exit.WithError("addon enable failed", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func displayVersion(version string) {
|
||||
prefix := ""
|
||||
if viper.GetString(config.MachineProfile) != constants.DefaultMachineName {
|
||||
|
|
@ -761,7 +751,7 @@ func validateUser(drvName string) {
|
|||
os.Exit(exit.Permissions)
|
||||
}
|
||||
_, err = config.Load(viper.GetString(config.MachineProfile))
|
||||
if err == nil || !os.IsNotExist(err) {
|
||||
if err == nil || !config.IsNotExist(err) {
|
||||
out.T(out.Tip, "Tip: To remove this root owned cluster, run: sudo {{.cmd}} delete", out.V{"cmd": minikubeCmd()})
|
||||
}
|
||||
if !useForce {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ var unpauseCmd = &cobra.Command{
|
|||
defer api.Close()
|
||||
cc, err := config.Load(cname)
|
||||
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
if err != nil && !config.IsNotExist(err) {
|
||||
exit.WithError("Error loading profile config", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
1
go.mod
1
go.mod
|
|
@ -72,7 +72,6 @@ require (
|
|||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456
|
||||
golang.org/x/text v0.3.2
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect
|
||||
gotest.tools v2.2.0+incompatible
|
||||
k8s.io/api v0.17.2
|
||||
k8s.io/apimachinery v0.17.2
|
||||
k8s.io/client-go v11.0.0+incompatible
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ package addons
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/pkg/errors"
|
||||
|
|
@ -41,6 +42,7 @@ const defaultStorageClassProvisioner = "standard"
|
|||
|
||||
// Set sets a value
|
||||
func Set(name, value, profile string) error {
|
||||
glog.Infof("Setting %s=%s in profile %q", name, value, profile)
|
||||
a, valid := isAddonValid(name)
|
||||
if !valid {
|
||||
return errors.Errorf("%s is not a valid addon", name)
|
||||
|
|
@ -66,6 +68,7 @@ func Set(name, value, profile string) error {
|
|||
return errors.Wrap(err, "running callbacks")
|
||||
}
|
||||
|
||||
glog.Infof("Writing new config for %q ...", profile)
|
||||
// Write the value
|
||||
return config.Write(profile, c)
|
||||
}
|
||||
|
|
@ -100,6 +103,7 @@ func SetBool(m *config.MachineConfig, name string, val string) error {
|
|||
|
||||
// enableOrDisableAddon updates addon status executing any commands necessary
|
||||
func enableOrDisableAddon(name, val, profile string) error {
|
||||
glog.Infof("Setting addon %s=%s in %q", name, val, profile)
|
||||
enable, err := strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "parsing bool: %s", name)
|
||||
|
|
@ -107,14 +111,14 @@ func enableOrDisableAddon(name, val, profile string) error {
|
|||
addon := assets.Addons[name]
|
||||
|
||||
// check addon status before enabling/disabling it
|
||||
alreadySet, err := isAddonAlreadySet(addon, enable)
|
||||
alreadySet, err := isAddonAlreadySet(addon, enable, profile)
|
||||
if err != nil {
|
||||
out.ErrT(out.Conflict, "{{.error}}", out.V{"error": err})
|
||||
return err
|
||||
}
|
||||
//if addon is already enabled or disabled, do nothing
|
||||
|
||||
if alreadySet {
|
||||
return nil
|
||||
glog.Warningf("addon %s should already be in state %v", name, val)
|
||||
}
|
||||
|
||||
if name == "istio" && enable {
|
||||
|
|
@ -134,20 +138,15 @@ func enableOrDisableAddon(name, val, profile string) error {
|
|||
}
|
||||
defer api.Close()
|
||||
|
||||
//if minikube is not running, we return and simply update the value in the addon
|
||||
//config and rewrite the file
|
||||
if !cluster.IsMinikubeRunning(api) {
|
||||
return nil
|
||||
}
|
||||
|
||||
cfg, err := config.Load(profile)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
if err != nil && !config.IsNotExist(err) {
|
||||
exit.WithCodeT(exit.Data, "Unable to load config: {{.error}}", out.V{"error": err})
|
||||
}
|
||||
|
||||
host, err := cluster.CheckIfHostExistsAndLoad(api, cfg.Name)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting host")
|
||||
host, err := cluster.CheckIfHostExistsAndLoad(api, profile)
|
||||
if err != nil || !cluster.IsHostRunning(api, profile) {
|
||||
glog.Warningf("%q is not running, writing %s=%v to disk and skipping enablement (err=%v)", profile, addon.Name(), enable, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd, err := machine.CommandRunner(host)
|
||||
|
|
@ -159,11 +158,10 @@ func enableOrDisableAddon(name, val, profile string) error {
|
|||
return enableOrDisableAddonInternal(addon, cmd, data, enable, profile)
|
||||
}
|
||||
|
||||
func isAddonAlreadySet(addon *assets.Addon, enable bool) (bool, error) {
|
||||
addonStatus, err := addon.IsEnabled()
|
||||
|
||||
func isAddonAlreadySet(addon *assets.Addon, enable bool, profile string) (bool, error) {
|
||||
addonStatus, err := addon.IsEnabled(profile)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "get the addon status")
|
||||
return false, errors.Wrap(err, "is enabled")
|
||||
}
|
||||
|
||||
if addonStatus && enable {
|
||||
|
|
@ -178,42 +176,50 @@ func isAddonAlreadySet(addon *assets.Addon, enable bool) (bool, error) {
|
|||
func enableOrDisableAddonInternal(addon *assets.Addon, cmd command.Runner, data interface{}, enable bool, profile string) error {
|
||||
files := []string{}
|
||||
for _, addon := range addon.Assets {
|
||||
var addonFile assets.CopyableFile
|
||||
var f assets.CopyableFile
|
||||
var err error
|
||||
if addon.IsTemplate() {
|
||||
addonFile, err = addon.Evaluate(data)
|
||||
f, err = addon.Evaluate(data)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "evaluate bundled addon %s asset", addon.GetAssetName())
|
||||
}
|
||||
|
||||
} else {
|
||||
addonFile = addon
|
||||
f = addon
|
||||
}
|
||||
fPath := path.Join(f.GetTargetDir(), f.GetTargetName())
|
||||
|
||||
if enable {
|
||||
if err := cmd.Copy(addonFile); err != nil {
|
||||
glog.Infof("installing %s", fPath)
|
||||
if err := cmd.Copy(f); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
glog.Infof("Removing %+v", fPath)
|
||||
defer func() {
|
||||
if err := cmd.Remove(addonFile); err != nil {
|
||||
glog.Warningf("error removing %s; addon should still be disabled as expected", addonFile)
|
||||
if err := cmd.Remove(f); err != nil {
|
||||
glog.Warningf("error removing %s; addon should still be disabled as expected", fPath)
|
||||
}
|
||||
}()
|
||||
}
|
||||
files = append(files, filepath.Join(addonFile.GetTargetDir(), addonFile.GetTargetName()))
|
||||
files = append(files, fPath)
|
||||
}
|
||||
command, err := kubectlCommand(profile, files, enable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result, err := cmd.RunCmd(command); err != nil {
|
||||
return errors.Wrapf(err, "error updating addon:\n%s", result.Output())
|
||||
glog.Infof("Running: %s", command)
|
||||
rr, err := cmd.RunCmd(command)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "addon apply")
|
||||
}
|
||||
glog.Infof("output:\n%s", rr.Output())
|
||||
return nil
|
||||
}
|
||||
|
||||
// enableOrDisableStorageClasses enables or disables storage classes
|
||||
func enableOrDisableStorageClasses(name, val, profile string) error {
|
||||
glog.Infof("enableOrDisableStorageClasses %s=%v on %q", name, val, profile)
|
||||
enable, err := strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error parsing boolean")
|
||||
|
|
@ -228,6 +234,17 @@ func enableOrDisableStorageClasses(name, val, profile string) error {
|
|||
return errors.Wrapf(err, "Error getting storagev1 interface %v ", err)
|
||||
}
|
||||
|
||||
api, err := machine.NewAPIClient()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "machine client")
|
||||
}
|
||||
defer api.Close()
|
||||
|
||||
if !cluster.IsHostRunning(api, profile) {
|
||||
glog.Warningf("%q is not running, writing %s=%v to disk and skipping enablement", profile, name, val)
|
||||
return enableOrDisableAddon(name, val, profile)
|
||||
}
|
||||
|
||||
if enable {
|
||||
// Only StorageClass for 'name' should be marked as default
|
||||
err = storageclass.SetDefaultStorageClass(storagev1, class)
|
||||
|
|
@ -244,3 +261,39 @@ func enableOrDisableStorageClasses(name, val, profile string) error {
|
|||
|
||||
return enableOrDisableAddon(name, val, profile)
|
||||
}
|
||||
|
||||
// Start enables the default addons for a profile, plus any additional
|
||||
func Start(profile string, additional []string) {
|
||||
start := time.Now()
|
||||
glog.Infof("enableAddons")
|
||||
defer func() {
|
||||
glog.Infof("enableAddons completed in %s", time.Since(start))
|
||||
}()
|
||||
toEnable := []string{}
|
||||
|
||||
// Apply addons that are enabled by default
|
||||
for name, a := range assets.Addons {
|
||||
enabled, err := a.IsEnabled(profile)
|
||||
if err != nil {
|
||||
glog.Errorf("is-enabled failed for %q: %v", a.Name(), err)
|
||||
continue
|
||||
}
|
||||
if enabled {
|
||||
toEnable = append(toEnable, name)
|
||||
}
|
||||
}
|
||||
|
||||
toEnable = append(toEnable, additional...)
|
||||
if len(toEnable) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
out.T(out.AddonEnable, "Enabling addons: {{.addons}}", out.V{"addons": strings.Join(toEnable, ", ")})
|
||||
for _, a := range toEnable {
|
||||
err := Set(a, "true", profile)
|
||||
if err != nil {
|
||||
// Intentionally non-fatal
|
||||
out.WarningT("Enabling '{{.name}}' returned an error: {{.error}}", out.V{"name": a, "error": err})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,93 +17,115 @@ limitations under the License.
|
|||
package addons
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
"k8s.io/minikube/pkg/minikube/assets"
|
||||
"k8s.io/minikube/pkg/minikube/config"
|
||||
"k8s.io/minikube/pkg/minikube/localpath"
|
||||
)
|
||||
|
||||
func createTestProfile(t *testing.T) string {
|
||||
t.Helper()
|
||||
td, err := ioutil.TempDir("", "profile")
|
||||
if err != nil {
|
||||
t.Fatalf("tempdir: %v", err)
|
||||
}
|
||||
|
||||
err = os.Setenv(localpath.MinikubeHome, td)
|
||||
if err != nil {
|
||||
t.Errorf("error setting up test environment. could not set %s", localpath.MinikubeHome)
|
||||
}
|
||||
|
||||
// Not necessary, but it is a handy random alphanumeric
|
||||
name := filepath.Base(td)
|
||||
if err := os.MkdirAll(config.ProfileFolderPath(name), 0777); err != nil {
|
||||
t.Fatalf("error creating temporary directory")
|
||||
}
|
||||
if err := config.DefaultLoader.WriteConfigToFile(name, &config.MachineConfig{}); err != nil {
|
||||
t.Fatalf("error creating temporary profile config: %v", err)
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func TestIsAddonAlreadySet(t *testing.T) {
|
||||
testCases := []struct {
|
||||
addonName string
|
||||
}{
|
||||
{
|
||||
addonName: "ingress",
|
||||
},
|
||||
|
||||
{
|
||||
addonName: "registry",
|
||||
},
|
||||
profile := createTestProfile(t)
|
||||
if err := Set("registry", "true", profile); err != nil {
|
||||
t.Errorf("unable to set registry true: %v", err)
|
||||
}
|
||||
enabled, err := assets.Addons["registry"].IsEnabled(profile)
|
||||
if err != nil {
|
||||
t.Errorf("registry: %v", err)
|
||||
}
|
||||
if !enabled {
|
||||
t.Errorf("expected registry to be enabled")
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
addon := assets.Addons[test.addonName]
|
||||
addonStatus, _ := addon.IsEnabled()
|
||||
|
||||
alreadySet, err := isAddonAlreadySet(addon, addonStatus)
|
||||
if !alreadySet {
|
||||
if addonStatus {
|
||||
t.Errorf("Did not get expected status, \n\n expected %+v already enabled", test.addonName)
|
||||
} else {
|
||||
t.Errorf("Did not get expected status, \n\n expected %+v already disabled", test.addonName)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("Got unexpected error: %+v", err)
|
||||
}
|
||||
enabled, err = assets.Addons["ingress"].IsEnabled(profile)
|
||||
if err != nil {
|
||||
t.Errorf("ingress: %v", err)
|
||||
}
|
||||
if enabled {
|
||||
t.Errorf("expected ingress to not be enabled")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestDisableUnknownAddon(t *testing.T) {
|
||||
tmpProfile := "temp-minikube-profile"
|
||||
if err := Set("InvalidAddon", "false", tmpProfile); err == nil {
|
||||
profile := createTestProfile(t)
|
||||
if err := Set("InvalidAddon", "false", profile); err == nil {
|
||||
t.Fatalf("Disable did not return error for unknown addon")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnableUnknownAddon(t *testing.T) {
|
||||
tmpProfile := "temp-minikube-profile"
|
||||
if err := Set("InvalidAddon", "true", tmpProfile); err == nil {
|
||||
profile := createTestProfile(t)
|
||||
if err := Set("InvalidAddon", "true", profile); err == nil {
|
||||
t.Fatalf("Enable did not return error for unknown addon")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnableAndDisableAddon(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
enable bool
|
||||
}{
|
||||
{
|
||||
name: "test enable",
|
||||
enable: true,
|
||||
}, {
|
||||
name: "test disable",
|
||||
enable: false,
|
||||
},
|
||||
profile := createTestProfile(t)
|
||||
|
||||
// enable
|
||||
if err := Set("dashboard", "true", profile); err != nil {
|
||||
t.Errorf("Disable returned unexpected error: " + err.Error())
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
tmpProfile := "temp-minikube-profile"
|
||||
if err := os.MkdirAll(config.ProfileFolderPath(tmpProfile), 0777); err != nil {
|
||||
t.Fatalf("error creating temporary directory")
|
||||
}
|
||||
defer os.RemoveAll(config.ProfileFolderPath(tmpProfile))
|
||||
c, err := config.DefaultLoader.LoadConfigFromFile(profile)
|
||||
if err != nil {
|
||||
t.Errorf("unable to load profile: %v", err)
|
||||
}
|
||||
if c.Addons["dashboard"] != true {
|
||||
t.Errorf("expected dashboard to be enabled")
|
||||
}
|
||||
|
||||
if err := config.DefaultLoader.WriteConfigToFile(tmpProfile, &config.MachineConfig{}); err != nil {
|
||||
t.Fatalf("error creating temporary profile config: %v", err)
|
||||
}
|
||||
if err := Set("dashboard", fmt.Sprintf("%t", test.enable), tmpProfile); err != nil {
|
||||
t.Fatalf("Disable returned unexpected error: " + err.Error())
|
||||
}
|
||||
c, err := config.DefaultLoader.LoadConfigFromFile(tmpProfile)
|
||||
if err != nil {
|
||||
t.Fatalf("error loading config: %v", err)
|
||||
}
|
||||
assert.Equal(t, c.Addons["dashboard"], test.enable)
|
||||
})
|
||||
// disable
|
||||
if err := Set("dashboard", "false", profile); err != nil {
|
||||
t.Errorf("Disable returned unexpected error: " + err.Error())
|
||||
}
|
||||
|
||||
c, err = config.DefaultLoader.LoadConfigFromFile(profile)
|
||||
if err != nil {
|
||||
t.Errorf("unable to load profile: %v", err)
|
||||
}
|
||||
if c.Addons["dashboard"] != false {
|
||||
t.Errorf("expected dashboard to be enabled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStart(t *testing.T) {
|
||||
profile := createTestProfile(t)
|
||||
Start(profile, []string{"dashboard"})
|
||||
|
||||
enabled, err := assets.Addons["dashboard"].IsEnabled(profile)
|
||||
if err != nil {
|
||||
t.Errorf("dashboard: %v", err)
|
||||
}
|
||||
if !enabled {
|
||||
t.Errorf("expected dashboard to be enabled")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||
package addons
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
|
||||
|
|
@ -53,7 +52,7 @@ func kubectlCommand(profile string, files []string, enable bool) (*exec.Cmd, err
|
|||
|
||||
func kubernetesVersion(profile string) (string, error) {
|
||||
cc, err := config.Load(profile)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
if err != nil && !config.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
version := constants.DefaultKubernetesVersion
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/viper"
|
||||
"k8s.io/minikube/pkg/minikube/config"
|
||||
"k8s.io/minikube/pkg/minikube/constants"
|
||||
"k8s.io/minikube/pkg/minikube/localpath"
|
||||
|
|
@ -54,14 +54,21 @@ func (a *Addon) Name() string {
|
|||
return a.addonName
|
||||
}
|
||||
|
||||
// IsEnabled checks if an Addon is enabled for the current profile
|
||||
func (a *Addon) IsEnabled() (bool, error) {
|
||||
c, err := config.Load(viper.GetString(config.MachineProfile))
|
||||
if err == nil {
|
||||
if status, ok := c.Addons[a.Name()]; ok {
|
||||
return status, nil
|
||||
}
|
||||
// IsEnabled checks if an Addon is enabled for the given profile
|
||||
func (a *Addon) IsEnabled(profile string) (bool, error) {
|
||||
c, err := config.Load(profile)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "load")
|
||||
}
|
||||
|
||||
// Is this addon explicitly listed in their configuration?
|
||||
status, ok := c.Addons[a.Name()]
|
||||
glog.V(1).Infof("IsEnabled %q = %v (listed in config=%v)", a.Name(), status, ok)
|
||||
if ok {
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// Return the default unconfigured state of the addon
|
||||
return a.enabled, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ package bsutil
|
|||
import (
|
||||
"path"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/minikube/pkg/minikube/assets"
|
||||
"k8s.io/minikube/pkg/minikube/config"
|
||||
"k8s.io/minikube/pkg/minikube/vmpath"
|
||||
|
|
@ -52,33 +51,3 @@ func ConfigFileAssets(cfg config.KubernetesConfig, kubeadm []byte, kubelet []byt
|
|||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
// AddAddons adds addons to list of files
|
||||
func AddAddons(files *[]assets.CopyableFile, data interface{}) error {
|
||||
// add addons to file list
|
||||
// custom addons
|
||||
if err := assets.AddMinikubeDirAssets(files); err != nil {
|
||||
return errors.Wrap(err, "adding minikube dir assets")
|
||||
}
|
||||
// bundled addons
|
||||
for _, addonBundle := range assets.Addons {
|
||||
if isEnabled, err := addonBundle.IsEnabled(); err == nil && isEnabled {
|
||||
for _, addon := range addonBundle.Assets {
|
||||
if addon.IsTemplate() {
|
||||
addonFile, err := addon.Evaluate(data)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "evaluate bundled addon %s asset", addon.GetAssetName())
|
||||
}
|
||||
|
||||
*files = append(*files, addonFile)
|
||||
} else {
|
||||
*files = append(*files, addon)
|
||||
}
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ func TestGenerateKubeadmYAMLDNS(t *testing.T) {
|
|||
t.Run(tname, func(t *testing.T) {
|
||||
cfg := tc.cfg
|
||||
cfg.Nodes = []config.Node{
|
||||
config.Node{
|
||||
{
|
||||
IP: "1.1.1.1",
|
||||
Name: "mk",
|
||||
ControlPlane: true,
|
||||
|
|
@ -179,7 +179,7 @@ func TestGenerateKubeadmYAML(t *testing.T) {
|
|||
{"options", "docker", false, config.MachineConfig{KubernetesConfig: config.KubernetesConfig{ExtraOptions: extraOpts}}},
|
||||
{"crio-options-gates", "crio", false, config.MachineConfig{KubernetesConfig: config.KubernetesConfig{ExtraOptions: extraOpts, FeatureGates: "a=b"}}},
|
||||
{"unknown-component", "docker", true, config.MachineConfig{KubernetesConfig: config.KubernetesConfig{ExtraOptions: config.ExtraOptionSlice{config.ExtraOption{Component: "not-a-real-component", Key: "killswitch", Value: "true"}}}}},
|
||||
{"containerd-api-port", "containerd", false, config.MachineConfig{Nodes: []config.Node{config.Node{Port: 12345}}}},
|
||||
{"containerd-api-port", "containerd", false, config.MachineConfig{Nodes: []config.Node{{Port: 12345}}}},
|
||||
{"containerd-pod-network-cidr", "containerd", false, config.MachineConfig{KubernetesConfig: config.KubernetesConfig{ExtraOptions: extraOptsPodCidr}}},
|
||||
{"image-repository", "docker", false, config.MachineConfig{KubernetesConfig: config.KubernetesConfig{ImageRepository: "test/repo"}}},
|
||||
}
|
||||
|
|
@ -199,7 +199,7 @@ func TestGenerateKubeadmYAML(t *testing.T) {
|
|||
cfg.Nodes[0].ControlPlane = true
|
||||
} else {
|
||||
cfg.Nodes = []config.Node{
|
||||
config.Node{
|
||||
{
|
||||
IP: "1.1.1.1",
|
||||
Name: "mk",
|
||||
ControlPlane: true,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ func TestGenerateKubeletConfig(t *testing.T) {
|
|||
ContainerRuntime: "docker",
|
||||
},
|
||||
Nodes: []config.Node{
|
||||
config.Node{
|
||||
{
|
||||
IP: "192.168.1.100",
|
||||
Name: "minikube",
|
||||
ControlPlane: true,
|
||||
|
|
@ -67,7 +67,7 @@ ExecStart=/var/lib/minikube/binaries/v1.11.10/kubelet --allow-privileged=true --
|
|||
ContainerRuntime: "cri-o",
|
||||
},
|
||||
Nodes: []config.Node{
|
||||
config.Node{
|
||||
{
|
||||
IP: "192.168.1.100",
|
||||
Name: "minikube",
|
||||
ControlPlane: true,
|
||||
|
|
@ -92,7 +92,7 @@ ExecStart=/var/lib/minikube/binaries/v1.17.2/kubelet --authorization-mode=Webhoo
|
|||
ContainerRuntime: "containerd",
|
||||
},
|
||||
Nodes: []config.Node{
|
||||
config.Node{
|
||||
{
|
||||
IP: "192.168.1.100",
|
||||
Name: "minikube",
|
||||
ControlPlane: true,
|
||||
|
|
@ -124,7 +124,7 @@ ExecStart=/var/lib/minikube/binaries/v1.17.2/kubelet --authorization-mode=Webhoo
|
|||
},
|
||||
},
|
||||
Nodes: []config.Node{
|
||||
config.Node{
|
||||
{
|
||||
IP: "192.168.1.100",
|
||||
Name: "minikube",
|
||||
ControlPlane: true,
|
||||
|
|
@ -150,7 +150,7 @@ ExecStart=/var/lib/minikube/binaries/v1.17.2/kubelet --authorization-mode=Webhoo
|
|||
ImageRepository: "docker-proxy-image.io/google_containers",
|
||||
},
|
||||
Nodes: []config.Node{
|
||||
config.Node{
|
||||
{
|
||||
IP: "192.168.1.100",
|
||||
Name: "minikube",
|
||||
ControlPlane: true,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ import (
|
|||
"k8s.io/minikube/pkg/drivers/kic"
|
||||
"k8s.io/minikube/pkg/drivers/kic/oci"
|
||||
"k8s.io/minikube/pkg/kapi"
|
||||
"k8s.io/minikube/pkg/minikube/assets"
|
||||
"k8s.io/minikube/pkg/minikube/bootstrapper"
|
||||
"k8s.io/minikube/pkg/minikube/bootstrapper/bsutil"
|
||||
"k8s.io/minikube/pkg/minikube/bootstrapper/bsutil/kverify"
|
||||
|
|
@ -493,10 +492,6 @@ func (k *Bootstrapper) UpdateCluster(cfg config.MachineConfig) error {
|
|||
}
|
||||
files := bsutil.ConfigFileAssets(cfg.KubernetesConfig, kubeadmCfg, kubeletCfg, kubeletService, cniFile)
|
||||
|
||||
if err := bsutil.AddAddons(&files, assets.GenerateTemplateData(cfg.KubernetesConfig)); err != nil {
|
||||
return errors.Wrap(err, "adding addons")
|
||||
}
|
||||
|
||||
// Combine mkdir request into a single call to reduce load
|
||||
dirs := []string{}
|
||||
for _, f := range files {
|
||||
|
|
|
|||
|
|
@ -640,17 +640,18 @@ func getIPForInterface(name string) (net.IP, error) {
|
|||
|
||||
// CheckIfHostExistsAndLoad checks if a host exists, and loads it if it does
|
||||
func CheckIfHostExistsAndLoad(api libmachine.API, machineName string) (*host.Host, error) {
|
||||
glog.Infof("Checking if %q exists ...", machineName)
|
||||
exists, err := api.Exists(machineName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Error checking that machine exists: %s", machineName)
|
||||
}
|
||||
if !exists {
|
||||
return nil, errors.Errorf("Machine does not exist for api.Exists(%s)", machineName)
|
||||
return nil, errors.Errorf("machine %q does not exist", machineName)
|
||||
}
|
||||
|
||||
host, err := api.Load(machineName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Error loading store for: %s", machineName)
|
||||
return nil, errors.Wrapf(err, "loading machine %q", machineName)
|
||||
}
|
||||
return host, nil
|
||||
}
|
||||
|
|
@ -679,14 +680,15 @@ func CreateSSHShell(api libmachine.API, args []string) error {
|
|||
return client.Shell(args...)
|
||||
}
|
||||
|
||||
// IsMinikubeRunning checks that minikube has a status available and that
|
||||
// the status is `Running`
|
||||
func IsMinikubeRunning(api libmachine.API) bool {
|
||||
s, err := GetHostStatus(api, viper.GetString(config.MachineProfile))
|
||||
// IsHostRunning asserts that this profile's primary host is in state "Running"
|
||||
func IsHostRunning(api libmachine.API, name string) bool {
|
||||
s, err := GetHostStatus(api, name)
|
||||
if err != nil {
|
||||
glog.Warningf("host status for %q returned error: %v", name, err)
|
||||
return false
|
||||
}
|
||||
if s != state.Running.String() {
|
||||
glog.Warningf("%q host status: %s", name, s)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -18,12 +18,13 @@ package config
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"k8s.io/minikube/pkg/minikube/localpath"
|
||||
)
|
||||
|
||||
|
|
@ -53,6 +54,22 @@ var (
|
|||
ErrKeyNotFound = errors.New("specified key could not be found in config")
|
||||
)
|
||||
|
||||
type ErrNotExist struct {
|
||||
s string
|
||||
}
|
||||
|
||||
func (e *ErrNotExist) Error() string {
|
||||
return e.s
|
||||
}
|
||||
|
||||
// IsNotExist returns whether the error means a nonexistent configuration
|
||||
func IsNotExist(err error) bool {
|
||||
if _, ok := err.(*ErrNotExist); ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MinikubeConfig represents minikube config
|
||||
type MinikubeConfig map[string]interface{}
|
||||
|
||||
|
|
@ -148,17 +165,20 @@ func (c *simpleConfigLoader) LoadConfigFromFile(profileName string, miniHome ...
|
|||
// Move to profile package
|
||||
path := profileFilePath(profileName, miniHome...)
|
||||
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return nil, err
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, &ErrNotExist{fmt.Sprintf("cluster %q does not exist", profileName)}
|
||||
}
|
||||
return nil, errors.Wrap(err, "stat")
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "read")
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &cc); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "unmarshal")
|
||||
}
|
||||
return &cc, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,8 @@ var styles = map[StyleEnum]style{
|
|||
MountOptions: {Prefix: "💾 "},
|
||||
Fileserver: {Prefix: "🚀 ", OmitNewline: true},
|
||||
DryRun: {Prefix: "🏜️ "},
|
||||
AddonEnable: {Prefix: "🌟 "},
|
||||
AddonDisable: {Prefix: "🌑 "},
|
||||
}
|
||||
|
||||
// Add a prefix to a string
|
||||
|
|
|
|||
|
|
@ -87,4 +87,6 @@ const (
|
|||
Pause
|
||||
Unpause
|
||||
DryRun
|
||||
AddonEnable
|
||||
AddonDisable
|
||||
)
|
||||
|
|
|
|||
|
|
@ -40,10 +40,14 @@ func TestAPIError(t *testing.T) {
|
|||
machineAPI, configLoader, machineName,
|
||||
}
|
||||
|
||||
s, r, err := inspector.getStateAndRoute()
|
||||
_, _, err := inspector.getStateAndRoute()
|
||||
if err == nil {
|
||||
t.Errorf("expected error, got nil")
|
||||
}
|
||||
|
||||
if err == nil || !strings.Contains(err.Error(), "Machine does not exist") {
|
||||
t.Errorf("cluster inspector should propagate errors from API, getStateAndRoute() returned \"%v, %v\", %v", s, r, err)
|
||||
// Make sure we properly propagate errors upward
|
||||
if !strings.Contains(err.Error(), "exist") {
|
||||
t.Errorf("getStateAndRoute error=%q, expected *exist*", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue