2023-01-20 15:53:27 +00:00
package main
import (
"context"
"errors"
"flag"
"os"
2023-05-10 11:48:41 +00:00
"strings"
2023-01-20 15:53:27 +00:00
"sync"
"time"
"github.com/kyverno/kyverno/cmd/internal"
"github.com/kyverno/kyverno/pkg/background"
2024-10-02 12:05:05 +00:00
"github.com/kyverno/kyverno/pkg/breaker"
2023-01-20 15:53:27 +00:00
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"github.com/kyverno/kyverno/pkg/config"
2024-02-02 11:37:58 +00:00
globalcontextcontroller "github.com/kyverno/kyverno/pkg/controllers/globalcontext"
2023-01-20 15:53:27 +00:00
policymetricscontroller "github.com/kyverno/kyverno/pkg/controllers/metrics/policy"
2023-01-31 07:46:38 +00:00
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
2023-11-21 10:01:51 +00:00
"github.com/kyverno/kyverno/pkg/engine/apicall"
2023-04-13 11:29:40 +00:00
"github.com/kyverno/kyverno/pkg/engine/jmespath"
2023-01-20 15:53:27 +00:00
"github.com/kyverno/kyverno/pkg/event"
2024-02-02 14:35:24 +00:00
"github.com/kyverno/kyverno/pkg/globalcontext/store"
2023-01-20 15:53:27 +00:00
"github.com/kyverno/kyverno/pkg/leaderelection"
"github.com/kyverno/kyverno/pkg/logging"
"github.com/kyverno/kyverno/pkg/metrics"
"github.com/kyverno/kyverno/pkg/policy"
2024-06-11 08:54:51 +00:00
"github.com/kyverno/kyverno/pkg/utils/generator"
2024-02-01 10:14:05 +00:00
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
apiserver "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
2023-01-20 15:53:27 +00:00
kubeinformers "k8s.io/client-go/informers"
kyamlopenapi "sigs.k8s.io/kustomize/kyaml/openapi"
)
const (
resyncPeriod = 15 * time . Minute
)
2024-02-01 10:14:05 +00:00
func sanityChecks ( apiserverClient apiserver . Interface ) error {
return kubeutils . CRDsInstalled ( apiserverClient , "updaterequests.kyverno.io" )
}
2023-01-20 15:53:27 +00:00
func createrLeaderControllers (
2023-02-03 05:01:11 +00:00
eng engineapi . Engine ,
2023-02-07 13:44:51 +00:00
genWorkers int ,
2023-01-20 15:53:27 +00:00
kubeInformer kubeinformers . SharedInformerFactory ,
kyvernoInformer kyvernoinformer . SharedInformerFactory ,
kyvernoClient versioned . Interface ,
dynamicClient dclient . Interface ,
configuration config . Configuration ,
metricsConfig metrics . MetricsConfigManager ,
eventGenerator event . Interface ,
2023-04-13 11:29:40 +00:00
jp jmespath . Interface ,
2023-06-13 12:21:40 +00:00
backgroundScanInterval time . Duration ,
2024-06-11 08:54:51 +00:00
urGenerator generator . UpdateRequestGenerator ,
2024-10-09 10:43:59 +00:00
backgroundReports bool ,
2024-10-02 12:05:05 +00:00
reportsBreaker breaker . Breaker ,
2023-01-20 15:53:27 +00:00
) ( [ ] internal . Controller , error ) {
policyCtrl , err := policy . NewPolicyController (
kyvernoClient ,
dynamicClient ,
2023-02-03 05:01:11 +00:00
eng ,
2023-01-20 15:53:27 +00:00
kyvernoInformer . Kyverno ( ) . V1 ( ) . ClusterPolicies ( ) ,
kyvernoInformer . Kyverno ( ) . V1 ( ) . Policies ( ) ,
2024-06-20 09:44:43 +00:00
kyvernoInformer . Kyverno ( ) . V2 ( ) . UpdateRequests ( ) ,
2023-01-20 15:53:27 +00:00
configuration ,
eventGenerator ,
kubeInformer . Core ( ) . V1 ( ) . Namespaces ( ) ,
logging . WithName ( "PolicyController" ) ,
2023-06-13 12:21:40 +00:00
backgroundScanInterval ,
2023-01-20 15:53:27 +00:00
metricsConfig ,
2023-04-13 11:29:40 +00:00
jp ,
2024-06-11 08:54:51 +00:00
urGenerator ,
2023-01-20 15:53:27 +00:00
)
if err != nil {
return nil , err
}
2023-02-07 13:44:51 +00:00
backgroundController := background . NewController (
kyvernoClient ,
dynamicClient ,
eng ,
kyvernoInformer . Kyverno ( ) . V1 ( ) . ClusterPolicies ( ) ,
kyvernoInformer . Kyverno ( ) . V1 ( ) . Policies ( ) ,
2024-06-20 09:44:43 +00:00
kyvernoInformer . Kyverno ( ) . V2 ( ) . UpdateRequests ( ) ,
2023-02-07 13:44:51 +00:00
kubeInformer . Core ( ) . V1 ( ) . Namespaces ( ) ,
eventGenerator ,
configuration ,
2023-04-13 11:29:40 +00:00
jp ,
2024-10-09 10:43:59 +00:00
backgroundReports ,
2024-10-02 12:05:05 +00:00
reportsBreaker ,
2023-02-07 13:44:51 +00:00
)
2023-01-20 15:53:27 +00:00
return [ ] internal . Controller {
internal . NewController ( "policy-controller" , policyCtrl , 2 ) ,
2023-02-07 13:44:51 +00:00
internal . NewController ( "background-controller" , backgroundController , genWorkers ) ,
2023-01-20 15:53:27 +00:00
} , err
}
func main ( ) {
var (
2023-11-21 10:01:51 +00:00
genWorkers int
maxQueuedEvents int
omitEvents string
maxAPICallResponseLength int64
2024-10-09 10:43:59 +00:00
backgroundReports bool
2024-10-02 12:05:05 +00:00
maxBackgroundReports int
2023-01-20 15:53:27 +00:00
)
flagset := flag . NewFlagSet ( "updaterequest-controller" , flag . ExitOnError )
2023-02-07 13:44:51 +00:00
flagset . IntVar ( & genWorkers , "genWorkers" , 10 , "Workers for the background controller." )
2023-01-20 15:53:27 +00:00
flagset . IntVar ( & maxQueuedEvents , "maxQueuedEvents" , 1000 , "Maximum events to be queued." )
2024-01-30 23:41:13 +00:00
flagset . StringVar ( & omitEvents , "omitEvents" , "" , "Set this flag to a comma sperated list of PolicyViolation, PolicyApplied, PolicyError, PolicySkipped to disable events, e.g. --omitEvents=PolicyApplied,PolicyViolation" )
2023-11-21 10:01:51 +00:00
flagset . Int64Var ( & maxAPICallResponseLength , "maxAPICallResponseLength" , 2 * 1000 * 1000 , "Maximum allowed response size from API Calls. A value of 0 bypasses checks (not recommended)." )
2024-10-11 07:34:41 +00:00
flagset . IntVar ( & maxBackgroundReports , "maxBackgroundReports" , 10000 , "Maximum number of ephemeralreports created for the background policies." )
2024-10-09 10:43:59 +00:00
flagset . BoolVar ( & backgroundReports , "backgroundReports" , true , "Enables or disables reports for mutate existing and generate rules." )
2024-10-11 07:34:41 +00:00
2023-01-20 15:53:27 +00:00
// config
appConfig := internal . NewConfiguration (
internal . WithProfiling ( ) ,
internal . WithMetrics ( ) ,
internal . WithTracing ( ) ,
internal . WithKubeconfig ( ) ,
2023-04-11 07:12:05 +00:00
internal . WithPolicyExceptions ( ) ,
internal . WithConfigMapCaching ( ) ,
2023-06-27 05:44:15 +00:00
internal . WithDeferredLoading ( ) ,
2023-04-11 13:32:17 +00:00
internal . WithRegistryClient ( ) ,
2023-04-11 17:44:49 +00:00
internal . WithLeaderElection ( ) ,
2023-04-14 09:00:52 +00:00
internal . WithKyvernoClient ( ) ,
internal . WithDynamicClient ( ) ,
internal . WithKyvernoDynamicClient ( ) ,
2024-01-03 01:12:05 +00:00
internal . WithEventsClient ( ) ,
2024-02-01 10:14:05 +00:00
internal . WithApiServerClient ( ) ,
2024-06-11 08:54:51 +00:00
internal . WithMetadataClient ( ) ,
2023-01-20 15:53:27 +00:00
internal . WithFlagSets ( flagset ) ,
)
// parse flags
internal . ParseFlags ( appConfig )
2024-06-10 09:11:07 +00:00
var wg sync . WaitGroup
func ( ) {
// setup
signalCtx , setup , sdown := internal . Setup ( appConfig , "kyverno-background-controller" , false )
defer sdown ( )
var err error
2024-10-02 12:05:05 +00:00
bgscanInterval := 30 * time . Second
2024-06-10 09:11:07 +00:00
val := os . Getenv ( "BACKGROUND_SCAN_INTERVAL" )
if val != "" {
if bgscanInterval , err = time . ParseDuration ( val ) ; err != nil {
setup . Logger . Error ( err , "failed to set the background scan interval" )
os . Exit ( 1 )
}
}
setup . Logger . V ( 2 ) . Info ( "setting the background scan interval" , "value" , bgscanInterval . String ( ) )
// THIS IS AN UGLY FIX
// ELSE KYAML IS NOT THREAD SAFE
kyamlopenapi . Schema ( )
if err := sanityChecks ( setup . ApiServerClient ) ; err != nil {
setup . Logger . Error ( err , "sanity checks failed" )
2023-06-13 12:21:40 +00:00
os . Exit ( 1 )
}
2024-06-10 09:11:07 +00:00
// informer factories
kyvernoInformer := kyvernoinformer . NewSharedInformerFactory ( setup . KyvernoClient , resyncPeriod )
polexCache , polexController := internal . NewExceptionSelector ( setup . Logger , kyvernoInformer )
eventGenerator := event . NewEventGenerator (
setup . EventsClient ,
logging . WithName ( "EventGenerator" ) ,
maxQueuedEvents ,
strings . Split ( omitEvents , "," ) ... ,
)
eventController := internal . NewController (
event . ControllerName ,
2024-02-23 10:34:04 +00:00
eventGenerator ,
2024-06-10 09:11:07 +00:00
event . Workers ,
)
2024-06-11 08:54:51 +00:00
urGenerator := generator . NewUpdateRequestGenerator ( setup . Configuration , setup . MetadataClient )
2024-06-10 09:11:07 +00:00
gcstore := store . New ( )
gceController := internal . NewController (
globalcontextcontroller . ControllerName ,
globalcontextcontroller . NewController (
kyvernoInformer . Kyverno ( ) . V2alpha1 ( ) . GlobalContextEntries ( ) ,
2023-04-14 09:00:52 +00:00
setup . KyvernoDynamicClient ,
2024-06-10 09:11:07 +00:00
setup . KyvernoClient ,
gcstore ,
2023-01-20 15:53:27 +00:00
eventGenerator ,
2024-06-10 09:11:07 +00:00
maxAPICallResponseLength ,
false ,
) ,
globalcontextcontroller . Workers ,
) // this controller only subscribe to events, nothing is returned...
policymetricscontroller . NewController (
setup . MetricsManager ,
kyvernoInformer . Kyverno ( ) . V1 ( ) . ClusterPolicies ( ) ,
kyvernoInformer . Kyverno ( ) . V1 ( ) . Policies ( ) ,
& wg ,
)
engine := internal . NewEngine (
signalCtx ,
setup . Logger ,
setup . Configuration ,
setup . MetricsConfiguration ,
setup . Jp ,
setup . KyvernoDynamicClient ,
setup . RegistryClient ,
setup . ImageVerifyCacheClient ,
setup . KubeClient ,
setup . KyvernoClient ,
setup . RegistrySecretLister ,
apicall . NewAPICallConfiguration ( maxAPICallResponseLength ) ,
polexCache ,
gcstore ,
)
2024-10-02 12:05:05 +00:00
ephrs , err := breaker . StartBackgroundReportsCounter ( signalCtx , setup . MetadataClient )
if err != nil {
setup . Logger . Error ( err , "failed to start background-scan reports watcher" )
os . Exit ( 1 )
}
reportsBreaker := breaker . NewBreaker ( "background scan reports" , func ( context . Context ) bool {
count , isRunning := ephrs . Count ( )
if ! isRunning {
return true
}
return count > maxBackgroundReports
} )
2024-06-10 09:11:07 +00:00
// start informers and wait for cache sync
if ! internal . StartInformersAndWaitForCacheSync ( signalCtx , setup . Logger , kyvernoInformer ) {
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-background-controller" ,
config . KyvernoNamespace ( ) ,
setup . LeaderElectionClient ,
config . KyvernoPodName ( ) ,
internal . LeaderElectionRetryPeriod ( ) ,
func ( ctx context . Context ) {
logger := setup . Logger . WithName ( "leader" )
// create leader factories
kubeInformer := kubeinformers . NewSharedInformerFactory ( setup . KubeClient , resyncPeriod )
kyvernoInformer := kyvernoinformer . NewSharedInformerFactory ( setup . KyvernoClient , resyncPeriod )
// create leader controllers
leaderControllers , err := createrLeaderControllers (
engine ,
genWorkers ,
kubeInformer ,
kyvernoInformer ,
setup . KyvernoClient ,
setup . KyvernoDynamicClient ,
setup . Configuration ,
setup . MetricsManager ,
eventGenerator ,
setup . Jp ,
bgscanInterval ,
2024-06-11 08:54:51 +00:00
urGenerator ,
2024-10-09 10:43:59 +00:00
backgroundReports ,
2024-10-02 12:05:05 +00:00
reportsBreaker ,
2024-06-10 09:11:07 +00:00
)
if err != nil {
logger . Error ( err , "failed to create leader controllers" )
os . Exit ( 1 )
}
// start informers and wait for cache sync
if ! internal . StartInformersAndWaitForCacheSync ( signalCtx , 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
for _ , controller := range leaderControllers {
controller . Run ( signalCtx , logger . WithName ( "controllers" ) , & wg )
}
// wait all controllers shut down
wg . Wait ( )
} ,
nil ,
)
if err != nil {
setup . Logger . Error ( err , "failed to initialize leader election" )
os . Exit ( 1 )
}
// start non leader controllers
eventController . Run ( signalCtx , setup . Logger , & wg )
gceController . Run ( signalCtx , setup . Logger , & wg )
if polexController != nil {
polexController . Run ( signalCtx , setup . Logger , & wg )
}
// start leader election
le . Run ( signalCtx )
} ( )
2024-01-30 22:08:15 +00:00
// wait for everything to shut down and exit
2023-04-03 15:17:44 +00:00
wg . Wait ( )
2023-01-20 15:53:27 +00:00
}