Merge pull request #1886 from r2d4/localkube-bootstrapper
Add localkube as a bootstrapperpull/1902/head
commit
b0db008b87
|
@ -29,6 +29,8 @@ import (
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const Bootstrapper = "bootstrapper"
|
||||||
|
|
||||||
type setFn func(string, string) error
|
type setFn func(string, string) error
|
||||||
|
|
||||||
type Setting struct {
|
type Setting struct {
|
||||||
|
@ -113,6 +115,10 @@ var settings = []Setting{
|
||||||
name: config.MachineProfile,
|
name: config.MachineProfile,
|
||||||
set: SetString,
|
set: SetString,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: Bootstrapper,
|
||||||
|
set: SetString, //TODO(r2d4): more validation here?
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "dashboard",
|
name: "dashboard",
|
||||||
set: SetBool,
|
set: SetBool,
|
||||||
|
|
|
@ -23,9 +23,9 @@ import (
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
|
||||||
cmdUtil "k8s.io/minikube/cmd/util"
|
cmdUtil "k8s.io/minikube/cmd/util"
|
||||||
"k8s.io/minikube/pkg/minikube/cluster"
|
|
||||||
"k8s.io/minikube/pkg/minikube/config"
|
|
||||||
"k8s.io/minikube/pkg/minikube/machine"
|
"k8s.io/minikube/pkg/minikube/machine"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,15 +45,12 @@ var logsCmd = &cobra.Command{
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
defer api.Close()
|
defer api.Close()
|
||||||
h, err := api.Load(config.GetMachineName())
|
clusterBootstrapper, err := GetClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorln("Error getting host")
|
glog.Exitf("Error getting cluster bootstrapper: %s", err)
|
||||||
}
|
}
|
||||||
cmdRunner, err := machine.GetCommandRunner(h)
|
|
||||||
if err != nil {
|
s, err := clusterBootstrapper.GetClusterLogs(follow)
|
||||||
glog.Errorln("Error getting command runner interface")
|
|
||||||
}
|
|
||||||
s, err := cluster.GetHostLogs(cmdRunner, follow)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error getting machine logs:", err)
|
log.Println("Error getting machine logs:", err)
|
||||||
cmdUtil.MaybeReportErrorAndExit(err)
|
cmdUtil.MaybeReportErrorAndExit(err)
|
||||||
|
|
|
@ -18,18 +18,23 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
goflag "flag"
|
goflag "flag"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/machine/libmachine"
|
||||||
"github.com/docker/machine/libmachine/log"
|
"github.com/docker/machine/libmachine/log"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
configCmd "k8s.io/minikube/cmd/minikube/cmd/config"
|
configCmd "k8s.io/minikube/cmd/minikube/cmd/config"
|
||||||
"k8s.io/minikube/cmd/util"
|
"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/config"
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
"k8s.io/minikube/pkg/minikube/notify"
|
"k8s.io/minikube/pkg/minikube/notify"
|
||||||
|
@ -98,7 +103,6 @@ func Execute() {
|
||||||
if err := RootCmd.Execute(); err != nil {
|
if err := RootCmd.Execute(); err != nil {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle config values for flags used in external packages (e.g. glog)
|
// Handle config values for flags used in external packages (e.g. glog)
|
||||||
|
@ -121,6 +125,7 @@ func setFlagsUsingViper() {
|
||||||
func init() {
|
func init() {
|
||||||
RootCmd.PersistentFlags().StringP(config.MachineProfile, "p", constants.DefaultMachineName, `The name of the minikube VM being used.
|
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`)
|
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.ConfigCmd)
|
||||||
RootCmd.AddCommand(configCmd.AddonsCmd)
|
RootCmd.AddCommand(configCmd.AddonsCmd)
|
||||||
RootCmd.AddCommand(configCmd.ProfileCmd)
|
RootCmd.AddCommand(configCmd.ProfileCmd)
|
||||||
|
@ -157,3 +162,20 @@ func setupViper() {
|
||||||
viper.SetDefault(config.WantKubectlDownloadMsg, true)
|
viper.SetDefault(config.WantKubectlDownloadMsg, true)
|
||||||
setFlagsUsingViper()
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -32,7 +32,9 @@ import (
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
|
||||||
cmdUtil "k8s.io/minikube/cmd/util"
|
cmdUtil "k8s.io/minikube/cmd/util"
|
||||||
|
"k8s.io/minikube/pkg/minikube/bootstrapper"
|
||||||
"k8s.io/minikube/pkg/minikube/cluster"
|
"k8s.io/minikube/pkg/minikube/cluster"
|
||||||
cfg "k8s.io/minikube/pkg/minikube/config"
|
cfg "k8s.io/minikube/pkg/minikube/config"
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
|
@ -91,6 +93,11 @@ func runStart(cmd *cobra.Command, args []string) {
|
||||||
}
|
}
|
||||||
defer api.Close()
|
defer api.Close()
|
||||||
|
|
||||||
|
exists, err := api.Exists(cfg.GetMachineName())
|
||||||
|
if err != nil {
|
||||||
|
glog.Exitf("checking if machine exists: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
diskSize := viper.GetString(humanReadableDiskSize)
|
diskSize := viper.GetString(humanReadableDiskSize)
|
||||||
diskSizeMB := util.CalculateDiskSizeInMB(diskSize)
|
diskSizeMB := util.CalculateDiskSizeInMB(diskSize)
|
||||||
|
|
||||||
|
@ -170,9 +177,10 @@ func runStart(cmd *cobra.Command, args []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kubernetesConfig := cluster.KubernetesConfig{
|
kubernetesConfig := bootstrapper.KubernetesConfig{
|
||||||
KubernetesVersion: selectedKubernetesVersion,
|
KubernetesVersion: selectedKubernetesVersion,
|
||||||
NodeIP: ip,
|
NodeIP: ip,
|
||||||
|
NodeName: cfg.GetMachineName(),
|
||||||
APIServerName: viper.GetString(apiServerName),
|
APIServerName: viper.GetString(apiServerName),
|
||||||
DNSDomain: viper.GetString(dnsDomain),
|
DNSDomain: viper.GetString(dnsDomain),
|
||||||
FeatureGates: viper.GetString(featureGates),
|
FeatureGates: viper.GetString(featureGates),
|
||||||
|
@ -181,6 +189,11 @@ func runStart(cmd *cobra.Command, args []string) {
|
||||||
ExtraOptions: extraOptions,
|
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
|
// Write profile cluster configuration to file
|
||||||
clusterConfig := cluster.Config{
|
clusterConfig := cluster.Config{
|
||||||
MachineConfig: config,
|
MachineConfig: config,
|
||||||
|
@ -191,30 +204,18 @@ func runStart(cmd *cobra.Command, args []string) {
|
||||||
glog.Errorln("Error saving profile cluster configuration: ", err)
|
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...")
|
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)
|
glog.Errorln("Error updating cluster: ", err)
|
||||||
cmdUtil.MaybeReportErrorAndExit(err)
|
cmdUtil.MaybeReportErrorAndExit(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Setting up certs...")
|
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)
|
glog.Errorln("Error configuring authentication: ", err)
|
||||||
cmdUtil.MaybeReportErrorAndExit(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...")
|
fmt.Println("Connecting to cluster...")
|
||||||
kubeHost, err := host.Driver.GetURL()
|
kubeHost, err := host.Driver.GetURL()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -243,6 +244,20 @@ func runStart(cmd *cobra.Command, args []string) {
|
||||||
cmdUtil.MaybeReportErrorAndExit(err)
|
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
|
// start 9p server mount
|
||||||
if viper.GetBool(createMount) {
|
if viper.GetBool(createMount) {
|
||||||
fmt.Printf("Setting up hostmount on %s...\n", viper.GetString(mountString))
|
fmt.Printf("Setting up hostmount on %s...\n", viper.GetString(mountString))
|
||||||
|
|
|
@ -24,6 +24,8 @@ import (
|
||||||
"github.com/docker/machine/libmachine/state"
|
"github.com/docker/machine/libmachine/state"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
cmdcfg "k8s.io/minikube/cmd/minikube/cmd/config"
|
||||||
cmdUtil "k8s.io/minikube/cmd/util"
|
cmdUtil "k8s.io/minikube/cmd/util"
|
||||||
"k8s.io/minikube/pkg/minikube/cluster"
|
"k8s.io/minikube/pkg/minikube/cluster"
|
||||||
"k8s.io/minikube/pkg/minikube/config"
|
"k8s.io/minikube/pkg/minikube/config"
|
||||||
|
@ -62,18 +64,14 @@ var statusCmd = &cobra.Command{
|
||||||
cs := state.None.String()
|
cs := state.None.String()
|
||||||
ks := state.None.String()
|
ks := state.None.String()
|
||||||
if ms == state.Running.String() {
|
if ms == state.Running.String() {
|
||||||
h, err := api.Load(config.GetMachineName())
|
clusterBootstrapper, err := GetClusterBootstrapper(api, viper.GetString(cmdcfg.Bootstrapper))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Exitln("Error getting host")
|
glog.Errorf("Error getting cluster bootstrapper: %s", err)
|
||||||
}
|
|
||||||
cmdRunner, err := machine.GetCommandRunner(h)
|
|
||||||
if err != nil {
|
|
||||||
glog.Errorln("Error getting command runner interface")
|
|
||||||
cmdUtil.MaybeReportErrorAndExit(err)
|
cmdUtil.MaybeReportErrorAndExit(err)
|
||||||
}
|
}
|
||||||
cs, err = cluster.GetLocalkubeStatus(cmdRunner)
|
cs, err = clusterBootstrapper.GetClusterStatus()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorln("Error localkube status:", err)
|
glog.Errorln("Error cluster status:", err)
|
||||||
cmdUtil.MaybeReportErrorAndExit(err)
|
cmdUtil.MaybeReportErrorAndExit(err)
|
||||||
}
|
}
|
||||||
ip, err := cluster.GetHostDriverIP(api)
|
ip, err := cluster.GetHostDriverIP(api)
|
||||||
|
|
|
@ -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"
|
||||||
|
)
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,17 +14,17 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cluster
|
package localkube
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
gflag "flag"
|
gflag "flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
"k8s.io/minikube/pkg/minikube/bootstrapper"
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ else
|
||||||
fi
|
fi
|
||||||
`
|
`
|
||||||
|
|
||||||
func GetStartCommand(kubernetesConfig KubernetesConfig) (string, error) {
|
func GetStartCommand(kubernetesConfig bootstrapper.KubernetesConfig) (string, error) {
|
||||||
localkubeStartCommand, err := GenLocalkubeStartCmd(kubernetesConfig)
|
localkubeStartCommand, err := GenLocalkubeStartCmd(kubernetesConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -93,7 +93,7 @@ func GetStartCommand(kubernetesConfig KubernetesConfig) (string, error) {
|
||||||
return buf.String(), nil
|
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))
|
t := template.Must(template.New("startCommand").Parse(startCommandNoSystemdTemplate))
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
data := struct {
|
data := struct {
|
||||||
|
@ -113,7 +113,7 @@ func GetStartCommandNoSystemd(kubernetesConfig KubernetesConfig, localkubeStartC
|
||||||
return buf.String(), nil
|
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)
|
t, err := template.New("localkubeConfig").Parse(localkubeSystemdTmpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -131,7 +131,7 @@ func GetStartCommandSystemd(kubernetesConfig KubernetesConfig, localkubeStartCmd
|
||||||
constants.LocalkubeServicePath), nil
|
constants.LocalkubeServicePath), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenLocalkubeStartCmd(kubernetesConfig KubernetesConfig) (string, error) {
|
func GenLocalkubeStartCmd(kubernetesConfig bootstrapper.KubernetesConfig) (string, error) {
|
||||||
flagVals := make([]string, len(constants.LogFlags))
|
flagVals := make([]string, len(constants.LogFlags))
|
||||||
for _, logFlag := range constants.LogFlags {
|
for _, logFlag := range constants.LogFlags {
|
||||||
if logVal := gflag.Lookup(logFlag); logVal != nil && logVal.Value.String() != logVal.DefValue {
|
if logVal := gflag.Lookup(logFlag); logVal != nil && logVal.Value.String() != logVal.DefValue {
|
||||||
|
@ -226,38 +226,3 @@ else
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
`, constants.LocalkubePIDPath)
|
`, 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
|
|
||||||
}
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cluster
|
package localkube
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gflag "flag"
|
gflag "flag"
|
||||||
|
@ -22,6 +22,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/minikube/pkg/minikube/bootstrapper"
|
||||||
"k8s.io/minikube/pkg/util"
|
"k8s.io/minikube/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ func TestGetStartCommandCustomValues(t *testing.T) {
|
||||||
"vmodule": "cluster*=5",
|
"vmodule": "cluster*=5",
|
||||||
}
|
}
|
||||||
flagMapToSetFlags(flagMap)
|
flagMapToSetFlags(flagMap)
|
||||||
startCommand, err := GetStartCommand(KubernetesConfig{})
|
startCommand, err := GetStartCommand(bootstrapper.KubernetesConfig{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error generating start command: %s", err)
|
t.Fatalf("Error generating start command: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -46,7 +47,7 @@ func TestGetStartCommandCustomValues(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetStartCommandExtraOptions(t *testing.T) {
|
func TestGetStartCommandExtraOptions(t *testing.T) {
|
||||||
k := KubernetesConfig{
|
k := bootstrapper.KubernetesConfig{
|
||||||
ExtraOptions: util.ExtraOptionSlice{
|
ExtraOptions: util.ExtraOptionSlice{
|
||||||
util.ExtraOption{Component: "a", Key: "b", Value: "c"},
|
util.ExtraOption{Component: "a", Key: "b", Value: "c"},
|
||||||
util.ExtraOption{Component: "d", Key: "e.f", Value: "g"},
|
util.ExtraOption{Component: "d", Key: "e.f", Value: "g"},
|
|
@ -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(©ableFiles)
|
||||||
|
// 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)
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package cluster
|
package localkube
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -27,13 +27,14 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"k8s.io/minikube/pkg/minikube/assets"
|
"k8s.io/minikube/pkg/minikube/assets"
|
||||||
|
"k8s.io/minikube/pkg/minikube/bootstrapper"
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
"k8s.io/minikube/pkg/util"
|
"k8s.io/minikube/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// localkubeCacher is a struct with methods designed for caching localkube
|
// localkubeCacher is a struct with methods designed for caching localkube
|
||||||
type localkubeCacher struct {
|
type localkubeCacher struct {
|
||||||
k8sConf KubernetesConfig
|
k8sConf bootstrapper.KubernetesConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *localkubeCacher) getLocalkubeCacheFilepath() string {
|
func (l *localkubeCacher) getLocalkubeCacheFilepath() string {
|
||||||
|
@ -41,6 +42,11 @@ func (l *localkubeCacher) getLocalkubeCacheFilepath() string {
|
||||||
filepath.Base(url.QueryEscape("localkube-"+l.k8sConf.KubernetesVersion)))
|
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 {
|
func (l *localkubeCacher) isLocalkubeCached() bool {
|
||||||
if _, err := os.Stat(l.getLocalkubeCacheFilepath()); os.IsNotExist(err) {
|
if _, err := os.Stat(l.getLocalkubeCacheFilepath()); os.IsNotExist(err) {
|
||||||
return false
|
return false
|
||||||
|
@ -71,7 +77,7 @@ func (l *localkubeCacher) fetchLocalkubeFromURI() (assets.CopyableFile, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Error parsing --kubernetes-version url")
|
return nil, errors.Wrap(err, "Error parsing --kubernetes-version url")
|
||||||
}
|
}
|
||||||
if urlObj.Scheme == fileScheme {
|
if urlObj.Scheme == constants.FileScheme {
|
||||||
return l.genLocalkubeFileFromFile()
|
return l.genLocalkubeFileFromFile()
|
||||||
}
|
}
|
||||||
return l.genLocalkubeFileFromURL()
|
return l.genLocalkubeFileFromURL()
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,15 +17,15 @@ limitations under the License.
|
||||||
package cluster
|
package cluster
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/machine/drivers/virtualbox"
|
"github.com/docker/machine/drivers/virtualbox"
|
||||||
|
@ -38,16 +38,10 @@ import (
|
||||||
"github.com/docker/machine/libmachine/state"
|
"github.com/docker/machine/libmachine/state"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/pkg/errors"
|
"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"
|
cfg "k8s.io/minikube/pkg/minikube/config"
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
"k8s.io/minikube/pkg/util"
|
"k8s.io/minikube/pkg/util"
|
||||||
"k8s.io/minikube/pkg/util/kubeconfig"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -154,22 +148,6 @@ func GetHostStatus(api libmachine.API) (string, error) {
|
||||||
return s.String(), nil
|
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
|
// GetHostDriverIP gets the ip address of the current minikube cluster
|
||||||
func GetHostDriverIP(api libmachine.API) (net.IP, error) {
|
func GetHostDriverIP(api libmachine.API) (net.IP, error) {
|
||||||
host, err := CheckIfApiExistsAndLoad(api)
|
host, err := CheckIfApiExistsAndLoad(api)
|
||||||
|
@ -188,121 +166,6 @@ func GetHostDriverIP(api libmachine.API) (net.IP, error) {
|
||||||
return ip, nil
|
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(©ableFiles)
|
|
||||||
// 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 {
|
func engineOptions(config MachineConfig) *engine.Options {
|
||||||
o := engine.Options{
|
o := engine.Options{
|
||||||
Env: config.DockerEnv,
|
Env: config.DockerEnv,
|
||||||
|
@ -400,20 +263,6 @@ func GetHostDockerEnv(api libmachine.API) (map[string]string, error) {
|
||||||
return envMap, nil
|
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
|
// 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 {
|
func MountHost(api libmachine.API, ip net.IP, path, port, mountVersion string, uid, gid, msize int) error {
|
||||||
host, err := CheckIfApiExistsAndLoad(api)
|
host, err := CheckIfApiExistsAndLoad(api)
|
||||||
|
@ -536,3 +385,38 @@ func EnsureMinikubeRunningOrExit(api libmachine.API, exitStatus int) {
|
||||||
os.Exit(exitStatus)
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ package cluster
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -26,7 +25,6 @@ import (
|
||||||
"github.com/docker/machine/libmachine/host"
|
"github.com/docker/machine/libmachine/host"
|
||||||
"github.com/docker/machine/libmachine/provision"
|
"github.com/docker/machine/libmachine/provision"
|
||||||
"github.com/docker/machine/libmachine/state"
|
"github.com/docker/machine/libmachine/state"
|
||||||
"k8s.io/minikube/pkg/minikube/bootstrapper"
|
|
||||||
"k8s.io/minikube/pkg/minikube/config"
|
"k8s.io/minikube/pkg/minikube/config"
|
||||||
"k8s.io/minikube/pkg/minikube/constants"
|
"k8s.io/minikube/pkg/minikube/constants"
|
||||||
"k8s.io/minikube/pkg/minikube/tests"
|
"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) {
|
func TestStartHostExists(t *testing.T) {
|
||||||
api := tests.NewMockAPI()
|
api := tests.NewMockAPI()
|
||||||
// Create an initial host.
|
// Create an initial host.
|
||||||
|
@ -609,46 +389,3 @@ func TestCreateSSHShell(t *testing.T) {
|
||||||
t.Fatalf("Expected ssh session to be run")
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -16,7 +16,10 @@ limitations under the License.
|
||||||
|
|
||||||
package cluster
|
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.
|
// MachineConfig contains the parameters used to start a cluster.
|
||||||
type MachineConfig struct {
|
type MachineConfig struct {
|
||||||
|
@ -37,20 +40,8 @@ type MachineConfig struct {
|
||||||
DisableDriverMounts bool // Only used by virtualbox and xhyve
|
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
|
// Config contains machine and k8s config
|
||||||
type Config struct {
|
type Config struct {
|
||||||
MachineConfig MachineConfig
|
MachineConfig MachineConfig
|
||||||
KubernetesConfig KubernetesConfig
|
KubernetesConfig bootstrapper.KubernetesConfig
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,7 @@ const (
|
||||||
KubernetesVersionGCSURL = "https://storage.googleapis.com/minikube/k8s_releases.json"
|
KubernetesVersionGCSURL = "https://storage.googleapis.com/minikube/k8s_releases.json"
|
||||||
DefaultWait = 20
|
DefaultWait = 20
|
||||||
DefaultInterval = 6
|
DefaultInterval = 6
|
||||||
|
DefaultClusterBootstrapper = "localkube"
|
||||||
)
|
)
|
||||||
|
|
||||||
var DefaultIsoUrl = fmt.Sprintf("https://storage.googleapis.com/%s/minikube-%s.iso", minikubeVersion.GetIsoPath(), minikubeVersion.GetIsoVersion())
|
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 IsMinikubeChildProcess = "IS_MINIKUBE_CHILD_PROCESS"
|
||||||
const DriverNone = "none"
|
const DriverNone = "none"
|
||||||
|
const FileScheme = "file"
|
||||||
|
|
Loading…
Reference in New Issue