scheduled_stop_test.go 6.2 KB
Newer Older
P
Priya Wadhwa 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// +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"
	"io/ioutil"
	"os"
	"os/exec"
27
	"runtime"
P
Priya Wadhwa 已提交
28
	"strconv"
29
	"strings"
P
Priya Wadhwa 已提交
30 31 32 33 34
	"syscall"
	"testing"
	"time"

	"github.com/docker/machine/libmachine/state"
35
	"k8s.io/minikube/pkg/minikube/constants"
P
Priya Wadhwa 已提交
36 37 38 39
	"k8s.io/minikube/pkg/minikube/localpath"
	"k8s.io/minikube/pkg/util/retry"
)

40 41 42 43
func TestScheduledStopWindows(t *testing.T) {
	if runtime.GOOS != "windows" {
		t.Skip("test only runs on windows")
	}
44
	if NoneDriver() {
45 46 47 48 49 50 51 52
		t.Skip("--schedule does not work with the none driver")
	}
	profile := UniqueProfileName("scheduled-stop")
	ctx, cancel := context.WithTimeout(context.Background(), Minutes(5))
	defer CleanupWithLogs(t, profile, cancel)
	startMinikube(ctx, t, profile)

	// schedule a stop for 5m from now
53
	stopMinikube(ctx, t, profile, []string{"--schedule", "5m"})
54
	// make sure timeToStop is present in status
55
	ensureMinikubeScheduledTime(ctx, t, profile, 5*time.Minute)
56 57 58 59 60 61 62 63 64 65
	// 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 {
		t.Fatalf("getting minikube-scheduled-stop status: %v\n%s", err, rr.Output())
	}
	if !strings.Contains(rr.Output(), "ActiveState=active") {
		t.Fatalf("minikube-scheduled-stop is not running: %v", rr.Output())
	}

	// reschedule stop for 5 seconds from now
66
	stopMinikube(ctx, t, profile, []string{"--schedule", "5s"})
67 68 69 70

	// sleep for 5 seconds
	time.Sleep(5 * time.Second)
	// make sure minikube status is "Stopped"
T
Tharun 已提交
71
	ensureMinikubeStatus(ctx, t, profile, "Host", state.Stopped.String())
72 73 74 75 76 77 78 79
}

func TestScheduledStopUnix(t *testing.T) {
	if runtime.GOOS == "windows" {
		t.Skip("test only runs on unix")
	}
	if NoneDriver() {
		t.Skip("--schedule does not work with the none driver")
80
	}
P
Priya Wadhwa 已提交
81
	profile := UniqueProfileName("scheduled-stop")
P
Priya Wadhwa 已提交
82
	ctx, cancel := context.WithTimeout(context.Background(), Minutes(5))
P
Priya Wadhwa 已提交
83 84 85 86
	defer CleanupWithLogs(t, profile, cancel)
	startMinikube(ctx, t, profile)

	// schedule a stop for 5 min from now and make sure PID is created
87
	stopMinikube(ctx, t, profile, []string{"--schedule", "5m"})
88
	// make sure timeToStop is present in status
89
	ensureMinikubeScheduledTime(ctx, t, profile, 5*time.Minute)
P
Priya Wadhwa 已提交
90 91 92 93 94
	pid := checkPID(t, profile)
	if !processRunning(t, pid) {
		t.Fatalf("process %v is not running", pid)
	}

95 96
	// schedule a second stop which should cancel the first scheduled stop
	stopMinikube(ctx, t, profile, []string{"--schedule", "8s"})
P
Priya Wadhwa 已提交
97 98 99 100
	if processRunning(t, pid) {
		t.Fatalf("process %v running but should have been killed on reschedule of stop", pid)
	}
	checkPID(t, profile)
101 102 103

	// cancel the shutdown and make sure minikube is still running after 8 seconds
	// sleep 12 just to be safe
104
	stopMinikube(ctx, t, profile, []string{"--cancel-scheduled"})
105
	time.Sleep(12 * time.Second)
T
Tharun 已提交
106
	ensureMinikubeStatus(ctx, t, profile, "Host", state.Running.String())
107 108 109 110 111 112

	// 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)
	}
113 114

	// make sure minikube status is "Stopped"
T
Tharun 已提交
115
	ensureMinikubeStatus(ctx, t, profile, "Host", state.Stopped.String())
P
Priya Wadhwa 已提交
116 117 118
}

func startMinikube(ctx context.Context, t *testing.T, profile string) {
119
	args := append([]string{"start", "-p", profile, "--memory=1900"}, StartArgs()...)
P
Priya Wadhwa 已提交
120 121 122 123 124 125
	rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Fatalf("starting minikube: %v\n%s", err, rr.Output())
	}
}

126 127 128
func stopMinikube(ctx context.Context, t *testing.T, profile string, additionalArgs []string) {
	args := []string{"stop", "-p", profile}
	args = append(args, additionalArgs...)
P
Priya Wadhwa 已提交
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
	rr, err := Run(t, exec.CommandContext(ctx, Target(), args...))
	if err != nil {
		t.Fatalf("starting minikube: %v\n%s", err, rr.Output())
	}
}

func checkPID(t *testing.T, profile string) string {
	file := localpath.PID(profile)
	var contents []byte
	getContents := func() error {
		var err error
		contents, err = ioutil.ReadFile(file)
		return err
	}
	// first, make sure the PID file exists
	if err := retry.Expo(getContents, 100*time.Microsecond, time.Minute*1); err != nil {
		t.Fatalf("error reading %s: %v", file, err)
	}
	return string(contents)
}

func processRunning(t *testing.T, pid string) bool {
	// make sure PID file contains a running process
	p, err := strconv.Atoi(pid)
	if err != nil {
		return false
	}
	process, err := os.FindProcess(p)
	if err != nil {
		return false
	}
	err = process.Signal(syscall.Signal(0))
	t.Log("signal error was: ", err)
	return err == nil
}
T
Tharun 已提交
164
func ensureMinikubeStatus(ctx context.Context, t *testing.T, profile, key string, wantStatus string) {
165
	checkStatus := func() error {
P
Priya Wadhwa 已提交
166 167
		ctx, cancel := context.WithDeadline(ctx, time.Now().Add(10*time.Second))
		defer cancel()
T
Tharun 已提交
168
		got := Status(ctx, t, Target(), profile, key, profile)
169
		if got != wantStatus {
T
Tharun 已提交
170
			return fmt.Errorf("expected post-stop %q status to be -%q- but got *%q*", key, wantStatus, got)
171 172 173
		}
		return nil
	}
P
Priya Wadhwa 已提交
174
	if err := retry.Expo(checkStatus, time.Second, time.Minute); err != nil {
175 176 177
		t.Fatalf("error %v", err)
	}
}
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

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)
	}
}