diff --git a/cmd/auto-pause/auto-pause.go b/cmd/auto-pause/auto-pause.go index 17d3a998fe..906a375159 100644 --- a/cmd/auto-pause/auto-pause.go +++ b/cmd/auto-pause/auto-pause.go @@ -28,25 +28,24 @@ import ( "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/cruntime" "k8s.io/minikube/pkg/minikube/exit" - "k8s.io/minikube/pkg/minikube/out" "k8s.io/minikube/pkg/minikube/reason" - "k8s.io/minikube/pkg/minikube/style" ) -var unpauseRequests = make(chan struct{}) -var done = make(chan struct{}) -var mu sync.Mutex +var ( + unpauseRequests = make(chan struct{}) + done = make(chan struct{}) + mu sync.Mutex + runtimePaused bool + version = "0.0.1" -var runtimePaused bool -var version = "0.0.1" - -var runtime = flag.String("container-runtime", "docker", "Container runtime to use for (un)pausing") + runtime = flag.String("container-runtime", "docker", "Container runtime to use for (un)pausing") + interval = flag.Duration("interval", time.Minute*1, "Interval of inactivity for pause to occur") +) func main() { flag.Parse() - // TODO: #10595 make this configurable - const interval = time.Minute * 1 + tickerChannel := time.NewTicker(*interval) // Check current state alreadyPaused() @@ -54,16 +53,15 @@ func main() { // channel for incoming messages go func() { for { - // On each iteration new timer is created select { - // TODO: #10596 make it memory-leak proof - case <-time.After(interval): + case <-tickerChannel.C: + tickerChannel.Stop() runPause() case <-unpauseRequests: - fmt.Printf("Got request\n") - if runtimePaused { - runUnpause() - } + tickerChannel.Stop() + log.Println("Got request") + runUnpause() + tickerChannel.Reset(*interval) done <- struct{}{} } @@ -86,9 +84,10 @@ func runPause() { mu.Lock() defer mu.Unlock() if runtimePaused { - out.Styled(style.AddonEnable, "Auto-pause is already enabled.") + log.Println("Already paused, skipping") return } + log.Println("Pausing...") r := command.NewExecRunner(true) @@ -104,13 +103,17 @@ func runPause() { runtimePaused = true - out.Step(style.Unpause, "Paused {{.count}} containers", out.V{"count": len(uids)}) + log.Printf("Paused %d containers", len(uids)) } func runUnpause() { - fmt.Println("unpausing...") mu.Lock() defer mu.Unlock() + if !runtimePaused { + log.Println("Already unpaused, skipping") + return + } + log.Println("Unpausing...") r := command.NewExecRunner(true) @@ -125,7 +128,7 @@ func runUnpause() { } runtimePaused = false - out.Step(style.Unpause, "Unpaused {{.count}} containers", out.V{"count": len(uids)}) + log.Printf("Unpaused %d containers", len(uids)) } func alreadyPaused() { @@ -142,5 +145,5 @@ func alreadyPaused() { if err != nil { 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) } diff --git a/cmd/minikube/cmd/config/configure.go b/cmd/minikube/cmd/config/configure.go index a877d49b87..2ae84602ea 100644 --- a/cmd/minikube/cmd/config/configure.go +++ b/cmd/minikube/cmd/config/configure.go @@ -20,6 +20,7 @@ import ( "net" "os" "regexp" + "time" "github.com/spf13/cobra" "k8s.io/minikube/pkg/addons" @@ -45,6 +46,8 @@ var addonsConfigureCmd = &cobra.Command{ exit.Message(reason.Usage, "usage: minikube addons configure ADDON_NAME") } + profile := ClusterFlagValue() + addon := args[0] // allows for additional prompting of information when enabling addons switch addon { @@ -109,12 +112,11 @@ var addonsConfigureCmd = &cobra.Command{ acrPassword = AskForPasswordValue("-- Enter service principal password to access Azure Container Registry: ") } - cname := ClusterFlagValue() namespace := "kube-system" // Create ECR Secret err := service.CreateSecret( - cname, + profile, namespace, "registry-creds-ecr", map[string]string{ @@ -136,7 +138,7 @@ var addonsConfigureCmd = &cobra.Command{ // Create GCR Secret err = service.CreateSecret( - cname, + profile, namespace, "registry-creds-gcr", map[string]string{ @@ -155,7 +157,7 @@ var addonsConfigureCmd = &cobra.Command{ // Create Docker Secret err = service.CreateSecret( - cname, + profile, namespace, "registry-creds-dpr", map[string]string{ @@ -175,7 +177,7 @@ var addonsConfigureCmd = &cobra.Command{ // Create Azure Container Registry Secret err = service.CreateSecret( - cname, + profile, namespace, "registry-creds-acr", map[string]string{ @@ -194,7 +196,6 @@ var addonsConfigureCmd = &cobra.Command{ } case "metallb": - profile := ClusterFlagValue() _, cfg := mustload.Partial(profile) 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}) } case "ingress": - profile := ClusterFlagValue() _, cfg := mustload.Partial(profile) 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}) } case "registry-aliases": - profile := ClusterFlagValue() _, cfg := mustload.Partial(profile) validator := func(s string) bool { 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}) } } - + 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: out.FailureT("{{.name}} has no available configuration options", out.V{"name": addon}) return diff --git a/cmd/minikube/cmd/start_flags.go b/cmd/minikube/cmd/start_flags.go index 5be215b850..7ba89f6c04 100644 --- a/cmd/minikube/cmd/start_flags.go +++ b/cmd/minikube/cmd/start_flags.go @@ -142,6 +142,7 @@ const ( socketVMnetPath = "socket-vmnet-path" staticIP = "static-ip" gpus = "gpus" + autoPauseInterval = "auto-pause-interval" ) 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().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().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 @@ -603,6 +605,7 @@ func generateNewConfigFromFlags(cmd *cobra.Command, k8sVersion string, rtime str }, MultiNodeRequested: viper.GetInt(nodes) > 1, GPUs: viper.GetString(gpus), + AutoPauseInterval: viper.GetDuration(autoPauseInterval), } cc.VerifyComponents = interpretWaitFlag(*cmd) 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.SocketVMnetClientPath, socketVMnetClientPath) updateStringFromFlag(cmd, &cc.SocketVMnetPath, socketVMnetPath) + updateDurationFromFlag(cmd, &cc.AutoPauseInterval, autoPauseInterval) if cmd.Flags().Changed(kubernetesVersion) { kubeVer, err := getKubernetesVersion(existing) diff --git a/deploy/addons/auto-pause/auto-pause.service.tmpl b/deploy/addons/auto-pause/auto-pause.service.tmpl index 0a5260a7b4..5e52966b18 100644 --- a/deploy/addons/auto-pause/auto-pause.service.tmpl +++ b/deploy/addons/auto-pause/auto-pause.service.tmpl @@ -3,7 +3,7 @@ Description=Auto Pause Service [Service] Type=simple -ExecStart=/bin/auto-pause --container-runtime={{.ContainerRuntime}} +ExecStart=/bin/auto-pause --container-runtime={{.ContainerRuntime}} --interval={{.AutoPauseInterval}} Restart=always [Install] diff --git a/pkg/minikube/assets/addons.go b/pkg/minikube/assets/addons.go index de8c41d1b0..d0d5f51f30 100644 --- a/pkg/minikube/assets/addons.go +++ b/pkg/minikube/assets/addons.go @@ -21,6 +21,7 @@ import ( "os" "runtime" "strings" + "time" semver "github.com/blang/semver/v4" "github.com/pkg/errors" @@ -937,6 +938,7 @@ func GenerateTemplateData(addon *Addon, cc *config.ClusterConfig, netInfo Networ Environment map[string]string LegacyPodSecurityPolicy bool LegacyRuntimeClass bool + AutoPauseInterval time.Duration }{ KubernetesVersion: make(map[string]uint64), PreOneTwentyKubernetes: false, @@ -958,6 +960,7 @@ func GenerateTemplateData(addon *Addon, cc *config.ClusterConfig, netInfo Networ }, LegacyPodSecurityPolicy: 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, "/") { opts.ImageRepository += "/" diff --git a/pkg/minikube/config/types.go b/pkg/minikube/config/types.go index 3a3e962128..f9e3e8225d 100644 --- a/pkg/minikube/config/types.go +++ b/pkg/minikube/config/types.go @@ -108,6 +108,7 @@ type ClusterConfig struct { SSHAuthSock string SSHAgentPID int 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.