@@ -14,6 +14,9 @@ import (
1414
1515 "helm.sh/helm/v3/pkg/release"
1616 "helm.sh/helm/v3/pkg/storage/driver"
17+ appsv1 "k8s.io/api/apps/v1"
18+ corev1 "k8s.io/api/core/v1"
19+ "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
1720 apierrors "k8s.io/apimachinery/pkg/api/errors"
1821 "k8s.io/apimachinery/pkg/api/meta"
1922 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -28,6 +31,7 @@ import (
2831 "sigs.k8s.io/controller-runtime/pkg/log"
2932 "sigs.k8s.io/yaml"
3033
34+ "github.com/cert-manager/cert-manager/pkg/apis/certmanager"
3135 helmclient "github.com/operator-framework/helm-operator-plugins/pkg/client"
3236
3337 ocv1 "github.com/operator-framework/operator-controller/api/v1"
@@ -208,10 +212,12 @@ func (r *SimpleRevisionGenerator) buildClusterExtensionRevision(
208212 annotations [labels .ServiceAccountNamespaceKey ] = ext .Spec .Namespace
209213
210214 phases := PhaseSort (objects )
215+ progressionProbes := defaultProgressionProbes ()
211216
212217 spec := ocv1ac .ClusterExtensionRevisionSpec ().
213218 WithLifecycleState (ocv1 .ClusterExtensionRevisionLifecycleStateActive ).
214- WithPhases (phases ... )
219+ WithPhases (phases ... ).
220+ WithProgressionProbes (progressionProbes ... )
215221 if p := ext .Spec .ProgressDeadlineMinutes ; p > 0 {
216222 spec .WithProgressDeadlineMinutes (p )
217223 }
@@ -602,6 +608,110 @@ func latestRevisionNumber(prevRevisions []ocv1.ClusterExtensionRevision) int64 {
602608 return prevRevisions [len (prevRevisions )- 1 ].Spec .Revision
603609}
604610
611+ func defaultProgressionProbes () []* ocv1ac.ProgressionProbeApplyConfiguration {
612+ crdProbe := ocv1ac .ProgressionProbe ().
613+ WithSelector (ocv1ac .ObjectSelector ().
614+ WithType (ocv1 .SelectorTypeGroupKind ).
615+ WithGroupKind (metav1.GroupKind {
616+ Group : "apiextensions.k8s.io" ,
617+ Kind : "CustomResourceDefinition" ,
618+ })).
619+ WithAssertions (ocv1ac .Assertion ().
620+ WithType (ocv1 .ProbeTypeConditionEqual ).
621+ WithConditionEqual (
622+ ocv1ac .ConditionEqualProbe ().
623+ WithType (string (apiextensions .Established )).
624+ WithStatus (string (corev1 .ConditionTrue ))))
625+
626+ // Checks if the Type: "Ready" Condition is "True"
627+ readyConditionAssertion := ocv1ac .Assertion ().
628+ WithType (ocv1 .ProbeTypeConditionEqual ).
629+ WithConditionEqual (
630+ ocv1ac .ConditionEqualProbe ().
631+ WithType ("Ready" ).
632+ WithStatus ("True" ))
633+
634+ certProbe := ocv1ac .ProgressionProbe ().
635+ WithSelector (ocv1ac .ObjectSelector ().
636+ WithType (ocv1 .SelectorTypeGroupKind ).
637+ WithGroupKind (metav1.GroupKind {
638+ Group : certmanager .GroupName ,
639+ Kind : "Certificate" ,
640+ })).
641+ WithAssertions (readyConditionAssertion )
642+ issuerProbe := ocv1ac .ProgressionProbe ().
643+ WithSelector (ocv1ac .ObjectSelector ().
644+ WithType (ocv1 .SelectorTypeGroupKind ).
645+ WithGroupKind (metav1.GroupKind {
646+ Group : certmanager .GroupName ,
647+ Kind : "Issuer" ,
648+ })).
649+ WithAssertions (readyConditionAssertion )
650+
651+ // namespaceActiveProbe is a probe which asserts that the namespace is in "Active" phase
652+ namespaceActiveProbe := ocv1ac .ProgressionProbe ().
653+ WithSelector (ocv1ac .ObjectSelector ().
654+ WithType (ocv1 .SelectorTypeGroupKind ).
655+ WithGroupKind (metav1.GroupKind {
656+ Group : corev1 .GroupName ,
657+ Kind : "Namespace" ,
658+ })).
659+ WithAssertions (ocv1ac .Assertion ().
660+ WithType (ocv1 .ProbeTypeFieldValue ).
661+ WithFieldValue (ocv1ac .FieldValueProbe ().
662+ WithFieldPath ("status.phase" ).
663+ WithValue (string (corev1 .NamespaceActive ))))
664+
665+ // pvcBoundProbe is a probe which asserts that the PVC is in "Bound" phase
666+ pvcBoundProbe := ocv1ac .ProgressionProbe ().
667+ WithSelector (ocv1ac .ObjectSelector ().
668+ WithType (ocv1 .SelectorTypeGroupKind ).
669+ WithGroupKind (metav1.GroupKind {
670+ Group : corev1 .GroupName ,
671+ Kind : "PersistentVolumeClaim" ,
672+ })).
673+ WithAssertions (ocv1ac .Assertion ().
674+ WithType (ocv1 .ProbeTypeFieldValue ).
675+ WithFieldValue (ocv1ac .FieldValueProbe ().
676+ WithFieldPath ("status.phase" ).
677+ WithValue (string (corev1 .ClaimBound ))))
678+
679+ // Checks if the Type: "Available" Condition is "True".
680+ availableConditionAssertion := ocv1ac .Assertion ().
681+ WithType (ocv1 .ProbeTypeConditionEqual ).
682+ WithConditionEqual (ocv1ac .ConditionEqualProbe ().
683+ WithType (string (appsv1 .DeploymentAvailable )).
684+ WithStatus (string (corev1 .ConditionTrue )))
685+
686+ // Checks if status.updatedReplicas == status.replicas.
687+ // Works for StatefulSets, Deployments and ReplicaSets.
688+ replicasUpdatedAssertion := ocv1ac .Assertion ().
689+ WithType (ocv1 .ProbeTypeFieldsEqual ).
690+ WithFieldsEqual (ocv1ac .FieldsEqualProbe ().
691+ WithFieldA ("status.updatedReplicas" ).
692+ WithFieldB ("status.replicas" ))
693+
694+ statefulSetProbe := ocv1ac .ProgressionProbe ().WithSelector (
695+ ocv1ac .ObjectSelector ().WithType (ocv1 .SelectorTypeGroupKind ).
696+ WithGroupKind (metav1.GroupKind {
697+ Group : appsv1 .GroupName ,
698+ Kind : "StatefulSet" ,
699+ }),
700+ ).WithAssertions (replicasUpdatedAssertion , availableConditionAssertion )
701+
702+ deploymentProbe := ocv1ac .ProgressionProbe ().WithSelector (
703+ ocv1ac .ObjectSelector ().WithType (ocv1 .SelectorTypeGroupKind ).
704+ WithGroupKind (metav1.GroupKind {
705+ Group : appsv1 .GroupName ,
706+ Kind : "Deployment" ,
707+ }),
708+ ).WithAssertions (replicasUpdatedAssertion , availableConditionAssertion )
709+
710+ return []* ocv1ac.ProgressionProbeApplyConfiguration {
711+ deploymentProbe , statefulSetProbe , pvcBoundProbe , namespaceActiveProbe , issuerProbe , certProbe , crdProbe ,
712+ }
713+ }
714+
605715func splitManifestDocuments (file string ) []string {
606716 // Estimate: typical manifests have ~50-100 lines per document
607717 // Pre-allocate for reasonable bundle size to reduce allocations
0 commit comments