2022-10-07 12:53:54 +02:00
package policy
import (
2022-11-28 11:30:14 +01:00
"context"
2023-03-17 11:48:48 +01:00
"sync"
2022-11-28 11:30:14 +01:00
2022-10-07 12:53:54 +02:00
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
2022-12-06 16:41:00 +01:00
"github.com/kyverno/kyverno/pkg/autogen"
2022-10-07 12:53:54 +02:00
kyvernov1informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
2022-12-06 16:41:00 +01:00
kyvernov1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
2022-10-07 12:53:54 +02:00
"github.com/kyverno/kyverno/pkg/metrics"
controllerutils "github.com/kyverno/kyverno/pkg/utils/controller"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
2023-06-19 11:09:08 +02:00
"go.opentelemetry.io/otel"
2022-12-06 16:41:00 +01:00
"go.opentelemetry.io/otel/attribute"
2023-02-23 18:54:33 +01:00
"go.opentelemetry.io/otel/metric"
2022-12-06 16:41:00 +01:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
2022-10-07 12:53:54 +02:00
)
type controller struct {
2022-11-30 14:37:53 +01:00
metricsConfig metrics . MetricsConfigManager
2023-05-11 12:16:48 +02:00
ruleInfo metric . Float64ObservableGauge
2022-12-06 16:41:00 +01:00
// listers
cpolLister kyvernov1listers . ClusterPolicyLister
polLister kyvernov1listers . PolicyLister
2023-03-17 11:48:48 +01:00
waitGroup * sync . WaitGroup
2022-10-07 12:53:54 +02:00
}
2022-12-06 16:41:00 +01:00
// TODO: this is a strange controller, it only processes events, this should be changed to a real controller.
2023-03-17 11:48:48 +01:00
func NewController (
metricsConfig metrics . MetricsConfigManager ,
cpolInformer kyvernov1informers . ClusterPolicyInformer ,
polInformer kyvernov1informers . PolicyInformer ,
waitGroup * sync . WaitGroup ,
) {
2023-06-19 11:09:08 +02:00
meterProvider := otel . GetMeterProvider ( )
2022-12-06 16:41:00 +01:00
meter := meterProvider . Meter ( metrics . MeterName )
2023-02-23 18:54:33 +01:00
policyRuleInfoMetric , err := meter . Float64ObservableGauge (
2022-12-06 16:41:00 +01:00
"kyverno_policy_rule_info_total" ,
2023-05-11 12:16:48 +02:00
metric . WithDescription ( "can be used to track the info of the rules or/and policies present in the cluster. 0 means the rule doesn't exist and has been deleted, 1 means the rule is currently existent in the cluster" ) ,
2022-12-06 16:41:00 +01:00
)
if err != nil {
logger . Error ( err , "Failed to create instrument, kyverno_policy_rule_info_total" )
}
2022-10-07 12:53:54 +02:00
c := controller {
metricsConfig : metricsConfig ,
2022-12-06 16:41:00 +01:00
ruleInfo : policyRuleInfoMetric ,
cpolLister : cpolInformer . Lister ( ) ,
polLister : polInformer . Lister ( ) ,
2023-03-17 11:48:48 +01:00
waitGroup : waitGroup ,
2022-10-07 12:53:54 +02:00
}
controllerutils . AddEventHandlers ( cpolInformer . Informer ( ) , c . addPolicy , c . updatePolicy , c . deletePolicy )
controllerutils . AddEventHandlers ( polInformer . Informer ( ) , c . addNsPolicy , c . updateNsPolicy , c . deleteNsPolicy )
2022-12-06 16:41:00 +01:00
if c . ruleInfo != nil {
2023-02-23 18:54:33 +01:00
_ , err := meter . RegisterCallback ( c . report , c . ruleInfo )
2022-12-06 16:41:00 +01:00
if err != nil {
logger . Error ( err , "Failed to register callback" )
}
}
}
2023-02-23 18:54:33 +01:00
func ( c * controller ) report ( ctx context . Context , observer metric . Observer ) error {
2022-12-06 16:41:00 +01:00
pols , err := c . polLister . Policies ( metav1 . NamespaceAll ) . List ( labels . Everything ( ) )
if err != nil {
logger . Error ( err , "failed to list policies" )
2023-02-23 18:54:33 +01:00
return err
2022-12-06 16:41:00 +01:00
}
for _ , policy := range pols {
2023-02-23 18:54:33 +01:00
err := c . reportPolicy ( ctx , policy , observer )
2022-12-06 16:41:00 +01:00
if err != nil {
logger . Error ( err , "failed to report policy metric" , "policy" , policy )
2023-02-23 18:54:33 +01:00
return err
2022-12-06 16:41:00 +01:00
}
}
cpols , err := c . cpolLister . List ( labels . Everything ( ) )
if err != nil {
logger . Error ( err , "failed to list cluster policies" )
2023-02-23 18:54:33 +01:00
return err
2022-12-06 16:41:00 +01:00
}
for _ , policy := range cpols {
2023-02-23 18:54:33 +01:00
err := c . reportPolicy ( ctx , policy , observer )
2022-12-06 16:41:00 +01:00
if err != nil {
logger . Error ( err , "failed to report policy metric" , "policy" , policy )
2023-02-23 18:54:33 +01:00
return err
2022-12-06 16:41:00 +01:00
}
}
2023-02-23 18:54:33 +01:00
return nil
2022-12-06 16:41:00 +01:00
}
2023-02-23 18:54:33 +01:00
func ( c * controller ) reportPolicy ( ctx context . Context , policy kyvernov1 . PolicyInterface , observer metric . Observer ) error {
2022-12-06 16:41:00 +01:00
name , namespace , policyType , backgroundMode , validationMode , err := metrics . GetPolicyInfos ( policy )
if err != nil {
return err
}
if c . metricsConfig . Config ( ) . CheckNamespace ( namespace ) {
if policyType == metrics . Cluster {
namespace = "-"
}
policyAttributes := [ ] attribute . KeyValue {
attribute . String ( "policy_namespace" , namespace ) ,
attribute . String ( "policy_name" , name ) ,
attribute . Bool ( "status_ready" , policy . IsReady ( ) ) ,
attribute . String ( "policy_validation_mode" , string ( validationMode ) ) ,
attribute . String ( "policy_type" , string ( policyType ) ) ,
attribute . String ( "policy_background_mode" , string ( backgroundMode ) ) ,
}
for _ , rule := range autogen . ComputeRules ( policy ) {
ruleType := metrics . ParseRuleType ( rule )
ruleAttributes := [ ] attribute . KeyValue {
attribute . String ( "rule_name" , rule . Name ) ,
attribute . String ( "rule_type" , string ( ruleType ) ) ,
}
2023-05-11 12:16:48 +02:00
observer . ObserveFloat64 ( c . ruleInfo , 1 , metric . WithAttributes ( append ( ruleAttributes , policyAttributes ... ) ... ) )
2022-12-06 16:41:00 +01:00
}
}
return nil
2022-10-07 12:53:54 +02:00
}
2023-03-17 11:48:48 +01:00
func ( c * controller ) startRountine ( routine func ( ) ) {
c . waitGroup . Add ( 1 )
go func ( ) {
defer c . waitGroup . Done ( )
routine ( )
} ( )
}
2022-10-07 12:53:54 +02:00
func ( c * controller ) addPolicy ( obj interface { } ) {
p := obj . ( * kyvernov1 . ClusterPolicy )
// register kyverno_policy_changes_total metric concurrently
2023-03-17 11:48:48 +01:00
c . startRountine ( func ( ) { c . registerPolicyChangesMetricAddPolicy ( context . TODO ( ) , logger , p ) } )
2022-10-07 12:53:54 +02:00
}
func ( c * controller ) updatePolicy ( old , cur interface { } ) {
oldP , curP := old . ( * kyvernov1 . ClusterPolicy ) , cur . ( * kyvernov1 . ClusterPolicy )
// register kyverno_policy_changes_total metric concurrently
2023-03-17 11:48:48 +01:00
c . startRountine ( func ( ) { c . registerPolicyChangesMetricUpdatePolicy ( context . TODO ( ) , logger , oldP , curP ) } )
2022-10-07 12:53:54 +02:00
}
func ( c * controller ) deletePolicy ( obj interface { } ) {
p , ok := kubeutils . GetObjectWithTombstone ( obj ) . ( * kyvernov1 . ClusterPolicy )
if ! ok {
logger . Info ( "Failed to get deleted object" , "obj" , obj )
return
}
// register kyverno_policy_changes_total metric concurrently
2023-03-17 11:48:48 +01:00
c . startRountine ( func ( ) { c . registerPolicyChangesMetricDeletePolicy ( context . TODO ( ) , logger , p ) } )
2022-10-07 12:53:54 +02:00
}
func ( c * controller ) addNsPolicy ( obj interface { } ) {
p := obj . ( * kyvernov1 . Policy )
// register kyverno_policy_changes_total metric concurrently
2023-03-17 11:48:48 +01:00
c . startRountine ( func ( ) { c . registerPolicyChangesMetricAddPolicy ( context . TODO ( ) , logger , p ) } )
2022-10-07 12:53:54 +02:00
}
func ( c * controller ) updateNsPolicy ( old , cur interface { } ) {
oldP , curP := old . ( * kyvernov1 . Policy ) , cur . ( * kyvernov1 . Policy )
// register kyverno_policy_changes_total metric concurrently
2023-03-17 11:48:48 +01:00
c . startRountine ( func ( ) { c . registerPolicyChangesMetricUpdatePolicy ( context . TODO ( ) , logger , oldP , curP ) } )
2022-10-07 12:53:54 +02:00
}
func ( c * controller ) deleteNsPolicy ( obj interface { } ) {
p , ok := kubeutils . GetObjectWithTombstone ( obj ) . ( * kyvernov1 . Policy )
if ! ok {
logger . Info ( "Failed to get deleted object" , "obj" , obj )
return
}
// register kyverno_policy_changes_total metric concurrently
2023-03-17 11:48:48 +01:00
c . startRountine ( func ( ) { c . registerPolicyChangesMetricDeletePolicy ( context . TODO ( ) , logger , p ) } )
2022-10-07 12:53:54 +02:00
}