2022-04-29 13:31:02 +08:00
|
|
|
package policy
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/gardener/controller-manager-library/pkg/logger"
|
|
|
|
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
|
|
|
|
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
|
|
|
"github.com/kyverno/kyverno/pkg/config"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
|
|
)
|
|
|
|
|
|
|
|
func (pc *PolicyController) updateUR(policyKey string, policy kyverno.PolicyInterface) {
|
|
|
|
logger := pc.log.WithName("updateUR").WithName(policyKey)
|
2022-05-06 13:46:36 +08:00
|
|
|
|
|
|
|
// TODO: add check for genExisting
|
|
|
|
if !policy.GetSpec().MutateExistingOnPolicyUpdate {
|
|
|
|
logger.V(4).Info("skip policy application on policy event", "policyKey", policyKey, "mutateExiting", policy.GetSpec().MutateExistingOnPolicyUpdate)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-29 13:31:02 +08:00
|
|
|
logger.Info("update URs on policy event")
|
|
|
|
|
|
|
|
mutateURs := pc.listMutateURs(policyKey, nil)
|
|
|
|
generateURs := pc.listGenerateURs(policyKey, nil)
|
2022-05-05 18:56:27 +08:00
|
|
|
updateUR(pc.kyvernoClient, policyKey, append(mutateURs, generateURs...), pc.log.WithName("updateUR"))
|
2022-04-29 13:31:02 +08:00
|
|
|
|
|
|
|
for _, rule := range policy.GetSpec().Rules {
|
|
|
|
var ruleType urkyverno.RequestType
|
|
|
|
if rule.IsMutateExisting() {
|
|
|
|
ruleType = urkyverno.Mutate
|
|
|
|
} else {
|
|
|
|
// TODO: assign generate ruleType
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
triggers := getTriggers(rule)
|
|
|
|
for _, trigger := range triggers {
|
|
|
|
var urs []*urkyverno.UpdateRequest
|
|
|
|
if ruleType == urkyverno.Mutate {
|
|
|
|
urs = pc.listMutateURs(policyKey, trigger)
|
|
|
|
} else {
|
|
|
|
urs = pc.listGenerateURs(policyKey, trigger)
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.V(4).Info("UR was created", "rule", rule.Name, "rule type", ruleType, "trigger", trigger.Namespace+trigger.Name)
|
|
|
|
|
|
|
|
if urs != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.Info("creating new UR")
|
|
|
|
ur := newUR(policy, trigger, ruleType)
|
|
|
|
new, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Create(context.TODO(), ur, metav1.CreateOptions{})
|
|
|
|
if err != nil {
|
|
|
|
pc.log.Error(err, "failed to create new UR policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
|
|
|
|
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.APIVersion, trigger.Kind, trigger.Namespace, trigger.Name))
|
|
|
|
continue
|
|
|
|
} else {
|
|
|
|
pc.log.V(4).Info("successfully created UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
|
|
|
|
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.APIVersion, trigger.Kind, trigger.Namespace, trigger.Name))
|
|
|
|
}
|
|
|
|
|
|
|
|
new.Status.State = urkyverno.Pending
|
|
|
|
if _, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(context.TODO(), new, metav1.UpdateOptions{}); err != nil {
|
|
|
|
pc.log.Error(err, "failed to set UpdateRequest state to Pending")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pc *PolicyController) listMutateURs(policyKey string, trigger *kyverno.ResourceSpec) []*urkyverno.UpdateRequest {
|
|
|
|
selector := createMutateLabels(policyKey, trigger)
|
|
|
|
mutateURs, err := pc.urLister.List(labels.SelectorFromSet(selector))
|
|
|
|
if err != nil {
|
|
|
|
logger.Error(err, "failed to list update request for mutate policy")
|
|
|
|
}
|
|
|
|
|
|
|
|
return mutateURs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pc *PolicyController) listGenerateURs(policyKey string, trigger *kyverno.ResourceSpec) []*urkyverno.UpdateRequest {
|
|
|
|
selector := createGenerateLabels(policyKey, trigger)
|
|
|
|
generateURs, err := pc.urLister.List(labels.SelectorFromSet(selector))
|
|
|
|
if err != nil {
|
|
|
|
logger.Error(err, "failed to list update request for generate policy")
|
|
|
|
}
|
|
|
|
|
|
|
|
return generateURs
|
|
|
|
}
|
|
|
|
|
|
|
|
func newUR(policy kyverno.PolicyInterface, trigger *kyverno.ResourceSpec, ruleType urkyverno.RequestType) *urkyverno.UpdateRequest {
|
|
|
|
var policyNameNamespaceKey string
|
|
|
|
|
|
|
|
if policy.IsNamespaced() {
|
|
|
|
policyNameNamespaceKey = policy.GetNamespace() + "/" + policy.GetName()
|
|
|
|
} else {
|
|
|
|
policyNameNamespaceKey = policy.GetName()
|
|
|
|
}
|
|
|
|
|
|
|
|
var label labels.Set
|
|
|
|
if ruleType == urkyverno.Mutate {
|
|
|
|
label = createMutateLabels(policyNameNamespaceKey, trigger)
|
|
|
|
} else {
|
|
|
|
label = createGenerateLabels(policyNameNamespaceKey, trigger)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &urkyverno.UpdateRequest{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
GenerateName: "ur-",
|
|
|
|
Namespace: config.KyvernoNamespace,
|
|
|
|
Labels: label,
|
|
|
|
},
|
|
|
|
Spec: urkyverno.UpdateRequestSpec{
|
|
|
|
Type: ruleType,
|
|
|
|
Policy: policyNameNamespaceKey,
|
|
|
|
Resource: kyverno.ResourceSpec{
|
|
|
|
Kind: trigger.Kind,
|
|
|
|
Namespace: trigger.Namespace,
|
|
|
|
Name: trigger.Name,
|
|
|
|
APIVersion: trigger.APIVersion,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func createMutateLabels(policyKey string, trigger *kyverno.ResourceSpec) labels.Set {
|
|
|
|
var selector labels.Set
|
|
|
|
if trigger == nil {
|
|
|
|
selector = labels.Set(map[string]string{
|
|
|
|
urkyverno.URMutatePolicyLabel: policyKey,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
selector = labels.Set(map[string]string{
|
|
|
|
urkyverno.URMutatePolicyLabel: policyKey,
|
|
|
|
urkyverno.URMutateTriggerNameLabel: trigger.Name,
|
|
|
|
urkyverno.URMutateTriggerNSLabel: trigger.Namespace,
|
|
|
|
urkyverno.URMutatetriggerKindLabel: trigger.Kind,
|
|
|
|
})
|
|
|
|
|
|
|
|
if trigger.APIVersion != "" {
|
|
|
|
selector[urkyverno.URMutatetriggerAPIVersionLabel] = trigger.APIVersion
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return selector
|
|
|
|
}
|
|
|
|
|
|
|
|
func createGenerateLabels(policyKey string, trigger *kyverno.ResourceSpec) labels.Set {
|
|
|
|
var selector labels.Set
|
|
|
|
if trigger == nil {
|
|
|
|
selector = labels.Set(map[string]string{
|
|
|
|
urkyverno.URGeneratePolicyLabel: policyKey,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
selector = labels.Set(map[string]string{
|
|
|
|
urkyverno.URGeneratePolicyLabel: policyKey,
|
|
|
|
"generate.kyverno.io/resource-name": trigger.Name,
|
|
|
|
"generate.kyverno.io/resource-kind": trigger.Kind,
|
|
|
|
"generate.kyverno.io/resource-namespace": trigger.Namespace,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return selector
|
|
|
|
}
|