提交 f8c1f05e 编写于 作者: S Sharif Elgamal

Merge branch 'master' of github.com:kubernetes/minikube into multi-vm

......@@ -100,8 +100,11 @@ var addonsConfigureCmd = &cobra.Command{
acrPassword = AskForPasswordValue("-- Enter service principal password to access Azure Container Registry: ")
}
cname := ClusterFlagValue()
// Create ECR Secret
err := service.CreateSecret(
cname,
"kube-system",
"registry-creds-ecr",
map[string]string{
......@@ -124,6 +127,7 @@ var addonsConfigureCmd = &cobra.Command{
// Create GCR Secret
err = service.CreateSecret(
cname,
"kube-system",
"registry-creds-gcr",
map[string]string{
......@@ -142,6 +146,7 @@ var addonsConfigureCmd = &cobra.Command{
// Create Docker Secret
err = service.CreateSecret(
cname,
"kube-system",
"registry-creds-dpr",
map[string]string{
......@@ -161,6 +166,7 @@ var addonsConfigureCmd = &cobra.Command{
// Create Azure Container Registry Secret
err = service.CreateSecret(
cname,
"kube-system",
"registry-creds-acr",
map[string]string{
......
......@@ -77,7 +77,7 @@ minikube addons enable {{.name}}`, out.V{"name": addonName})
namespace := "kube-system"
key := "kubernetes.io/minikube-addons-endpoint"
serviceList, err := service.GetServiceListByLabel(namespace, key, addonName)
serviceList, err := service.GetServiceListByLabel(cname, namespace, key, addonName)
if err != nil {
exit.WithCodeT(exit.Unavailable, "Error getting service with namespace: {{.namespace}} and labels {{.labelName}}:{{.addonName}}: {{.error}}", out.V{"namespace": namespace, "labelName": key, "addonName": addonName, "error": err})
}
......@@ -89,7 +89,7 @@ You can add one by annotating a service with the label {{.labelName}}:{{.addonNa
svc := serviceList.Items[i].ObjectMeta.Name
var urlString []string
if urlString, err = service.WaitForService(co.API, namespace, svc, addonsURLTemplate, addonsURLMode, https, wait, interval); err != nil {
if urlString, err = service.WaitForService(co.API, co.Config.Name, namespace, svc, addonsURLTemplate, addonsURLMode, https, wait, interval); err != nil {
exit.WithCodeT(exit.Unavailable, "Wait failed: {{.error}}", out.V{"error": err})
}
......
......@@ -83,8 +83,9 @@ var dashboardCmd = &cobra.Command{
ns := "kubernetes-dashboard"
svc := "kubernetes-dashboard"
out.ErrT(out.Verifying, "Verifying dashboard health ...")
checkSVC := func() error { return service.CheckService(ns, svc) }
if err = retry.Expo(checkSVC, 1*time.Second, time.Minute*5); err != nil {
checkSVC := func() error { return service.CheckService(cname, ns, svc) }
// for slow machines or parallels in CI to avoid #7503
if err = retry.Expo(checkSVC, 100*time.Microsecond, time.Minute*10); err != nil {
exit.WithCodeT(exit.Unavailable, "dashboard service is not running: {{.error}}", out.V{"error": err})
}
......@@ -97,7 +98,7 @@ var dashboardCmd = &cobra.Command{
out.ErrT(out.Verifying, "Verifying proxy health ...")
chkURL := func() error { return checkURL(url) }
if err = retry.Expo(chkURL, 1*time.Second, 3*time.Minute); err != nil {
if err = retry.Expo(chkURL, 100*time.Microsecond, 10*time.Minute); err != nil {
exit.WithCodeT(exit.Unavailable, "{{.url}} is not accessible: {{.error}}", out.V{"url": url, "error": err})
}
......
......@@ -33,7 +33,9 @@ import (
"github.com/spf13/cobra"
"k8s.io/minikube/pkg/drivers/kic/oci"
"k8s.io/minikube/pkg/kapi"
"k8s.io/minikube/pkg/minikube/browser"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/mustload"
......@@ -78,12 +80,12 @@ var serviceCmd = &cobra.Command{
cname := ClusterFlagValue()
co := mustload.Healthy(cname)
if runtime.GOOS == "darwin" && co.Config.Driver == oci.Docker {
if driver.NeedsPortForward(co.Config.Driver) {
startKicServiceTunnel(svc, cname)
return
}
urls, err := service.WaitForService(co.API, namespace, svc, serviceURLTemplate, serviceURLMode, https, wait, interval)
urls, err := service.WaitForService(co.API, co.Config.Name, namespace, svc, serviceURLTemplate, serviceURLMode, https, wait, interval)
if err != nil {
var s *service.SVCNotFoundError
if errors.As(err, &s) {
......@@ -112,7 +114,7 @@ func startKicServiceTunnel(svc, configName string) {
ctrlC := make(chan os.Signal, 1)
signal.Notify(ctrlC, os.Interrupt)
clientset, err := service.K8s.GetClientset(1 * time.Second)
clientset, err := kapi.Client(configName)
if err != nil {
exit.WithError("error creating clientset", err)
}
......@@ -137,7 +139,7 @@ func startKicServiceTunnel(svc, configName string) {
service.PrintServiceList(os.Stdout, data)
openURLs(svc, urls)
out.WarningT("Because you are using docker driver on Mac, the terminal needs to be open to run it.")
out.WarningT("Because you are using a Docker driver on {{.operating_system}}, the terminal needs to be open to run it.", out.V{"operating_system": runtime.GOOS})
<-ctrlC
......
......@@ -40,7 +40,7 @@ var serviceListCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
co := mustload.Healthy(ClusterFlagValue())
serviceURLs, err := service.GetServiceURLs(co.API, serviceListNamespace, serviceURLTemplate)
serviceURLs, err := service.GetServiceURLs(co.API, co.Config.Name, serviceListNamespace, serviceURLTemplate)
if err != nil {
out.FatalT("Failed to get service URL: {{.error}}", out.V{"error": err})
out.ErrT(out.Notice, "Check that minikube is running and that you have specified the correct namespace (-n flag) if required.")
......
......@@ -21,19 +21,18 @@ import (
"os"
"os/signal"
"path/filepath"
"runtime"
"strconv"
"time"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/minikube/pkg/drivers/kic/oci"
"k8s.io/minikube/pkg/kapi"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/driver"
"k8s.io/minikube/pkg/minikube/exit"
"k8s.io/minikube/pkg/minikube/localpath"
"k8s.io/minikube/pkg/minikube/mustload"
"k8s.io/minikube/pkg/minikube/service"
"k8s.io/minikube/pkg/minikube/tunnel"
"k8s.io/minikube/pkg/minikube/tunnel/kic"
)
......@@ -65,7 +64,7 @@ var tunnelCmd = &cobra.Command{
// We define the tunnel and minikube error free if the API server responds within a second.
// This also contributes to better UX, the tunnel status check can happen every second and
// doesn't hang on the API server call during startup and shutdown time or if there is a temporary error.
clientset, err := service.K8s.GetClientset(1 * time.Second)
clientset, err := kapi.Client(cname)
if err != nil {
exit.WithError("error creating clientset", err)
}
......@@ -78,7 +77,8 @@ var tunnelCmd = &cobra.Command{
cancel()
}()
if runtime.GOOS == "darwin" && co.Config.Driver == oci.Docker {
if driver.NeedsPortForward(co.Config.Driver) {
port, err := oci.ForwardedPort(oci.Docker, cname, 22)
if err != nil {
exit.WithError("error getting ssh port", err)
......
......@@ -35,7 +35,11 @@ var rootCmd = &cobra.Command{
return validateArgs(args)
},
RunE: func(cmd *cobra.Command, args []string) error {
return perf.CompareMinikubeStart(context.Background(), os.Stdout, args)
binaries, err := retrieveBinaries(args)
if err != nil {
return err
}
return perf.CompareMinikubeStart(context.Background(), os.Stdout, binaries)
},
}
......@@ -46,6 +50,18 @@ func validateArgs(args []string) error {
return nil
}
func retrieveBinaries(args []string) ([]*perf.Binary, error) {
binaries := []*perf.Binary{}
for _, a := range args {
binary, err := perf.NewBinary(a)
if err != nil {
return nil, err
}
binaries = append(binaries, binary)
}
return binaries, nil
}
// Execute runs the mkcmp command
func Execute() {
if err := rootCmd.Execute(); err != nil {
......
......@@ -42,6 +42,7 @@ jobs=(
'none_Linux'
'Docker_Linux'
'Docker_macOS'
'Docker_Windows'
'Podman_Linux'
)
......
......@@ -17,9 +17,9 @@ gsutil.cmd -m cp gs://minikube-builds/$env:MINIKUBE_LOCATION/minikube-windows-am
gsutil.cmd -m cp gs://minikube-builds/$env:MINIKUBE_LOCATION/e2e-windows-amd64.exe out/
gsutil.cmd -m cp -r gs://minikube-builds/$env:MINIKUBE_LOCATION/testdata .
./out/minikube-windows-amd64.exe delete
./out/minikube-windows-amd64.exe delete --all
out/e2e-windows-amd64.exe -minikube-start-args="--driver=hyperv --hyperv-virtual-switch=primary-virtual-switch" -binary=out/minikube-windows-amd64.exe -test.v -test.timeout=65m
out/e2e-windows-amd64.exe -minikube-start-args="--driver=hyperv" -binary=out/minikube-windows-amd64.exe -test.v -test.timeout=65m
$env:result=$lastexitcode
# If the last exit code was 0->success, x>0->error
If($env:result -eq 0){$env:status="success"}
......
......@@ -244,7 +244,7 @@ func enableOrDisableAddonInternal(cc *config.ClusterConfig, addon *assets.Addon,
return err
}
return retry.Expo(apply, 1*time.Second, time.Second*30)
return retry.Expo(apply, 100*time.Microsecond, time.Minute)
}
// enableOrDisableStorageClasses enables or disables storage classes
......@@ -259,10 +259,6 @@ func enableOrDisableStorageClasses(cc *config.ClusterConfig, name string, val st
if name == "storage-provisioner-gluster" {
class = "glusterfile"
}
storagev1, err := storageclass.GetStoragev1()
if err != nil {
return errors.Wrapf(err, "Error getting storagev1 interface %v ", err)
}
api, err := machine.NewAPIClient()
if err != nil {
......@@ -279,6 +275,11 @@ func enableOrDisableStorageClasses(cc *config.ClusterConfig, name string, val st
return enableOrDisableAddon(cc, name, val)
}
storagev1, err := storageclass.GetStoragev1(cc.Name)
if err != nil {
return errors.Wrapf(err, "Error getting storagev1 interface %v ", err)
}
if enable {
// Only StorageClass for 'name' should be marked as default
err = storageclass.SetDefaultStorageClass(storagev1, class)
......
......@@ -38,6 +38,7 @@ import (
"k8s.io/minikube/pkg/minikube/cruntime"
"k8s.io/minikube/pkg/minikube/download"
"k8s.io/minikube/pkg/minikube/sysinit"
"k8s.io/minikube/pkg/util/retry"
)
// Driver represents a kic driver https://minikube.sigs.k8s.io/docs/reference/drivers/docker
......@@ -258,9 +259,14 @@ func (d *Driver) Kill() error {
if err := sysinit.New(d.exec).ForceStop("kubelet"); err != nil {
glog.Warningf("couldn't force stop kubelet. will continue with kill anyways: %v", err)
}
cmd := exec.Command(d.NodeConfig.OCIBinary, "kill", d.MachineName)
if err := cmd.Run(); err != nil {
return errors.Wrapf(err, "killing kic node %s", d.MachineName)
if err := oci.ShutDown(d.OCIBinary, d.MachineName); err != nil {
glog.Warningf("couldn't shutdown the container, will continue with kill anyways: %v", err)
}
cr := command.NewExecRunner() // using exec runner for interacting with dameon.
if _, err := cr.RunCmd(exec.Command(d.NodeConfig.OCIBinary, "kill", d.MachineName)); err != nil {
return errors.Wrapf(err, "killing %q", d.MachineName)
}
return nil
}
......@@ -292,40 +298,43 @@ func (d *Driver) Remove() error {
func (d *Driver) Restart() error {
s, err := d.GetState()
if err != nil {
return errors.Wrap(err, "get kic state")
glog.Warningf("get state during restart: %v", err)
}
switch s {
case state.Stopped:
if s == state.Stopped { // don't stop if already stopped
return d.Start()
case state.Running, state.Error:
if err = d.Stop(); err != nil {
return fmt.Errorf("restarting a kic stop phase %v", err)
}
if err = d.Start(); err != nil {
return fmt.Errorf("restarting a kic start phase %v", err)
}
return nil
}
if err = d.Stop(); err != nil {
return fmt.Errorf("stop during restart %v", err)
}
if err = d.Start(); err != nil {
return fmt.Errorf("start during restart %v", err)
}
return nil
return fmt.Errorf("restarted not implemented for kic state %s yet", s)
}
// Start a _stopped_ kic container
// not meant to be used for Create().
// Start an already created kic container
func (d *Driver) Start() error {
s, err := d.GetState()
if err != nil {
return errors.Wrap(err, "get kic state")
cr := command.NewExecRunner() // using exec runner for interacting with docker/podman daemon
if _, err := cr.RunCmd(exec.Command(d.NodeConfig.OCIBinary, "start", d.MachineName)); err != nil {
return errors.Wrap(err, "start")
}
if s == state.Stopped {
cmd := exec.Command(d.NodeConfig.OCIBinary, "start", d.MachineName)
if err := cmd.Run(); err != nil {
return errors.Wrapf(err, "starting a stopped kic node %s", d.MachineName)
checkRunning := func() error {
s, err := oci.ContainerStatus(d.NodeConfig.OCIBinary, d.MachineName)
if err != nil {
return err
}
if s != state.Running {
return fmt.Errorf("expected container state be running but got %q", s)
}
glog.Infof("container %q state is running.", d.MachineName)
return nil
}
// TODO:medyagh maybe make it idempotent
return fmt.Errorf("cant start a not-stopped (%s) kic node", s)
if err := retry.Expo(checkRunning, 500*time.Microsecond, time.Second*30); err != nil {
return err
}
return nil
}
// Stop a host gracefully, including any containers that we are managing.
......
......@@ -25,6 +25,7 @@ import (
"bufio"
"bytes"
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/constants"
......@@ -171,7 +172,7 @@ func CreateContainerNode(p CreateParams) error {
if err != nil {
return fmt.Errorf("temporary error checking status for %q : %v", p.Name, err)
}
if s != "running" {
if s != state.Running {
return fmt.Errorf("temporary error created container %q is not running yet", p.Name)
}
glog.Infof("the created container %q has a running status.", p.Name)
......@@ -488,9 +489,23 @@ func PointToHostDockerDaemon() error {
}
// ContainerStatus returns status of a container running,exited,...
func ContainerStatus(ociBin string, name string) (string, error) {
func ContainerStatus(ociBin string, name string) (state.State, error) {
out, err := WarnIfSlow(ociBin, "inspect", name, "--format={{.State.Status}}")
return strings.TrimSpace(string(out)), err
o := strings.TrimSpace(string(out))
switch o {
case "running":
return state.Running, nil
case "exited":
return state.Stopped, nil
case "paused":
return state.Paused, nil
case "restarting":
return state.Starting, nil
case "dead":
return state.Error, nil
default:
return state.None, errors.Wrapf(err, "unknown state %q", name)
}
}
// Shutdown will run command to shut down the container
......@@ -506,7 +521,7 @@ func ShutDown(ociBin string, name string) error {
// wait till it is stoped
stopped := func() error {
st, err := ContainerStatus(ociBin, name)
if st == "exited" {
if st == state.Stopped {
glog.Infof("container %s status is %s", name, st)
return nil
}
......
/*
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 ktmpl
import "text/template"
// V1Alpha1 is for Kubernetes v1.11
var V1Alpha1 = template.Must(template.New("configTmpl-v1alpha1").Funcs(template.FuncMap{
"printMapInOrder": printMapInOrder,
}).Parse(`apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
{{if .NoTaintMaster}}noTaintMaster: true{{end}}
api:
advertiseAddress: {{.AdvertiseAddress}}
bindPort: {{.APIServerPort}}
controlPlaneEndpoint: {{.ControlPlaneAddress}}
kubernetesVersion: {{.KubernetesVersion}}
certificatesDir: {{.CertDir}}
networking:
serviceSubnet: {{.ServiceCIDR}}
etcd:
dataDir: {{.EtcdDataDir}}
nodeName: "{{.NodeName}}"
apiServerCertSANs: ["127.0.0.1", "localhost", "{{.AdvertiseAddress}}"]
{{if .ImageRepository}}imageRepository: {{.ImageRepository}}
{{end}}{{if .CRISocket}}criSocket: {{.CRISocket}}
{{end}}{{range .ComponentOptions}}{{.Component}}ExtraArgs:{{range $i, $val := printMapInOrder .ExtraArgs ": " }}
{{$val}}{{end}}
{{end}}{{if .FeatureArgs}}featureGates: {{range $i, $val := .FeatureArgs}}
{{$i}}: {{$val}}{{end}}
{{end}}`))
......@@ -110,10 +110,7 @@ func GenerateKubeadmYAML(cc config.ClusterConfig, n config.Node, r cruntime.Mana
opts.NoTaintMaster = true
b := bytes.Buffer{}
configTmpl := ktmpl.V1Alpha1
if version.GTE(semver.MustParse("1.12.0")) {
configTmpl = ktmpl.V1Alpha3
}
configTmpl := ktmpl.V1Alpha3
// v1beta1 works in v1.13, but isn't required until v1.14.
if version.GTE(semver.MustParse("1.14.0-alpha.0")) {
configTmpl = ktmpl.V1Beta1
......
......@@ -70,7 +70,7 @@ func getExtraOptsPodCidr() []config.ExtraOption {
func recentReleases() ([]string, error) {
// test the 6 most recent releases
versions := []string{"v1.19", "v1.18", "v1.17", "v1.16", "v1.15", "v1.14", "v1.13", "v1.12", "v1.11"}
versions := []string{"v1.19", "v1.18", "v1.17", "v1.16", "v1.15", "v1.14", "v1.13", "v1.12"}
foundNewest := false
foundDefault := false
......
......@@ -55,7 +55,7 @@ Wants=docker.socket
[Service]
ExecStart=
ExecStart=/var/lib/minikube/binaries/v1.11.10/kubelet --allow-privileged=true --authorization-mode=Webhook --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --cadvisor-port=0 --cgroup-driver=cgroupfs --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-domain=cluster.local --config=/var/lib/kubelet/config.yaml --container-runtime=docker --fail-swap-on=false --hostname-override=minikube --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.1.100 --pod-manifest-path=/etc/kubernetes/manifests
ExecStart=/var/lib/minikube/binaries/v1.12.0/kubelet --allow-privileged=true --authorization-mode=Webhook --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --cadvisor-port=0 --cgroup-driver=cgroupfs --client-ca-file=/var/lib/minikube/certs/ca.crt --cluster-domain=cluster.local --config=/var/lib/kubelet/config.yaml --container-runtime=docker --fail-swap-on=false --hostname-override=minikube --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.1.100 --pod-manifest-path=/etc/kubernetes/manifests
[Install]
`,
......@@ -200,10 +200,7 @@ ExecStart=/var/lib/minikube/binaries/v1.18.0/kubelet --authorization-mode=Webhoo
Context: 1,
})
if err != nil {
t.Fatalf("diff error: %v", err)
}
if diff != "" {
t.Errorf("unexpected diff:\n%s", diff)
t.Fatalf("diff error: %v\n%s", err, diff)
}
})
}
......
......@@ -18,36 +18,36 @@ limitations under the License.
package kverify
import (
"fmt"
"time"
"github.com/golang/glog"
"github.com/pkg/errors"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/minikube/pkg/util/retry"
kconst "k8s.io/kubernetes/cmd/kubeadm/app/constants"
)
// WaitForDefaultSA waits for the default service account to be created.
func WaitForDefaultSA(cs *kubernetes.Clientset, timeout time.Duration) error {
glog.Info("waiting for default service account to be created ...")
start := time.Now()
saReady := func() error {
saReady := func() (bool, error) {
// equivalent to manual check of 'kubectl --context profile get serviceaccount default'
sas, err := cs.CoreV1().ServiceAccounts("default").List(meta.ListOptions{})
if err != nil {
glog.Infof("temproary error waiting for default SA: %v", err)
return err
return false, nil
}
for _, sa := range sas.Items {
if sa.Name == "default" {
glog.Infof("found service account: %q", sa.Name)
return nil
return true, nil
}
}
return fmt.Errorf("couldn't find default service account")
return false, nil
}
if err := retry.Expo(saReady, 500*time.Millisecond, timeout); err != nil {
if err := wait.PollImmediate(kconst.APICallRetryInterval, timeout, saReady); err != nil {
return errors.Wrapf(err, "waited %s for SA", time.Since(start))
}
......
......@@ -101,18 +101,6 @@ func TestKubeadmImages(t *testing.T) {
"kubernetesui/dashboard:v2.0.0-rc6",
"kubernetesui/metrics-scraper:v1.0.2",
}},
{"v1.11.10", "", []string{
"k8s.gcr.io/kube-proxy-amd64:v1.11.10",
"k8s.gcr.io/kube-scheduler-amd64:v1.11.10",
"k8s.gcr.io/kube-controller-manager-amd64:v1.11.10",
"k8s.gcr.io/kube-apiserver-amd64:v1.11.10",
"k8s.gcr.io/coredns:1.1.3",
"k8s.gcr.io/etcd-amd64:3.2.18",
"k8s.gcr.io/pause:3.1",
"gcr.io/k8s-minikube/storage-provisioner:v1.8.1",
"kubernetesui/dashboard:v2.0.0-rc6",
"kubernetesui/metrics-scraper:v1.0.2",
}},
}
for _, tc := range tests {
got, err := Kubeadm(tc.mirror, tc.version)
......
......@@ -37,6 +37,7 @@ import (
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
kconst "k8s.io/kubernetes/cmd/kubeadm/app/constants"
"k8s.io/minikube/pkg/drivers/kic"
......@@ -202,9 +203,13 @@ func (k *Bootstrapper) init(cfg config.ClusterConfig) error {
}
var wg sync.WaitGroup
wg.Add(4)
wg.Add(3)
go func() {
// we need to have cluster role binding before applying overlay to avoid #7428
if err := k.elevateKubeSystemPrivileges(cfg); err != nil {
glog.Errorf("unable to create cluster role binding, some addons might not work: %v", err)
}
// the overlay is required for containerd and cri-o runtime: see #7428
if driver.IsKIC(cfg.Driver) && cfg.KubernetesConfig.ContainerRuntime != "docker" {
if err := k.applyKICOverlay(cfg); err != nil {
......@@ -228,13 +233,6 @@ func (k *Bootstrapper) init(cfg config.ClusterConfig) error {
wg.Done()
}()
go func() {
if err := k.elevateKubeSystemPrivileges(cfg); err != nil {
glog.Warningf("unable to create cluster role binding, some addons might not work: %v", err)
}
wg.Done()
}()
wg.Wait()
return nil
}
......@@ -424,7 +422,8 @@ func (k *Bootstrapper) needsReset(conf string, hostname string, port int, client
glog.Infof("needs reset: %v", err)
return true
}
// to be used in the ingeration test to verify it wont reset.
glog.Infof("The running cluster does not need a reset. hostname: %s", hostname)
return false
}
......@@ -523,7 +522,7 @@ func (k *Bootstrapper) restartCluster(cfg config.ClusterConfig) error {
_, err := k.c.RunCmd(exec.Command("/bin/bash", "-c", fmt.Sprintf("%s phase addon all --config %s", baseCmd, conf)))
return err
}
if err = retry.Expo(addonPhase, 1*time.Second, 30*time.Second); err != nil {
if err = retry.Expo(addonPhase, 100*time.Microsecond, 30*time.Second); err != nil {
glog.Warningf("addon install failed, wil retry: %v", err)
return errors.Wrap(err, "addons")
}
......@@ -820,6 +819,10 @@ func (k *Bootstrapper) applyNodeLabels(cfg config.ClusterConfig) error {
// elevateKubeSystemPrivileges gives the kube-system service account cluster admin privileges to work with RBAC.
func (k *Bootstrapper) elevateKubeSystemPrivileges(cfg config.ClusterConfig) error {
start := time.Now()
defer func() {
glog.Infof("duration metric: took %s to wait for elevateKubeSystemPrivileges.", time.Since(start))
}()
// Allow no more than 5 seconds for creating cluster role bindings
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
......@@ -836,6 +839,24 @@ func (k *Bootstrapper) elevateKubeSystemPrivileges(cfg config.ClusterConfig) err
return nil
}
}
glog.Infof("duration metric: took %s to wait for elevateKubeSystemPrivileges.", time.Since(start))
return err
if cfg.VerifyComponents[kverify.DefaultSAWaitKey] {
// double checking defalut sa was created.
// good for ensuring using minikube in CI is robust.
checkSA := func() (bool, error) {
cmd = exec.Command("sudo", kubectlPath(cfg),
"get", "sa", "default", fmt.Sprintf("--kubeconfig=%s", path.Join(vmpath.GuestPersistentDir, "kubeconfig")))
rr, err = k.c.RunCmd(cmd)
if err != nil {
return false, nil
}
return true, nil
}
// retry up to make sure SA is created
if err := wait.PollImmediate(kconst.APICallRetryInterval, time.Minute, checkSA); err != nil {
return errors.Wrap(err, "ensure sa was created")
}
}
return nil
}
......@@ -31,7 +31,7 @@ const (
// NewestKubernetesVersion is the newest Kubernetes version to test against
NewestKubernetesVersion = "v1.18.0"
// OldestKubernetesVersion is the oldest Kubernetes version to test against
OldestKubernetesVersion = "v1.11.10"
OldestKubernetesVersion = "v1.12.0"
// DefaultClusterName is the default nane for the k8s cluster
DefaultClusterName = "minikube"
// DockerDaemonPort is the port Docker daemon listening inside a minikube node (vm or container).
......
......@@ -21,6 +21,7 @@ import (
"io/ioutil"
"net/url"
"os"
"path"
"path/filepath"
"strconv"
......@@ -30,6 +31,7 @@ import (
"k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/tools/clientcmd/api/latest"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/localpath"
pkgutil "k8s.io/minikube/pkg/util"
"k8s.io/minikube/pkg/util/lock"
)
......@@ -103,24 +105,43 @@ func Endpoint(contextName string, configPath ...string) (string, int, error) {
}
// UpdateEndpoint overwrites the IP stored in kubeconfig with the provided IP.
func UpdateEndpoint(contextName string, hostname string, port int, path string) (bool, error) {
func UpdateEndpoint(contextName string, hostname string, port int, confpath string) (bool, error) {
if hostname == "" {
return false, fmt.Errorf("empty ip")
}
err := VerifyEndpoint(contextName, hostname, port, path)
err := VerifyEndpoint(contextName, hostname, port, confpath)
if err == nil {
return false, nil
}
glog.Infof("verify returned: %v", err)
cfg, err := readOrNew(path)
cfg, err := readOrNew(confpath)
if err != nil {
return false, errors.Wrap(err, "read")
}
cfg.Clusters[contextName].Server = "https://" + hostname + ":" + strconv.Itoa(port)
err = writeToFile(cfg, path)
address := "https://" + hostname + ":" + strconv.Itoa(port)
// if the kubeconfig is missed, create new one
if len(cfg.Clusters) == 0 {
lp := localpath.Profile(contextName)
gp := localpath.MiniPath()
kcs := &Settings{
ClusterName: contextName,
ClusterServerAddress: address,
ClientCertificate: path.Join(lp, "client.crt"),
ClientKey: path.Join(lp, "client.key"),
CertificateAuthority: path.Join(gp, "ca.crt"),
KeepContext: false,
}
err = PopulateFromSettings(kcs, cfg)
if err != nil {
return false, errors.Wrap(err, "populating kubeconfig")
}
}
cfg.Clusters[contextName].Server = address
err = writeToFile(cfg, confpath)
if err != nil {
return false, errors.Wrap(err, "write")
}
......
......@@ -136,8 +136,8 @@ func createHost(api libmachine.API, cfg config.ClusterConfig, n config.Node) (*h
cstart := time.Now()
glog.Infof("libmachine.API.Create for %q (driver=%q)", cfg.Name, cfg.Driver)
// Allow two minutes to create host before failing fast
if err := timedCreateHost(h, api, 2*time.Minute); err != nil {
if err := timedCreateHost(h, api, 4*time.Minute); err != nil {
return nil, errors.Wrap(err, "creating host")
}
glog.Infof("duration metric: libmachine.API.Create for %q took %s", cfg.Name, time.Since(cstart))
......
......@@ -275,24 +275,16 @@ func setupKubeAdm(mAPI libmachine.API, cfg config.ClusterConfig, n config.Node,
out.T(out.Option, "{{.extra_option_component_name}}.{{.key}}={{.value}}", out.V{"extra_option_component_name": eo.Component, "key": eo.Key, "value": eo.Value})
}
// Loads cached images, generates config files, download binaries
// update cluster and set up certs in parallel
var parallel sync.WaitGroup
parallel.Add(2)
go func() {
if err := bs.UpdateCluster(cfg); err != nil {
exit.WithError("Failed to update cluster", err)
}
parallel.Done()
}()
// update cluster and set up certs
go func() {
if err := bs.SetupCerts(cfg.KubernetesConfig, n); err != nil {
exit.WithError("Failed to setup certs", err)
}
parallel.Done()
}()
if err := bs.UpdateCluster(cfg); err != nil {
exit.WithError("Failed to update cluster", err)
}
if err := bs.SetupCerts(cfg.KubernetesConfig, n); err != nil {
exit.WithError("Failed to setup certs", err)
}
parallel.Wait()
return bs
}
......
/*
Copyright 2020 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 perf
import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/pkg/errors"
"k8s.io/minikube/pkg/minikube/constants"
)
type Binary struct {
path string
pr int
}
const (
prPrefix = "pr://"
)
// NewBinary returns a new binary type
func NewBinary(b string) (*Binary, error) {
// If it doesn't have the prefix, assume a path
if !strings.HasPrefix(b, prPrefix) {
return &Binary{
path: b,
}, nil
}
return newBinaryFromPR(b)
}
// Name returns the name of the binary
func (b *Binary) Name() string {
if b.pr != 0 {
return fmt.Sprintf("Minikube (PR %d)", b.pr)
}
return filepath.Base(b.path)
}
// newBinaryFromPR downloads the minikube binary built for the pr by Jenkins from GCS
func newBinaryFromPR(pr string) (*Binary, error) {
pr = strings.TrimPrefix(pr, prPrefix)
// try to convert to int
i, err := strconv.Atoi(pr)
if err != nil {
return nil, errors.Wrapf(err, "converting %s to an integer", pr)
}
b := &Binary{
path: localMinikubePath(i),
pr: i,
}
if err := downloadBinary(remoteMinikubeURL(i), b.path); err != nil {
return nil, errors.Wrapf(err, "downloading minikube")
}
return b, nil
}
func remoteMinikubeURL(pr int) string {
return fmt.Sprintf("https://storage.googleapis.com/minikube-builds/%d/minikube-linux-amd64", pr)
}
func localMinikubePath(pr int) string {
return fmt.Sprintf("%s/minikube-binaries/%d/minikube", constants.DefaultMinipath, pr)
}
func downloadBinary(url, path string) error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
return err
}
f, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0777)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, resp.Body)
return err
}
......@@ -35,21 +35,26 @@ const (
var (
// For testing
collectTimeMinikubeStart = timeMinikubeStart
collectTimeMinikubeStart = collectTimes
)
// CompareMinikubeStart compares the time to run `minikube start` between two minikube binaries
func CompareMinikubeStart(ctx context.Context, out io.Writer, binaries []string) error {
durations, err := collectTimes(ctx, binaries)
func CompareMinikubeStart(ctx context.Context, out io.Writer, binaries []*Binary) error {
durations, err := collectTimeMinikubeStart(ctx, binaries)
if err != nil {
return err
}
fmt.Fprintf(out, "Old binary: %v\nNew binary: %v\nAverage Old: %f\nAverage New: %f\n", durations[0], durations[1], average(durations[0]), average(durations[1]))
for i, d := range durations {
fmt.Fprintf(out, "Results for %s:\n", binaries[i].Name())
fmt.Fprintf(out, "Times: %v\n", d)
fmt.Fprintf(out, "Average Time: %f\n\n", average(d))
}
return nil
}
func collectTimes(ctx context.Context, binaries []string) ([][]float64, error) {
func collectTimes(ctx context.Context, binaries []*Binary) ([][]float64, error) {
durations := make([][]float64, len(binaries))
for i := range durations {
durations[i] = make([]float64, runs)
......@@ -58,9 +63,9 @@ func collectTimes(ctx context.Context, binaries []string) ([][]float64, error) {
for r := 0; r < runs; r++ {
log.Printf("Executing run %d...", r)
for index, binary := range binaries {
duration, err := collectTimeMinikubeStart(ctx, binary)
duration, err := timeMinikubeStart(ctx, binary)
if err != nil {
return nil, errors.Wrapf(err, "timing run %d with %s", r, binary)
return nil, errors.Wrapf(err, "timing run %d with %s", r, binary.Name())
}
durations[index][r] = duration
}
......@@ -79,12 +84,12 @@ func average(nums []float64) float64 {
// timeMinikubeStart returns the time it takes to execute `minikube start`
// It deletes the VM after `minikube start`.
func timeMinikubeStart(ctx context.Context, binary string) (float64, error) {
startCmd := exec.CommandContext(ctx, binary, "start")
func timeMinikubeStart(ctx context.Context, binary *Binary) (float64, error) {
startCmd := exec.CommandContext(ctx, binary.path, "start")
startCmd.Stdout = os.Stdout
startCmd.Stderr = os.Stderr
deleteCmd := exec.CommandContext(ctx, binary, "delete")
deleteCmd := exec.CommandContext(ctx, binary.path, "delete")
defer func() {
if err := deleteCmd.Run(); err != nil {
log.Printf("error deleting minikube: %v", err)
......
......@@ -19,86 +19,64 @@ package perf
import (
"bytes"
"context"
"reflect"
"testing"
"github.com/google/go-cmp/cmp"
)
func mockCollectTimeMinikubeStart(durations []float64) func(ctx context.Context, binary string) (float64, error) {
index := 0
return func(context.Context, string) (float64, error) {
duration := durations[index]
index++
return duration, nil
func mockCollectTimes(times [][]float64) func(ctx context.Context, binaries []*Binary) ([][]float64, error) {
return func(ctx context.Context, binaries []*Binary) ([][]float64, error) {
return times, nil
}
}
func TestCompareMinikubeStartOutput(t *testing.T) {
binaries := []*Binary{
{
path: "minikube1",
}, {
path: "minikube2",
},
}
tests := []struct {
description string
durations []float64
times [][]float64
expected string
}{
{
description: "standard run",
durations: []float64{4.5, 6},
expected: "Old binary: [4.5]\nNew binary: [6]\nAverage Old: 4.500000\nAverage New: 6.000000\n",
times: [][]float64{{4.5, 6}, {1, 2}},
expected: `Results for minikube1:
Times: [4.5 6]
Average Time: 5.250000
Results for minikube2:
Times: [1 2]
Average Time: 1.500000
`,
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
originalCollectTimes := collectTimeMinikubeStart
collectTimeMinikubeStart = mockCollectTimeMinikubeStart(test.durations)
originalCollectTimes := collectTimes
collectTimeMinikubeStart = mockCollectTimes(test.times)
defer func() { collectTimeMinikubeStart = originalCollectTimes }()
buf := bytes.NewBuffer([]byte{})
err := CompareMinikubeStart(context.Background(), buf, []string{"", ""})
err := CompareMinikubeStart(context.Background(), buf, binaries)
if err != nil {
t.Fatalf("error comparing minikube start: %v", err)
}
actual := buf.String()
if test.expected != actual {
t.Fatalf("actual output does not match expected output\nActual: %v\nExpected: %v", actual, test.expected)
if diff := cmp.Diff(test.expected, actual); diff != "" {
t.Errorf("machines mismatch (-want +got):\n%s", diff)
}
})
}
}
func TestCollectTimes(t *testing.T) {
tests := []struct {
description string
durations []float64
expected [][]float64
}{
{
description: "test collect time",
durations: []float64{1, 2},
expected: [][]float64{
{1},
{2},
},
},
}
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
originalCollectTimes := collectTimeMinikubeStart
collectTimeMinikubeStart = mockCollectTimeMinikubeStart(test.durations)
defer func() { collectTimeMinikubeStart = originalCollectTimes }()
actual, err := collectTimes(context.Background(), []string{"", ""})
if err != nil {
t.Fatalf("error collecting times: %v", err)
}
if !reflect.DeepEqual(actual, test.expected) {
t.Fatalf("actual output does not match expected output\nActual: %v\nExpected: %v", actual, test.expected)
}
})
}
}
func TestAverage(t *testing.T) {
tests := []struct {
description string
......
......@@ -31,23 +31,17 @@ import (
"github.com/golang/glog"
"github.com/olekukonko/tablewriter"
"github.com/pkg/errors"
"github.com/spf13/viper"
core "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
typed_core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/kapi"
"k8s.io/minikube/pkg/minikube/machine"
"k8s.io/minikube/pkg/minikube/out"
"k8s.io/minikube/pkg/minikube/proxy"
"k8s.io/minikube/pkg/util/retry"
)
const (
defaultK8sClientTimeout = 60 * time.Second
// DefaultWait is the default wait time, in seconds
DefaultWait = 2
// DefaultInterval is the default interval, in seconds
......@@ -56,8 +50,7 @@ const (
// K8sClient represents a kubernetes client
type K8sClient interface {
GetCoreClient() (typed_core.CoreV1Interface, error)
GetClientset(timeout time.Duration) (*kubernetes.Clientset, error)
GetCoreClient(string) (typed_core.CoreV1Interface, error)
}
// K8sClientGetter can get a K8sClient
......@@ -71,39 +64,14 @@ func init() {
}
// GetCoreClient returns a core client
func (k *K8sClientGetter) GetCoreClient() (typed_core.CoreV1Interface, error) {
client, err := k.GetClientset(defaultK8sClientTimeout)
func (k *K8sClientGetter) GetCoreClient(context string) (typed_core.CoreV1Interface, error) {
client, err := kapi.Client(context)
if err != nil {
return nil, errors.Wrap(err, "getting clientset")
return nil, errors.Wrap(err, "client")
}
return client.CoreV1(), nil
}
// GetClientset returns a clientset
func (*K8sClientGetter) GetClientset(timeout time.Duration) (*kubernetes.Clientset, error) {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
profile := viper.GetString(config.ProfileName)
configOverrides := &clientcmd.ConfigOverrides{
Context: clientcmdapi.Context{
Cluster: profile,
AuthInfo: profile,
},
}
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
clientConfig, err := kubeConfig.ClientConfig()
if err != nil {
return nil, fmt.Errorf("kubeConfig: %v", err)
}
clientConfig.Timeout = timeout
clientConfig = proxy.UpdateTransport(clientConfig)
client, err := kubernetes.NewForConfig(clientConfig)
if err != nil {
return nil, errors.Wrap(err, "client from config")
}
return client, nil
}
// SvcURL represents a service URL. Each item in the URLs field combines the service URL with one of the configured
// node ports. The PortNames field contains the configured names of the ports in the URLs field (sorted correspondingly -
// first item in PortNames belongs to the first item in URLs).
......@@ -119,8 +87,8 @@ type URLs []SvcURL
// GetServiceURLs returns a SvcURL object for every service in a particular namespace.
// Accepts a template for formatting
func GetServiceURLs(api libmachine.API, namespace string, t *template.Template) (URLs, error) {
host, err := machine.LoadHost(api, viper.GetString(config.ProfileName))
func GetServiceURLs(api libmachine.API, cname string, namespace string, t *template.Template) (URLs, error) {
host, err := machine.LoadHost(api, cname)
if err != nil {
return nil, err
}
......@@ -130,7 +98,7 @@ func GetServiceURLs(api libmachine.API, namespace string, t *template.Template)
return nil, err
}
client, err := K8s.GetCoreClient()
client, err := K8s.GetCoreClient(cname)
if err != nil {
return nil, err
}
......@@ -155,8 +123,8 @@ func GetServiceURLs(api libmachine.API, namespace string, t *template.Template)
}
// GetServiceURLsForService returns a SvcUrl object for a service in a namespace. Supports optional formatting.
func GetServiceURLsForService(api libmachine.API, namespace, service string, t *template.Template) (SvcURL, error) {
host, err := machine.LoadHost(api, viper.GetString(config.ProfileName))
func GetServiceURLsForService(api libmachine.API, cname string, namespace, service string, t *template.Template) (SvcURL, error) {
host, err := machine.LoadHost(api, cname)
if err != nil {
return SvcURL{}, errors.Wrap(err, "Error checking if api exist and loading it")
}
......@@ -166,7 +134,7 @@ func GetServiceURLsForService(api libmachine.API, namespace, service string, t *
return SvcURL{}, errors.Wrap(err, "Error getting ip from host")
}
client, err := K8s.GetCoreClient()
client, err := K8s.GetCoreClient(cname)
if err != nil {
return SvcURL{}, err
}
......@@ -226,8 +194,8 @@ func printURLsForService(c typed_core.CoreV1Interface, ip, service, namespace st
}
// CheckService checks if a service is listening on a port.
func CheckService(namespace string, service string) error {
client, err := K8s.GetCoreClient()
func CheckService(cname string, namespace string, service string) error {
client, err := K8s.GetCoreClient(cname)
if err != nil {
return errors.Wrap(err, "Error getting kubernetes client")
}
......@@ -283,7 +251,7 @@ func (t SVCNotFoundError) Error() string {
}
// WaitForService waits for a service, and return the urls when available
func WaitForService(api libmachine.API, namespace string, service string, urlTemplate *template.Template, urlMode bool, https bool,
func WaitForService(api libmachine.API, cname string, namespace string, service string, urlTemplate *template.Template, urlMode bool, https bool,
wait int, interval int) ([]string, error) {
var urlList []string
// Convert "Amount of time to wait" and "interval of each check" to attempts
......@@ -291,18 +259,18 @@ func WaitForService(api libmachine.API, namespace string, service string, urlTem
interval = 1
}
err := CheckService(namespace, service)
err := CheckService(cname, namespace, service)
if err != nil {
return nil, &SVCNotFoundError{err}
}
chkSVC := func() error { return CheckService(namespace, service) }
chkSVC := func() error { return CheckService(cname, namespace, service) }
if err := retry.Expo(chkSVC, time.Duration(interval)*time.Second, time.Duration(wait)*time.Second); err != nil {
return nil, &SVCNotFoundError{err}
}
serviceURL, err := GetServiceURLsForService(api, namespace, service, urlTemplate)
serviceURL, err := GetServiceURLsForService(api, cname, namespace, service, urlTemplate)
if err != nil {
return urlList, errors.Wrap(err, "Check that minikube is running and that you have specified the correct namespace")
}
......@@ -330,8 +298,8 @@ func WaitForService(api libmachine.API, namespace string, service string, urlTem
}
// GetServiceListByLabel returns a ServiceList by label
func GetServiceListByLabel(namespace string, key string, value string) (*core.ServiceList, error) {
client, err := K8s.GetCoreClient()
func GetServiceListByLabel(cname string, namespace string, key string, value string) (*core.ServiceList, error) {
client, err := K8s.GetCoreClient(cname)
if err != nil {
return &core.ServiceList{}, &retry.RetriableError{Err: err}
}
......@@ -349,8 +317,8 @@ func getServiceListFromServicesByLabel(services typed_core.ServiceInterface, key
}
// CreateSecret creates or modifies secrets
func CreateSecret(namespace, name string, dataValues map[string]string, labels map[string]string) error {
client, err := K8s.GetCoreClient()
func CreateSecret(cname string, namespace, name string, dataValues map[string]string, labels map[string]string) error {
client, err := K8s.GetCoreClient(cname)
if err != nil {
return &retry.RetriableError{Err: err}
}
......@@ -363,7 +331,7 @@ func CreateSecret(namespace, name string, dataValues map[string]string, labels m
// Delete existing secret
if len(secret.Name) > 0 {
err = DeleteSecret(namespace, name)
err = DeleteSecret(cname, namespace, name)
if err != nil {
return &retry.RetriableError{Err: err}
}
......@@ -394,8 +362,8 @@ func CreateSecret(namespace, name string, dataValues map[string]string, labels m
}
// DeleteSecret deletes a secret from a namespace
func DeleteSecret(namespace, name string) error {
client, err := K8s.GetCoreClient()
func DeleteSecret(cname string, namespace, name string) error {
client, err := K8s.GetCoreClient(cname)
if err != nil {
return &retry.RetriableError{Err: err}
}
......
......@@ -26,8 +26,6 @@ import (
"testing"
"text/template"
"time"
"github.com/docker/machine/libmachine"
"github.com/docker/machine/libmachine/host"
"github.com/pkg/errors"
......@@ -35,7 +33,6 @@ import (
core "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes"
typed_core "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/kubernetes/typed/core/v1/fake"
testing_fake "k8s.io/client-go/testing"
......@@ -55,7 +52,7 @@ type MockClientGetter struct {
// Force GetCoreClient to fail
var getCoreClientFail bool
func (m *MockClientGetter) GetCoreClient() (typed_core.CoreV1Interface, error) {
func (m *MockClientGetter) GetCoreClient(string) (typed_core.CoreV1Interface, error) {
if getCoreClientFail {
return nil, fmt.Errorf("test Error - Mocked Get")
}
......@@ -65,10 +62,6 @@ func (m *MockClientGetter) GetCoreClient() (typed_core.CoreV1Interface, error) {
secretsMap: m.secretsMap}, nil
}
func (m *MockClientGetter) GetClientset(timeout time.Duration) (*kubernetes.Clientset, error) {
return nil, nil
}
func (m *MockCoreClient) Secrets(ns string) typed_core.SecretInterface {
return &fake.FakeSecrets{Fake: &fake.FakeCoreV1{Fake: &testing_fake.Fake{}}}
}
......@@ -476,7 +469,7 @@ func TestGetServiceURLs(t *testing.T) {
servicesMap: serviceNamespaces,
endpointsMap: endpointNamespaces,
}
urls, err := GetServiceURLs(test.api, test.namespace, defaultTemplate)
urls, err := GetServiceURLs(test.api, "minikube", test.namespace, defaultTemplate)
if err != nil && !test.err {
t.Errorf("Error GetServiceURLs %v", err)
}
......@@ -544,7 +537,7 @@ func TestGetServiceURLsForService(t *testing.T) {
servicesMap: serviceNamespaces,
endpointsMap: endpointNamespaces,
}
svcURL, err := GetServiceURLsForService(test.api, test.namespace, test.service, defaultTemplate)
svcURL, err := GetServiceURLsForService(test.api, "minikube", test.namespace, test.service, defaultTemplate)
if err != nil && !test.err {
t.Errorf("Error GetServiceURLsForService %v", err)
}
......@@ -626,7 +619,7 @@ users:
os.Setenv("KUBECONFIG", mockK8sConfigPath)
k8s := K8sClientGetter{}
_, err = k8s.GetCoreClient()
_, err = k8s.GetCoreClient("minikube")
if err != nil && !test.err {
t.Fatalf("GetCoreClient returned unexpected error: %v", err)
}
......@@ -691,7 +684,7 @@ func TestGetServiceListByLabel(t *testing.T) {
secretsMap: secretsNamespaces,
}
getCoreClientFail = test.failedGetClient
svcs, err := GetServiceListByLabel(test.ns, test.name, test.label)
svcs, err := GetServiceListByLabel("minikube", test.ns, test.name, test.label)
if err != nil && !test.err {
t.Fatalf("Test %v got unexpected error: %v", test.description, err)
}
......@@ -741,7 +734,7 @@ func TestCheckService(t *testing.T) {
secretsMap: secretsNamespaces,
}
getCoreClientFail = test.failedGetClient
err := CheckService(test.ns, test.name)
err := CheckService("minikube", test.ns, test.name)
if err == nil && test.err {
t.Fatalf("Test %v expected error but got nil", test.description)
}
......@@ -780,7 +773,7 @@ func TestDeleteSecret(t *testing.T) {
secretsMap: secretsNamespaces,
}
getCoreClientFail = test.failedGetClient
err := DeleteSecret(test.ns, test.name)
err := DeleteSecret("minikube", test.ns, test.name)
if err == nil && test.err {
t.Fatalf("Test %v expected error but got nil", test.description)
}
......@@ -819,7 +812,7 @@ func TestCreateSecret(t *testing.T) {
secretsMap: secretsNamespaces,
}
getCoreClientFail = test.failedGetClient
err := CreateSecret(test.ns, test.name, map[string]string{"ns": "secret"}, map[string]string{"ns": "baz"})
err := CreateSecret("minikube", test.ns, test.name, map[string]string{"ns": "secret"}, map[string]string{"ns": "baz"})
if err == nil && test.err {
t.Fatalf("Test %v expected error but got nil", test.description)
}
......@@ -921,7 +914,7 @@ func TestWaitAndMaybeOpenService(t *testing.T) {
}
var urlList []string
urlList, err := WaitForService(test.api, test.namespace, test.service, defaultTemplate, test.urlMode, test.https, 1, 0)
urlList, err := WaitForService(test.api, "minikube", test.namespace, test.service, defaultTemplate, test.urlMode, test.https, 1, 0)
if test.err && err == nil {
t.Fatalf("WaitForService expected to fail for test: %v", test)
}
......@@ -986,7 +979,7 @@ func TestWaitAndMaybeOpenServiceForNotDefaultNamspace(t *testing.T) {
servicesMap: serviceNamespaceOther,
endpointsMap: endpointNamespaces,
}
_, err := WaitForService(test.api, test.namespace, test.service, defaultTemplate, test.urlMode, test.https, 1, 0)
_, err := WaitForService(test.api, "minikube", test.namespace, test.service, defaultTemplate, test.urlMode, test.https, 1, 0)
if test.err && err == nil {
t.Fatalf("WaitForService expected to fail for test: %v", test)
}
......
......@@ -22,9 +22,8 @@ import (
"github.com/pkg/errors"
v1 "k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
storagev1 "k8s.io/client-go/kubernetes/typed/storage/v1"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/minikube/pkg/kapi"
)
func annotateDefaultStorageClass(storage storagev1.StorageV1Interface, class *v1.StorageClass, enable bool) error {
......@@ -71,25 +70,11 @@ func SetDefaultStorageClass(storage storagev1.StorageV1Interface, name string) e
}
// GetStoragev1 return storage v1 interface for client
func GetStoragev1() (storagev1.StorageV1Interface, error) {
client, err := getClient()
func GetStoragev1(context string) (storagev1.StorageV1Interface, error) {
client, err := kapi.Client(context)
if err != nil {
return nil, err
}
sv1 := client.StorageV1()
return sv1, nil
}
func getClient() (*kubernetes.Clientset, error) {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
config, err := kubeConfig.ClientConfig()
if err != nil {
return nil, errors.Wrap(err, "Error creating kubeConfig")
}
client, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, errors.Wrap(err, "Error creating new client from kubeConfig.ClientConfig()")
}
return client, nil
}
......@@ -212,45 +212,6 @@ users:
- name: minikube
`
func TestGetClient(t *testing.T) {
var tests = []struct {
description string
config string
err bool
}{
{
description: "ok",
config: mockK8sConfig,
},
{
description: "no valid config",
config: "this is not valid config",
err: true,
},
}
configFile, err := ioutil.TempFile("/tmp", "")
if err != nil {
t.Fatalf(err.Error())
}
defer os.Remove(configFile.Name())
for _, test := range tests {
t.Run(test.description, func(t *testing.T) {
if err := setK8SConfig(test.config, configFile.Name()); err != nil {
t.Fatalf(err.Error())
}
_, err = getClient()
if err != nil && !test.err {
t.Fatalf("Unexpected err: %v for test: %v", err, test.description)
}
if err == nil && test.err {
t.Fatalf("Expected err for test: %v", test.description)
}
})
}
}
func TestGetStoragev1(t *testing.T) {
var tests = []struct {
description string
......@@ -278,7 +239,8 @@ func TestGetStoragev1(t *testing.T) {
t.Fatalf(err.Error())
}
_, err = GetStoragev1()
// context name is hardcoded by mockK8sConfig
_, err = GetStoragev1("minikube")
if err != nil && !test.err {
t.Fatalf("Unexpected err: %v for test: %v", err, test.description)
}
......
......@@ -177,7 +177,7 @@ func (p *BuildrootProvisioner) Provision(swarmOptions swarm.Options, authOptions
return nil
}
err := retry.Expo(configAuth, time.Second, 2*time.Minute)
err := retry.Expo(configAuth, 100*time.Microsecond, 2*time.Minute)
if err != nil {
glog.Infof("Error configuring auth during provisioning %v", err)
return err
......
......@@ -180,7 +180,7 @@ func (p *UbuntuProvisioner) Provision(swarmOptions swarm.Options, authOptions au
return nil
}
err := retry.Expo(configAuth, time.Second, 2*time.Minute)
err := retry.Expo(configAuth, 100*time.Microsecond, 2*time.Minute)
if err != nil {
glog.Infof("Error configuring auth during provisioning %v", err)
......
......@@ -21,10 +21,22 @@ package integration
import (
"context"
"os/exec"
"regexp"
"strings"
"testing"
)
// stderrWhitelist are regular expressions acceptable to find in normal stderr
var stderrWhitelist = []string{
// kubectl out of date warning
`kubectl`,
// slow docker warning
`slow|long time|Restarting the docker service may improve`,
}
// stderrWhitelistRe combines rootCauses into a single regex
var stderrWhitelistRe = regexp.MustCompile(strings.Join(stderrWhitelist, "|"))
// TestErrorSpam asserts that there are no errors displayed
func TestErrorSpam(t *testing.T) {
if NoneDriver() {
......@@ -41,20 +53,22 @@ func TestErrorSpam(t *testing.T) {
rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
if err != nil {
t.Errorf("failed to start minikube with args: %q : %v", rr.Command(), err)
t.Errorf("%q failed: %v", rr.Command(), err)
}
for _, line := range strings.Split(rr.Stderr.String(), "\n") {
if strings.HasPrefix(line, "E") {
t.Errorf("unexpected error log in stderr: %q", line)
t.Errorf("unexpected error log: %q", line)
continue
}
if strings.Contains(line, "kubectl") || strings.Contains(line, "slow") || strings.Contains(line, "long time") {
if stderrWhitelistRe.MatchString(line) {
t.Logf("acceptable stderr: %q", line)
continue
}
if len(strings.TrimSpace(line)) > 0 {
t.Errorf("unexpected stderr line: %q", line)
t.Errorf("unexpected stderr: %q", line)
}
}
......@@ -62,7 +76,7 @@ func TestErrorSpam(t *testing.T) {
keywords := []string{"error", "fail", "warning", "conflict"}
for _, keyword := range keywords {
if strings.Contains(line, keyword) {
t.Errorf("unexpected %q in stdout line: %q", keyword, line)
t.Errorf("unexpected %q in stdout: %q", keyword, line)
}
}
}
......
......@@ -21,6 +21,7 @@ package integration
import (
"context"
"os/exec"
"strings"
"testing"
)
......@@ -39,6 +40,7 @@ func TestPause(t *testing.T) {
validator validateFunc
}{
{"Start", validateFreshStart},
{"SecondStartNoReset", validateStartNoReset},
{"Pause", validatePause},
{"Unpause", validateUnpause},
{"PauseAgain", validatePause},
......@@ -54,13 +56,29 @@ func TestPause(t *testing.T) {
}
func validateFreshStart(ctx context.Context, t *testing.T, profile string) {
args := append([]string{"start", "-p", profile, "--memory=1800", "--install-addons=false", "--wait=false"}, StartArgs()...)
args := append([]string{"start", "-p", profile, "--memory=1800", "--install-addons=false", "--wait=all"}, StartArgs()...)
rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
if err != nil {
t.Fatalf("failed to start minikube with args: %q : %v", rr.Command(), err)
}
}
// validateStartNoReset validates that starting a running cluster won't invoke a reset
func validateStartNoReset(ctx context.Context, t *testing.T, profile string) {
args := []string{"start", "-p", profile, "--alsologtostderr", "-v=5"}
rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
if err != nil {
t.Fatalf("failed to second start a running minikube with args: %q : %v", rr.Command(), err)
}
if !NoneDriver() {
softLog := "The running cluster does not need a reset"
if !strings.Contains(rr.Output(), softLog) {
t.Errorf("expected the second start log outputs to include %q but got: %s", softLog, rr.Output())
}
}
}
func validatePause(ctx context.Context, t *testing.T, profile string) {
args := []string{"pause", "-p", profile, "--alsologtostderr", "-v=5"}
rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
......
// +build integration
/*
Copyright 2020 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 integration
import (
"context"
"fmt"
"os/exec"
"strings"
"testing"
)
func TestPreload(t *testing.T) {
if NoneDriver() {
t.Skipf("skipping %s - incompatible with none driver", t.Name())
}
profile := UniqueProfileName("test-preload")
ctx, cancel := context.WithTimeout(context.Background(), Minutes(40))
defer CleanupWithLogs(t, profile, cancel)
startArgs := []string{"start", "-p", profile, "--memory=2200", "--alsologtostderr", "-v=3", "--wait=true", "--preload=false"}
startArgs = append(startArgs, StartArgs()...)
k8sVersion := "v1.17.0"
startArgs = append(startArgs, fmt.Sprintf("--kubernetes-version=%s", k8sVersion))
rr, err := Run(t, exec.CommandContext(ctx, Target(), startArgs...))
if err != nil {
t.Fatalf("%s failed: %v", rr.Command(), err)
}
// Now, pull the busybox image into the VMs docker daemon
image := "busybox"
rr, err = Run(t, exec.CommandContext(ctx, Target(), "ssh", "-p", profile, "--", "docker", "pull", image))
if err != nil {
t.Fatalf("%s failed: %v", rr.Command(), err)
}
// Restart minikube with v1.17.3, which has a preloaded tarball
startArgs = []string{"start", "-p", profile, "--memory=2200", "--alsologtostderr", "-v=3", "--wait=true"}
startArgs = append(startArgs, StartArgs()...)
k8sVersion = "v1.17.3"
startArgs = append(startArgs, fmt.Sprintf("--kubernetes-version=%s", k8sVersion))
rr, err = Run(t, exec.CommandContext(ctx, Target(), startArgs...))
if err != nil {
t.Fatalf("%s failed: %v", rr.Command(), err)
}
rr, err = Run(t, exec.CommandContext(ctx, Target(), "ssh", "-p", profile, "--", "docker", "images"))
if err != nil {
t.Fatalf("%s failed: %v", rr.Command(), err)
}
if !strings.Contains(rr.Output(), image) {
t.Fatalf("Expected to find %s in output of `docker images`, instead got %s", image, rr.Output())
}
}
......@@ -44,7 +44,7 @@ func TestStartStop(t *testing.T) {
version string
args []string
}{
{"old-docker", constants.OldestKubernetesVersion, []string{
{"old-k8s-version", constants.OldestKubernetesVersion, []string{
// default is the network created by libvirt, if we change the name minikube won't boot
// because the given network doesn't exist
"--kvm-network=default",
......@@ -174,50 +174,6 @@ func TestStartStop(t *testing.T) {
})
}
func TestStartStopWithPreload(t *testing.T) {
if NoneDriver() {
t.Skipf("skipping %s - incompatible with none driver", t.Name())
}
profile := UniqueProfileName("test-preload")
ctx, cancel := context.WithTimeout(context.Background(), Minutes(40))
defer CleanupWithLogs(t, profile, cancel)
startArgs := []string{"start", "-p", profile, "--memory=2200", "--alsologtostderr", "-v=3", "--wait=true", "--preload=false"}
startArgs = append(startArgs, StartArgs()...)
k8sVersion := "v1.17.0"
startArgs = append(startArgs, fmt.Sprintf("--kubernetes-version=%s", k8sVersion))
rr, err := Run(t, exec.CommandContext(ctx, Target(), startArgs...))
if err != nil {
t.Fatalf("%s failed: %v", rr.Command(), err)
}
// Now, pull the busybox image into the VMs docker daemon
image := "busybox"
rr, err = Run(t, exec.CommandContext(ctx, Target(), "ssh", "-p", profile, "--", "docker", "pull", image))
if err != nil {
t.Fatalf("%s failed: %v", rr.Command(), err)
}
// Restart minikube with v1.17.3, which has a preloaded tarball
startArgs = []string{"start", "-p", profile, "--memory=2200", "--alsologtostderr", "-v=3", "--wait=true"}
startArgs = append(startArgs, StartArgs()...)
k8sVersion = "v1.17.3"
startArgs = append(startArgs, fmt.Sprintf("--kubernetes-version=%s", k8sVersion))
rr, err = Run(t, exec.CommandContext(ctx, Target(), startArgs...))
if err != nil {
t.Fatalf("%s failed: %v", rr.Command(), err)
}
rr, err = Run(t, exec.CommandContext(ctx, Target(), "ssh", "-p", profile, "--", "docker", "images"))
if err != nil {
t.Fatalf("%s failed: %v", rr.Command(), err)
}
if !strings.Contains(rr.Output(), image) {
t.Fatalf("Expected to find %s in output of `docker images`, instead got %s", image, rr.Output())
}
}
// testPodScheduling asserts that this configuration can schedule new pods
func testPodScheduling(ctx context.Context, t *testing.T, profile string) {
t.Helper()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册