141 lines
3.1 KiB
Go
141 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"strconv"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
"k8s.io/client-go/rest"
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
"k8s.io/client-go/util/homedir"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
"code.icb4dc0.de/prskr/kreaper/reaper"
|
|
)
|
|
|
|
const defaultKreaperLifetime = 5 * time.Minute
|
|
|
|
var (
|
|
kubeconfig string
|
|
dryRun bool
|
|
logLevel *zapcore.Level
|
|
kreaper = reaper.Kreaper{
|
|
Target: lookupEnvOr("KREAPER_TARGET", "", reaper.ParseTarget),
|
|
}
|
|
)
|
|
|
|
func main() {
|
|
prepareFlags()
|
|
setupLogging()
|
|
|
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
|
|
|
|
if err := run(ctx); err != nil {
|
|
cancel()
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func run(ctx context.Context) error {
|
|
logger := zap.L()
|
|
|
|
restCfg, err := loadRestConfig()
|
|
if err != nil {
|
|
logger.Error("Failed to get cluster config", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
if kreaper.Client, err = client.NewWithWatch(restCfg, client.Options{}); err != nil {
|
|
logger.Error("failed to prepare Kubernetes API client", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
return kreaper.Kill(ctx)
|
|
}
|
|
|
|
func setupLogging() {
|
|
cfg := zap.NewProductionConfig()
|
|
cfg.Level = zap.NewAtomicLevelAt(*logLevel)
|
|
logger, err := cfg.Build()
|
|
if err != nil {
|
|
log.Fatalf("Failed to setup logging: %v", err)
|
|
}
|
|
|
|
zap.ReplaceGlobals(logger)
|
|
}
|
|
|
|
func prepareFlags() {
|
|
logLevel = zap.LevelFlag("log-level", zapcore.InfoLevel, "Log level to use")
|
|
flag.Var(&kreaper.Target, "target", "Target that should be monitored")
|
|
|
|
flag.BoolVar(
|
|
&dryRun,
|
|
"dry-run",
|
|
lookupEnvOr("KREAPER_DRY_RUN", false, strconv.ParseBool),
|
|
"Don't actually delete anything but only list all found pods matching the target - env variable: KREAPER_DRY_RUN",
|
|
)
|
|
|
|
flag.DurationVar(
|
|
&kreaper.Lifetime,
|
|
"lifetime",
|
|
lookupEnvOr("KREAPER_LIFETIME", defaultKreaperLifetime, time.ParseDuration),
|
|
"Lifetime after which all matching targets will be deleted - env variable: KREAPER_LIFETIME",
|
|
)
|
|
|
|
flag.StringVar(
|
|
&kreaper.TargetNamespace,
|
|
"target-namespace",
|
|
lookupEnvOr("KREAPER_TARGET_NAMESPACE", "default", identity[string]),
|
|
"Set target namespace in which kreaper will look for pods - env variable: KREAPER_TARGET_NAMESPACE",
|
|
)
|
|
|
|
var kubeconfigFallback string
|
|
if home := homedir.HomeDir(); home != "" {
|
|
kubeconfigFallback = filepath.Join(home, ".kube", "config")
|
|
}
|
|
|
|
flag.StringVar(
|
|
&kubeconfig,
|
|
"kubeconfig",
|
|
lookupEnvOr("KUBECONFIG", kubeconfigFallback, identity[string]),
|
|
"absolute path to the kubeconfig file",
|
|
)
|
|
|
|
flag.Parse()
|
|
}
|
|
|
|
func loadRestConfig() (cfg *rest.Config, err error) {
|
|
if cfg, err = rest.InClusterConfig(); err == nil {
|
|
return cfg, nil
|
|
}
|
|
|
|
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
|
}
|
|
|
|
//nolint:nolintlint // false postivie
|
|
//nolint:ireturn // false positive
|
|
func lookupEnvOr[T any](envKey string, fallback T, parse func(envVal string) (T, error)) T {
|
|
envVal := os.Getenv(envKey)
|
|
if envVal == "" {
|
|
return fallback
|
|
}
|
|
|
|
if parsed, err := parse(envVal); err != nil {
|
|
return fallback
|
|
} else {
|
|
return parsed
|
|
}
|
|
}
|
|
|
|
//nolint:nolintlint // false postivie
|
|
//nolint:ireturn // false positive
|
|
func identity[T any](in T) (T, error) {
|
|
return in, nil
|
|
}
|