Merge pull request #1886 from r2d4/localkube-bootstrapper

Add localkube as a bootstrapper
pull/1902/head
Matt Rickard 2017-08-30 10:51:24 -07:00 committed by GitHub
commit b0db008b87
19 changed files with 761 additions and 559 deletions

View File

@ -29,6 +29,8 @@ import (
"k8s.io/minikube/pkg/minikube/constants"
)
const Bootstrapper = "bootstrapper"
type setFn func(string, string) error
type Setting struct {
@ -113,6 +115,10 @@ var settings = []Setting{
name: config.MachineProfile,
set: SetString,
},
{
name: Bootstrapper,
set: SetString, //TODO(r2d4): more validation here?
},
{
name: "dashboard",
set: SetBool,

View File

@ -23,9 +23,9 @@ import (
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/machine"
)
@ -45,15 +45,12 @@ var logsCmd = &cobra.Command{
os.Exit(1)
}
defer api.Close()
h, err := api.Load(config.GetMachineName())
clusterBootstrapper, err := GetClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper))
if err != nil {
glog.Errorln("Error getting host")
glog.Exitf("Error getting cluster bootstrapper: %s", err)
}
cmdRunner, err := machine.GetCommandRunner(h)
if err != nil {
glog.Errorln("Error getting command runner interface")
}
s, err := cluster.GetHostLogs(cmdRunner, follow)
s, err := clusterBootstrapper.GetClusterLogs(follow)
if err != nil {
log.Println("Error getting machine logs:", err)
cmdUtil.MaybeReportErrorAndExit(err)

View File

@ -18,18 +18,23 @@ package cmd
import (
goflag "flag"
"fmt"
"io/ioutil"
"os"
"runtime"
"strings"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/log"
"github.com/golang/glog"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
configCmd "k8s.io/minikube/cmd/minikube/cmd/config"
"k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/bootstrapper/localkube"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/notify"
@ -98,7 +103,6 @@ func Execute() {
if err := RootCmd.Execute(); err != nil {
os.Exit(1)
}
}
// Handle config values for flags used in external packages (e.g. glog)
@ -121,6 +125,7 @@ func setFlagsUsingViper() {
func init() {
RootCmd.PersistentFlags().StringP(config.MachineProfile, "p", constants.DefaultMachineName, `The name of the minikube VM being used.
This can be modified to allow for multiple minikube instances to be run independently`)
RootCmd.PersistentFlags().StringP(configCmd.Bootstrapper, "b", constants.DefaultClusterBootstrapper, "The name of the cluster bootstrapper that will set up the kubernetes cluster.")
RootCmd.AddCommand(configCmd.ConfigCmd)
RootCmd.AddCommand(configCmd.AddonsCmd)
RootCmd.AddCommand(configCmd.ProfileCmd)
@ -157,3 +162,20 @@ func setupViper() {
viper.SetDefault(config.WantKubectlDownloadMsg, true)
setFlagsUsingViper()
}
// GetClusterBootstrapper returns a new bootstrapper for the cluster
func GetClusterBootstrapper(api libmachine.API, bootstrapperName string) (bootstrapper.Bootstrapper, error) {
var b bootstrapper.Bootstrapper
var err error
switch bootstrapperName {
case bootstrapper.BootstrapperTypeLocalkube:
b, err = localkube.NewLocalkubeBootstrapper(api)
if err != nil {
return nil, errors.Wrap(err, "getting localkube bootstrapper")
}
default:
return nil, fmt.Errorf("Unknown bootstrapper: %s", bootstrapperName)
}
return b, nil
}

View File

@ -32,7 +32,9 @@ import (
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/cluster"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
@ -91,6 +93,11 @@ func runStart(cmd *cobra.Command, args []string) {
}
defer api.Close()
exists, err := api.Exists(cfg.GetMachineName())
if err != nil {
glog.Exitf("checking if machine exists: %s", err)
}
diskSize := viper.GetString(humanReadableDiskSize)
diskSizeMB := util.CalculateDiskSizeInMB(diskSize)
@ -170,9 +177,10 @@ func runStart(cmd *cobra.Command, args []string) {
}
}
kubernetesConfig := cluster.KubernetesConfig{
kubernetesConfig := bootstrapper.KubernetesConfig{
KubernetesVersion: selectedKubernetesVersion,
NodeIP: ip,
NodeName: cfg.GetMachineName(),
APIServerName: viper.GetString(apiServerName),
DNSDomain: viper.GetString(dnsDomain),
FeatureGates: viper.GetString(featureGates),
@ -181,6 +189,11 @@ func runStart(cmd *cobra.Command, args []string) {
ExtraOptions: extraOptions,
}
clusterBootstrapper, err := GetClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper))
if err != nil {
glog.Exitf("Error getting cluster bootstrapper: %s", err)
}
// Write profile cluster configuration to file
clusterConfig := cluster.Config{
MachineConfig: config,
@ -191,30 +204,18 @@ func runStart(cmd *cobra.Command, args []string) {
glog.Errorln("Error saving profile cluster configuration: ", err)
}
cmdRunner, err := machine.GetCommandRunner(host)
if err != nil {
glog.Errorln("Error getting command runner interface")
}
fmt.Println("Moving files into cluster...")
if err := cluster.UpdateCluster(cmdRunner, kubernetesConfig); err != nil {
if err := clusterBootstrapper.UpdateCluster(kubernetesConfig); err != nil {
glog.Errorln("Error updating cluster: ", err)
cmdUtil.MaybeReportErrorAndExit(err)
}
fmt.Println("Setting up certs...")
if err := cluster.SetupCerts(cmdRunner, kubernetesConfig); err != nil {
if err := clusterBootstrapper.SetupCerts(kubernetesConfig); err != nil {
glog.Errorln("Error configuring authentication: ", err)
cmdUtil.MaybeReportErrorAndExit(err)
}
fmt.Println("Starting cluster components...")
if err := cluster.StartCluster(cmdRunner, kubernetesConfig); err != nil {
glog.Errorln("Error starting cluster: ", err)
cmdUtil.MaybeReportErrorAndExit(err)
}
fmt.Println("Connecting to cluster...")
kubeHost, err := host.Driver.GetURL()
if err != nil {
@ -243,6 +244,20 @@ func runStart(cmd *cobra.Command, args []string) {
cmdUtil.MaybeReportErrorAndExit(err)
}
fmt.Println("Starting cluster components...")
if !exists {
if err := clusterBootstrapper.StartCluster(kubernetesConfig); err != nil {
glog.Errorln("Error starting cluster: ", err)
cmdUtil.MaybeReportErrorAndExit(err)
}
} else {
if err := clusterBootstrapper.RestartCluster(kubernetesConfig); err != nil {
glog.Errorln("Error restarting cluster: ", err)
cmdUtil.MaybeReportErrorAndExit(err)
}
}
// start 9p server mount
if viper.GetBool(createMount) {
fmt.Printf("Setting up hostmount on %s...\n", viper.GetString(mountString))

View File

@ -24,6 +24,8 @@ import (
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
cmdUtil "k8s.io/minikube/cmd/util"
"k8s.io/minikube/pkg/minikube/cluster"
"k8s.io/minikube/pkg/minikube/config"
@ -62,18 +64,14 @@ var statusCmd = &cobra.Command{
cs := state.None.String()
ks := state.None.String()
if ms == state.Running.String() {
h, err := api.Load(config.GetMachineName())
clusterBootstrapper, err := GetClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper))
if err != nil {
glog.Exitln("Error getting host")
}
cmdRunner, err := machine.GetCommandRunner(h)
if err != nil {
glog.Errorln("Error getting command runner interface")
glog.Errorf("Error getting cluster bootstrapper: %s", err)
cmdUtil.MaybeReportErrorAndExit(err)
}
cs, err = cluster.GetLocalkubeStatus(cmdRunner)
cs, err = clusterBootstrapper.GetClusterStatus()
if err != nil {
glog.Errorln("Error localkube status:", err)
glog.Errorln("Error cluster status:", err)
cmdUtil.MaybeReportErrorAndExit(err)
}
ip, err := cluster.GetHostDriverIP(api)

View File

@ -0,0 +1,46 @@
/*
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 bootstrapper
import "k8s.io/minikube/pkg/util"
// Bootstrapper contains all the methods needed to bootstrap a kubernetes cluster
type Bootstrapper interface {
StartCluster(KubernetesConfig) error
UpdateCluster(KubernetesConfig) error
RestartCluster(KubernetesConfig) error
GetClusterLogs(follow bool) (string, error)
SetupCerts(cfg KubernetesConfig) error
GetClusterStatus() (string, error)
}
// KubernetesConfig contains the parameters used to configure the VM Kubernetes.
type KubernetesConfig struct {
KubernetesVersion string
NodeIP string
NodeName string
APIServerName string
DNSDomain string
ContainerRuntime string
NetworkPlugin string
FeatureGates string
ExtraOptions util.ExtraOptionSlice
}
const (
BootstrapperTypeLocalkube = "localkube"
)

View File

@ -0,0 +1,110 @@
/*
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 bootstrapper
import (
"net"
"path/filepath"
"strings"
"github.com/golang/glog"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/tools/clientcmd/api/latest"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
"k8s.io/minikube/pkg/util/kubeconfig"
)
var (
certs = []string{"ca.crt", "ca.key", "apiserver.crt", "apiserver.key"}
// This is the internalIP , the API server and other components communicate on.
internalIP = net.ParseIP(util.DefaultServiceClusterIP)
)
// SetupCerts gets the generated credentials required to talk to the APIServer.
func SetupCerts(cmd CommandRunner, k8s KubernetesConfig) error {
localPath := constants.GetMinipath()
glog.Infoln("Setting up certificates for IP: %s", k8s.NodeIP)
ip := net.ParseIP(k8s.NodeIP)
caCert := filepath.Join(localPath, "ca.crt")
caKey := filepath.Join(localPath, "ca.key")
publicPath := filepath.Join(localPath, "apiserver.crt")
privatePath := filepath.Join(localPath, "apiserver.key")
if err := generateCerts(caCert, caKey, publicPath, privatePath, ip, k8s.APIServerName, k8s.DNSDomain); err != nil {
return errors.Wrap(err, "Error generating certs")
}
copyableFiles := []assets.CopyableFile{}
for _, cert := range certs {
p := filepath.Join(localPath, cert)
perms := "0644"
if strings.HasSuffix(cert, ".key") {
perms = "0600"
}
certFile, err := assets.NewFileAsset(p, util.DefaultCertPath, cert, perms)
if err != nil {
return err
}
copyableFiles = append(copyableFiles, certFile)
}
kubeCfgSetup := &kubeconfig.KubeConfigSetup{
ClusterName: k8s.NodeName,
ClusterServerAddress: "https://localhost:8443",
ClientCertificate: filepath.Join(util.DefaultCertPath, "apiserver.crt"),
ClientKey: filepath.Join(util.DefaultCertPath, "apiserver.key"),
CertificateAuthority: filepath.Join(util.DefaultCertPath, "ca.crt"),
KeepContext: false,
}
kubeCfg := api.NewConfig()
kubeconfig.PopulateKubeConfig(kubeCfgSetup, kubeCfg)
data, err := runtime.Encode(latest.Codec, kubeCfg)
if err != nil {
return errors.Wrap(err, "encoding kubeconfig")
}
kubeCfgFile := assets.NewMemoryAsset(data,
util.DefaultLocalkubeDirectory, "kubeconfig", "0644")
copyableFiles = append(copyableFiles, kubeCfgFile)
for _, f := range copyableFiles {
if err := cmd.Copy(f); err != nil {
return err
}
}
return nil
}
func generateCerts(caCert, caKey, pub, priv string, ip net.IP, name string, dnsDomain string) error {
if !(util.CanReadFile(caCert) && util.CanReadFile(caKey)) {
if err := util.GenerateCACert(caCert, caKey, name); err != nil {
return errors.Wrap(err, "Error generating certificate")
}
}
ips := []net.IP{ip, internalIP}
if err := util.GenerateSignedCert(pub, priv, ips, util.GetAlternateDNS(dnsDomain), caCert, caKey); err != nil {
return errors.Wrap(err, "Error generating signed cert")
}
return nil
}

View File

@ -0,0 +1,52 @@
/*
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 bootstrapper
import (
"os"
"path/filepath"
"testing"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/tests"
)
func TestSetupCerts(t *testing.T) {
tempDir := tests.MakeTempDir()
defer os.RemoveAll(tempDir)
f := NewFakeCommandRunner()
k8s := KubernetesConfig{
APIServerName: constants.APIServerName,
DNSDomain: constants.ClusterDNSDomain,
}
var filesToBeTransferred []string
for _, cert := range certs {
filesToBeTransferred = append(filesToBeTransferred, filepath.Join(constants.GetMinipath(), cert))
}
if err := SetupCerts(f, k8s); err != nil {
t.Fatalf("Error starting cluster: %s", err)
}
for _, cert := range filesToBeTransferred {
_, err := f.GetFileToContents(cert)
if err != nil {
t.Errorf("Cert not generated: %s", cert)
}
}
}

View File

@ -14,17 +14,17 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cluster
package localkube
import (
"bytes"
gflag "flag"
"fmt"
"net"
"strings"
"text/template"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/constants"
)
@ -65,7 +65,7 @@ else
fi
`
func GetStartCommand(kubernetesConfig KubernetesConfig) (string, error) {
func GetStartCommand(kubernetesConfig bootstrapper.KubernetesConfig) (string, error) {
localkubeStartCommand, err := GenLocalkubeStartCmd(kubernetesConfig)
if err != nil {
return "", err
@ -93,7 +93,7 @@ func GetStartCommand(kubernetesConfig KubernetesConfig) (string, error) {
return buf.String(), nil
}
func GetStartCommandNoSystemd(kubernetesConfig KubernetesConfig, localkubeStartCmd string) (string, error) {
func GetStartCommandNoSystemd(kubernetesConfig bootstrapper.KubernetesConfig, localkubeStartCmd string) (string, error) {
t := template.Must(template.New("startCommand").Parse(startCommandNoSystemdTemplate))
buf := bytes.Buffer{}
data := struct {
@ -113,7 +113,7 @@ func GetStartCommandNoSystemd(kubernetesConfig KubernetesConfig, localkubeStartC
return buf.String(), nil
}
func GetStartCommandSystemd(kubernetesConfig KubernetesConfig, localkubeStartCmd string) (string, error) {
func GetStartCommandSystemd(kubernetesConfig bootstrapper.KubernetesConfig, localkubeStartCmd string) (string, error) {
t, err := template.New("localkubeConfig").Parse(localkubeSystemdTmpl)
if err != nil {
return "", err
@ -131,7 +131,7 @@ func GetStartCommandSystemd(kubernetesConfig KubernetesConfig, localkubeStartCmd
constants.LocalkubeServicePath), nil
}
func GenLocalkubeStartCmd(kubernetesConfig KubernetesConfig) (string, error) {
func GenLocalkubeStartCmd(kubernetesConfig bootstrapper.KubernetesConfig) (string, error) {
flagVals := make([]string, len(constants.LogFlags))
for _, logFlag := range constants.LogFlags {
if logVal := gflag.Lookup(logFlag); logVal != nil && logVal.Value.String() != logVal.DefValue {
@ -226,38 +226,3 @@ else
fi
fi
`, constants.LocalkubePIDPath)
func GetMountCleanupCommand(path string) string {
return fmt.Sprintf("sudo umount %s;", path)
}
var mountTemplate = `
sudo mkdir -p {{.Path}} || true;
sudo mount -t 9p -o trans=tcp,port={{.Port}},dfltuid={{.UID}},dfltgid={{.GID}},version={{.Version}},msize={{.Msize}} {{.IP}} {{.Path}};
sudo chmod 775 {{.Path}};`
func GetMountCommand(ip net.IP, path, port, mountVersion string, uid, gid, msize int) (string, error) {
t := template.Must(template.New("mountCommand").Parse(mountTemplate))
buf := bytes.Buffer{}
data := struct {
IP string
Path string
Port string
Version string
UID int
GID int
Msize int
}{
IP: ip.String(),
Path: path,
Port: port,
Version: mountVersion,
UID: uid,
GID: gid,
Msize: msize,
}
if err := t.Execute(&buf, data); err != nil {
return "", err
}
return buf.String(), nil
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cluster
package localkube
import (
gflag "flag"
@ -22,6 +22,7 @@ import (
"strings"
"testing"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/util"
)
@ -31,7 +32,7 @@ func TestGetStartCommandCustomValues(t *testing.T) {
"vmodule": "cluster*=5",
}
flagMapToSetFlags(flagMap)
startCommand, err := GetStartCommand(KubernetesConfig{})
startCommand, err := GetStartCommand(bootstrapper.KubernetesConfig{})
if err != nil {
t.Fatalf("Error generating start command: %s", err)
}
@ -46,7 +47,7 @@ func TestGetStartCommandCustomValues(t *testing.T) {
}
func TestGetStartCommandExtraOptions(t *testing.T) {
k := KubernetesConfig{
k := bootstrapper.KubernetesConfig{
ExtraOptions: util.ExtraOptionSlice{
util.ExtraOption{Component: "a", Key: "b", Value: "c"},
util.ExtraOption{Component: "d", Key: "e.f", Value: "g"},

View File

@ -0,0 +1,148 @@
/*
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 localkube
import (
"fmt"
"strings"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/sshutil"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/state"
"github.com/pkg/errors"
)
type LocalkubeBootstrapper struct {
cmd bootstrapper.CommandRunner
}
func NewLocalkubeBootstrapper(api libmachine.API) (*LocalkubeBootstrapper, error) {
h, err := api.Load(config.GetMachineName())
if err != nil {
return nil, errors.Wrap(err, "getting api client")
}
var cmd bootstrapper.CommandRunner
// The none driver executes commands directly on the host
if h.Driver.DriverName() == constants.DriverNone {
cmd = &bootstrapper.ExecRunner{}
} else {
client, err := sshutil.NewSSHClient(h.Driver)
if err != nil {
return nil, errors.Wrap(err, "getting ssh client")
}
cmd = bootstrapper.NewSSHRunner(client)
}
return &LocalkubeBootstrapper{
cmd: cmd,
}, nil
}
// GetClusterLogs If follow is specified, it will tail the logs
func (lk *LocalkubeBootstrapper) GetClusterLogs(follow bool) (string, error) {
logsCommand, err := GetLogsCommand(follow)
if err != nil {
return "", errors.Wrap(err, "Error getting logs command")
}
logs, err := lk.cmd.CombinedOutput(logsCommand)
if err != nil {
return "", errors.Wrap(err, "getting cluster logs")
}
return logs, nil
}
// GetClusterStatus gets the status of localkube from the host VM.
func (lk *LocalkubeBootstrapper) GetClusterStatus() (string, error) {
s, err := lk.cmd.CombinedOutput(localkubeStatusCommand)
if err != nil {
return "", err
}
s = strings.TrimSpace(s)
if state.Running.String() == s {
return state.Running.String(), nil
} else if state.Stopped.String() == s {
return state.Stopped.String(), nil
} else {
return "", fmt.Errorf("Error: Unrecognize output from GetLocalkubeStatus: %s", s)
}
}
// StartCluster starts a k8s cluster on the specified Host.
func (lk *LocalkubeBootstrapper) StartCluster(kubernetesConfig bootstrapper.KubernetesConfig) error {
startCommand, err := GetStartCommand(kubernetesConfig)
if err != nil {
return errors.Wrapf(err, "Error generating start command: %s", err)
}
err = lk.cmd.Run(startCommand) //needs to be sudo for none driver
if err != nil {
return errors.Wrapf(err, "Error running ssh command: %s", startCommand)
}
return nil
}
func (lk *LocalkubeBootstrapper) RestartCluster(kubernetesConfig bootstrapper.KubernetesConfig) error {
return lk.StartCluster(kubernetesConfig)
}
func (lk *LocalkubeBootstrapper) UpdateCluster(config bootstrapper.KubernetesConfig) error {
copyableFiles := []assets.CopyableFile{}
var localkubeFile assets.CopyableFile
var err error
//add url/file/bundled localkube to file list
if localkubeURIWasSpecified(config) && config.KubernetesVersion != constants.DefaultKubernetesVersion {
lCacher := localkubeCacher{config}
localkubeFile, err = lCacher.fetchLocalkubeFromURI()
if err != nil {
return errors.Wrap(err, "Error updating localkube from uri")
}
} else {
localkubeFile = assets.NewBinDataAsset("out/localkube", "/usr/local/bin", "localkube", "0777")
}
copyableFiles = append(copyableFiles, localkubeFile)
// add addons to file list
// custom addons
assets.AddMinikubeAddonsDirToAssets(&copyableFiles)
// bundled addons
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
}
}
for _, f := range copyableFiles {
if err := lk.cmd.Copy(f); err != nil {
return err
}
}
return nil
}
func (lk *LocalkubeBootstrapper) SetupCerts(k8s bootstrapper.KubernetesConfig) error {
return bootstrapper.SetupCerts(lk.cmd, k8s)
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package cluster
package localkube
import (
"fmt"
@ -27,13 +27,14 @@ import (
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
)
// localkubeCacher is a struct with methods designed for caching localkube
type localkubeCacher struct {
k8sConf KubernetesConfig
k8sConf bootstrapper.KubernetesConfig
}
func (l *localkubeCacher) getLocalkubeCacheFilepath() string {
@ -41,6 +42,11 @@ func (l *localkubeCacher) getLocalkubeCacheFilepath() string {
filepath.Base(url.QueryEscape("localkube-"+l.k8sConf.KubernetesVersion)))
}
func localkubeURIWasSpecified(config bootstrapper.KubernetesConfig) bool {
// see if flag is different than default -> it was passed by user
return config.KubernetesVersion != constants.DefaultKubernetesVersion
}
func (l *localkubeCacher) isLocalkubeCached() bool {
if _, err := os.Stat(l.getLocalkubeCacheFilepath()); os.IsNotExist(err) {
return false
@ -71,7 +77,7 @@ func (l *localkubeCacher) fetchLocalkubeFromURI() (assets.CopyableFile, error) {
if err != nil {
return nil, errors.Wrap(err, "Error parsing --kubernetes-version url")
}
if urlObj.Scheme == fileScheme {
if urlObj.Scheme == constants.FileScheme {
return l.genLocalkubeFileFromFile()
}
return l.genLocalkubeFileFromURL()

View File

@ -0,0 +1,265 @@
/*
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 localkube
import (
"os"
"testing"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/tests"
)
func TestStartCluster(t *testing.T) {
expectedStartCmd, err := GetStartCommand(bootstrapper.KubernetesConfig{})
if err != nil {
t.Fatalf("generating start command: %s", err)
}
cases := []struct {
description string
startCmd string
}{
{
description: "start cluster success",
startCmd: expectedStartCmd,
},
{
description: "start cluster failure",
startCmd: "something else",
},
}
for _, test := range cases {
t.Run(test.description, func(t *testing.T) {
t.Parallel()
f := bootstrapper.NewFakeCommandRunner()
f.SetCommandToOutput(map[string]string{test.startCmd: "ok"})
l := LocalkubeBootstrapper{f}
err := l.StartCluster(bootstrapper.KubernetesConfig{})
if err != nil && test.startCmd == expectedStartCmd {
t.Errorf("Error starting cluster: %s", err)
}
})
}
}
func TestUpdateCluster(t *testing.T) {
defaultCfg := bootstrapper.KubernetesConfig{
KubernetesVersion: constants.DefaultKubernetesVersion,
}
defaultAddons := []string{
"deploy/addons/kube-dns/kube-dns-cm.yaml",
"deploy/addons/kube-dns/kube-dns-svc.yaml",
"deploy/addons/addon-manager.yaml",
"deploy/addons/dashboard/dashboard-rc.yaml",
"deploy/addons/dashboard/dashboard-svc.yaml",
"deploy/addons/storageclass/storageclass.yaml",
"deploy/addons/kube-dns/kube-dns-controller.yaml",
}
cases := []struct {
description string
k8s bootstrapper.KubernetesConfig
expectedFiles []string
shouldErr bool
}{
{
description: "transfer localkube correct",
k8s: defaultCfg,
expectedFiles: []string{"out/localkube"},
},
{
description: "addons are transferred",
k8s: defaultCfg,
expectedFiles: defaultAddons,
},
{
description: "no localkube version",
k8s: bootstrapper.KubernetesConfig{},
shouldErr: true,
},
}
for _, test := range cases {
t.Run(test.description, func(t *testing.T) {
t.Parallel()
f := bootstrapper.NewFakeCommandRunner()
l := LocalkubeBootstrapper{f}
err := l.UpdateCluster(test.k8s)
if err != nil && !test.shouldErr {
t.Errorf("Error updating cluster: %s", err)
return
}
if err == nil && test.shouldErr {
t.Error("Didn't get error, but expected to")
return
}
for _, expectedFile := range test.expectedFiles {
_, err := f.GetFileToContents(expectedFile)
if err != nil {
t.Errorf("Expected file %s, but was not present", expectedFile)
}
}
})
}
}
func TestGetLocalkubeStatus(t *testing.T) {
cases := []struct {
description string
statusCmdMap map[string]string
expectedStatus string
shouldErr bool
}{
{
description: "get status running",
statusCmdMap: map[string]string{localkubeStatusCommand: "Running"},
expectedStatus: "Running",
},
{
description: "get status stopped",
statusCmdMap: map[string]string{localkubeStatusCommand: "Stopped"},
expectedStatus: "Stopped",
},
{
description: "get status unknown status",
statusCmdMap: map[string]string{localkubeStatusCommand: "Recalculating..."},
shouldErr: true,
},
{
description: "get status error",
statusCmdMap: map[string]string{"a": "b"},
shouldErr: true,
},
}
for _, test := range cases {
t.Run(test.description, func(t *testing.T) {
t.Parallel()
f := bootstrapper.NewFakeCommandRunner()
f.SetCommandToOutput(test.statusCmdMap)
l := LocalkubeBootstrapper{f}
actualStatus, err := l.GetClusterStatus()
if err != nil && !test.shouldErr {
t.Errorf("Error getting localkube status: %s", err)
return
}
if err == nil && test.shouldErr {
t.Error("Didn't get error, but expected to")
return
}
if test.expectedStatus != actualStatus {
t.Errorf("Expected status: %s, Actual status: %s", test.expectedStatus, actualStatus)
}
})
}
}
func TestGetHostLogs(t *testing.T) {
logs, err := GetLogsCommand(false)
if err != nil {
t.Fatalf("Error getting logs command: %s", err)
}
logsf, err := GetLogsCommand(true)
if err != nil {
t.Fatalf("Error gettings logs -f command: %s", err)
}
cases := []struct {
description string
logsCmdMap map[string]string
follow bool
shouldErr bool
}{
{
description: "get logs correct",
logsCmdMap: map[string]string{logs: "fee"},
},
{
description: "follow logs correct",
logsCmdMap: map[string]string{logsf: "fi"},
follow: true,
},
{
description: "get logs incorrect",
logsCmdMap: map[string]string{"fo": "fum"},
shouldErr: true,
},
}
for _, test := range cases {
t.Run(test.description, func(t *testing.T) {
t.Parallel()
f := bootstrapper.NewFakeCommandRunner()
f.SetCommandToOutput(test.logsCmdMap)
l := LocalkubeBootstrapper{f}
_, err := l.GetClusterLogs(test.follow)
if err != nil && !test.shouldErr {
t.Errorf("Error getting localkube logs: %s", err)
return
}
if err == nil && test.shouldErr {
t.Error("Didn't get error, but expected to")
return
}
})
}
}
func TestIsLocalkubeCached(t *testing.T) {
tempDir := tests.MakeTempDir()
defer os.RemoveAll(tempDir)
inputArr := [...]string{
"v1.3.3",
"1.3.0",
"http://test-url.localkube.com/localkube-binary",
"file:///test/dir/to/localkube-binary",
}
localkubeCacher := localkubeCacher{
k8sConf: bootstrapper.KubernetesConfig{},
}
inner := func(input string) {
localkubeCacher.k8sConf = bootstrapper.KubernetesConfig{
KubernetesVersion: input,
}
if localkubeCacher.isLocalkubeCached() {
t.Errorf("IsLocalKubeCached returned true even though %s was not cached",
localkubeCacher.getLocalkubeCacheFilepath())
return
}
f, err := os.Create(localkubeCacher.getLocalkubeCacheFilepath())
if err != nil {
t.Errorf("failed to create dummy cache file: %v", err)
return
}
f.Close()
defer os.Remove(f.Name())
if !localkubeCacher.isLocalkubeCached() {
t.Errorf("IsLocalKubeCached returned false even though %s was cached",
localkubeCacher.getLocalkubeCacheFilepath())
}
}
for _, input := range inputArr {
inner(input)
}
}

View File

@ -17,15 +17,15 @@ limitations under the License.
package cluster
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"html/template"
"net"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"time"
"github.com/docker/machine/drivers/virtualbox"
@ -38,16 +38,10 @@ import (
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/tools/clientcmd/api/latest"
"k8s.io/minikube/pkg/minikube/assets"
"k8s.io/minikube/pkg/minikube/bootstrapper"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/util"
"k8s.io/minikube/pkg/util/kubeconfig"
)
var (
@ -154,22 +148,6 @@ func GetHostStatus(api libmachine.API) (string, error) {
return s.String(), nil
}
// GetLocalkubeStatus gets the status of localkube from the host VM.
func GetLocalkubeStatus(cmd bootstrapper.CommandRunner) (string, error) {
s, err := cmd.CombinedOutput(localkubeStatusCommand)
if err != nil {
return "", err
}
s = strings.TrimSpace(s)
if state.Running.String() == s {
return state.Running.String(), nil
} else if state.Stopped.String() == s {
return state.Stopped.String(), nil
} else {
return "", fmt.Errorf("Error: Unrecognize output from GetLocalkubeStatus: %s", s)
}
}
// GetHostDriverIP gets the ip address of the current minikube cluster
func GetHostDriverIP(api libmachine.API) (net.IP, error) {
host, err := CheckIfApiExistsAndLoad(api)
@ -188,121 +166,6 @@ func GetHostDriverIP(api libmachine.API) (net.IP, error) {
return ip, nil
}
// StartCluster starts a k8s cluster on the specified Host.
func StartCluster(cmd bootstrapper.CommandRunner, kubernetesConfig KubernetesConfig) error {
startCommand, err := GetStartCommand(kubernetesConfig)
if err != nil {
return errors.Wrapf(err, "Error generating start command: %s", err)
}
if err := cmd.Run(startCommand); err != nil {
return errors.Wrapf(err, "Error running start command: %s", startCommand)
}
return nil
}
func UpdateCluster(cmd bootstrapper.CommandRunner, config KubernetesConfig) error {
copyableFiles := []assets.CopyableFile{}
var localkubeFile assets.CopyableFile
var err error
//add url/file/bundled localkube to file list
if localkubeURIWasSpecified(config) && config.KubernetesVersion != constants.DefaultKubernetesVersion {
lCacher := localkubeCacher{config}
localkubeFile, err = lCacher.fetchLocalkubeFromURI()
if err != nil {
return errors.Wrap(err, "Error updating localkube from uri")
}
} else {
localkubeFile = assets.NewBinDataAsset("out/localkube", "/usr/local/bin", "localkube", "0777")
}
copyableFiles = append(copyableFiles, localkubeFile)
// add addons to file list
// custom addons
assets.AddMinikubeAddonsDirToAssets(&copyableFiles)
// bundled addons
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
}
}
for _, f := range copyableFiles {
// fmt.Println(f.GetAssetName())
if err := cmd.Copy(f); err != nil {
return err
}
}
return nil
}
func localkubeURIWasSpecified(config KubernetesConfig) bool {
// see if flag is different than default -> it was passed by user
return config.KubernetesVersion != constants.DefaultKubernetesVersion
}
// SetupCerts gets the generated credentials required to talk to the APIServer.
func SetupCerts(cmd bootstrapper.CommandRunner, k8s KubernetesConfig) error {
localPath := constants.GetMinipath()
ip := net.ParseIP(k8s.NodeIP)
glog.Infoln("Setting up certificates for IP: %s", ip)
caCert := filepath.Join(localPath, "ca.crt")
caKey := filepath.Join(localPath, "ca.key")
publicPath := filepath.Join(localPath, "apiserver.crt")
privatePath := filepath.Join(localPath, "apiserver.key")
if err := GenerateCerts(caCert, caKey, publicPath, privatePath, ip, k8s.APIServerName, k8s.DNSDomain); err != nil {
return errors.Wrap(err, "Error generating certs")
}
copyableFiles := []assets.CopyableFile{}
for _, cert := range certs {
p := filepath.Join(localPath, cert)
perms := "0644"
if strings.HasSuffix(cert, ".key") {
perms = "0600"
}
certFile, err := assets.NewFileAsset(p, util.DefaultCertPath, cert, perms)
if err != nil {
return err
}
copyableFiles = append(copyableFiles, certFile)
}
kubeCfgSetup := &kubeconfig.KubeConfigSetup{
ClusterName: cfg.GetMachineName(),
ClusterServerAddress: "https://localhost:8443",
ClientCertificate: filepath.Join(util.DefaultCertPath, "apiserver.crt"),
ClientKey: filepath.Join(util.DefaultCertPath, "apiserver.key"),
CertificateAuthority: filepath.Join(util.DefaultCertPath, "ca.crt"),
KeepContext: false,
}
kubeCfg := api.NewConfig()
kubeconfig.PopulateKubeConfig(kubeCfgSetup, kubeCfg)
data, err := runtime.Encode(latest.Codec, kubeCfg)
if err != nil {
return errors.Wrap(err, "setup certs: encoding kubeconfig")
}
kubeCfgFile := assets.NewMemoryAsset(data,
util.DefaultLocalkubeDirectory, "kubeconfig", "0644")
copyableFiles = append(copyableFiles, kubeCfgFile)
for _, f := range copyableFiles {
if err := cmd.Copy(f); err != nil {
return err
}
}
return nil
}
func engineOptions(config MachineConfig) *engine.Options {
o := engine.Options{
Env: config.DockerEnv,
@ -400,20 +263,6 @@ func GetHostDockerEnv(api libmachine.API) (map[string]string, error) {
return envMap, nil
}
// GetHostLogs gets the localkube logs of the host VM.
// If follow is specified, it will tail the logs
func GetHostLogs(cmd bootstrapper.CommandRunner, follow bool) (string, error) {
logsCommand, err := GetLogsCommand(follow)
if err != nil {
return "", errors.Wrap(err, "Error getting logs command")
}
logs, err := cmd.CombinedOutput(logsCommand)
if err != nil {
return "", errors.Wrap(err, "running logs command")
}
return logs, nil
}
// MountHost runs the mount command from the 9p client on the VM to the 9p server on the host
func MountHost(api libmachine.API, ip net.IP, path, port, mountVersion string, uid, gid, msize int) error {
host, err := CheckIfApiExistsAndLoad(api)
@ -536,3 +385,38 @@ func EnsureMinikubeRunningOrExit(api libmachine.API, exitStatus int) {
os.Exit(exitStatus)
}
}
func GetMountCleanupCommand(path string) string {
return fmt.Sprintf("sudo umount %s;", path)
}
var mountTemplate = `
sudo mkdir -p {{.Path}} || true;
sudo mount -t 9p -o trans=tcp,port={{.Port}},dfltuid={{.UID}},dfltgid={{.GID}},version={{.Version}},msize={{.Msize}} {{.IP}} {{.Path}};
sudo chmod 775 {{.Path}};`
func GetMountCommand(ip net.IP, path, port, mountVersion string, uid, gid, msize int) (string, error) {
t := template.Must(template.New("mountCommand").Parse(mountTemplate))
buf := bytes.Buffer{}
data := struct {
IP string
Path string
Port string
Version string
UID int
GID int
Msize int
}{
IP: ip.String(),
Path: path,
Port: port,
Version: mountVersion,
UID: uid,
GID: gid,
Msize: msize,
}
if err := t.Execute(&buf, data); err != nil {
return "", err
}
return buf.String(), nil
}

View File

@ -18,7 +18,6 @@ package cluster
import (
"os"
"path/filepath"
"strings"
"testing"
@ -26,7 +25,6 @@ import (
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/provision"
"github.com/docker/machine/libmachine/state"
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/tests"
@ -81,224 +79,6 @@ func TestCreateHost(t *testing.T) {
}
}
func TestStartCluster(t *testing.T) {
expectedStartCmd, err := GetStartCommand(KubernetesConfig{})
if err != nil {
t.Fatalf("generating start command: %s", err)
}
cases := []struct {
description string
startCmd string
}{
{
description: "start cluster success",
startCmd: expectedStartCmd,
},
{
description: "start cluster failure",
startCmd: "something else",
},
}
for _, test := range cases {
t.Run(test.description, func(t *testing.T) {
t.Parallel()
f := bootstrapper.NewFakeCommandRunner()
f.SetCommandToOutput(map[string]string{test.startCmd: "ok"})
err := StartCluster(f, KubernetesConfig{})
if err != nil && test.startCmd == expectedStartCmd {
t.Errorf("Error starting cluster: %s", err)
}
})
}
}
func TestUpdateCluster(t *testing.T) {
defaultCfg := KubernetesConfig{
KubernetesVersion: constants.DefaultKubernetesVersion,
}
defaultAddons := []string{
"deploy/addons/kube-dns/kube-dns-cm.yaml",
"deploy/addons/kube-dns/kube-dns-svc.yaml",
"deploy/addons/addon-manager.yaml",
"deploy/addons/dashboard/dashboard-rc.yaml",
"deploy/addons/dashboard/dashboard-svc.yaml",
"deploy/addons/storageclass/storageclass.yaml",
"deploy/addons/kube-dns/kube-dns-controller.yaml",
}
cases := []struct {
description string
k8s KubernetesConfig
expectedFiles []string
shouldErr bool
}{
{
description: "transfer localkube correct",
k8s: defaultCfg,
expectedFiles: []string{"out/localkube"},
},
{
description: "addons are transferred",
k8s: defaultCfg,
expectedFiles: defaultAddons,
},
{
description: "no localkube version",
k8s: KubernetesConfig{},
shouldErr: true,
},
}
for _, test := range cases {
t.Run(test.description, func(t *testing.T) {
t.Parallel()
f := bootstrapper.NewFakeCommandRunner()
err := UpdateCluster(f, test.k8s)
if err != nil && !test.shouldErr {
t.Errorf("Error updating cluster: %s", err)
return
}
if err == nil && test.shouldErr {
t.Error("Didn't get error, but expected to")
return
}
for _, expectedFile := range test.expectedFiles {
_, err := f.GetFileToContents(expectedFile)
if err != nil {
t.Errorf("Expected file %s, but was not present", expectedFile)
}
}
})
}
}
func TestGetLocalkubeStatus(t *testing.T) {
cases := []struct {
description string
statusCmdMap map[string]string
expectedStatus string
shouldErr bool
}{
{
description: "get status running",
statusCmdMap: map[string]string{localkubeStatusCommand: "Running"},
expectedStatus: "Running",
},
{
description: "get status stopped",
statusCmdMap: map[string]string{localkubeStatusCommand: "Stopped"},
expectedStatus: "Stopped",
},
{
description: "get status unknown status",
statusCmdMap: map[string]string{localkubeStatusCommand: "Recalculating..."},
shouldErr: true,
},
{
description: "get status error",
statusCmdMap: map[string]string{"a": "b"},
shouldErr: true,
},
}
for _, test := range cases {
t.Run(test.description, func(t *testing.T) {
t.Parallel()
f := bootstrapper.NewFakeCommandRunner()
f.SetCommandToOutput(test.statusCmdMap)
actualStatus, err := GetLocalkubeStatus(f)
if err != nil && !test.shouldErr {
t.Errorf("Error getting localkube status: %s", err)
return
}
if err == nil && test.shouldErr {
t.Error("Didn't get error, but expected to")
return
}
if test.expectedStatus != actualStatus {
t.Errorf("Expected status: %s, Actual status: %s", test.expectedStatus, actualStatus)
}
})
}
}
func TestGetHostLogs(t *testing.T) {
logs, err := GetLogsCommand(false)
if err != nil {
t.Fatalf("Error getting logs command: %s", err)
}
logsf, err := GetLogsCommand(true)
if err != nil {
t.Fatalf("Error gettings logs -f command: %s", err)
}
cases := []struct {
description string
logsCmdMap map[string]string
follow bool
shouldErr bool
}{
{
description: "get logs correct",
logsCmdMap: map[string]string{logs: "fee"},
},
{
description: "follow logs correct",
logsCmdMap: map[string]string{logsf: "fi"},
follow: true,
},
{
description: "get logs incorrect",
logsCmdMap: map[string]string{"fo": "fum"},
shouldErr: true,
},
}
for _, test := range cases {
t.Run(test.description, func(t *testing.T) {
t.Parallel()
f := bootstrapper.NewFakeCommandRunner()
f.SetCommandToOutput(test.logsCmdMap)
_, err := GetHostLogs(f, test.follow)
if err != nil && !test.shouldErr {
t.Errorf("Error getting localkube logs: %s", err)
return
}
if err == nil && test.shouldErr {
t.Error("Didn't get error, but expected to")
return
}
})
}
}
func TestSetupCerts(t *testing.T) {
tempDir := tests.MakeTempDir()
defer os.RemoveAll(tempDir)
f := bootstrapper.NewFakeCommandRunner()
k8s := KubernetesConfig{
APIServerName: constants.APIServerName,
DNSDomain: constants.ClusterDNSDomain,
}
var filesToBeTransferred []string
for _, cert := range certs {
filesToBeTransferred = append(filesToBeTransferred, filepath.Join(constants.GetMinipath(), cert))
}
if err := SetupCerts(f, k8s); err != nil {
t.Fatalf("Error starting cluster: %s", err)
}
for _, cert := range filesToBeTransferred {
_, err := f.GetFileToContents(cert)
if err != nil {
t.Errorf("Cert not generated: %s", cert)
}
}
}
func TestStartHostExists(t *testing.T) {
api := tests.NewMockAPI()
// Create an initial host.
@ -609,46 +389,3 @@ func TestCreateSSHShell(t *testing.T) {
t.Fatalf("Expected ssh session to be run")
}
}
func TestIsLocalkubeCached(t *testing.T) {
tempDir := tests.MakeTempDir()
defer os.RemoveAll(tempDir)
inputArr := [...]string{
"v1.3.3",
"1.3.0",
"http://test-url.localkube.com/localkube-binary",
"file:///test/dir/to/localkube-binary",
}
localkubeCacher := localkubeCacher{
k8sConf: KubernetesConfig{},
}
inner := func(input string) {
localkubeCacher.k8sConf = KubernetesConfig{
KubernetesVersion: input,
}
if localkubeCacher.isLocalkubeCached() {
t.Errorf("IsLocalKubeCached returned true even though %s was not cached",
localkubeCacher.getLocalkubeCacheFilepath())
return
}
f, err := os.Create(localkubeCacher.getLocalkubeCacheFilepath())
if err != nil {
t.Errorf("failed to create dummy cache file: %v", err)
return
}
f.Close()
defer os.Remove(f.Name())
if !localkubeCacher.isLocalkubeCached() {
t.Errorf("IsLocalKubeCached returned false even though %s was cached",
localkubeCacher.getLocalkubeCacheFilepath())
}
}
for _, input := range inputArr {
inner(input)
}
}

View File

@ -1,43 +0,0 @@
/*
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 cluster
import (
"net"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/util"
)
var (
// This is the internalIP , the API server and other components communicate on.
internalIP = net.ParseIP(util.DefaultServiceClusterIP)
)
func GenerateCerts(caCert, caKey, pub, priv string, ip net.IP, name string, dnsDomain string) error {
if !(util.CanReadFile(caCert) && util.CanReadFile(caKey)) {
if err := util.GenerateCACert(caCert, caKey, name); err != nil {
return errors.Wrap(err, "Error generating certificate")
}
}
ips := []net.IP{ip, internalIP}
if err := util.GenerateSignedCert(pub, priv, ips, util.GetAlternateDNS(dnsDomain), caCert, caKey); err != nil {
return errors.Wrap(err, "Error generating signed cert")
}
return nil
}

View File

@ -16,7 +16,10 @@ limitations under the License.
package cluster
import "k8s.io/minikube/pkg/util"
import (
"k8s.io/minikube/pkg/minikube/bootstrapper"
"k8s.io/minikube/pkg/util"
)
// MachineConfig contains the parameters used to start a cluster.
type MachineConfig struct {
@ -37,20 +40,8 @@ type MachineConfig struct {
DisableDriverMounts bool // Only used by virtualbox and xhyve
}
// KubernetesConfig contains the parameters used to configure the VM Kubernetes.
type KubernetesConfig struct {
KubernetesVersion string
NodeIP string
APIServerName string
DNSDomain string
ContainerRuntime string
NetworkPlugin string
FeatureGates string
ExtraOptions util.ExtraOptionSlice
}
// Config contains machine and k8s config
type Config struct {
MachineConfig MachineConfig
KubernetesConfig KubernetesConfig
KubernetesConfig bootstrapper.KubernetesConfig
}

View File

@ -97,6 +97,7 @@ const (
KubernetesVersionGCSURL = "https://storage.googleapis.com/minikube/k8s_releases.json"
DefaultWait = 20
DefaultInterval = 6
DefaultClusterBootstrapper = "localkube"
)
var DefaultIsoUrl = fmt.Sprintf("https://storage.googleapis.com/%s/minikube-%s.iso", minikubeVersion.GetIsoPath(), minikubeVersion.GetIsoVersion())
@ -144,3 +145,4 @@ const (
const IsMinikubeChildProcess = "IS_MINIKUBE_CHILD_PROCESS"
const DriverNone = "none"
const FileScheme = "file"