Reimplement reverted auto-pause PRs with fixes
parent
02002071fe
commit
83076e3b65
|
@ -28,25 +28,24 @@ import (
|
||||||
"k8s.io/minikube/pkg/minikube/command"
|
"k8s.io/minikube/pkg/minikube/command"
|
||||||
"k8s.io/minikube/pkg/minikube/cruntime"
|
"k8s.io/minikube/pkg/minikube/cruntime"
|
||||||
"k8s.io/minikube/pkg/minikube/exit"
|
"k8s.io/minikube/pkg/minikube/exit"
|
||||||
"k8s.io/minikube/pkg/minikube/out"
|
|
||||||
"k8s.io/minikube/pkg/minikube/reason"
|
"k8s.io/minikube/pkg/minikube/reason"
|
||||||
"k8s.io/minikube/pkg/minikube/style"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var unpauseRequests = make(chan struct{})
|
var (
|
||||||
var done = make(chan struct{})
|
unpauseRequests = make(chan struct{})
|
||||||
var mu sync.Mutex
|
done = make(chan struct{})
|
||||||
|
mu sync.Mutex
|
||||||
|
runtimePaused bool
|
||||||
|
version = "0.0.1"
|
||||||
|
|
||||||
var runtimePaused bool
|
runtime = flag.String("container-runtime", "docker", "Container runtime to use for (un)pausing")
|
||||||
var version = "0.0.1"
|
interval = flag.Duration("interval", time.Minute*1, "Interval of inactivity for pause to occur")
|
||||||
|
)
|
||||||
var runtime = flag.String("container-runtime", "docker", "Container runtime to use for (un)pausing")
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// TODO: #10595 make this configurable
|
tickerChannel := time.NewTicker(*interval)
|
||||||
const interval = time.Minute * 1
|
|
||||||
|
|
||||||
// Check current state
|
// Check current state
|
||||||
alreadyPaused()
|
alreadyPaused()
|
||||||
|
@ -54,16 +53,15 @@ func main() {
|
||||||
// channel for incoming messages
|
// channel for incoming messages
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
// On each iteration new timer is created
|
|
||||||
select {
|
select {
|
||||||
// TODO: #10596 make it memory-leak proof
|
case <-tickerChannel.C:
|
||||||
case <-time.After(interval):
|
tickerChannel.Stop()
|
||||||
runPause()
|
runPause()
|
||||||
case <-unpauseRequests:
|
case <-unpauseRequests:
|
||||||
fmt.Printf("Got request\n")
|
tickerChannel.Stop()
|
||||||
if runtimePaused {
|
log.Println("Got request")
|
||||||
runUnpause()
|
runUnpause()
|
||||||
}
|
tickerChannel.Reset(*interval)
|
||||||
|
|
||||||
done <- struct{}{}
|
done <- struct{}{}
|
||||||
}
|
}
|
||||||
|
@ -86,9 +84,10 @@ func runPause() {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
if runtimePaused {
|
if runtimePaused {
|
||||||
out.Styled(style.AddonEnable, "Auto-pause is already enabled.")
|
log.Println("Already paused, skipping")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Println("Pausing...")
|
||||||
|
|
||||||
r := command.NewExecRunner(true)
|
r := command.NewExecRunner(true)
|
||||||
|
|
||||||
|
@ -104,13 +103,17 @@ func runPause() {
|
||||||
|
|
||||||
runtimePaused = true
|
runtimePaused = true
|
||||||
|
|
||||||
out.Step(style.Unpause, "Paused {{.count}} containers", out.V{"count": len(uids)})
|
log.Printf("Paused %d containers", len(uids))
|
||||||
}
|
}
|
||||||
|
|
||||||
func runUnpause() {
|
func runUnpause() {
|
||||||
fmt.Println("unpausing...")
|
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
if !runtimePaused {
|
||||||
|
log.Println("Already unpaused, skipping")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Println("Unpausing...")
|
||||||
|
|
||||||
r := command.NewExecRunner(true)
|
r := command.NewExecRunner(true)
|
||||||
|
|
||||||
|
@ -125,7 +128,7 @@ func runUnpause() {
|
||||||
}
|
}
|
||||||
runtimePaused = false
|
runtimePaused = false
|
||||||
|
|
||||||
out.Step(style.Unpause, "Unpaused {{.count}} containers", out.V{"count": len(uids)})
|
log.Printf("Unpaused %d containers", len(uids))
|
||||||
}
|
}
|
||||||
|
|
||||||
func alreadyPaused() {
|
func alreadyPaused() {
|
||||||
|
@ -142,5 +145,5 @@ func alreadyPaused() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit.Error(reason.GuestCheckPaused, "Fail check if container paused", err)
|
exit.Error(reason.GuestCheckPaused, "Fail check if container paused", err)
|
||||||
}
|
}
|
||||||
out.Step(style.Check, "containers paused status: {{.paused}}", out.V{"paused": runtimePaused})
|
log.Printf("containers paused status: %t", runtimePaused)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"k8s.io/minikube/pkg/addons"
|
"k8s.io/minikube/pkg/addons"
|
||||||
|
@ -45,6 +46,8 @@ var addonsConfigureCmd = &cobra.Command{
|
||||||
exit.Message(reason.Usage, "usage: minikube addons configure ADDON_NAME")
|
exit.Message(reason.Usage, "usage: minikube addons configure ADDON_NAME")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
profile := ClusterFlagValue()
|
||||||
|
|
||||||
addon := args[0]
|
addon := args[0]
|
||||||
// allows for additional prompting of information when enabling addons
|
// allows for additional prompting of information when enabling addons
|
||||||
switch addon {
|
switch addon {
|
||||||
|
@ -109,12 +112,11 @@ var addonsConfigureCmd = &cobra.Command{
|
||||||
acrPassword = AskForPasswordValue("-- Enter service principal password to access Azure Container Registry: ")
|
acrPassword = AskForPasswordValue("-- Enter service principal password to access Azure Container Registry: ")
|
||||||
}
|
}
|
||||||
|
|
||||||
cname := ClusterFlagValue()
|
|
||||||
namespace := "kube-system"
|
namespace := "kube-system"
|
||||||
|
|
||||||
// Create ECR Secret
|
// Create ECR Secret
|
||||||
err := service.CreateSecret(
|
err := service.CreateSecret(
|
||||||
cname,
|
profile,
|
||||||
namespace,
|
namespace,
|
||||||
"registry-creds-ecr",
|
"registry-creds-ecr",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
|
@ -136,7 +138,7 @@ var addonsConfigureCmd = &cobra.Command{
|
||||||
|
|
||||||
// Create GCR Secret
|
// Create GCR Secret
|
||||||
err = service.CreateSecret(
|
err = service.CreateSecret(
|
||||||
cname,
|
profile,
|
||||||
namespace,
|
namespace,
|
||||||
"registry-creds-gcr",
|
"registry-creds-gcr",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
|
@ -155,7 +157,7 @@ var addonsConfigureCmd = &cobra.Command{
|
||||||
|
|
||||||
// Create Docker Secret
|
// Create Docker Secret
|
||||||
err = service.CreateSecret(
|
err = service.CreateSecret(
|
||||||
cname,
|
profile,
|
||||||
namespace,
|
namespace,
|
||||||
"registry-creds-dpr",
|
"registry-creds-dpr",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
|
@ -175,7 +177,7 @@ var addonsConfigureCmd = &cobra.Command{
|
||||||
|
|
||||||
// Create Azure Container Registry Secret
|
// Create Azure Container Registry Secret
|
||||||
err = service.CreateSecret(
|
err = service.CreateSecret(
|
||||||
cname,
|
profile,
|
||||||
namespace,
|
namespace,
|
||||||
"registry-creds-acr",
|
"registry-creds-acr",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
|
@ -194,7 +196,6 @@ var addonsConfigureCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
case "metallb":
|
case "metallb":
|
||||||
profile := ClusterFlagValue()
|
|
||||||
_, cfg := mustload.Partial(profile)
|
_, cfg := mustload.Partial(profile)
|
||||||
|
|
||||||
validator := func(s string) bool {
|
validator := func(s string) bool {
|
||||||
|
@ -214,7 +215,6 @@ var addonsConfigureCmd = &cobra.Command{
|
||||||
out.ErrT(style.Fatal, "Failed to configure metallb IP {{.profile}}", out.V{"profile": profile})
|
out.ErrT(style.Fatal, "Failed to configure metallb IP {{.profile}}", out.V{"profile": profile})
|
||||||
}
|
}
|
||||||
case "ingress":
|
case "ingress":
|
||||||
profile := ClusterFlagValue()
|
|
||||||
_, cfg := mustload.Partial(profile)
|
_, cfg := mustload.Partial(profile)
|
||||||
|
|
||||||
validator := func(s string) bool {
|
validator := func(s string) bool {
|
||||||
|
@ -236,7 +236,6 @@ var addonsConfigureCmd = &cobra.Command{
|
||||||
out.ErrT(style.Fatal, "Failed to save config {{.profile}}", out.V{"profile": profile})
|
out.ErrT(style.Fatal, "Failed to save config {{.profile}}", out.V{"profile": profile})
|
||||||
}
|
}
|
||||||
case "registry-aliases":
|
case "registry-aliases":
|
||||||
profile := ClusterFlagValue()
|
|
||||||
_, cfg := mustload.Partial(profile)
|
_, cfg := mustload.Partial(profile)
|
||||||
validator := func(s string) bool {
|
validator := func(s string) bool {
|
||||||
format := regexp.MustCompile(`^([a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+)+(\ [a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+)*$`)
|
format := regexp.MustCompile(`^([a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+)+(\ [a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+)*$`)
|
||||||
|
@ -255,7 +254,27 @@ var addonsConfigureCmd = &cobra.Command{
|
||||||
out.ErrT(style.Fatal, "Failed to configure registry-aliases {{.profile}}", out.V{"profile": profile})
|
out.ErrT(style.Fatal, "Failed to configure registry-aliases {{.profile}}", out.V{"profile": profile})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "auto-pause":
|
||||||
|
_, cfg := mustload.Partial(profile)
|
||||||
|
intervalInput := AskForStaticValue("-- Enter interval time of auto-pause-interval (ex. 1m0s): ")
|
||||||
|
intervalTime, err := time.ParseDuration(intervalInput)
|
||||||
|
if err != nil {
|
||||||
|
out.ErrT(style.Fatal, "Interval is an invalid duration: {{.error}}", out.V{"error": err})
|
||||||
|
}
|
||||||
|
if intervalTime != intervalTime.Abs() || intervalTime.String() == "0s" {
|
||||||
|
out.ErrT(style.Fatal, "Interval must be greater than 0s")
|
||||||
|
}
|
||||||
|
cfg.AutoPauseInterval = intervalTime
|
||||||
|
if err := config.SaveProfile(profile, cfg); err != nil {
|
||||||
|
out.ErrT(style.Fatal, "Failed to save config {{.profile}}", out.V{"profile": profile})
|
||||||
|
}
|
||||||
|
addon := assets.Addons["auto-pause"]
|
||||||
|
if addon.IsEnabled(cfg) {
|
||||||
|
// Re-enable auto-pause addon in order to update interval time
|
||||||
|
if err := addons.EnableOrDisableAddon(cfg, "auto-pause", "true"); err != nil {
|
||||||
|
out.ErrT(style.Fatal, "Failed to configure auto-pause {{.profile}}", out.V{"profile": profile})
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
out.FailureT("{{.name}} has no available configuration options", out.V{"name": addon})
|
out.FailureT("{{.name}} has no available configuration options", out.V{"name": addon})
|
||||||
return
|
return
|
||||||
|
|
|
@ -142,6 +142,7 @@ const (
|
||||||
socketVMnetPath = "socket-vmnet-path"
|
socketVMnetPath = "socket-vmnet-path"
|
||||||
staticIP = "static-ip"
|
staticIP = "static-ip"
|
||||||
gpus = "gpus"
|
gpus = "gpus"
|
||||||
|
autoPauseInterval = "auto-pause-interval"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -204,6 +205,7 @@ func initMinikubeFlags() {
|
||||||
startCmd.Flags().Bool(disableMetrics, false, "If set, disables metrics reporting (CPU and memory usage), this can improve CPU usage. Defaults to false.")
|
startCmd.Flags().Bool(disableMetrics, false, "If set, disables metrics reporting (CPU and memory usage), this can improve CPU usage. Defaults to false.")
|
||||||
startCmd.Flags().String(staticIP, "", "Set a static IP for the minikube cluster, the IP must be: private, IPv4, and the last octet must be between 2 and 254, for example 192.168.200.200 (Docker and Podman drivers only)")
|
startCmd.Flags().String(staticIP, "", "Set a static IP for the minikube cluster, the IP must be: private, IPv4, and the last octet must be between 2 and 254, for example 192.168.200.200 (Docker and Podman drivers only)")
|
||||||
startCmd.Flags().StringP(gpus, "g", "", "Allow pods to use your NVIDIA GPUs. Options include: [all,nvidia] (Docker driver with Docker container-runtime only)")
|
startCmd.Flags().StringP(gpus, "g", "", "Allow pods to use your NVIDIA GPUs. Options include: [all,nvidia] (Docker driver with Docker container-runtime only)")
|
||||||
|
startCmd.Flags().Duration(autoPauseInterval, time.Minute*1, "Duration of inactivity before the minikube VM is paused (default 1m0s)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// initKubernetesFlags inits the commandline flags for Kubernetes related options
|
// initKubernetesFlags inits the commandline flags for Kubernetes related options
|
||||||
|
@ -603,6 +605,7 @@ func generateNewConfigFromFlags(cmd *cobra.Command, k8sVersion string, rtime str
|
||||||
},
|
},
|
||||||
MultiNodeRequested: viper.GetInt(nodes) > 1,
|
MultiNodeRequested: viper.GetInt(nodes) > 1,
|
||||||
GPUs: viper.GetString(gpus),
|
GPUs: viper.GetString(gpus),
|
||||||
|
AutoPauseInterval: viper.GetDuration(autoPauseInterval),
|
||||||
}
|
}
|
||||||
cc.VerifyComponents = interpretWaitFlag(*cmd)
|
cc.VerifyComponents = interpretWaitFlag(*cmd)
|
||||||
if viper.GetBool(createMount) && driver.IsKIC(drvName) {
|
if viper.GetBool(createMount) && driver.IsKIC(drvName) {
|
||||||
|
@ -817,6 +820,7 @@ func updateExistingConfigFromFlags(cmd *cobra.Command, existing *config.ClusterC
|
||||||
updateStringFromFlag(cmd, &cc.CustomQemuFirmwarePath, qemuFirmwarePath)
|
updateStringFromFlag(cmd, &cc.CustomQemuFirmwarePath, qemuFirmwarePath)
|
||||||
updateStringFromFlag(cmd, &cc.SocketVMnetClientPath, socketVMnetClientPath)
|
updateStringFromFlag(cmd, &cc.SocketVMnetClientPath, socketVMnetClientPath)
|
||||||
updateStringFromFlag(cmd, &cc.SocketVMnetPath, socketVMnetPath)
|
updateStringFromFlag(cmd, &cc.SocketVMnetPath, socketVMnetPath)
|
||||||
|
updateDurationFromFlag(cmd, &cc.AutoPauseInterval, autoPauseInterval)
|
||||||
|
|
||||||
if cmd.Flags().Changed(kubernetesVersion) {
|
if cmd.Flags().Changed(kubernetesVersion) {
|
||||||
kubeVer, err := getKubernetesVersion(existing)
|
kubeVer, err := getKubernetesVersion(existing)
|
||||||
|
|
|
@ -3,7 +3,7 @@ Description=Auto Pause Service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
ExecStart=/bin/auto-pause --container-runtime={{.ContainerRuntime}}
|
ExecStart=/bin/auto-pause --container-runtime={{.ContainerRuntime}} --interval={{.AutoPauseInterval}}
|
||||||
Restart=always
|
Restart=always
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
semver "github.com/blang/semver/v4"
|
semver "github.com/blang/semver/v4"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -937,6 +938,7 @@ func GenerateTemplateData(addon *Addon, cc *config.ClusterConfig, netInfo Networ
|
||||||
Environment map[string]string
|
Environment map[string]string
|
||||||
LegacyPodSecurityPolicy bool
|
LegacyPodSecurityPolicy bool
|
||||||
LegacyRuntimeClass bool
|
LegacyRuntimeClass bool
|
||||||
|
AutoPauseInterval time.Duration
|
||||||
}{
|
}{
|
||||||
KubernetesVersion: make(map[string]uint64),
|
KubernetesVersion: make(map[string]uint64),
|
||||||
PreOneTwentyKubernetes: false,
|
PreOneTwentyKubernetes: false,
|
||||||
|
@ -958,6 +960,7 @@ func GenerateTemplateData(addon *Addon, cc *config.ClusterConfig, netInfo Networ
|
||||||
},
|
},
|
||||||
LegacyPodSecurityPolicy: v.LT(semver.Version{Major: 1, Minor: 25}),
|
LegacyPodSecurityPolicy: v.LT(semver.Version{Major: 1, Minor: 25}),
|
||||||
LegacyRuntimeClass: v.LT(semver.Version{Major: 1, Minor: 25}),
|
LegacyRuntimeClass: v.LT(semver.Version{Major: 1, Minor: 25}),
|
||||||
|
AutoPauseInterval: cc.AutoPauseInterval,
|
||||||
}
|
}
|
||||||
if opts.ImageRepository != "" && !strings.HasSuffix(opts.ImageRepository, "/") {
|
if opts.ImageRepository != "" && !strings.HasSuffix(opts.ImageRepository, "/") {
|
||||||
opts.ImageRepository += "/"
|
opts.ImageRepository += "/"
|
||||||
|
|
|
@ -108,6 +108,7 @@ type ClusterConfig struct {
|
||||||
SSHAuthSock string
|
SSHAuthSock string
|
||||||
SSHAgentPID int
|
SSHAgentPID int
|
||||||
GPUs string
|
GPUs string
|
||||||
|
AutoPauseInterval time.Duration // Specifies interval of time to wait before checking if cluster should be paused
|
||||||
}
|
}
|
||||||
|
|
||||||
// KubernetesConfig contains the parameters used to configure the VM Kubernetes.
|
// KubernetesConfig contains the parameters used to configure the VM Kubernetes.
|
||||||
|
|
Loading…
Reference in New Issue