@@ -564,6 +564,20 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
564564 continue
565565 }
566566
567+ // Applicable for Gatekeeper versions v3.17 and later.
568+ if isGkConstraintTemplate {
569+ sentMsg , err := r .emitGKConstraintTemplateErrMsg (ctx , tObjectUnstructured ,
570+ res , instance , tIndex , tName )
571+ if err != nil {
572+ return reconcile.Result {}, err
573+ }
574+
575+ if sentMsg {
576+ // Skip success event emitting
577+ continue
578+ }
579+ }
580+
567581 successMsg := fmt .Sprintf ("Policy template %s created successfully" , tName )
568582
569583 tLogger .Info ("Policy template created successfully" )
@@ -622,6 +636,25 @@ func (r *PolicyReconciler) Reconcile(ctx context.Context, request reconcile.Requ
622636 continue
623637 }
624638
639+ // Applicable for Gatekeeper versions v3.17 and later.
640+ if isGkConstraintTemplate {
641+ sentErrMsg , err := r .emitGKConstraintTemplateErrMsg (ctx , tObjectUnstructured ,
642+ res , instance , tIndex , tName )
643+ if err != nil {
644+ return reconcile.Result {}, err
645+ }
646+
647+ if ! sentErrMsg {
648+ tLogger .Info ("Emitting status event for " + gvk .Kind )
649+ msg := fmt .Sprintf ("%s %s was created successfully" , gvk .Kind , tName )
650+
651+ emitErr := r .emitTemplateSuccess (ctx , instance , tIndex , tName , isClusterScoped , msg )
652+ if emitErr != nil {
653+ resultError = emitErr
654+ }
655+ }
656+ }
657+
625658 if len (dependencyFailures ) > 0 {
626659 // template must be pending, need to delete it and error
627660 tLogger .Info ("Dependencies were not satisfied for the policy template" ,
@@ -1091,8 +1124,12 @@ func (r *PolicyReconciler) cleanUpExcessTemplates(
10911124 r .setCreatedGkConstraint (false )
10921125 }
10931126 // Iterate over the ConstraintTemplates to gather the Constraints on the cluster
1127+ // In Gatekeeper v3.17 and later, ConstraintTemplates are created even if they contain errors.
1128+ // Only append to tmplGVRs if the ConstraintTemplate's status.created field is true.
10941129 for _ , gkCT := range gkConstraintTemplateListv1 .Items {
1095- gkCT := gkCT
1130+ if ! gkCT .Status .Created {
1131+ continue
1132+ }
10961133
10971134 tmplGVRs = append (tmplGVRs , gvrScoped {
10981135 gvr : schema.GroupVersionResource {
@@ -1740,3 +1777,42 @@ func getDupName(pol *policiesv1.Policy) string {
17401777
17411778 return ""
17421779}
1780+
1781+ // emitGKConstraintTemplateErrMsg generates an error message based
1782+ // on the Gatekeeper ConstraintTemplate status.
1783+ // retrieves the "status.created" field from a Gatekeeper ConstraintTemplate.
1784+ // In Gatekeeper 3.17 and later, if a ConstraintTemplate contains a Rego syntax error,
1785+ // it is still created, but its status field will have "created: false" instead of failing outright.
1786+ // Returns true if an error message is emitted.
1787+ func (r * PolicyReconciler ) emitGKConstraintTemplateErrMsg (
1788+ ctx context.Context ,
1789+ tObjectUnstructured * unstructured.Unstructured ,
1790+ res dynamic.ResourceInterface ,
1791+ instance * policiesv1.Policy ,
1792+ tIndex int ,
1793+ tName string ,
1794+ ) (bool , error ) {
1795+ name := tObjectUnstructured .GetName ()
1796+
1797+ template , err := res .Get (ctx , name , metav1.GetOptions {})
1798+ if err != nil {
1799+ return false , err
1800+ }
1801+
1802+ created , ok , err := unstructured .NestedBool (template .Object , "status" , "created" )
1803+ if ! ok || err != nil {
1804+ errMsg := fmt .Sprintf ("Failed to retrieve status.created from ConstraintTemplate %s: %v" , name , err )
1805+ _ = r .emitTemplateError (ctx , instance , tIndex , tName , true , errMsg )
1806+
1807+ return true , nil
1808+ }
1809+
1810+ if ! created {
1811+ errMsg := fmt .Sprintf ("Failed to create Gatekeeper ConstraintTemplate. Check the status of %s." , name )
1812+ _ = r .emitTemplateError (ctx , instance , tIndex , tName , true , errMsg )
1813+
1814+ return true , nil
1815+ }
1816+
1817+ return false , nil
1818+ }
0 commit comments