diff --git a/cmd/build/helmify/kustomize-for-helm.yaml b/cmd/build/helmify/kustomize-for-helm.yaml index 8e87903194c..55cdf4044fe 100644 --- a/cmd/build/helmify/kustomize-for-helm.yaml +++ b/cmd/build/helmify/kustomize-for-helm.yaml @@ -178,6 +178,7 @@ spec: - --audit-events-involved-namespace={{ .Values.auditEventsInvolvedNamespace }} - --operation=audit - --operation=status + - --operation=generate - HELMSUBST_PUBSUB_ARGS - HELMSUBST_MUTATION_STATUS_ENABLED_ARG - --logtostderr diff --git a/manifest_staging/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml b/manifest_staging/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml index a2c596bfa09..40e9fda98e7 100644 --- a/manifest_staging/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml +++ b/manifest_staging/charts/gatekeeper/templates/gatekeeper-audit-deployment.yaml @@ -69,6 +69,7 @@ spec: - --audit-events-involved-namespace={{ .Values.auditEventsInvolvedNamespace }} - --operation=audit - --operation=status + - --operation=generate {{ if .Values.audit.enablePubsub}} - --enable-pub-sub={{ .Values.audit.enablePubsub }} - --audit-connection={{ .Values.audit.connection }} diff --git a/pkg/controller/constraint/constraint_controller.go b/pkg/controller/constraint/constraint_controller.go index 089d3cb1e42..e19c90553d6 100644 --- a/pkg/controller/constraint/constraint_controller.go +++ b/pkg/controller/constraint/constraint_controller.go @@ -23,6 +23,7 @@ import ( "reflect" "strings" "sync" + "time" "github.com/go-logr/logr" "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1" @@ -65,10 +66,11 @@ import ( ) var ( - log = logf.Log.V(logging.DebugLevel).WithName("controller").WithValues(logging.Process, "constraint_controller") - discoveryErr *apiutil.ErrResourceDiscoveryFailed - DefaultGenerateVAPB = flag.Bool("default-create-vap-binding-for-constraints", false, "Create VAPBinding resource for constraint of the template containing VAP-style CEL source. Allowed values are false: do not create Validating Admission Policy Binding, true: create Validating Admission Policy Binding.") - DefaultGenerateVAP = flag.Bool("default-create-vap-for-templates", false, "Create VAP resource for template containing VAP-style CEL source. Allowed values are false: do not create Validating Admission Policy unless generateVAP: true is set on constraint template explicitly, true: create Validating Admission Policy unless generateVAP: false is set on constraint template explicitly.") + log = logf.Log.V(logging.DebugLevel).WithName("controller").WithValues(logging.Process, "constraint_controller") + discoveryErr *apiutil.ErrResourceDiscoveryFailed + defaultWaitForGeneration = flag.Int("default-wait-for-generation", 30, "Wait to generate ValidatingAdmissionPolicyBinding after the constraint is created. Defaults to 30 seconds.") + DefaultGenerateVAPB = flag.Bool("default-create-vap-binding-for-constraints", false, "Create VAPBinding resource for constraint of the template containing VAP-style CEL source. Allowed values are false: do not create Validating Admission Policy Binding, true: create Validating Admission Policy Binding.") + DefaultGenerateVAP = flag.Bool("default-create-vap-for-templates", false, "Create VAP resource for template containing VAP-style CEL source. Allowed values are false: do not create Validating Admission Policy unless generateVAP: true is set on constraint template explicitly, true: create Validating Admission Policy unless generateVAP: false is set on constraint template explicitly.") ) var ( @@ -305,106 +307,108 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R status.Status.Errors = nil if c, err := r.cfClient.GetConstraint(instance); err != nil || !reflect.DeepEqual(instance, c) { - err := util.ValidateEnforcementAction(enforcementAction, instance.Object) - if err != nil { - return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not validate enforcement actions") - } - generateVAPB, VAPEnforcementActions, err := shouldGenerateVAPB(*DefaultGenerateVAPB, enforcementAction, instance) - if err != nil { - log.Error(err, "could not determine if ValidatingAdmissionPolicyBinding should be generated") - return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not determine if ValidatingAdmissionPolicyBinding should be generated") - } - isAPIEnabled := false - var groupVersion *schema.GroupVersion - if generateVAPB { - isAPIEnabled, groupVersion = IsVapAPIEnabled() - } - if generateVAPB { - if !isAPIEnabled { - log.Error(ErrValidatingAdmissionPolicyAPIDisabled, "Cannot generate ValidatingAdmissionPolicyBinding", "constraint", instance.GetName()) - _ = r.reportErrorOnConstraintStatus(ctx, status, ErrValidatingAdmissionPolicyAPIDisabled, "cannot generate ValidatingAdmissionPolicyBinding") - generateVAPB = false - } else { - unversionedCT := &templates.ConstraintTemplate{} - if err := r.scheme.Convert(ct, unversionedCT, nil); err != nil { - return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not convert ConstraintTemplate to unversioned") - } - hasVAP, err := ShouldGenerateVAP(unversionedCT) - switch { - case errors.Is(err, celSchema.ErrCodeNotDefined): - generateVAPB = false - case err != nil: - log.Error(err, "could not determine if ConstraintTemplate is configured to generate ValidatingAdmissionPolicy", "constraint", instance.GetName(), "constraint_template", ct.GetName()) - _ = r.reportErrorOnConstraintStatus(ctx, status, err, "could not determine if ConstraintTemplate is configured to generate ValidatingAdmissionPolicy") - generateVAPB = false - case !hasVAP: - log.Error(ErrVAPConditionsNotSatisfied, "Cannot generate ValidatingAdmissionPolicyBinding", "constraint", instance.GetName(), "constraint_template", ct.GetName()) - _ = r.reportErrorOnConstraintStatus(ctx, status, ErrVAPConditionsNotSatisfied, "Cannot generate ValidatingAdmissionPolicyBinding") - generateVAPB = false - default: - } - } - } - r.log.Info("constraint controller", "generateVAPB", generateVAPB) - // generate vapbinding resources - if generateVAPB && groupVersion != nil { - currentVapBinding, err := vapBindingForVersion(*groupVersion) + if operations.IsAssigned(operations.Generate) { + err := util.ValidateEnforcementAction(enforcementAction, instance.Object) if err != nil { - return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not get ValidatingAdmissionPolicyBinding API version") - } - vapBindingName := fmt.Sprintf("gatekeeper-%s", instance.GetName()) - log.Info("check if vapbinding exists", "vapBindingName", vapBindingName) - if err := r.reader.Get(ctx, types.NamespacedName{Name: vapBindingName}, currentVapBinding); err != nil { - if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { - return reconcile.Result{}, err - } - currentVapBinding = nil + return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not validate enforcement actions") } - transformedVapBinding, err := transform.ConstraintToBinding(instance, VAPEnforcementActions) + generateVAPB, VAPEnforcementActions, err := shouldGenerateVAPB(*DefaultGenerateVAPB, enforcementAction, instance) if err != nil { - return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not transform constraint to ValidatingAdmissionPolicyBinding") + log.Error(err, "could not determine if ValidatingAdmissionPolicyBinding should be generated") + return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not determine if ValidatingAdmissionPolicyBinding should be generated") } - - newVapBinding, err := getRunTimeVAPBinding(groupVersion, transformedVapBinding, currentVapBinding) - if err != nil { - return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not get ValidatingAdmissionPolicyBinding object with runtime group version") + isAPIEnabled := false + var groupVersion *schema.GroupVersion + if generateVAPB { + isAPIEnabled, groupVersion = IsVapAPIEnabled() } - - if err := controllerutil.SetControllerReference(instance, newVapBinding, r.scheme); err != nil { - return reconcile.Result{}, err + if generateVAPB { + if !isAPIEnabled { + log.Error(ErrValidatingAdmissionPolicyAPIDisabled, "Cannot generate ValidatingAdmissionPolicyBinding", "constraint", instance.GetName()) + _ = r.reportErrorOnConstraintStatus(ctx, status, ErrValidatingAdmissionPolicyAPIDisabled, "cannot generate ValidatingAdmissionPolicyBinding") + generateVAPB = false + } else { + unversionedCT := &templates.ConstraintTemplate{} + if err := r.scheme.Convert(ct, unversionedCT, nil); err != nil { + return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not convert ConstraintTemplate to unversioned") + } + hasVAP, err := ShouldGenerateVAP(unversionedCT) + switch { + case errors.Is(err, celSchema.ErrCodeNotDefined): + generateVAPB = false + case err != nil: + log.Error(err, "could not determine if ConstraintTemplate is configured to generate ValidatingAdmissionPolicy", "constraint", instance.GetName(), "constraint_template", ct.GetName()) + _ = r.reportErrorOnConstraintStatus(ctx, status, err, "could not determine if ConstraintTemplate is configured to generate ValidatingAdmissionPolicy") + generateVAPB = false + case !hasVAP: + log.Error(ErrVAPConditionsNotSatisfied, "Cannot generate ValidatingAdmissionPolicyBinding", "constraint", instance.GetName(), "constraint_template", ct.GetName()) + _ = r.reportErrorOnConstraintStatus(ctx, status, ErrVAPConditionsNotSatisfied, "Cannot generate ValidatingAdmissionPolicyBinding") + generateVAPB = false + default: + } + } } - - if currentVapBinding == nil { - log.Info("creating vapbinding") - if err := r.writer.Create(ctx, newVapBinding); err != nil { - return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, fmt.Sprintf("could not create ValidatingAdmissionPolicyBinding: %s", vapBindingName)) + r.log.Info("constraint controller", "generateVAPB", generateVAPB) + // generate vapbinding resources + if generateVAPB && groupVersion != nil { + currentVapBinding, err := vapBindingForVersion(*groupVersion) + if err != nil { + return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not get ValidatingAdmissionPolicyBinding API version") } - } else if !reflect.DeepEqual(currentVapBinding, newVapBinding) { - log.Info("updating vapbinding") - if err := r.writer.Update(ctx, newVapBinding); err != nil { - return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, fmt.Sprintf("could not update ValidatingAdmissionPolicyBinding: %s", vapBindingName)) + vapBindingName := fmt.Sprintf("gatekeeper-%s", instance.GetName()) + log.Info("check if vapbinding exists", "vapBindingName", vapBindingName) + if err := r.reader.Get(ctx, types.NamespacedName{Name: vapBindingName}, currentVapBinding); err != nil { + if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { + return reconcile.Result{}, err + } + currentVapBinding = nil } - } - } - // do not generate vapbinding resources - // remove if exists - if !generateVAPB && groupVersion != nil { - currentVapBinding, err := vapBindingForVersion(*groupVersion) - if err != nil { - return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not get ValidatingAdmissionPolicyBinding API version") - } - vapBindingName := fmt.Sprintf("gatekeeper-%s", instance.GetName()) - log.Info("check if vapbinding exists", "vapBindingName", vapBindingName) - if err := r.reader.Get(ctx, types.NamespacedName{Name: vapBindingName}, currentVapBinding); err != nil { - if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { + transformedVapBinding, err := transform.ConstraintToBinding(instance, VAPEnforcementActions) + if err != nil { + return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not transform constraint to ValidatingAdmissionPolicyBinding") + } + + newVapBinding, err := getRunTimeVAPBinding(groupVersion, transformedVapBinding, currentVapBinding) + if err != nil { + return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not get ValidatingAdmissionPolicyBinding object with runtime group version") + } + + if err := controllerutil.SetControllerReference(instance, newVapBinding, r.scheme); err != nil { return reconcile.Result{}, err } - currentVapBinding = nil + + if currentVapBinding == nil && instance.GetCreationTimestamp().Add(time.Duration(*defaultWaitForGeneration)).Before(time.Now()) { + log.Info("creating vapbinding") + if err := r.writer.Create(ctx, newVapBinding); err != nil { + return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, fmt.Sprintf("could not create ValidatingAdmissionPolicyBinding: %s", vapBindingName)) + } + } else if !reflect.DeepEqual(currentVapBinding, newVapBinding) { + log.Info("updating vapbinding") + if err := r.writer.Update(ctx, newVapBinding); err != nil { + return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, fmt.Sprintf("could not update ValidatingAdmissionPolicyBinding: %s", vapBindingName)) + } + } } - if currentVapBinding != nil { - log.Info("deleting vapbinding") - if err := r.writer.Delete(ctx, currentVapBinding); err != nil { - return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, fmt.Sprintf("could not delete ValidatingAdmissionPolicyBinding: %s", vapBindingName)) + // do not generate vapbinding resources + // remove if exists + if !generateVAPB && groupVersion != nil { + currentVapBinding, err := vapBindingForVersion(*groupVersion) + if err != nil { + return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, "could not get ValidatingAdmissionPolicyBinding API version") + } + vapBindingName := fmt.Sprintf("gatekeeper-%s", instance.GetName()) + log.Info("check if vapbinding exists", "vapBindingName", vapBindingName) + if err := r.reader.Get(ctx, types.NamespacedName{Name: vapBindingName}, currentVapBinding); err != nil { + if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { + return reconcile.Result{}, err + } + currentVapBinding = nil + } + if currentVapBinding != nil { + log.Info("deleting vapbinding") + if err := r.writer.Delete(ctx, currentVapBinding); err != nil { + return reconcile.Result{}, r.reportErrorOnConstraintStatus(ctx, status, err, fmt.Sprintf("could not delete ValidatingAdmissionPolicyBinding: %s", vapBindingName)) + } } } } diff --git a/pkg/controller/constrainttemplate/constrainttemplate_controller.go b/pkg/controller/constrainttemplate/constrainttemplate_controller.go index a9dbb7cccea..35fa047aede 100644 --- a/pkg/controller/constrainttemplate/constrainttemplate_controller.go +++ b/pkg/controller/constrainttemplate/constrainttemplate_controller.go @@ -378,13 +378,8 @@ func (r *ReconcileConstraintTemplate) Reconcile(ctx context.Context, request rec r.metrics.registry.add(request.NamespacedName, metrics.ErrorStatus) return reconcile.Result{}, err } - generateVap, err := constraint.ShouldGenerateVAP(unversionedCT) - if err != nil && !errors.Is(err, celSchema.ErrCodeNotDefined) { - logger.Error(err, "generateVap error") - } - logger.Info("generateVap", "r.generateVap", generateVap) - result, err := r.handleUpdate(ctx, ct, unversionedCT, proposedCRD, currentCRD, status, generateVap) + result, err := r.handleUpdate(ctx, ct, unversionedCT, proposedCRD, currentCRD, status) if err != nil { logger.Error(err, "handle update error") logError(request.NamespacedName.Name) @@ -417,7 +412,6 @@ func (r *ReconcileConstraintTemplate) handleUpdate( unversionedCT *templates.ConstraintTemplate, proposedCRD, currentCRD *apiextensionsv1.CustomResourceDefinition, status *statusv1beta1.ConstraintTemplatePodStatus, - generateVap bool, ) (reconcile.Result, error) { name := proposedCRD.GetName() logger := logger.WithValues("name", ct.GetName(), "crdName", name) @@ -445,29 +439,31 @@ func (r *ReconcileConstraintTemplate) handleUpdate( t := r.tracker.For(gvkConstraintTemplate) t.Observe(unversionedCT) - var newCRD *apiextensionsv1.CustomResourceDefinition - if currentCRD == nil { - newCRD = proposedCRD.DeepCopy() - } else { - newCRD = currentCRD.DeepCopy() - newCRD.Spec = proposedCRD.Spec - } - - if err := controllerutil.SetControllerReference(ct, newCRD, r.scheme); err != nil { - return reconcile.Result{}, err - } + if operations.IsAssigned(operations.Generate) { + var newCRD *apiextensionsv1.CustomResourceDefinition + if currentCRD == nil { + newCRD = proposedCRD.DeepCopy() + } else { + newCRD = currentCRD.DeepCopy() + newCRD.Spec = proposedCRD.Spec + } - if currentCRD == nil { - logger.Info("creating crd") - if err := r.Create(ctx, newCRD); err != nil { - err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not create CRD", status, err) + if err := controllerutil.SetControllerReference(ct, newCRD, r.scheme); err != nil { return reconcile.Result{}, err } - } else if !reflect.DeepEqual(newCRD, currentCRD) { - logger.Info("updating crd") - if err := r.Update(ctx, newCRD); err != nil { - err := r.reportErrorOnCTStatus(ctx, ErrUpdateCode, "Could not update CRD", status, err) - return reconcile.Result{}, err + + if currentCRD == nil { + logger.Info("creating crd") + if err := r.Create(ctx, newCRD); err != nil { + err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not create CRD", status, err) + return reconcile.Result{}, err + } + } else if !reflect.DeepEqual(newCRD, currentCRD) { + logger.Info("updating crd") + if err := r.Update(ctx, newCRD); err != nil { + err := r.reportErrorOnCTStatus(ctx, ErrUpdateCode, "Could not update CRD", status, err) + return reconcile.Result{}, err + } } } // This must go after CRD creation/update as otherwise AddWatch will always fail @@ -476,98 +472,108 @@ func (r *ReconcileConstraintTemplate) handleUpdate( logger.Error(err, "error adding template to watch registry") return reconcile.Result{}, err } - isVapAPIEnabled := false - var groupVersion *schema.GroupVersion - if generateVap { - isVapAPIEnabled, groupVersion = constraint.IsVapAPIEnabled() - } - logger.Info("isVapAPIEnabled", "isVapAPIEnabled", isVapAPIEnabled) - logger.Info("groupVersion", "groupVersion", groupVersion) - if generateVap && (!isVapAPIEnabled || groupVersion == nil) { - logger.Error(constraint.ErrValidatingAdmissionPolicyAPIDisabled, "ValidatingAdmissionPolicy resource cannot be generated for ConstraintTemplate", "name", ct.GetName()) - err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "ValidatingAdmissionPolicy resource cannot be generated for ConstraintTemplate", status, constraint.ErrValidatingAdmissionPolicyAPIDisabled) - return reconcile.Result{}, err - } - // generating vap resources - if generateVap && isVapAPIEnabled && groupVersion != nil { - currentVap, err := vapForVersion(groupVersion) - if err != nil { - logger.Error(err, "error getting vap object with respective groupVersion") - err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not get VAP with runtime group version", status, err) - return reconcile.Result{}, err - } - vapName := fmt.Sprintf("gatekeeper-%s", unversionedCT.GetName()) - logger.Info("check if vap exists", "vapName", vapName) - if err := r.Get(ctx, types.NamespacedName{Name: vapName}, currentVap); err != nil { - if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { - return reconcile.Result{}, err - } - currentVap = nil - } - logger.Info("get vap", "vapName", vapName, "currentVap", currentVap) - transformedVap, err := transform.TemplateToPolicyDefinition(unversionedCT) - if err != nil { - logger.Error(err, "transform to vap error", "vapName", vapName) - err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not transform to vap object", status, err) - return reconcile.Result{}, err + + if operations.IsAssigned(operations.Generate) { + isVapAPIEnabled := false + var groupVersion *schema.GroupVersion + generateVap, err := constraint.ShouldGenerateVAP(unversionedCT) + if err != nil && !errors.Is(err, celSchema.ErrCodeNotDefined) { + logger.Error(err, "generateVap error") } + logger.Info("generateVap", "r.generateVap", generateVap) - newVap, err := getRunTimeVAP(groupVersion, transformedVap, currentVap) - if err != nil { - logger.Error(err, "getRunTimeVAP error", "vapName", vapName) - err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not get runtime vap object", status, err) - return reconcile.Result{}, err + if generateVap { + isVapAPIEnabled, groupVersion = constraint.IsVapAPIEnabled() } + logger.Info("isVapAPIEnabled", "isVapAPIEnabled", isVapAPIEnabled) + logger.Info("groupVersion", "groupVersion", groupVersion) - if err := controllerutil.SetControllerReference(ct, newVap, r.scheme); err != nil { + if generateVap && (!isVapAPIEnabled || groupVersion == nil) { + logger.Error(constraint.ErrValidatingAdmissionPolicyAPIDisabled, "ValidatingAdmissionPolicy resource cannot be generated for ConstraintTemplate", "name", ct.GetName()) + err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "ValidatingAdmissionPolicy resource cannot be generated for ConstraintTemplate", status, constraint.ErrValidatingAdmissionPolicyAPIDisabled) return reconcile.Result{}, err } - - if currentVap == nil { - logger.Info("creating vap", "vapName", vapName) - if err := r.Create(ctx, newVap); err != nil { - logger.Info("creating vap error", "vapName", vapName, "error", err) - err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not create vap object", status, err) + // generating vap resources + if generateVap && isVapAPIEnabled && groupVersion != nil { + currentVap, err := vapForVersion(groupVersion) + if err != nil { + logger.Error(err, "error getting vap object with respective groupVersion") + err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not get VAP with runtime group version", status, err) return reconcile.Result{}, err } - // after vap is created, trigger update event for all constraints - if err := r.triggerConstraintEvents(ctx, ct, status); err != nil { + vapName := fmt.Sprintf("gatekeeper-%s", unversionedCT.GetName()) + logger.Info("check if vap exists", "vapName", vapName) + if err := r.Get(ctx, types.NamespacedName{Name: vapName}, currentVap); err != nil { + if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { + return reconcile.Result{}, err + } + currentVap = nil + } + logger.Info("get vap", "vapName", vapName, "currentVap", currentVap) + transformedVap, err := transform.TemplateToPolicyDefinition(unversionedCT) + if err != nil { + logger.Error(err, "transform to vap error", "vapName", vapName) + err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not transform to vap object", status, err) return reconcile.Result{}, err } - } else if !reflect.DeepEqual(currentVap, newVap) { - logger.Info("updating vap") - if err := r.Update(ctx, newVap); err != nil { - err := r.reportErrorOnCTStatus(ctx, ErrUpdateCode, "Could not update vap object", status, err) + + newVap, err := getRunTimeVAP(groupVersion, transformedVap, currentVap) + if err != nil { + logger.Error(err, "getRunTimeVAP error", "vapName", vapName) + err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not get runtime vap object", status, err) return reconcile.Result{}, err } - } - } - // do not generate vap resources - // remove if exists - if !generateVap && isVapAPIEnabled && groupVersion != nil { - currentVap, err := vapForVersion(groupVersion) - if err != nil { - logger.Error(err, "error getting vap object with respective groupVersion") - err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not get VAP with correct group version", status, err) - return reconcile.Result{}, err - } - vapName := fmt.Sprintf("gatekeeper-%s", unversionedCT.GetName()) - logger.Info("check if vap exists", "vapName", vapName) - if err := r.Get(ctx, types.NamespacedName{Name: vapName}, currentVap); err != nil { - if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { + + if err := controllerutil.SetControllerReference(ct, newVap, r.scheme); err != nil { return reconcile.Result{}, err } - currentVap = nil + + if currentVap == nil { + logger.Info("creating vap", "vapName", vapName) + if err := r.Create(ctx, newVap); err != nil { + logger.Info("creating vap error", "vapName", vapName, "error", err) + err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not create vap object", status, err) + return reconcile.Result{}, err + } + // after vap is created, trigger update event for all constraints + if err := r.triggerConstraintEvents(ctx, ct, status); err != nil { + return reconcile.Result{}, err + } + } else if !reflect.DeepEqual(currentVap, newVap) { + logger.Info("updating vap") + if err := r.Update(ctx, newVap); err != nil { + err := r.reportErrorOnCTStatus(ctx, ErrUpdateCode, "Could not update vap object", status, err) + return reconcile.Result{}, err + } + } } - if currentVap != nil { - logger.Info("deleting vap") - if err := r.Delete(ctx, currentVap); err != nil { - err := r.reportErrorOnCTStatus(ctx, ErrUpdateCode, "Could not delete vap object", status, err) + // do not generate vap resources + // remove if exists + if !generateVap && isVapAPIEnabled && groupVersion != nil { + currentVap, err := vapForVersion(groupVersion) + if err != nil { + logger.Error(err, "error getting vap object with respective groupVersion") + err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not get VAP with correct group version", status, err) return reconcile.Result{}, err } - // after vap is deleted, trigger update event for all constraints - if err := r.triggerConstraintEvents(ctx, ct, status); err != nil { - return reconcile.Result{}, err + vapName := fmt.Sprintf("gatekeeper-%s", unversionedCT.GetName()) + logger.Info("check if vap exists", "vapName", vapName) + if err := r.Get(ctx, types.NamespacedName{Name: vapName}, currentVap); err != nil { + if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { + return reconcile.Result{}, err + } + currentVap = nil + } + if currentVap != nil { + logger.Info("deleting vap") + if err := r.Delete(ctx, currentVap); err != nil { + err := r.reportErrorOnCTStatus(ctx, ErrUpdateCode, "Could not delete vap object", status, err) + return reconcile.Result{}, err + } + // after vap is deleted, trigger update event for all constraints + if err := r.triggerConstraintEvents(ctx, ct, status); err != nil { + return reconcile.Result{}, err + } } } } diff --git a/pkg/operations/operations.go b/pkg/operations/operations.go index 100f19bfcea..c3485c348e0 100644 --- a/pkg/operations/operations.go +++ b/pkg/operations/operations.go @@ -21,6 +21,7 @@ const ( MutationWebhook = Operation("mutation-webhook") Status = Operation("status") Webhook = Operation("webhook") + Generate = Operation("generate") ) var ( @@ -33,6 +34,7 @@ var ( MutationWebhook, Status, Webhook, + Generate, } operationsMtx sync.RWMutex diff --git a/pkg/operations/operations_test.go b/pkg/operations/operations_test.go index 1865a6c630e..b9df2a7f1dc 100644 --- a/pkg/operations/operations_test.go +++ b/pkg/operations/operations_test.go @@ -15,7 +15,7 @@ func Test_Flags(t *testing.T) { }{ "default": { input: []string{}, - expected: map[Operation]bool{Audit: true, Webhook: true, Status: true, MutationStatus: true, MutationWebhook: true, MutationController: true}, + expected: map[Operation]bool{Audit: true, Webhook: true, Status: true, MutationStatus: true, MutationWebhook: true, MutationController: true, Generate: true}, }, "multiple": { input: []string{"-operation", "audit", "-operation", "webhook"},