diff --git a/cmd/minikube/cmd/status.go b/cmd/minikube/cmd/status.go index 11950ee7d0..bfcde0880b 100644 --- a/cmd/minikube/cmd/status.go +++ b/cmd/minikube/cmd/status.go @@ -135,6 +135,7 @@ type Status struct { APIServer string Kubeconfig string Worker bool + TimeToStop string } // ClusterState holds a cluster state representation @@ -142,6 +143,7 @@ type ClusterState struct { BaseState BinaryVersion string + TimeToStop string Components map[string]BaseState Nodes []NodeState } @@ -180,6 +182,7 @@ host: {{.Host}} kubelet: {{.Kubelet}} apiserver: {{.APIServer}} kubeconfig: {{.Kubeconfig}} +timeToStop: {{.TimeToStop}} ` workerStatusFormat = `{{.Name}} @@ -307,6 +310,7 @@ func nodeStatus(api libmachine.API, cc config.ClusterConfig, n config.Node) (*St Kubelet: Nonexistent, Kubeconfig: Nonexistent, Worker: !controlPlane, + TimeToStop: Nonexistent, } hs, err := machine.Status(api, name) @@ -366,7 +370,10 @@ func nodeStatus(api libmachine.API, cc config.ClusterConfig, n config.Node) (*St stk := kverify.ServiceStatus(cr, "kubelet") st.Kubelet = stk.String() - + if cc.ScheduledStop != nil { + initiationTime := time.Unix(cc.ScheduledStop.InitiationTime, 0) + st.TimeToStop = time.Until(initiationTime.Add(cc.ScheduledStop.Duration)).String() + } // Early exit for worker nodes if !controlPlane { return st, nil @@ -478,6 +485,7 @@ func clusterState(sts []*Status) ClusterState { statusName = sts[0].Host } sc := statusCode(statusName) + cs := ClusterState{ BinaryVersion: version.GetVersion(), @@ -488,6 +496,8 @@ func clusterState(sts []*Status) ClusterState { StatusDetail: codeDetails[sc], }, + TimeToStop: sts[0].TimeToStop, + Components: map[string]BaseState{ "kubeconfig": {Name: "kubeconfig", StatusCode: statusCode(sts[0].Kubeconfig)}, }, diff --git a/cmd/minikube/cmd/status_test.go b/cmd/minikube/cmd/status_test.go index 8bae781037..aa9f905c22 100644 --- a/cmd/minikube/cmd/status_test.go +++ b/cmd/minikube/cmd/status_test.go @@ -51,18 +51,18 @@ func TestStatusText(t *testing.T) { }{ { name: "ok", - state: &Status{Name: "minikube", Host: "Running", Kubelet: "Running", APIServer: "Running", Kubeconfig: Configured}, - want: "minikube\ntype: Control Plane\nhost: Running\nkubelet: Running\napiserver: Running\nkubeconfig: Configured\n\n", + state: &Status{Name: "minikube", Host: "Running", Kubelet: "Running", APIServer: "Running", Kubeconfig: Configured, TimeToStop: "10m"}, + want: "minikube\ntype: Control Plane\nhost: Running\nkubelet: Running\napiserver: Running\nkubeconfig: Configured\ntimeToStop: 10m\n\n", }, { name: "paused", - state: &Status{Name: "minikube", Host: "Running", Kubelet: "Stopped", APIServer: "Paused", Kubeconfig: Configured}, - want: "minikube\ntype: Control Plane\nhost: Running\nkubelet: Stopped\napiserver: Paused\nkubeconfig: Configured\n\n", + state: &Status{Name: "minikube", Host: "Running", Kubelet: "Stopped", APIServer: "Paused", Kubeconfig: Configured, TimeToStop: Nonexistent}, + want: "minikube\ntype: Control Plane\nhost: Running\nkubelet: Stopped\napiserver: Paused\nkubeconfig: Configured\ntimeToStop: Nonexistent\n\n", }, { name: "down", - state: &Status{Name: "minikube", Host: "Stopped", Kubelet: "Stopped", APIServer: "Stopped", Kubeconfig: Misconfigured}, - want: "minikube\ntype: Control Plane\nhost: Stopped\nkubelet: Stopped\napiserver: Stopped\nkubeconfig: Misconfigured\n\n\nWARNING: Your kubectl is pointing to stale minikube-vm.\nTo fix the kubectl context, run `minikube update-context`\n", + state: &Status{Name: "minikube", Host: "Stopped", Kubelet: "Stopped", APIServer: "Stopped", Kubeconfig: Misconfigured, TimeToStop: Nonexistent}, + want: "minikube\ntype: Control Plane\nhost: Stopped\nkubelet: Stopped\napiserver: Stopped\nkubeconfig: Misconfigured\ntimeToStop: Nonexistent\n\n\nWARNING: Your kubectl is pointing to stale minikube-vm.\nTo fix the kubectl context, run `minikube update-context`\n", }, } for _, tc := range tests { @@ -86,9 +86,9 @@ func TestStatusJSON(t *testing.T) { name string state *Status }{ - {"ok", &Status{Host: "Running", Kubelet: "Running", APIServer: "Running", Kubeconfig: Configured}}, - {"paused", &Status{Host: "Running", Kubelet: "Stopped", APIServer: "Paused", Kubeconfig: Configured}}, - {"down", &Status{Host: "Stopped", Kubelet: "Stopped", APIServer: "Stopped", Kubeconfig: Misconfigured}}, + {"ok", &Status{Host: "Running", Kubelet: "Running", APIServer: "Running", Kubeconfig: Configured, TimeToStop: "10m"}}, + {"paused", &Status{Host: "Running", Kubelet: "Stopped", APIServer: "Paused", Kubeconfig: Configured, TimeToStop: Nonexistent}}, + {"down", &Status{Host: "Stopped", Kubelet: "Stopped", APIServer: "Stopped", Kubeconfig: Misconfigured, TimeToStop: Nonexistent}}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { diff --git a/hack/jenkins/common.sh b/hack/jenkins/common.sh index aebdb5cea0..7592218c26 100755 --- a/hack/jenkins/common.sh +++ b/hack/jenkins/common.sh @@ -21,7 +21,7 @@ # OS_ARCH: The operating system and the architecture separated by a hyphen '-' (e.g. darwin-amd64, linux-amd64, windows-amd64) # VM_DRIVER: the driver to use for the test # EXTRA_START_ARGS: additional flags to pass into minikube start -# EXTRA_ARGS: additional flags to pass into minikube +# EXTRA_TEST_ARGS: additional flags to pass into go test # JOB_NAME: the name of the logfile and check name to update on github readonly TEST_ROOT="${HOME}/minikube-integration" @@ -221,17 +221,17 @@ fi # clean up none drivers binding on 8443 - none_procs=$(sudo lsof -i :8443 | tail -n +2 | awk '{print $2}' || true) - if [[ "${none_procs}" != "" ]]; then - echo "Found stale api servers listening on 8443 processes to kill: " - for p in $none_procs - do +none_procs=$(sudo lsof -i :8443 | tail -n +2 | awk '{print $2}' || true) +if [[ "${none_procs}" != "" ]]; then + echo "Found stale api servers listening on 8443 processes to kill: " + for p in $none_procs + do echo "Kiling stale none driver: $p" sudo -E ps -f -p $p || true sudo -E kill $p || true sudo -E kill -9 $p || true - done - fi + done +fi function cleanup_stale_routes() { local show="netstat -rn -f inet" diff --git a/hack/jenkins/linux_integration_tests_none.sh b/hack/jenkins/linux_integration_tests_none.sh index 0549fde508..ce36afee5f 100755 --- a/hack/jenkins/linux_integration_tests_none.sh +++ b/hack/jenkins/linux_integration_tests_none.sh @@ -29,7 +29,7 @@ set -e OS_ARCH="linux-amd64" VM_DRIVER="none" JOB_NAME="none_Linux" -EXTRA_ARGS="--bootstrapper=kubeadm" +EXTRA_START_ARGS="--bootstrapper=kubeadm" EXPECTED_DEFAULT_DRIVER="kvm2" SUDO_PREFIX="sudo -E " diff --git a/hack/jenkins/linux_integration_tests_podman.sh b/hack/jenkins/linux_integration_tests_podman.sh index 3b61c15604..186e9e0a43 100755 --- a/hack/jenkins/linux_integration_tests_podman.sh +++ b/hack/jenkins/linux_integration_tests_podman.sh @@ -32,7 +32,7 @@ JOB_NAME="Experimental_Podman_Linux" mkdir -p cron && gsutil -qm rsync "gs://minikube-builds/${MINIKUBE_LOCATION}/cron" cron || echo "FAILED TO GET CRON FILES" sudo install cron/cleanup_and_reboot_Linux.sh /etc/cron.hourly/cleanup_and_reboot || echo "FAILED TO INSTALL CLEANUP" -EXTRA_ARGS="--container-runtime=containerd" +EXTRA_START_ARGS="--container-runtime=containerd" # remove possible left over podman containers sudo podman rm -f -v $(sudo podman ps -aq) || true diff --git a/hack/jenkins/osx_integration_tests_hyperkit.sh b/hack/jenkins/osx_integration_tests_hyperkit.sh index 74eb7e8380..f4e6726d77 100755 --- a/hack/jenkins/osx_integration_tests_hyperkit.sh +++ b/hack/jenkins/osx_integration_tests_hyperkit.sh @@ -29,8 +29,7 @@ set -e OS_ARCH="darwin-amd64" VM_DRIVER="hyperkit" JOB_NAME="HyperKit_macOS" -EXTRA_ARGS="--bootstrapper=kubeadm" -EXTRA_START_ARGS="" +EXTRA_TEST_ARGS="-test.run TestFunctional" EXPECTED_DEFAULT_DRIVER="hyperkit" diff --git a/hack/jenkins/osx_integration_tests_virtualbox.sh b/hack/jenkins/osx_integration_tests_virtualbox.sh index c897457e3d..67505da506 100755 --- a/hack/jenkins/osx_integration_tests_virtualbox.sh +++ b/hack/jenkins/osx_integration_tests_virtualbox.sh @@ -28,7 +28,7 @@ set -e OS_ARCH="darwin-amd64" VM_DRIVER="virtualbox" JOB_NAME="VirtualBox_macOS" -EXTRA_ARGS="--bootstrapper=kubeadm" +EXTRA_START_ARGS="--bootstrapper=kubeadm" # hyperkit behaves better, so it has higher precedence. # Assumes that hyperkit is also installed on the VirtualBox CI host. EXPECTED_DEFAULT_DRIVER="hyperkit" diff --git a/pkg/drivers/kic/types.go b/pkg/drivers/kic/types.go index d38b979b05..2a8b06c215 100644 --- a/pkg/drivers/kic/types.go +++ b/pkg/drivers/kic/types.go @@ -24,9 +24,9 @@ import ( const ( // Version is the current version of kic - Version = "v0.0.15-snapshot2" + Version = "v0.0.15-snapshot3" // SHA of the kic base image - baseImageSHA = "0973e4bcdfef0dc8c5a581ecfcca5e36fa6a1cc8773e832ecfd31de3d2b6bf46" + baseImageSHA = "d6162757b2cb147e4afc5217372171518f15683f6c1a63f25f9121ff61ca654c" ) var ( diff --git a/site/content/en/docs/commands/start.md b/site/content/en/docs/commands/start.md index d24e0f719e..df2ae1a176 100644 --- a/site/content/en/docs/commands/start.md +++ b/site/content/en/docs/commands/start.md @@ -26,7 +26,7 @@ minikube start [flags] --apiserver-names strings A set of apiserver names which are used in the generated certificate for kubernetes. This can be used if you want to make the apiserver available from outside the machine --apiserver-port int The apiserver listening port (default 8443) --auto-update-drivers If set, automatically updates drivers to the latest version. Defaults to true. (default true) - --base-image string The base image to use for docker/podman drivers. Intended for local development. (default "gcr.io/k8s-minikube/kicbase:v0.0.15-snapshot2@sha256:0973e4bcdfef0dc8c5a581ecfcca5e36fa6a1cc8773e832ecfd31de3d2b6bf46") + --base-image string The base image to use for docker/podman drivers. Intended for local development. (default "gcr.io/k8s-minikube/kicbase:v0.0.15-snapshot3@sha256:d6162757b2cb147e4afc5217372171518f15683f6c1a63f25f9121ff61ca654c") --cache-images If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none. (default true) --cni string CNI plug-in to use. Valid options: auto, bridge, calico, cilium, flannel, kindnet, or path to a CNI manifest (default: auto) --container-runtime string The container runtime to be used (docker, cri-o, containerd). (default "docker") diff --git a/site/content/en/docs/commands/status.md b/site/content/en/docs/commands/status.md index f4902dab0b..e5c3c89e7d 100644 --- a/site/content/en/docs/commands/status.md +++ b/site/content/en/docs/commands/status.md @@ -23,7 +23,7 @@ minikube status [flags] ``` -f, --format string Go template format string for the status output. The format for Go templates can be found here: https://golang.org/pkg/text/template/ - For the list accessible variables for the template, see the struct values here: https://godoc.org/k8s.io/minikube/cmd/minikube/cmd#Status (default "{{.Name}}\ntype: Control Plane\nhost: {{.Host}}\nkubelet: {{.Kubelet}}\napiserver: {{.APIServer}}\nkubeconfig: {{.Kubeconfig}}\n\n") + For the list accessible variables for the template, see the struct values here: https://godoc.org/k8s.io/minikube/cmd/minikube/cmd#Status (default "{{.Name}}\ntype: Control Plane\nhost: {{.Host}}\nkubelet: {{.Kubelet}}\napiserver: {{.APIServer}}\nkubeconfig: {{.Kubeconfig}}\ntimeToStop: {{.TimeToStop}}\n\n") -l, --layout string output layout (EXPERIMENTAL, JSON only): 'nodes' or 'cluster' (default "nodes") -n, --node string The node to check status for. Defaults to control plane. Leave blank with default format for status on all nodes. -o, --output string minikube status --output OUTPUT. json, text (default "text") diff --git a/test/integration/scheduled_stop_test.go b/test/integration/scheduled_stop_test.go index 508a385999..f10c4e2d6b 100644 --- a/test/integration/scheduled_stop_test.go +++ b/test/integration/scheduled_stop_test.go @@ -51,7 +51,8 @@ func TestScheduledStopWindows(t *testing.T) { // schedule a stop for 5m from now stopMinikube(ctx, t, profile, []string{"--schedule", "5m"}) - + // make sure timeToStop is present in status + ensureMinikubeScheduledTime(ctx, t, profile, 5*time.Minute) // make sure the systemd service is running rr, err := Run(t, exec.CommandContext(ctx, Target(), []string{"ssh", "-p", profile, "--", "sudo", "systemctl", "show", constants.ScheduledStopSystemdService, "--no-page"}...)) if err != nil { @@ -67,7 +68,9 @@ func TestScheduledStopWindows(t *testing.T) { // sleep for 5 seconds time.Sleep(5 * time.Second) // make sure minikube status is "Stopped" - ensureMinikubeStatus(ctx, t, profile, state.Stopped.String()) + ensureMinikubeStatus(ctx, t, profile, "Host", state.Stopped.String()) + // make sure minikube timtostop is "Nonexistent" + ensureMinikubeStatus(ctx, t, profile, "TimeToStop", "Nonexistent") } func TestScheduledStopUnix(t *testing.T) { @@ -84,6 +87,8 @@ func TestScheduledStopUnix(t *testing.T) { // schedule a stop for 5 min from now and make sure PID is created stopMinikube(ctx, t, profile, []string{"--schedule", "5m"}) + // make sure timeToStop is present in status + ensureMinikubeScheduledTime(ctx, t, profile, 5*time.Minute) pid := checkPID(t, profile) if !processRunning(t, pid) { t.Fatalf("process %v is not running", pid) @@ -100,14 +105,18 @@ func TestScheduledStopUnix(t *testing.T) { // sleep 12 just to be safe stopMinikube(ctx, t, profile, []string{"--cancel-scheduled"}) time.Sleep(12 * time.Second) - ensureMinikubeStatus(ctx, t, profile, state.Running.String()) + ensureMinikubeStatus(ctx, t, profile, "Host", state.Running.String()) // schedule another stop, make sure minikube status is "Stopped" stopMinikube(ctx, t, profile, []string{"--schedule", "5s"}) if processRunning(t, pid) { t.Fatalf("process %v running but should have been killed on reschedule of stop", pid) } - ensureMinikubeStatus(ctx, t, profile, state.Stopped.String()) + + // make sure minikube status is "Stopped" + ensureMinikubeStatus(ctx, t, profile, "Host", state.Stopped.String()) + // make sure minikube timtostop is "Nonexistent" + ensureMinikubeStatus(ctx, t, profile, "TimeToStop", "Nonexistent") } func startMinikube(ctx context.Context, t *testing.T, profile string) { @@ -156,14 +165,13 @@ func processRunning(t *testing.T, pid string) bool { t.Log("signal error was: ", err) return err == nil } -func ensureMinikubeStatus(ctx context.Context, t *testing.T, profile, wantStatus string) { - // wait allotted time to make sure minikube status is "Stopped" +func ensureMinikubeStatus(ctx context.Context, t *testing.T, profile, key string, wantStatus string) { checkStatus := func() error { ctx, cancel := context.WithDeadline(ctx, time.Now().Add(10*time.Second)) defer cancel() - got := Status(ctx, t, Target(), profile, "Host", profile) + got := Status(ctx, t, Target(), profile, key, profile) if got != wantStatus { - return fmt.Errorf("expected post-stop host status to be -%q- but got *%q*", state.Stopped, got) + return fmt.Errorf("expected post-stop %q status to be -%q- but got *%q*", key, wantStatus, got) } return nil } @@ -171,3 +179,19 @@ func ensureMinikubeStatus(ctx context.Context, t *testing.T, profile, wantStatus t.Fatalf("error %v", err) } } + +func ensureMinikubeScheduledTime(ctx context.Context, t *testing.T, profile string, givenTime time.Duration) { + checkTime := func() error { + ctx, cancel := context.WithDeadline(ctx, time.Now().Add(10*time.Second)) + defer cancel() + got := Status(ctx, t, Target(), profile, "TimeToStop", profile) + gotTime, _ := time.ParseDuration(got) + if gotTime < givenTime { + return nil + } + return fmt.Errorf("expected scheduled stop TimeToStop to be less than *%q* but got *%q*", givenTime, got) + } + if err := retry.Expo(checkTime, time.Second, time.Minute); err != nil { + t.Fatalf("error %v", err) + } +}