Merge pull request #9793 from tharun208/feat/show_scheduled_stop_status

feat(minikube) display scheduledstop status in minikube status
pull/9883/head
priyawadhwa 2020-12-08 11:42:06 -08:00 committed by GitHub
commit 83f9bd1df3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 19 deletions

View File

@ -135,6 +135,7 @@ type Status struct {
APIServer string APIServer string
Kubeconfig string Kubeconfig string
Worker bool Worker bool
TimeToStop string
} }
// ClusterState holds a cluster state representation // ClusterState holds a cluster state representation
@ -142,6 +143,7 @@ type ClusterState struct {
BaseState BaseState
BinaryVersion string BinaryVersion string
TimeToStop string
Components map[string]BaseState Components map[string]BaseState
Nodes []NodeState Nodes []NodeState
} }
@ -180,6 +182,7 @@ host: {{.Host}}
kubelet: {{.Kubelet}} kubelet: {{.Kubelet}}
apiserver: {{.APIServer}} apiserver: {{.APIServer}}
kubeconfig: {{.Kubeconfig}} kubeconfig: {{.Kubeconfig}}
timeToStop: {{.TimeToStop}}
` `
workerStatusFormat = `{{.Name}} workerStatusFormat = `{{.Name}}
@ -307,6 +310,7 @@ func nodeStatus(api libmachine.API, cc config.ClusterConfig, n config.Node) (*St
Kubelet: Nonexistent, Kubelet: Nonexistent,
Kubeconfig: Nonexistent, Kubeconfig: Nonexistent,
Worker: !controlPlane, Worker: !controlPlane,
TimeToStop: Nonexistent,
} }
hs, err := machine.Status(api, name) 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") stk := kverify.ServiceStatus(cr, "kubelet")
st.Kubelet = stk.String() 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 // Early exit for worker nodes
if !controlPlane { if !controlPlane {
return st, nil return st, nil
@ -478,6 +485,7 @@ func clusterState(sts []*Status) ClusterState {
statusName = sts[0].Host statusName = sts[0].Host
} }
sc := statusCode(statusName) sc := statusCode(statusName)
cs := ClusterState{ cs := ClusterState{
BinaryVersion: version.GetVersion(), BinaryVersion: version.GetVersion(),
@ -488,6 +496,8 @@ func clusterState(sts []*Status) ClusterState {
StatusDetail: codeDetails[sc], StatusDetail: codeDetails[sc],
}, },
TimeToStop: sts[0].TimeToStop,
Components: map[string]BaseState{ Components: map[string]BaseState{
"kubeconfig": {Name: "kubeconfig", StatusCode: statusCode(sts[0].Kubeconfig)}, "kubeconfig": {Name: "kubeconfig", StatusCode: statusCode(sts[0].Kubeconfig)},
}, },

View File

@ -51,18 +51,18 @@ func TestStatusText(t *testing.T) {
}{ }{
{ {
name: "ok", name: "ok",
state: &Status{Name: "minikube", Host: "Running", Kubelet: "Running", APIServer: "Running", Kubeconfig: Configured}, 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\n\n", want: "minikube\ntype: Control Plane\nhost: Running\nkubelet: Running\napiserver: Running\nkubeconfig: Configured\ntimeToStop: 10m\n\n",
}, },
{ {
name: "paused", name: "paused",
state: &Status{Name: "minikube", Host: "Running", Kubelet: "Stopped", APIServer: "Paused", Kubeconfig: Configured}, 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\n\n", want: "minikube\ntype: Control Plane\nhost: Running\nkubelet: Stopped\napiserver: Paused\nkubeconfig: Configured\ntimeToStop: Nonexistent\n\n",
}, },
{ {
name: "down", name: "down",
state: &Status{Name: "minikube", Host: "Stopped", Kubelet: "Stopped", APIServer: "Stopped", Kubeconfig: Misconfigured}, 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\n\n\nWARNING: Your kubectl is pointing to stale minikube-vm.\nTo fix the kubectl context, run `minikube update-context`\n", 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 { for _, tc := range tests {
@ -86,9 +86,9 @@ func TestStatusJSON(t *testing.T) {
name string name string
state *Status state *Status
}{ }{
{"ok", &Status{Host: "Running", Kubelet: "Running", APIServer: "Running", Kubeconfig: Configured}}, {"ok", &Status{Host: "Running", Kubelet: "Running", APIServer: "Running", Kubeconfig: Configured, TimeToStop: "10m"}},
{"paused", &Status{Host: "Running", Kubelet: "Stopped", APIServer: "Paused", Kubeconfig: Configured}}, {"paused", &Status{Host: "Running", Kubelet: "Stopped", APIServer: "Paused", Kubeconfig: Configured, TimeToStop: Nonexistent}},
{"down", &Status{Host: "Stopped", Kubelet: "Stopped", APIServer: "Stopped", Kubeconfig: Misconfigured}}, {"down", &Status{Host: "Stopped", Kubelet: "Stopped", APIServer: "Stopped", Kubeconfig: Misconfigured, TimeToStop: Nonexistent}},
} }
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {

View File

@ -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/ -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") -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. -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") -o, --output string minikube status --output OUTPUT. json, text (default "text")

View File

@ -51,7 +51,8 @@ func TestScheduledStopWindows(t *testing.T) {
// schedule a stop for 5m from now // schedule a stop for 5m from now
stopMinikube(ctx, t, profile, []string{"--schedule", "5m"}) 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 // 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"}...)) rr, err := Run(t, exec.CommandContext(ctx, Target(), []string{"ssh", "-p", profile, "--", "sudo", "systemctl", "show", constants.ScheduledStopSystemdService, "--no-page"}...))
if err != nil { if err != nil {
@ -67,7 +68,9 @@ func TestScheduledStopWindows(t *testing.T) {
// sleep for 5 seconds // sleep for 5 seconds
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
// make sure minikube status is "Stopped" // 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) { 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 // schedule a stop for 5 min from now and make sure PID is created
stopMinikube(ctx, t, profile, []string{"--schedule", "5m"}) 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) pid := checkPID(t, profile)
if !processRunning(t, pid) { if !processRunning(t, pid) {
t.Fatalf("process %v is not running", pid) t.Fatalf("process %v is not running", pid)
@ -100,14 +105,18 @@ func TestScheduledStopUnix(t *testing.T) {
// sleep 12 just to be safe // sleep 12 just to be safe
stopMinikube(ctx, t, profile, []string{"--cancel-scheduled"}) stopMinikube(ctx, t, profile, []string{"--cancel-scheduled"})
time.Sleep(12 * time.Second) 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" // schedule another stop, make sure minikube status is "Stopped"
stopMinikube(ctx, t, profile, []string{"--schedule", "5s"}) stopMinikube(ctx, t, profile, []string{"--schedule", "5s"})
if processRunning(t, pid) { if processRunning(t, pid) {
t.Fatalf("process %v running but should have been killed on reschedule of stop", 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) { 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) t.Log("signal error was: ", err)
return err == nil return err == nil
} }
func ensureMinikubeStatus(ctx context.Context, t *testing.T, profile, wantStatus string) { func ensureMinikubeStatus(ctx context.Context, t *testing.T, profile, key string, wantStatus string) {
// wait allotted time to make sure minikube status is "Stopped"
checkStatus := func() error { checkStatus := func() error {
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(10*time.Second)) ctx, cancel := context.WithDeadline(ctx, time.Now().Add(10*time.Second))
defer cancel() defer cancel()
got := Status(ctx, t, Target(), profile, "Host", profile) got := Status(ctx, t, Target(), profile, key, profile)
if got != wantStatus { 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 return nil
} }
@ -171,3 +179,19 @@ func ensureMinikubeStatus(ctx context.Context, t *testing.T, profile, wantStatus
t.Fatalf("error %v", err) 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)
}
}