1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00
kyverno/cmd/cleanup-controller/main.go
Ved Ratan 9f2cc6c99c
feat: add ttl controller (#7821)
* added the ttl controller

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fixed label and vars

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* added logger

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* applied fixes

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* removed comments

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* lint

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* lint

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* lint

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* more lint fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* applied changes

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* minor fixes

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix logger, separate parse logic

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* added tests

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* added kuttl tests, validation utilities

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* commented code

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* renamed tests

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix test

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* created log.go

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix log.go

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* added README.md refactor code

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* lint fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* lint

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* lint fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* added validation webhook

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* label-validation fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* added flag, updated verbs

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* updated verbs

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* updated helm chart

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* test fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* lint

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* linter

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* imporoved webhook validation

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* linter fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* lint

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* lint fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* fix codegen

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* webhook names and path constants

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* constant label

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix label selector

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* kuttl test fix

Signed-off-by: Ved Ratan <vedratan8@gmail.com>

* helm docs

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix controller logger

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix: manager logger

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix failure policy

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* kuttl tests

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* move kuttl tests in separate job

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* remove rbac steps

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* remove configmaps from core cluster role

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix logger

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* rename flag

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* kuttl

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix error

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* fix linter

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

---------

Signed-off-by: Ved Ratan <vedratan8@gmail.com>
Signed-off-by: Ved Ratan <82467006+VedRatan@users.noreply.github.com>
Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
2023-08-02 16:47:40 +02:00

310 lines
10 KiB
Go

package main
import (
"context"
"errors"
"flag"
"os"
"sync"
"time"
"github.com/kyverno/kyverno/api/kyverno"
admissionhandlers "github.com/kyverno/kyverno/cmd/cleanup-controller/handlers/admission"
cleanuphandlers "github.com/kyverno/kyverno/cmd/cleanup-controller/handlers/cleanup"
labelhandlers "github.com/kyverno/kyverno/cmd/cleanup-controller/handlers/resource-admission"
"github.com/kyverno/kyverno/cmd/internal"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/controllers/certmanager"
"github.com/kyverno/kyverno/pkg/controllers/cleanup"
genericloggingcontroller "github.com/kyverno/kyverno/pkg/controllers/generic/logging"
genericwebhookcontroller "github.com/kyverno/kyverno/pkg/controllers/generic/webhook"
ttlcontroller "github.com/kyverno/kyverno/pkg/controllers/ttl-controller"
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/informers"
"github.com/kyverno/kyverno/pkg/leaderelection"
"github.com/kyverno/kyverno/pkg/logging"
"github.com/kyverno/kyverno/pkg/tls"
"github.com/kyverno/kyverno/pkg/webhooks"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeinformers "k8s.io/client-go/informers"
)
const (
resyncPeriod = 15 * time.Minute
webhookWorkers = 2
policyWebhookControllerName = "policy-webhook-controller"
ttlWebhookControllerName = "ttl-webhook-controller"
)
// TODO:
// - helm review labels / selectors
// - implement probes
// - supports certs in cronjob
type probes struct{}
func (probes) IsReady(context.Context) bool {
return true
}
func (probes) IsLive(context.Context) bool {
return true
}
func main() {
var (
dumpPayload bool
serverIP string
servicePort int
maxQueuedEvents int
interval time.Duration
)
flagset := flag.NewFlagSet("cleanup-controller", flag.ExitOnError)
flagset.BoolVar(&dumpPayload, "dumpPayload", false, "Set this flag to activate/deactivate debug mode.")
flagset.StringVar(&serverIP, "serverIP", "", "IP address where Kyverno controller runs. Only required if out-of-cluster.")
flagset.IntVar(&servicePort, "servicePort", 443, "Port used by the Kyverno Service resource and for webhook configurations.")
flagset.IntVar(&maxQueuedEvents, "maxQueuedEvents", 1000, "Maximum events to be queued.")
flagset.DurationVar(&interval, "ttlReconciliationInterval", time.Minute, "Set this flag to set the interval after which the resource controller reconciliation should occur")
// config
appConfig := internal.NewConfiguration(
internal.WithProfiling(),
internal.WithMetrics(),
internal.WithTracing(),
internal.WithKubeconfig(),
internal.WithLeaderElection(),
internal.WithKyvernoClient(),
internal.WithKyvernoDynamicClient(),
internal.WithConfigMapCaching(),
internal.WithDeferredLoading(),
internal.WithFlagSets(flagset),
internal.WithMetadataClient(),
)
// parse flags
internal.ParseFlags(appConfig)
// setup
ctx, setup, sdown := internal.Setup(appConfig, "kyverno-cleanup-controller", false)
defer sdown()
// certificates informers
caSecret := informers.NewSecretInformer(setup.KubeClient, config.KyvernoNamespace(), tls.GenerateRootCASecretName(), resyncPeriod)
tlsSecret := informers.NewSecretInformer(setup.KubeClient, config.KyvernoNamespace(), tls.GenerateTLSPairSecretName(), resyncPeriod)
if !informers.StartInformersAndWaitForCacheSync(ctx, setup.Logger, caSecret, tlsSecret) {
setup.Logger.Error(errors.New("failed to wait for cache sync"), "failed to wait for cache sync")
os.Exit(1)
}
// setup leader election
le, err := leaderelection.New(
setup.Logger.WithName("leader-election"),
"kyverno-cleanup-controller",
config.KyvernoNamespace(),
setup.LeaderElectionClient,
config.KyvernoPodName(),
internal.LeaderElectionRetryPeriod(),
func(ctx context.Context) {
logger := setup.Logger.WithName("leader")
// informer factories
kubeInformer := kubeinformers.NewSharedInformerFactoryWithOptions(setup.KubeClient, resyncPeriod)
kyvernoInformer := kyvernoinformer.NewSharedInformerFactory(setup.KyvernoClient, resyncPeriod)
// controllers
renewer := tls.NewCertRenewer(
setup.KubeClient.CoreV1().Secrets(config.KyvernoNamespace()),
tls.CertRenewalInterval,
tls.CAValidityDuration,
tls.TLSValidityDuration,
serverIP,
)
certController := internal.NewController(
certmanager.ControllerName,
certmanager.NewController(
caSecret,
tlsSecret,
renewer,
),
certmanager.Workers,
)
policyValidatingWebhookController := internal.NewController(
policyWebhookControllerName,
genericwebhookcontroller.NewController(
policyWebhookControllerName,
setup.KubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations(),
kubeInformer.Admissionregistration().V1().ValidatingWebhookConfigurations(),
caSecret,
config.CleanupValidatingWebhookConfigurationName,
config.CleanupValidatingWebhookServicePath,
serverIP,
int32(servicePort),
nil,
[]admissionregistrationv1.RuleWithOperations{
{
Rule: admissionregistrationv1.Rule{
APIGroups: []string{"kyverno.io"},
APIVersions: []string{"v2alpha1"},
Resources: []string{
"cleanuppolicies/*",
"clustercleanuppolicies/*",
},
},
Operations: []admissionregistrationv1.OperationType{
admissionregistrationv1.Create,
admissionregistrationv1.Update,
},
},
},
genericwebhookcontroller.Fail,
genericwebhookcontroller.None,
setup.Configuration,
),
webhookWorkers,
)
ttlWebhookController := internal.NewController(
ttlWebhookControllerName,
genericwebhookcontroller.NewController(
ttlWebhookControllerName,
setup.KubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations(),
kubeInformer.Admissionregistration().V1().ValidatingWebhookConfigurations(),
caSecret,
config.TtlValidatingWebhookConfigurationName,
config.TtlValidatingWebhookServicePath,
serverIP,
int32(servicePort),
&metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: kyverno.LabelCleanupTtl,
Operator: metav1.LabelSelectorOpExists,
},
},
},
[]admissionregistrationv1.RuleWithOperations{
{
Rule: admissionregistrationv1.Rule{
APIGroups: []string{"*"},
APIVersions: []string{"*"},
Resources: []string{"*"},
},
Operations: []admissionregistrationv1.OperationType{
admissionregistrationv1.Create,
admissionregistrationv1.Update,
},
},
},
genericwebhookcontroller.Ignore,
genericwebhookcontroller.None,
setup.Configuration,
),
webhookWorkers,
)
cleanupController := internal.NewController(
cleanup.ControllerName,
cleanup.NewController(
setup.KubeClient,
kyvernoInformer.Kyverno().V2alpha1().ClusterCleanupPolicies(),
kyvernoInformer.Kyverno().V2alpha1().CleanupPolicies(),
kubeInformer.Batch().V1().CronJobs(),
"https://"+config.KyvernoServiceName()+"."+config.KyvernoNamespace()+".svc",
),
cleanup.Workers,
)
ttlManagerController := internal.NewController(
ttlcontroller.ControllerName,
ttlcontroller.NewManager(
setup.MetadataClient,
setup.KubeClient.Discovery(),
setup.KubeClient.AuthorizationV1(),
interval,
),
ttlcontroller.Workers,
)
// start informers and wait for cache sync
if !internal.StartInformersAndWaitForCacheSync(ctx, logger, kyvernoInformer, kubeInformer) {
logger.Error(errors.New("failed to wait for cache sync"), "failed to wait for cache sync")
os.Exit(1)
}
// start leader controllers
var wg sync.WaitGroup
certController.Run(ctx, logger, &wg)
policyValidatingWebhookController.Run(ctx, logger, &wg)
ttlWebhookController.Run(ctx, logger, &wg)
cleanupController.Run(ctx, logger, &wg)
ttlManagerController.Run(ctx, logger, &wg)
wg.Wait()
},
nil,
)
if err != nil {
setup.Logger.Error(err, "failed to initialize leader election")
os.Exit(1)
}
// informer factories
kubeInformer := kubeinformers.NewSharedInformerFactoryWithOptions(setup.KubeClient, resyncPeriod)
kyvernoInformer := kyvernoinformer.NewSharedInformerFactory(setup.KyvernoClient, resyncPeriod)
// listers
cpolLister := kyvernoInformer.Kyverno().V2alpha1().ClusterCleanupPolicies().Lister()
polLister := kyvernoInformer.Kyverno().V2alpha1().CleanupPolicies().Lister()
nsLister := kubeInformer.Core().V1().Namespaces().Lister()
// log policy changes
genericloggingcontroller.NewController(
setup.Logger.WithName("cleanup-policy"),
"CleanupPolicy",
kyvernoInformer.Kyverno().V2alpha1().CleanupPolicies(),
genericloggingcontroller.CheckGeneration,
)
genericloggingcontroller.NewController(
setup.Logger.WithName("cluster-cleanup-policy"),
"ClusterCleanupPolicy",
kyvernoInformer.Kyverno().V2alpha1().ClusterCleanupPolicies(),
genericloggingcontroller.CheckGeneration,
)
eventGenerator := event.NewEventCleanupGenerator(
setup.KyvernoDynamicClient,
kyvernoInformer.Kyverno().V2alpha1().ClusterCleanupPolicies(),
kyvernoInformer.Kyverno().V2alpha1().CleanupPolicies(),
maxQueuedEvents,
logging.WithName("EventGenerator"),
)
// start informers and wait for cache sync
if !internal.StartInformersAndWaitForCacheSync(ctx, setup.Logger, kubeInformer, kyvernoInformer) {
os.Exit(1)
}
// start event generator
var wg sync.WaitGroup
go eventGenerator.Run(ctx, 3, &wg)
// create handlers
admissionHandlers := admissionhandlers.New(setup.KyvernoDynamicClient)
cmResolver := internal.NewConfigMapResolver(ctx, setup.Logger, setup.KubeClient, resyncPeriod)
cleanupHandlers := cleanuphandlers.New(
setup.Logger.WithName("cleanup-handler"),
setup.KyvernoDynamicClient,
cpolLister,
polLister,
nsLister,
cmResolver,
setup.Jp,
eventGenerator,
)
// create server
server := NewServer(
func() ([]byte, []byte, error) {
secret, err := tlsSecret.Lister().Secrets(config.KyvernoNamespace()).Get(tls.GenerateTLSPairSecretName())
if err != nil {
return nil, nil, err
}
return secret.Data[corev1.TLSCertKey], secret.Data[corev1.TLSPrivateKeyKey], nil
},
admissionHandlers.Validate,
labelhandlers.Validate,
cleanupHandlers.Cleanup,
setup.MetricsManager,
webhooks.DebugModeOptions{
DumpPayload: dumpPayload,
},
probes{},
setup.Configuration,
)
// start server
server.Run(ctx.Done())
// start leader election
le.Run(ctx)
}