Reimplement reverted auto-pause PRs with fixes

pull/17936/head
Steven Powell 2024-01-11 16:04:27 -08:00
parent 02002071fe
commit 83076e3b65
6 changed files with 63 additions and 33 deletions

View File

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

View File

@ -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

View File

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

View File

@ -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]

View File

@ -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 += "/"

View File

@ -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.