2022-11-14 12:00:40 +01:00
package main
2022-11-14 18:30:12 +01:00
import (
"context"
"flag"
2022-11-16 18:41:33 +05:30
"net/http"
2022-11-14 18:30:12 +01:00
"os"
2022-11-25 15:29:45 +05:30
"os/signal"
"sync"
"syscall"
2022-11-14 18:30:12 +01:00
"time"
"github.com/go-logr/logr"
2022-11-18 15:21:15 +01:00
"github.com/kyverno/kyverno/cmd/internal"
2022-11-25 15:29:45 +05:30
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions"
2022-11-16 18:41:33 +05:30
"github.com/kyverno/kyverno/pkg/clients/dclient"
2022-11-22 14:37:27 +01:00
dynamicclient "github.com/kyverno/kyverno/pkg/clients/dynamic"
2022-11-21 18:16:25 +01:00
kubeclient "github.com/kyverno/kyverno/pkg/clients/kube"
2022-11-25 15:29:45 +05:30
kyvernoclient "github.com/kyverno/kyverno/pkg/clients/kyverno"
2022-11-14 18:30:12 +01:00
"github.com/kyverno/kyverno/pkg/config"
2022-11-25 15:29:45 +05:30
"github.com/kyverno/kyverno/pkg/controllers/cleanup"
2022-11-14 18:30:12 +01:00
"github.com/kyverno/kyverno/pkg/logging"
2022-11-16 18:41:33 +05:30
"github.com/kyverno/kyverno/pkg/metrics"
2022-11-14 18:30:12 +01:00
corev1 "k8s.io/api/core/v1"
kubeinformers "k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
)
var (
2022-11-16 18:41:33 +05:30
otel string
otelCollector string
metricsPort string
transportCreds string
disableMetricsExport bool
2022-11-14 18:30:12 +01:00
)
const (
2022-11-18 15:21:15 +01:00
resyncPeriod = 15 * time . Minute
2022-11-14 18:30:12 +01:00
)
2022-11-28 11:30:14 +01:00
func setupMetrics ( ctx context . Context , logger logr . Logger , kubeClient kubernetes . Interface ) ( * metrics . MetricsConfig , context . CancelFunc , error ) {
2022-11-16 18:41:33 +05:30
logger = logger . WithName ( "metrics" )
logger . Info ( "setup metrics..." , "otel" , otel , "port" , metricsPort , "collector" , otelCollector , "creds" , transportCreds )
2022-11-25 14:14:55 +01:00
metricsConfiguration := internal . GetMetricsConfiguration ( logger , kubeClient )
2022-11-16 18:41:33 +05:30
metricsAddr := ":" + metricsPort
metricsConfig , metricsServerMux , metricsPusher , err := metrics . InitMetrics (
2022-11-28 11:30:14 +01:00
ctx ,
2022-11-16 18:41:33 +05:30
disableMetricsExport ,
otel ,
metricsAddr ,
otelCollector ,
2022-11-25 14:14:55 +01:00
metricsConfiguration ,
2022-11-16 18:41:33 +05:30
transportCreds ,
kubeClient ,
logging . WithName ( "metrics" ) ,
)
if err != nil {
return nil , nil , err
}
var cancel context . CancelFunc
if otel == "grpc" {
cancel = func ( ) {
ctx , cancel := context . WithTimeout ( context . Background ( ) , 20 * time . Second )
defer cancel ( )
metrics . ShutDownController ( ctx , metricsPusher )
}
}
if otel == "prometheus" {
go func ( ) {
if err := http . ListenAndServe ( metricsAddr , metricsServerMux ) ; err != nil {
logger . Error ( err , "failed to enable metrics" , "address" , metricsAddr )
}
} ( )
}
return metricsConfig , cancel , nil
}
2022-11-25 15:29:45 +05:30
func setupSignals ( ) ( context . Context , context . CancelFunc ) {
return signal . NotifyContext ( context . Background ( ) , os . Interrupt , syscall . SIGTERM )
}
2022-11-14 12:00:40 +01:00
func main ( ) {
2022-11-24 20:57:01 +01:00
// application flags
flagset := flag . NewFlagSet ( "application" , flag . ExitOnError )
flagset . StringVar ( & otel , "otelConfig" , "prometheus" , "Set this flag to 'grpc', to enable exporting metrics to an Opentelemetry Collector. The default collector is set to \"prometheus\"" )
flagset . StringVar ( & otelCollector , "otelCollector" , "opentelemetrycollector.kyverno.svc.cluster.local" , "Set this flag to the OpenTelemetry Collector Service Address. Kyverno will try to connect to this on the metrics port." )
flagset . StringVar ( & transportCreds , "transportCreds" , "" , "Set this flag to the CA secret containing the certificate which is used by our Opentelemetry Metrics Client. If empty string is set, means an insecure connection will be used" )
flagset . StringVar ( & metricsPort , "metricsPort" , "8000" , "Expose prometheus metrics at the given port, default to 8000." )
flagset . BoolVar ( & disableMetricsExport , "disableMetrics" , false , "Set this flag to 'true' to disable metrics." )
2022-11-18 15:21:15 +01:00
// config
2022-11-23 11:36:15 +01:00
appConfig := internal . NewConfiguration (
internal . WithProfiling ( ) ,
internal . WithTracing ( ) ,
internal . WithKubeconfig ( ) ,
2022-11-24 20:57:01 +01:00
internal . WithFlagSets ( flagset ) ,
2022-11-23 11:36:15 +01:00
)
2022-11-14 18:30:12 +01:00
// parse flags
2022-11-24 20:57:01 +01:00
internal . ParseFlags ( appConfig )
2022-11-14 18:30:12 +01:00
// setup logger
2022-11-18 15:21:15 +01:00
// show version
// start profiling
2022-11-24 20:57:01 +01:00
// setup signals
// setup maxprocs
ctx , logger , sdown := internal . Setup ( )
defer sdown ( )
2022-11-23 11:36:15 +01:00
// create raw client
rawClient := internal . CreateKubernetesClient ( logger )
2022-11-17 17:01:30 +01:00
// setup metrics
2022-11-28 11:30:14 +01:00
metricsConfig , metricsShutdown , err := setupMetrics ( ctx , logger , rawClient )
2022-11-16 18:41:33 +05:30
if err != nil {
logger . Error ( err , "failed to setup metrics" )
os . Exit ( 1 )
}
if metricsShutdown != nil {
defer metricsShutdown ( )
}
2022-11-25 15:29:45 +05:30
// setup signals
signalCtx , signalCancel := setupSignals ( )
defer signalCancel ( )
2022-11-17 17:01:30 +01:00
// create instrumented clients
2022-11-23 11:36:15 +01:00
kubeClient := internal . CreateKubernetesClient ( logger , kubeclient . WithMetrics ( metricsConfig , metrics . KubeClient ) , kubeclient . WithTracing ( ) )
dynamicClient := internal . CreateDynamicClient ( logger , dynamicclient . WithMetrics ( metricsConfig , metrics . KyvernoClient ) , dynamicclient . WithTracing ( ) )
dClient , err := dclient . NewClient ( signalCtx , dynamicClient , kubeClient , 15 * time . Minute )
2022-11-16 18:41:33 +05:30
if err != nil {
2022-11-23 11:36:15 +01:00
logger . Error ( err , "failed to create dynamic client" )
2022-11-16 18:41:33 +05:30
os . Exit ( 1 )
}
2022-11-25 15:29:45 +05:30
clientConfig := internal . CreateClientConfig ( logger )
kyvernoClient , err := kyvernoclient . NewForConfig (
clientConfig ,
kyvernoclient . WithMetrics ( metricsConfig , metrics . KubeClient ) ,
kyvernoclient . WithTracing ( ) ,
)
if err != nil {
logger . Error ( err , "failed to create kyverno client" )
os . Exit ( 1 )
}
kubeInformer := kubeinformers . NewSharedInformerFactoryWithOptions ( kubeClient , resyncPeriod )
2022-11-17 17:01:30 +01:00
kubeKyvernoInformer := kubeinformers . NewSharedInformerFactoryWithOptions ( kubeClient , resyncPeriod , kubeinformers . WithNamespace ( config . KyvernoNamespace ( ) ) )
2022-11-25 15:29:45 +05:30
kyvernoInformer := kyvernoinformer . NewSharedInformerFactory ( kyvernoClient , resyncPeriod )
cleanupController := cleanup . NewController (
kubeClient ,
kyvernoInformer . Kyverno ( ) . V1alpha1 ( ) . ClusterCleanupPolicies ( ) ,
kyvernoInformer . Kyverno ( ) . V1alpha1 ( ) . CleanupPolicies ( ) ,
kubeInformer . Batch ( ) . V1 ( ) . CronJobs ( ) ,
)
controller := newController ( cleanup . ControllerName , * cleanupController , cleanup . Workers )
2022-11-16 18:41:33 +05:30
policyHandlers := NewHandlers (
2022-11-23 11:36:15 +01:00
dClient ,
2022-11-16 18:41:33 +05:30
)
2022-11-14 18:30:12 +01:00
secretLister := kubeKyvernoInformer . Core ( ) . V1 ( ) . Secrets ( ) . Lister ( )
2022-11-16 18:41:33 +05:30
// start informers and wait for cache sync
// we need to call start again because we potentially registered new informers
2022-11-24 20:57:01 +01:00
if ! internal . StartInformersAndWaitForCacheSync ( ctx , kubeKyvernoInformer ) {
2022-11-16 18:41:33 +05:30
os . Exit ( 1 )
}
2022-11-25 15:29:45 +05:30
var wg sync . WaitGroup
controller . run ( signalCtx , logger . WithName ( "cleanup-controller" ) , & wg )
2022-11-14 18:30:12 +01:00
server := NewServer (
2022-11-16 18:41:33 +05:30
policyHandlers ,
2022-11-14 18:30:12 +01:00
func ( ) ( [ ] byte , [ ] byte , error ) {
secret , err := secretLister . Secrets ( config . KyvernoNamespace ( ) ) . Get ( "cleanup-controller-tls" )
if err != nil {
return nil , nil , err
}
return secret . Data [ corev1 . TLSCertKey ] , secret . Data [ corev1 . TLSPrivateKeyKey ] , nil
} ,
)
// start webhooks server
2022-11-24 20:57:01 +01:00
server . Run ( ctx . Done ( ) )
2022-11-14 18:30:12 +01:00
// wait for termination signal
2022-11-24 20:57:01 +01:00
<- ctx . Done ( )
2022-11-25 15:29:45 +05:30
wg . Wait ( )
2022-11-14 12:00:40 +01:00
}