Repository: openshift/cluster-ingress-operator
Pull request #1217: OCPBUGS-54745: status: Conditionally add CRDs to relatedObjects
Author: login: Miciah
Labels: name: lgtm
description: Indicates that a PR is ready to be merged.
name: approved
description: Indicates a PR has been approved by an approver from all required OWNERS files.
name: qe-approved
description: Signifies that QE has signed off on this PR
name: jira/severity-important
description: Referenced Jira bug's severity is important for the branch this PR is targeting.
name: jira/valid-bug
description: Indicates that a referenced Jira bug is valid for the branch this PR is targeting.
name: jira/valid-reference
description: Indicates that this PR references a valid Jira ticket of any type.
Created: 2025-04-09T00:24:57Z | Merged: 2025-05-29T01:17:59Z

#### status: Omit istios namespace in `relatedObjects`

Omit the namespace for the istios resource in `relatedObjects` as the istios resource is cluster-scoped.


#### status: Omit gateways namespace in `relatedObjects`

Omit the namespace for the gateways resource in `relatedObjects` as Istio manages gateways in all namespaces.


#### `getOperatorState`: Add `context` parameter

Pass `ctx` from the controller's `Reconcile` method to `getOperatorState`, and use it instead of `context.TODO()`.


#### status: Conditionally add CRDs to `relatedObjects`

Check whether the gatewayclasses, gateways, and istios CRDs actually exist before adding them to `relatedObjects`.

Watch customresourcedefinitions in the status controller so that it updates `relatedObjects` as these CRDs are created.

Check the "GatewayAPIController" featuregate to determine whether to add the gatewayclasses, gateways, istios, and subscriptions resources to relatedObjects, in addition to checking the "GatewayAPI" featuregate.

Before this change, the operator could add istios to `relatedObjects` even if the OSSM subscription failed to install.  By convention, an operator should only add resources to `relatedObjects` if those resources exist.


Diff:
diff --git a/pkg/operator/controller/status/controller.go b/pkg/operator/controller/status/controller.go
index 5bd956da9d..be802cca64 100644
--- a/pkg/operator/controller/status/controller.go
+++ b/pkg/operator/controller/status/controller.go
@@ -24,9 +24,11 @@ import (
 
 	corev1 "k8s.io/api/core/v1"
 
+	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	"k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/apimachinery/pkg/util/sets"
 	utilclock "k8s.io/utils/clock"
 
 	gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1"
@@ -50,13 +52,27 @@ const (
 
 	ingressesEqualConditionMessage = "desired and current number of IngressControllers are equal"
 
+	// gatewaysResourceName is the name of the Gateway API gateways CRD.
+	gatewaysResourceName = "gateways.gateway.networking.k8s.io"
+	// gatewayclassesResourceName is the name of the Gateway API
+	// gatewayclasses CRD.
+	gatewayclassesResourceName = "gatewayclasses.gateway.networking.k8s.io"
+	// istiosResourceName is the name of the Sail Operator istios CRD.
+	istiosResourceName = "istios.sailoperator.io"
+
 	controllerName = "status_controller"
 )
 
-var log = logf.Logger.WithName(controllerName)
+var (
+	log = logf.Logger.WithName(controllerName)
+
+	// clock is to enable unit testing
+	clock utilclock.Clock = utilclock.RealClock{}
 
-// clock is to enable unit testing
-var clock utilclock.Clock = utilclock.RealClock{}
+	// relatedObjectsCRDs is a set of names of CRDs that we add to
+	// relatedObjects if they exist.
+	relatedObjectsCRDs = sets.New[string](gatewaysResourceName, gatewayclassesResourceName, istiosResourceName)
+)
 
 // New creates the status controller. This is the controller that handles all
 // the logic for creating the ClusterOperator operator and updating its status.
@@ -99,15 +115,15 @@ func New(mgr manager.Manager, config Config) (controller.Controller, error) {
 		return nil, err
 	}
 
-	// If the "GatewayAPI" controller featuregate is enabled, watch
-	// subscriptions so that this controller can update status when the OSSM
-	// subscription is created or updated.  Note that the subscriptions
-	// resource only exists if the "OperatorLifecycleManager" capability is
-	// enabled, so we cannot watch it if the capability is not enabled.
-	// Additionally, the default catalog only exists if the "marketplace"
-	// capability is enabled, so we cannot install OSSM without that
-	// capability.
-	if config.GatewayAPIEnabled && config.MarketplaceEnabled && config.OperatorLifecycleManagerEnabled {
+	// If the "GatewayAPI" and "GatewayAPIController" featuregates are
+	// enabled, watch subscriptions so that this controller can update
+	// status when the OSSM subscription is created or updated.  Note that
+	// the subscriptions resource only exists if the
+	// "OperatorLifecycleManager" capability is enabled, so we cannot watch
+	// it if the capability is not enabled.  Additionally, the default
+	// catalog only exists if the "marketplace" capability is enabled, so we
+	// cannot install OSSM without that capability.
+	if config.GatewayAPIEnabled && config.GatewayAPIControllerEnabled && config.MarketplaceEnabled && config.OperatorLifecycleManagerEnabled {
 		if err := c.Watch(source.Kind[client.Object](operatorCache, &operatorsv1alpha1.Subscription{}, handler.EnqueueRequestsFromMapFunc(toDefaultIngressController), predicate.Funcs{
 			CreateFunc: func(e event.CreateEvent) bool {
 				return e.Object.GetNamespace() == operatorcontroller.OpenshiftOperatorNamespace
@@ -124,6 +140,22 @@ func New(mgr manager.Manager, config Config) (controller.Controller, error) {
 		})); err != nil {
 			return nil, err
 		}
+		if err := c.Watch(source.Kind[client.Object](operatorCache, &apiextensionsv1.CustomResourceDefinition{}, handler.EnqueueRequestsFromMapFunc(toDefaultIngressController), predicate.Funcs{
+			CreateFunc: func(e event.CreateEvent) bool {
+				return relatedObjectsCRDs.Has(e.Object.GetName())
+			},
+			UpdateFunc: func(e event.UpdateEvent) bool {
+				return false
+			},
+			DeleteFunc: func(e event.DeleteEvent) bool {
+				return relatedObjectsCRDs.Has(e.Object.GetName())
+			},
+			GenericFunc: func(e event.GenericEvent) bool {
+				return false
+			},
+		})); err != nil {
+			return nil, err
+		}
 	}
 
 	return c, nil
@@ -133,6 +165,9 @@ func New(mgr manager.Manager, config Config) (controller.Controller, error) {
 type Config struct {
 	// GatewayAPIEnabled indicates that the "GatewayAPI" featuregate is enabled.
 	GatewayAPIEnabled bool
+	// GatewayAPIControllerEnabled indicates that the "GatewayAPIController"
+	// featuregate is enabled.
+	GatewayAPIControllerEnabled bool
 	// MarketplaceEnabled indicates whether the "marketplace" capability is
 	// enabled.
 	MarketplaceEnabled bool
@@ -183,7 +218,7 @@ func (r *reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
 	}
 	oldStatus := co.Status.DeepCopy()
 
-	state, err := r.getOperatorState(ingressNamespace, canaryNamespace, co)
+	state, err := r.getOperatorState(ctx, ingressNamespace, canaryNamespace, co)
 	if err != nil {
 		return reconcile.Result{}, fmt.Errorf("failed to get operator state: %v", err)
 	}
@@ -220,11 +255,7 @@ func (r *reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
 			Name:     state.CanaryNamespace.Name,
 		})
 	}
-	if r.config.GatewayAPIEnabled {
-		related = append(related, configv1.ObjectReference{
-			Group:    gatewayapiv1.GroupName,
-			Resource: "gatewayclasses",
-		})
+	if r.config.GatewayAPIEnabled && r.config.GatewayAPIControllerEnabled {
 		if state.haveOSSMSubscription {
 			subscriptionName := operatorcontroller.ServiceMeshOperatorSubscriptionName()
 			related = append(related, configv1.ObjectReference{
@@ -233,18 +264,25 @@ func (r *reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
 				Namespace: subscriptionName.Namespace,
 				Name:      subscriptionName.Name,
 			})
-			if state.IngressNamespace != nil {
-				related = append(related, configv1.ObjectReference{
-					Group:     sailv1.GroupVersion.Group,
-					Resource:  "istios",
-					Namespace: state.IngressNamespace.Name,
-				})
-				related = append(related, configv1.ObjectReference{
-					Group:     gatewayapiv1.GroupName,
-					Resource:  "gateways",
-					Namespace: state.IngressNamespace.Name,
-				})
-			}
+		}
+		if state.haveIstiosResource {
+			related = append(related, configv1.ObjectReference{
+				Group:    sailv1.GroupVersion.Group,
+				Resource: "istios",
+			})
+		}
+		if state.haveGatewayclassesResource {
+			related = append(related, configv1.ObjectReference{
+				Group:    gatewayapiv1.GroupName,
+				Resource: "gatewayclasses",
+			})
+		}
+		if state.haveGatewaysResource {
+			related = append(related, configv1.ObjectReference{
+				Group:     gatewayapiv1.GroupName,
+				Resource:  "gateways",
+				Namespace: "", // Include all namespaces.
+			})
 		}
 	}
 
@@ -317,17 +355,26 @@ type operatorState struct {
 	IngressControllers []operatorv1.IngressController
 	DNSRecords         []iov1.DNSRecord
 
-	haveOSSMSubscription        bool
 	unmanagedGatewayAPICRDNames string
+	// haveOSSMSubscription means that the subscription for OSSM 3 exists.
+	haveOSSMSubscription bool
+	// haveIstiosResource means that the "istios.sailproject.io" CRD exists.
+	haveIstiosResource bool
+	// haveGatewaysResource means that the
+	// "gateways.gateway.networking.k8s.io" CRD exists.
+	haveGatewaysResource bool
+	// haveGatewayclassesResource means that the
+	// "gatewayclasses.gateway.networking.k8s.io" CRD exists.
+	haveGatewayclassesResource bool
 }
 
 // getOperatorState gets and returns the resources necessary to compute the
 // operator's current state.
-func (r *reconciler) getOperatorState(ingressNamespace, canaryNamespace string, co *configv1.ClusterOperator) (operatorState, error) {
+func (r *reconciler) getOperatorState(ctx context.Context, ingressNamespace, canaryNamespace string, co *configv1.ClusterOperator) (operatorState, error) {
 	state := operatorState{}
 
 	ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ingressNamespace}}
-	if err := r.client.Get(context.TODO(), types.NamespacedName{Name: ingressNamespace}, ns); err != nil {
+	if err := r.client.Get(ctx, types.NamespacedName{Name: ingressNamespace}, ns); err != nil {
 		if !errors.IsNotFound(err) {
 			return state, fmt.Errorf("failed to get namespace %q: %v", ingressNamespace, err)
 		}
@@ -336,7 +383,7 @@ func (r *reconciler) getOperatorState(ingressNamespace, canaryNamespace string,
 	}
 
 	ns = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: canaryNamespace}}
-	if err := r.client.Get(context.TODO(), types.NamespacedName{Name: canaryNamespace}, ns); err != nil {
+	if err := r.client.Get(ctx, types.NamespacedName{Name: canaryNamespace}, ns); err != nil {
 		if !errors.IsNotFound(err) {
 			return state, fmt.Errorf("failed to get namespace %q: %v", canaryNamespace, err)
 		}
@@ -345,17 +392,25 @@ func (r *reconciler) getOperatorState(ingressNamespace, canaryNamespace string,
 	}
 
 	ingressList := &operatorv1.IngressControllerList{}
-	if err := r.cache.List(context.TODO(), ingressList, client.InNamespace(r.config.Namespace)); err != nil {
+	if err := r.cache.List(ctx, ingressList, client.InNamespace(r.config.Namespace)); err != nil {
 		return state, fmt.Errorf("failed to list ingresscontrollers in %q: %v", r.config.Namespace, err)
 	} else {
 		state.IngressControllers = ingressList.Items
 	}
 
 	if r.config.GatewayAPIEnabled {
-		if r.config.MarketplaceEnabled && r.config.OperatorLifecycleManagerEnabled {
+		if len(co.Status.Extension.Raw) > 0 {
+			extension := &IngressOperatorStatusExtension{}
+			if err := json.Unmarshal(co.Status.Extension.Raw, extension); err != nil {
+				return state, fmt.Errorf("failed to unmarshal status extension of cluster operator %q: %w", co.Name, err)
+			}
+			state.unmanagedGatewayAPICRDNames = extension.UnmanagedGatewayAPICRDNames
+		}
+
+		if r.config.GatewayAPIControllerEnabled && r.config.MarketplaceEnabled && r.config.OperatorLifecycleManagerEnabled {
 			var subscription operatorsv1alpha1.Subscription
 			subscriptionName := operatorcontroller.ServiceMeshOperatorSubscriptionName()
-			if err := r.cache.Get(context.TODO(), subscriptionName, &subscription); err != nil {
+			if err := r.cache.Get(ctx, subscriptionName, &subscription); err != nil {
 				if !errors.IsNotFound(err) {
 					return state, fmt.Errorf("failed to get subscription %q: %v", subscriptionName, err)
 				}
@@ -363,14 +418,35 @@ func (r *reconciler) getOperatorState(ingressNamespace, canaryNamespace string,
 				state.haveOSSMSubscription = true
 
 			}
-		}
 
-		if len(co.Status.Extension.Raw) > 0 {
-			extension := &IngressOperatorStatusExtension{}
-			if err := json.Unmarshal(co.Status.Extension.Raw, extension); err != nil {
-				return state, fmt.Errorf("failed to unmarshal status extension of cluster operator %q: %w", co.Name, err)
+			var (
+				crd                                  apiextensionsv1.CustomResourceDefinition
+				gatewaysResourceNamespacedName       = types.NamespacedName{Name: gatewaysResourceName}
+				gatewayclassesResourceNamespacedName = types.NamespacedName{Name: gatewayclassesResourceName}
+				istiosResourceNamespacedName         = types.NamespacedName{Name: istiosResourceName}
+			)
+
+			if err := r.cache.Get(ctx, gatewaysResourceNamespacedName, &crd); err != nil {
+				if !errors.IsNotFound(err) {
+					return state, fmt.Errorf("failed to get CRD %q: %v", gatewaysResourceName, err)
+				}
+			} else {
+				state.haveGatewaysResource = true
+			}
+			if err := r.cache.Get(ctx, gatewayclassesResourceNamespacedName, &crd); err != nil {
+				if !errors.IsNotFound(err) {
+					return state, fmt.Errorf("failed to get CRD %q: %v", gatewayclassesResourceName, err)
+				}
+			} else {
+				state.haveGatewayclassesResource = true
+			}
+			if err := r.cache.Get(ctx, istiosResourceNamespacedName, &crd); err != nil {
+				if !errors.IsNotFound(err) {
+					return state, fmt.Errorf("failed to get CRD %q: %v", istiosResourceName, err)
+				}
+			} else {
+				state.haveIstiosResource = true
 			}
-			state.unmanagedGatewayAPICRDNames = extension.UnmanagedGatewayAPICRDNames
 		}
 	}
 
diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go
index f9d9ea3306..bf749eb849 100644
--- a/pkg/operator/operator.go
+++ b/pkg/operator/operator.go
@@ -225,6 +225,7 @@ func New(config operatorconfig.Config, kubeConfig *rest.Config) (*Operator, erro
 		CanaryImage:                     config.CanaryImage,
 		OperatorReleaseVersion:          config.OperatorReleaseVersion,
 		GatewayAPIEnabled:               gatewayAPIEnabled,
+		GatewayAPIControllerEnabled:     gatewayAPIControllerEnabled,
 		MarketplaceEnabled:              marketplaceEnabled,
 		OperatorLifecycleManagerEnabled: olmEnabled,
 	}); err != nil {
diff --git a/test/e2e/operator_test.go b/test/e2e/operator_test.go
index 09d997de97..eb5ad72328 100644
--- a/test/e2e/operator_test.go
+++ b/test/e2e/operator_test.go
@@ -233,12 +233,23 @@ func TestClusterOperatorStatusRelatedObjects(t *testing.T) {
 	if gatewayAPIEnabled, err := isFeatureGateEnabled(features.FeatureGateGatewayAPI); err != nil {
 		t.Fatalf("Failed to look up %q featuregate: %v", features.FeatureGateGatewayAPI, err)
 	} else if gatewayAPIEnabled {
-		expected = append(expected, configv1.ObjectReference{
-			Group:    "gateway.networking.k8s.io",
-			Resource: "gatewayclasses",
-		})
-		// This test runs before TestGatewayAPI, so we do *not* expect
-		// to see subscriptions, istios, or gateways in relatedObjects.
+		if gatewayAPIControllerEnabled, err := isFeatureGateEnabled(features.FeatureGateGatewayAPIController); err != nil {
+			t.Fatalf("Failed to look up %q featuregate: %v", features.FeatureGateGatewayAPIController, err)
+		} else if gatewayAPIControllerEnabled {
+			// This test runs before TestGatewayAPI creates the
+			// subscription to install OSSM, so we do *not* expect
+			// to see subscriptions or istios in relatedObjects.
+			// However, we *do* expect to see gatewayclasses and
+			// gateways whenever the GatewayAPI and
+			// GatewayAPIController featuregates are enabled.
+			expected = append(expected, configv1.ObjectReference{
+				Group:    "gateway.networking.k8s.io",
+				Resource: "gatewayclasses",
+			}, configv1.ObjectReference{
+				Group:    "gateway.networking.k8s.io",
+				Resource: "gateways",
+			})
+		}
 	}
 
 	coName := controller.IngressClusterOperatorName()


Reviews:
user: login: candita
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T21:24:40Z
user: login: Miciah
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T23:44:36Z
user: login: candita
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T21:53:17Z
user: login: candita
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T22:04:45Z
user: login: Miciah
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T22:43:45Z
user: login: Miciah
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T22:44:43Z
user: login: alebedev87
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T10:02:43Z
user: login: Miciah
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T18:45:04Z
user: login: Miciah
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T19:25:00Z
user: login: alebedev87
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T10:55:57Z
user: login: Miciah
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T20:10:44Z
user: login: alebedev87
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T16:42:01Z

Review comments:
diff_hunk: @@ -331,13 +382,44 @@ func (r *reconciler) getOperatorState(ingressNamespace, canaryNamespace string)
 	if r.config.GatewayAPIEnabled {
 		var subscription operatorsv1alpha1.Subscription
 		subscriptionName := operatorcontroller.ServiceMeshOperatorSubscriptionName()
-		if err := r.cache.Get(context.TODO(), subscriptionName, &subscription); err != nil {
+		if err := r.cache.Get(ctx, subscriptionName, &subscription); err != nil {
 			if !errors.IsNotFound(err) {
 				return state, fmt.Errorf("failed to get subscription %q: %v", subscriptionName, err)
 			}
 		} else {
 			state.haveOSSMSubscription = true
 		}
+
+		if r.config.GatewayAPIControllerEnabled {
+			var (
+				crd                                  apiextensionsv1.CustomResourceDefinition
+				gatewaysResourceNamespacedName       = types.NamespacedName{Name: gatewaysResourceName}
+				gatewayclassesResourceNamespacedName = types.NamespacedName{Name: gatewayclassesResourceName}
+				istiosResourceNamespacedName         = types.NamespacedName{Name: istiosResourceName}
+			)
+
+			if err := r.cache.Get(ctx, gatewaysResourceNamespacedName, &crd); err != nil {
+				if !errors.IsNotFound(err) {
path: pkg/operator/controller/status/controller.go
user: login: candita
body: Does it matter much if there was a prior resource, then it was deleted?  E.g. someone removed the Istio or other CRDs we're checking here - do we then need to remove these from relatedObjects?  Or is it okay because this is reconciled periodically?
created_at: 2025-04-09T21:24:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -331,13 +382,44 @@ func (r *reconciler) getOperatorState(ingressNamespace, canaryNamespace string)
 	if r.config.GatewayAPIEnabled {
 		var subscription operatorsv1alpha1.Subscription
 		subscriptionName := operatorcontroller.ServiceMeshOperatorSubscriptionName()
-		if err := r.cache.Get(context.TODO(), subscriptionName, &subscription); err != nil {
+		if err := r.cache.Get(ctx, subscriptionName, &subscription); err != nil {
 			if !errors.IsNotFound(err) {
 				return state, fmt.Errorf("failed to get subscription %q: %v", subscriptionName, err)
 			}
 		} else {
 			state.haveOSSMSubscription = true
 		}
+
+		if r.config.GatewayAPIControllerEnabled {
+			var (
+				crd                                  apiextensionsv1.CustomResourceDefinition
+				gatewaysResourceNamespacedName       = types.NamespacedName{Name: gatewaysResourceName}
+				gatewayclassesResourceNamespacedName = types.NamespacedName{Name: gatewayclassesResourceName}
+				istiosResourceNamespacedName         = types.NamespacedName{Name: istiosResourceName}
+			)
+
+			if err := r.cache.Get(ctx, gatewaysResourceNamespacedName, &crd); err != nil {
+				if !errors.IsNotFound(err) {
path: pkg/operator/controller/status/controller.go
user: login: Miciah
body: The watch on CRDs should trigger reconciliation if the istios CRD is deleted: https://github.com/openshift/cluster-ingress-operator/blob/0fa1281ffd86f48464e2f09c302f47f41bc4a8d6/pkg/operator/controller/status/controller.go#L135-L143

`getOperatorState` intializes `operatorState` leaving `haveIstiosResource` false and only sets it to true if a `Get` on the istios CRD returns a nil error value, meaning the CRD is present:
https://github.com/openshift/cluster-ingress-operator/blob/0fa1281ffd86f48464e2f09c302f47f41bc4a8d6/pkg/operator/controller/status/controller.go#L354-L355
https://github.com/openshift/cluster-ingress-operator/blob/0fa1281ffd86f48464e2f09c302f47f41bc4a8d6/pkg/operator/controller/status/controller.go#L415-L421

Then `Reconcile` only adds istios to `relatedObjects` if `haveIstiosResource` is true:
https://github.com/openshift/cluster-ingress-operator/blob/0fa1281ffd86f48464e2f09c302f47f41bc4a8d6/pkg/operator/controller/status/controller.go#L255-L260

So we should be fine.  
created_at: 2025-04-09T23:44:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -237,8 +237,18 @@ func TestClusterOperatorStatusRelatedObjects(t *testing.T) {
 			Group:    "gateway.networking.k8s.io",
 			Resource: "gatewayclasses",
 		})
-		// This test runs before TestGatewayAPI, so we do *not* expect
-		// to see subscriptions, istios, or gateways in relatedObjects.
+		if gatewayAPIControllerEnabled, err := isFeatureGateEnabled(features.FeatureGateGatewayAPIController); err != nil {
+			t.Fatalf("Failed to look up %q featuregate: %v", features.FeatureGateGatewayAPIController, err)
+		} else if gatewayAPIControllerEnabled {
+			expected = append(expected, configv1.ObjectReference{
+				Group:     "gateway.networking.k8s.io",
+				Resource:  "gateways",
+				Namespace: "openshift-ingress",
path: test/e2e/operator_test.go
user: login: candita
body: Should the namespace be blank here?


created_at: 2025-04-15T21:53:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -237,8 +237,18 @@ func TestClusterOperatorStatusRelatedObjects(t *testing.T) {
 			Group:    "gateway.networking.k8s.io",
 			Resource: "gatewayclasses",
 		})
-		// This test runs before TestGatewayAPI, so we do *not* expect
-		// to see subscriptions, istios, or gateways in relatedObjects.
+		if gatewayAPIControllerEnabled, err := isFeatureGateEnabled(features.FeatureGateGatewayAPIController); err != nil {
path: test/e2e/operator_test.go
user: login: candita
body: Based on the test output, gateways is never appended to expected.  Does anything enable `FeatureGateGatewayAPIController` before this test is run?
created_at: 2025-04-15T22:04:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -237,8 +237,18 @@ func TestClusterOperatorStatusRelatedObjects(t *testing.T) {
 			Group:    "gateway.networking.k8s.io",
 			Resource: "gatewayclasses",
 		})
-		// This test runs before TestGatewayAPI, so we do *not* expect
-		// to see subscriptions, istios, or gateways in relatedObjects.
+		if gatewayAPIControllerEnabled, err := isFeatureGateEnabled(features.FeatureGateGatewayAPIController); err != nil {
+			t.Fatalf("Failed to look up %q featuregate: %v", features.FeatureGateGatewayAPIController, err)
+		} else if gatewayAPIControllerEnabled {
+			expected = append(expected, configv1.ObjectReference{
+				Group:     "gateway.networking.k8s.io",
+				Resource:  "gateways",
+				Namespace: "openshift-ingress",
path: test/e2e/operator_test.go
user: login: Miciah
body: Possibly.  My thinking was that we were telling people to create gateways in the "openshift-ingress" namespace, so the platform-managed ones should be there, we're allowing gateways in other namespaces as well (we just won't manage DNS for them).  Based on that, I suppose it makes sense to leave the namespace blank.  
created_at: 2025-04-15T22:43:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -237,8 +237,18 @@ func TestClusterOperatorStatusRelatedObjects(t *testing.T) {
 			Group:    "gateway.networking.k8s.io",
 			Resource: "gatewayclasses",
 		})
-		// This test runs before TestGatewayAPI, so we do *not* expect
-		// to see subscriptions, istios, or gateways in relatedObjects.
+		if gatewayAPIControllerEnabled, err := isFeatureGateEnabled(features.FeatureGateGatewayAPIController); err != nil {
path: test/e2e/operator_test.go
user: login: Miciah
body: The featuregate should be enabled in the techpreview jobs and not currently enabled in any other jobs.  
created_at: 2025-04-15T22:44:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -219,18 +252,25 @@ func (r *reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
 				Namespace: subscriptionName.Namespace,
 				Name:      subscriptionName.Name,
 			})
-			if state.IngressNamespace != nil {
-				related = append(related, configv1.ObjectReference{
-					Group:     sailv1.GroupVersion.Group,
-					Resource:  "istios",
-					Namespace: state.IngressNamespace.Name,
-				})
-				related = append(related, configv1.ObjectReference{
-					Group:     gatewayapiv1.GroupName,
-					Resource:  "gateways",
-					Namespace: state.IngressNamespace.Name,
-				})
-			}
+		}
+		if state.haveIstiosResource {
+			related = append(related, configv1.ObjectReference{
+				Group:    sailv1.GroupVersion.Group,
+				Resource: "istios",
+			})
+		}
+		if state.haveGatewayclassesResource {
+			related = append(related, configv1.ObjectReference{
+				Group:    gatewayapiv1.GroupName,
+				Resource: "gatewayclasses",
+			})
+		}
+		if state.haveGatewaysResource {
+			related = append(related, configv1.ObjectReference{
+				Group:     gatewayapiv1.GroupName,
+				Resource:  "gateways",
+				Namespace: "", // Include all namespaces.
path: pkg/operator/controller/status/controller.go
user: login: alebedev87
body: Does it mean that we include all resources with this group to the related objects (not CRD)? If so, I have the question below.

From one hand, [`PILOT_ENABLE_GATEWAY_CONTROLLER_MODE` description](https://github.com/openshift/cluster-ingress-operator/blob/86f19bd34a6f24e6836d4496fc17a13671379af0/pkg/operator/controller/gatewayclass/istio.go#L86-L90) says that gateway api resources are watched from all namespaces (btw I failed to find this variable in [downstream istio](https://github.com/openshift-service-mesh/istio/blob/748c90d41d4b04cb0aa3a1251dd24e07a1f27bfc/pilot/pkg/features/pilot.go)). From the other hand [we don't manage DNS for gateways from namespaces other than `openshift-ingress`](https://github.com/openshift/cluster-ingress-operator/blob/86f19bd34a6f24e6836d4496fc17a13671379af0/pkg/operator/controller/gateway-service-dns/controller.go#L109-L114). Do we consider gateways with BYO DNS are managed by us?
created_at: 2025-04-22T09:42:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -355,6 +404,37 @@ func (r *reconciler) getOperatorState(ingressNamespace, canaryNamespace string,
 			}
 			state.unmanagedGatewayAPICRDNames = extension.UnmanagedGatewayAPICRDNames
 		}
+
+		if r.config.GatewayAPIControllerEnabled {
path: pkg/operator/controller/status/controller.go
user: login: alebedev87
body: I'm wondering about the logic to put the check for `Gateway`/`GatewayClass` CRDs into this condition while `Subscription` check remains in the condition above (`GatewayAPI` featuregate). `Subscription` and `Istio` CRD can only be created when `GatewayAPIController` is enabled while `Gateway`/`GatewayClass` CRDs are created when `GatewayAPI` is enabled.
created_at: 2025-04-22T10:00:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -219,18 +252,25 @@ func (r *reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
 				Namespace: subscriptionName.Namespace,
 				Name:      subscriptionName.Name,
 			})
-			if state.IngressNamespace != nil {
-				related = append(related, configv1.ObjectReference{
-					Group:     sailv1.GroupVersion.Group,
-					Resource:  "istios",
-					Namespace: state.IngressNamespace.Name,
-				})
-				related = append(related, configv1.ObjectReference{
-					Group:     gatewayapiv1.GroupName,
-					Resource:  "gateways",
-					Namespace: state.IngressNamespace.Name,
-				})
-			}
+		}
+		if state.haveIstiosResource {
+			related = append(related, configv1.ObjectReference{
+				Group:    sailv1.GroupVersion.Group,
+				Resource: "istios",
+			})
+		}
+		if state.haveGatewayclassesResource {
+			related = append(related, configv1.ObjectReference{
+				Group:    gatewayapiv1.GroupName,
+				Resource: "gatewayclasses",
+			})
+		}
+		if state.haveGatewaysResource {
+			related = append(related, configv1.ObjectReference{
+				Group:     gatewayapiv1.GroupName,
+				Resource:  "gateways",
+				Namespace: "", // Include all namespaces.
path: pkg/operator/controller/status/controller.go
user: login: Miciah
body: > Does it mean that we include all resources with this group to the related objects (not CRD)? 

Yes.  The reference specifies the "gateways" resource but doesn't specify the namespace, so the reference includes any gateway in any namespace.  

> From one hand, [`PILOT_ENABLE_GATEWAY_CONTROLLER_MODE` description](https://github.com/openshift/cluster-ingress-operator/blob/86f19bd34a6f24e6836d4496fc17a13671379af0/pkg/operator/controller/gatewayclass/istio.go#L86-L90) says that gateway api resources are watched from all namespaces (btw I failed to find this variable in [downstream istio](https://github.com/openshift-service-mesh/istio/blob/748c90d41d4b04cb0aa3a1251dd24e07a1f27bfc/pilot/pkg/features/pilot.go)).

`PILOT_ENABLE_GATEWAY_CONTROLLER_MODE` is referenced here: https://github.com/openshift-service-mesh/sail-operator/blob/release-3.0/chart/samples/gwControllerMode.yaml#L14

However, I think that this variable is actually ignored by OSSM 3, as you say, as it has been superseded by EnhancedResourceScoping.  @dgn, is this correct?  Is the example Helm chart out of date?  

I intend to remove setting `PILOT_ENABLE_GATEWAY_CONTROLLER_MODE` from this operator with https://github.com/openshift/cluster-ingress-operator/pull/1227/commits/43caa071bd32d2285fbce6f4cac7b0cff2c7dd15.

> From the other hand [we don't manage DNS for gateways from namespaces other than `openshift-ingress`](https://github.com/openshift/cluster-ingress-operator/blob/86f19bd34a6f24e6836d4496fc17a13671379af0/pkg/operator/controller/gateway-service-dns/controller.go#L109-L114). Do we consider gateways with BYO DNS are managed by us?

Yes, Istio provisions a proxy even if cluster-ingress-operator doesn't publish a DNS record, so I consider such gateways to be managed by the OpenShift platform.  
created_at: 2025-05-14T18:45:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -355,6 +404,37 @@ func (r *reconciler) getOperatorState(ingressNamespace, canaryNamespace string,
 			}
 			state.unmanagedGatewayAPICRDNames = extension.UnmanagedGatewayAPICRDNames
 		}
+
+		if r.config.GatewayAPIControllerEnabled {
path: pkg/operator/controller/status/controller.go
user: login: Miciah
body: That's a fair point.  I address it with https://github.com/openshift/cluster-ingress-operator/compare/1c68435a08d7a3adac8744082ed74146548b9f7c..6f42089c113be8c5286f35aefa9d52130753face by conditionalizing more logic on `GatewayAPIControllerEnabled`.  This also relates to (and conflicted with) the changes in #1232.  
created_at: 2025-05-14T19:25:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -345,32 +392,61 @@ func (r *reconciler) getOperatorState(ingressNamespace, canaryNamespace string,
 	}
 
 	ingressList := &operatorv1.IngressControllerList{}
-	if err := r.cache.List(context.TODO(), ingressList, client.InNamespace(r.config.Namespace)); err != nil {
+	if err := r.cache.List(ctx, ingressList, client.InNamespace(r.config.Namespace)); err != nil {
 		return state, fmt.Errorf("failed to list ingresscontrollers in %q: %v", r.config.Namespace, err)
 	} else {
 		state.IngressControllers = ingressList.Items
 	}
 
 	if r.config.GatewayAPIEnabled {
-		if r.config.MarketplaceEnabled && r.config.OperatorLifecycleManagerEnabled {
+		if len(co.Status.Extension.Raw) > 0 {
+			extension := &IngressOperatorStatusExtension{}
+			if err := json.Unmarshal(co.Status.Extension.Raw, extension); err != nil {
+				return state, fmt.Errorf("failed to unmarshal status extension of cluster operator %q: %w", co.Name, err)
+			}
+			state.unmanagedGatewayAPICRDNames = extension.UnmanagedGatewayAPICRDNames
+		}
+
+		if r.config.GatewayAPIControllerEnabled && r.config.MarketplaceEnabled && r.config.OperatorLifecycleManagerEnabled {
 			var subscription operatorsv1alpha1.Subscription
 			subscriptionName := operatorcontroller.ServiceMeshOperatorSubscriptionName()
-			if err := r.cache.Get(context.TODO(), subscriptionName, &subscription); err != nil {
+			if err := r.cache.Get(ctx, subscriptionName, &subscription); err != nil {
 				if !errors.IsNotFound(err) {
 					return state, fmt.Errorf("failed to get subscription %q: %v", subscriptionName, err)
 				}
 			} else {
 				state.haveOSSMSubscription = true
 
 			}
-		}
 
-		if len(co.Status.Extension.Raw) > 0 {
-			extension := &IngressOperatorStatusExtension{}
-			if err := json.Unmarshal(co.Status.Extension.Raw, extension); err != nil {
-				return state, fmt.Errorf("failed to unmarshal status extension of cluster operator %q: %w", co.Name, err)
+			var (
+				crd                                  apiextensionsv1.CustomResourceDefinition
+				gatewaysResourceNamespacedName       = types.NamespacedName{Name: gatewaysResourceName}
+				gatewayclassesResourceNamespacedName = types.NamespacedName{Name: gatewayclassesResourceName}
+				istiosResourceNamespacedName         = types.NamespacedName{Name: istiosResourceName}
+			)
+
+			if err := r.cache.Get(ctx, gatewaysResourceNamespacedName, &crd); err != nil {
+				if !errors.IsNotFound(err) {
+					return state, fmt.Errorf("failed to get CRD %q: %v", gatewaysResourceName, err)
+				}
+			} else {
+				state.haveGatewaysResource = true
+			}
+			if err := r.cache.Get(ctx, gatewayclassesResourceNamespacedName, &crd); err != nil {
+				if !errors.IsNotFound(err) {
+					return state, fmt.Errorf("failed to get CRD %q: %v", gatewayclassesResourceName, err)
+				}
+			} else {
+				state.haveGatewayclassesResource = true
+			}
path: pkg/operator/controller/status/controller.go
user: login: alebedev87
body: `GatewayClass`es and `Gateway`s can be created even if OLM capabilities are not present. Should we move them up? Out of `if r.config.GatewayAPIControllerEnabled && r.config.MarketplaceEnabled && r.config.OperatorLifecycleManagerEnabled` condition.
created_at: 2025-05-16T10:55:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -345,32 +392,61 @@ func (r *reconciler) getOperatorState(ingressNamespace, canaryNamespace string,
 	}
 
 	ingressList := &operatorv1.IngressControllerList{}
-	if err := r.cache.List(context.TODO(), ingressList, client.InNamespace(r.config.Namespace)); err != nil {
+	if err := r.cache.List(ctx, ingressList, client.InNamespace(r.config.Namespace)); err != nil {
 		return state, fmt.Errorf("failed to list ingresscontrollers in %q: %v", r.config.Namespace, err)
 	} else {
 		state.IngressControllers = ingressList.Items
 	}
 
 	if r.config.GatewayAPIEnabled {
-		if r.config.MarketplaceEnabled && r.config.OperatorLifecycleManagerEnabled {
+		if len(co.Status.Extension.Raw) > 0 {
+			extension := &IngressOperatorStatusExtension{}
+			if err := json.Unmarshal(co.Status.Extension.Raw, extension); err != nil {
+				return state, fmt.Errorf("failed to unmarshal status extension of cluster operator %q: %w", co.Name, err)
+			}
+			state.unmanagedGatewayAPICRDNames = extension.UnmanagedGatewayAPICRDNames
+		}
+
+		if r.config.GatewayAPIControllerEnabled && r.config.MarketplaceEnabled && r.config.OperatorLifecycleManagerEnabled {
 			var subscription operatorsv1alpha1.Subscription
 			subscriptionName := operatorcontroller.ServiceMeshOperatorSubscriptionName()
-			if err := r.cache.Get(context.TODO(), subscriptionName, &subscription); err != nil {
+			if err := r.cache.Get(ctx, subscriptionName, &subscription); err != nil {
 				if !errors.IsNotFound(err) {
 					return state, fmt.Errorf("failed to get subscription %q: %v", subscriptionName, err)
 				}
 			} else {
 				state.haveOSSMSubscription = true
 
 			}
-		}
 
-		if len(co.Status.Extension.Raw) > 0 {
-			extension := &IngressOperatorStatusExtension{}
-			if err := json.Unmarshal(co.Status.Extension.Raw, extension); err != nil {
-				return state, fmt.Errorf("failed to unmarshal status extension of cluster operator %q: %w", co.Name, err)
+			var (
+				crd                                  apiextensionsv1.CustomResourceDefinition
+				gatewaysResourceNamespacedName       = types.NamespacedName{Name: gatewaysResourceName}
+				gatewayclassesResourceNamespacedName = types.NamespacedName{Name: gatewayclassesResourceName}
+				istiosResourceNamespacedName         = types.NamespacedName{Name: istiosResourceName}
+			)
+
+			if err := r.cache.Get(ctx, gatewaysResourceNamespacedName, &crd); err != nil {
+				if !errors.IsNotFound(err) {
+					return state, fmt.Errorf("failed to get CRD %q: %v", gatewaysResourceName, err)
+				}
+			} else {
+				state.haveGatewaysResource = true
+			}
+			if err := r.cache.Get(ctx, gatewayclassesResourceNamespacedName, &crd); err != nil {
+				if !errors.IsNotFound(err) {
+					return state, fmt.Errorf("failed to get CRD %q: %v", gatewayclassesResourceName, err)
+				}
+			} else {
+				state.haveGatewayclassesResource = true
+			}
path: pkg/operator/controller/status/controller.go
user: login: Miciah
body: I've gone back and forth on this matter, and I think there are reasonable arguments either way.  In my most recent update, I have conditionalized adding gatewayclasses and gateways to `relatedObjects` with the condition `r.config.GatewayAPIControllerEnabled && r.config.MarketplaceEnabled && r.config.OperatorLifecycleManagerEnabled` on the grounds that we are only adding these resources to `relatedObjects` as part of, and in support of, the controller feature.  That is, if we didn't provide our own controller and were only providing the CRDs, then we wouldn't bother gathering gatewayclasses or gateways; we only need these resources in order to diagnose issues with the gateway controller.  

If the operator could specify gateways and gatewayclasses by controller name in the `relatedObjects` specification, I would consider doing that.  As it is, the operator would need to check the controller name on each gatewayclass and then check the gatewayclass name on each gateway in order to add each individual gatewayclass or gateway that our controller managed, and I don't think that that would be appropriate or worth the effort.
created_at: 2025-05-16T20:10:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -345,32 +392,61 @@ func (r *reconciler) getOperatorState(ingressNamespace, canaryNamespace string,
 	}
 
 	ingressList := &operatorv1.IngressControllerList{}
-	if err := r.cache.List(context.TODO(), ingressList, client.InNamespace(r.config.Namespace)); err != nil {
+	if err := r.cache.List(ctx, ingressList, client.InNamespace(r.config.Namespace)); err != nil {
 		return state, fmt.Errorf("failed to list ingresscontrollers in %q: %v", r.config.Namespace, err)
 	} else {
 		state.IngressControllers = ingressList.Items
 	}
 
 	if r.config.GatewayAPIEnabled {
-		if r.config.MarketplaceEnabled && r.config.OperatorLifecycleManagerEnabled {
+		if len(co.Status.Extension.Raw) > 0 {
+			extension := &IngressOperatorStatusExtension{}
+			if err := json.Unmarshal(co.Status.Extension.Raw, extension); err != nil {
+				return state, fmt.Errorf("failed to unmarshal status extension of cluster operator %q: %w", co.Name, err)
+			}
+			state.unmanagedGatewayAPICRDNames = extension.UnmanagedGatewayAPICRDNames
+		}
+
+		if r.config.GatewayAPIControllerEnabled && r.config.MarketplaceEnabled && r.config.OperatorLifecycleManagerEnabled {
 			var subscription operatorsv1alpha1.Subscription
 			subscriptionName := operatorcontroller.ServiceMeshOperatorSubscriptionName()
-			if err := r.cache.Get(context.TODO(), subscriptionName, &subscription); err != nil {
+			if err := r.cache.Get(ctx, subscriptionName, &subscription); err != nil {
 				if !errors.IsNotFound(err) {
 					return state, fmt.Errorf("failed to get subscription %q: %v", subscriptionName, err)
 				}
 			} else {
 				state.haveOSSMSubscription = true
 
 			}
-		}
 
-		if len(co.Status.Extension.Raw) > 0 {
-			extension := &IngressOperatorStatusExtension{}
-			if err := json.Unmarshal(co.Status.Extension.Raw, extension); err != nil {
-				return state, fmt.Errorf("failed to unmarshal status extension of cluster operator %q: %w", co.Name, err)
+			var (
+				crd                                  apiextensionsv1.CustomResourceDefinition
+				gatewaysResourceNamespacedName       = types.NamespacedName{Name: gatewaysResourceName}
+				gatewayclassesResourceNamespacedName = types.NamespacedName{Name: gatewayclassesResourceName}
+				istiosResourceNamespacedName         = types.NamespacedName{Name: istiosResourceName}
+			)
+
+			if err := r.cache.Get(ctx, gatewaysResourceNamespacedName, &crd); err != nil {
+				if !errors.IsNotFound(err) {
+					return state, fmt.Errorf("failed to get CRD %q: %v", gatewaysResourceName, err)
+				}
+			} else {
+				state.haveGatewaysResource = true
+			}
+			if err := r.cache.Get(ctx, gatewayclassesResourceNamespacedName, &crd); err != nil {
+				if !errors.IsNotFound(err) {
+					return state, fmt.Errorf("failed to get CRD %q: %v", gatewayclassesResourceName, err)
+				}
+			} else {
+				state.haveGatewayclassesResource = true
+			}
path: pkg/operator/controller/status/controller.go
user: login: alebedev87
body: > That is, if we didn't provide our own controller and were only providing the CRDs, then we wouldn't bother gathering gatewayclasses or gateways; we only need these resources in order to diagnose issues with the gateway controller.

Ack.
created_at: 2025-05-21T16:42:01Z
author_association: CONTRIBUTOR

PR comments:
user: login: openshift-ci-robot
created_at: 2025-04-09T00:25:03Z
body: @Miciah: This pull request references [Jira Issue OCPBUGS-54745](https://issues.redhat.com//browse/OCPBUGS-54745), which is invalid:
 - expected the bug to target the "4.19.0" version, but no target version was set

Comment <code>/jira refresh</code> to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

<details>

In response to [this](https://github.com/openshift/cluster-ingress-operator/pull/1217):

>#### `getOperatorState`: Add `context` parameter
> 
>Pass `ctx` from the controller's `Reconcile` method to `getOperatorState, and use it instead of `context.TODO()`.
>  
>#### status: Conditionally add CRDs to `relatedObjects`
> 
>Check whether the gatewayclasses, gateways, and istios CRDs actually exist before adding them to relatedObjects.
> 
>Also, use the "GatewayAPIController" featuregate for the gateways and istios resources, rather than the "GatewayAPI" featuregate.
> 
>Before this change, the operator could add istios to `relatedObjects` even if the OSSM subscription failed to install.  By convention, an operator should only add resources to `relatedObjects` if those resources exist.
> 


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift%2Fcluster-ingress-operator).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: CONTRIBUTOR
user: login: Miciah
created_at: 2025-04-09T00:29:52Z
body: /jira refresh
author_association: CONTRIBUTOR
user: login: openshift-ci-robot
created_at: 2025-04-09T00:30:01Z
body: @Miciah: This pull request references [Jira Issue OCPBUGS-54745](https://issues.redhat.com//browse/OCPBUGS-54745), which is valid. The bug has been moved to the POST state.

<details><summary>3 validation(s) were run on this bug</summary>

* bug is open, matching expected state (open)
* bug target version (4.19.0) matches configured target version for branch (4.19.0)
* bug is in the state New, which is one of the valid states (NEW, ASSIGNED, POST)</details>

Requesting review from QA contact:
/cc @lihongan

<details>

In response to [this](https://github.com/openshift/cluster-ingress-operator/pull/1217#issuecomment-2787934807):

>/jira refresh


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift%2Fcluster-ingress-operator).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: CONTRIBUTOR
user: login: candita
created_at: 2025-04-09T15:23:35Z
body: /assign @alebedev87 
/assign
author_association: CONTRIBUTOR
user: login: candita
created_at: 2025-04-09T21:32:44Z
body: Cluster install failure
/test e2e-aws-operator-techpreview
author_association: CONTRIBUTOR
user: login: Miciah
created_at: 2025-04-10T13:23:22Z
body: /test all
since #1214 merged.  
author_association: CONTRIBUTOR
user: login: candita
created_at: 2025-04-11T16:36:20Z
body: /retest-required
author_association: CONTRIBUTOR
user: login: candita
created_at: 2025-04-11T16:50:49Z
body: E2E Test failure:
 operator_test.go:254: 
Expected [{Group: Resource:namespaces Namespace: Name:openshift-ingress-operator} 
{Group:operator.openshift.io Resource:ingresscontrollers Namespace:openshift-ingress-operator Name:} {Group:ingress.operator.openshift.io Resource:dnsrecords Namespace:openshift-ingress-operator Name:} 
{Group: Resource:namespaces Namespace: Name:openshift-ingress} 
{Group:ingress.operator.openshift.io Resource:dnsrecords Namespace:openshift-ingress Name:} 
{Group: Resource:namespaces Namespace: Name:openshift-ingress-canary} 
{Group:gateway.networking.k8s.io Resource:gatewayclasses Namespace: Name:}],

found [{Group: Resource:namespaces Namespace: Name:openshift-ingress-operator} 
{Group:operator.openshift.io Resource:ingresscontrollers Namespace:openshift-ingress-operator Name:} {Group:ingress.operator.openshift.io Resource:dnsrecords Namespace:openshift-ingress-operator Name:} 
{Group: Resource:namespaces Namespace: Name:openshift-ingress} 
{Group:ingress.operator.openshift.io Resource:dnsrecords Namespace:openshift-ingress Name:} 
{Group: Resource:namespaces Namespace: Name:openshift-ingress-canary} 
{Group:gateway.networking.k8s.io Resource:gatewayclasses Namespace: Name:} 
**{Group:gateway.networking.k8s.io Resource:gateways Namespace:openshift-ingress Name:}]**
    operator_test.go:264: Did not get expected status related objects: timed out waiting for the condition
author_association: CONTRIBUTOR
user: login: Miciah
created_at: 2025-04-11T17:20:12Z
body: https://github.com/openshift/cluster-ingress-operator/compare/0fa1281ffd86f48464e2f09c302f47f41bc4a8d6..c7db35d125f750f799fe98bf48a850089b1b09e2 makes two changes:

- Only add the "subscriptions" resource to `relatedObjects` if the "GatewayAPIController" featuregate is enabled.
- Adjust `TestClusterOperatorStatusRelatedObjects` to expect "gateways" in `relatedObjects` if the "GatewayAPIController" featuregate is enabled.  
author_association: CONTRIBUTOR
user: login: candita
created_at: 2025-04-11T21:41:11Z
body: /test e2e-aws-gatewayapi

author_association: CONTRIBUTOR
user: login: candita
created_at: 2025-04-11T23:14:32Z
body: /retest
author_association: CONTRIBUTOR
user: login: candita
created_at: 2025-04-15T21:39:34Z
body: /retest-required
author_association: CONTRIBUTOR
user: login: Miciah
created_at: 2025-04-15T23:22:19Z
body: https://github.com/openshift/cluster-ingress-operator/compare/c7db35d125f750f799fe98bf48a850089b1b09e2..4ca2f3ee05bcafa57afef7ab12e18e29f934db4b makes these changes:

- Update the status controller to add "gatewayclasses" to `relatedObjects` if, and only if, *both* the "GatewayAPI" *and* "GatewayAPIController" featuregates are enabled.
- Omit the namespace for gateways in `relatedObjects` as Istio manages gateways in any namespace.  
- Update `TestClusterOperatorStatusRelatedObjects` accordingly.  
author_association: CONTRIBUTOR
user: login: Miciah
created_at: 2025-04-15T23:55:22Z
body: https://github.com/openshift/cluster-ingress-operator/compare/570e600bbad851844800ab080b32df0796bd7a04..ad9275e5917f18ad9739586e627ba7cb22c1fce2 rebases for #1205.  
author_association: CONTRIBUTOR
user: login: Miciah
created_at: 2025-04-16T00:03:24Z
body: https://github.com/openshift/cluster-ingress-operator/compare/ad9275e5917f18ad9739586e627ba7cb22c1fce2..1c68435a08d7a3adac8744082ed74146548b9f7c deletes an unnecessary check for the operand namespace's existence, which is unnecessary when we don't specify the operand namespace for a resource in `relatedObjects`.  
author_association: CONTRIBUTOR
user: login: candita
created_at: 2025-04-18T20:15:59Z
body: /retest-required
author_association: CONTRIBUTOR
user: login: candita
created_at: 2025-04-21T16:45:42Z
body: /retest-required
author_association: CONTRIBUTOR
user: login: candita
created_at: 2025-04-21T21:33:24Z
body: /retest-required
author_association: CONTRIBUTOR
user: login: Miciah
created_at: 2025-04-23T13:20:50Z
body: /hold
We'll merge this after branch cut.  
author_association: CONTRIBUTOR
user: login: rhamini3
created_at: 2025-04-24T20:28:51Z
body: /test e2e-gcp-ovn-techpreview
author_association: CONTRIBUTOR
user: login: openshift-ci[bot]
created_at: 2025-04-24T20:28:54Z
body: @rhamini3: The specified target(s) for `/test` were not found.
The following commands are available to trigger required jobs:
```
/test e2e-aws-operator
```
```
/test e2e-aws-ovn
```
```
/test e2e-aws-ovn-serial
```
```
/test e2e-aws-ovn-upgrade
```
```
/test e2e-azure-operator
```
```
/test e2e-gcp-operator
```
```
/test e2e-hypershift
```
```
/test hypershift-e2e-aks
```
```
/test images
```
```
/test unit
```
```
/test verify
```

The following commands are available to trigger optional jobs:
```
/test e2e-aws-gatewayapi
```
```
/test e2e-aws-gatewayapi-conformance
```
```
/test e2e-aws-operator-techpreview
```
```
/test e2e-aws-ovn-single-node
```
```
/test e2e-aws-ovn-techpreview
```
```
/test e2e-azure-manual-oidc
```
```
/test e2e-azure-ovn
```
```
/test e2e-gcp-ovn
```
```
/test e2e-ibmcloud-operator
```
```
/test e2e-openstack-operator
```
```
/test okd-scos-e2e-aws-ovn
```
```
/test okd-scos-images
```

Use `/test all` to run the following jobs that were automatically triggered:
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-aws-gatewayapi
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-aws-operator
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-aws-operator-techpreview
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-aws-ovn
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-aws-ovn-serial
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-aws-ovn-single-node
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-aws-ovn-techpreview
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-aws-ovn-upgrade
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-azure-operator
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-azure-ovn
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-gcp-operator
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-gcp-ovn
```
```
pull-ci-openshift-cluster-ingress-operator-master-e2e-hypershift
```
```
pull-ci-openshift-cluster-ingress-operator-master-hypershift-e2e-aks
```
```
pull-ci-openshift-cluster-ingress-operator-master-images
```
```
pull-ci-openshift-cluster-ingress-operator-master-okd-scos-e2e-aws-ovn
```
```
pull-ci-openshift-cluster-ingress-operator-master-unit
```
```
pull-ci-openshift-cluster-ingress-operator-master-verify
```



<details>

In response to [this](https://github.com/openshift/cluster-ingress-operator/pull/1217#issuecomment-2828783199):

>/test e2e-gcp-ovn-techpreview


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>
author_association: CONTRIBUTOR
user: login: rhamini3
created_at: 2025-04-30T18:30:18Z
body: Valid related objects test is now passing with the proposed changes in [AWS Tech Preview](https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_cluster-ingress-operator/1217/pull-ci-openshift-cluster-ingress-operator-master-e2e-aws-ovn-techpreview/1912295818073739264)
Marking bug as verified
/label qe-approved
author_association: CONTRIBUTOR
user: login: openshift-ci-robot
created_at: 2025-04-30T18:30:24Z
body: @Miciah: This pull request references [Jira Issue OCPBUGS-54745](https://issues.redhat.com//browse/OCPBUGS-54745), which is valid.

<details><summary>3 validation(s) were run on this bug</summary>

* bug is open, matching expected state (open)
* bug target version (4.19.0) matches configured target version for branch (4.19.0)
* bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)</details>

No GitHub users were found matching the public email listed for the QA contact in Jira (iamin@redhat.com), skipping review request.

<details>

In response to [this](https://github.com/openshift/cluster-ingress-operator/pull/1217):

>#### `getOperatorState`: Add `context` parameter
> 
>Pass `ctx` from the controller's `Reconcile` method to `getOperatorState, and use it instead of `context.TODO()`.
>  
>#### status: Conditionally add CRDs to `relatedObjects`
> 
>Check whether the gatewayclasses, gateways, and istios CRDs actually exist before adding them to relatedObjects.
> 
>Also, use the "GatewayAPIController" featuregate for the gateways and istios resources, rather than the "GatewayAPI" featuregate.
> 
>Before this change, the operator could add istios to `relatedObjects` even if the OSSM subscription failed to install.  By convention, an operator should only add resources to `relatedObjects` if those resources exist.
> 


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift%2Fcluster-ingress-operator).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: CONTRIBUTOR
user: login: openshift-ci-robot
created_at: 2025-05-14T19:24:00Z
body: @Miciah: This pull request references [Jira Issue OCPBUGS-54745](https://issues.redhat.com//browse/OCPBUGS-54745), which is invalid:
 - expected the bug to target either version "4.20.*" or "openshift-4.20.*", but it targets "4.19.0" instead

Comment <code>/jira refresh</code> to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

<details>

In response to [this](https://github.com/openshift/cluster-ingress-operator/pull/1217):

>#### status: Omit istios namespace in `relatedObjects`
>
>Omit the namespace for the istios resource in `relatedObjects` as the istios resource is cluster-scoped.
>
>
>#### status: Omit gateways namespace in `relatedObjects`
>
>Omit the namespace for the gateways resource in `relatedObjects` as Istio manages gateways in all namespaces.
>
>
>#### `getOperatorState`: Add `context` parameter
>
>Pass `ctx` from the controller's `Reconcile` method to `getOperatorState, and use it instead of `context.TODO()`.
>
>
>#### status: Conditionally add CRDs to `relatedObjects`
>
>Check whether the gatewayclasses, gateways, and istios CRDs actually exist before adding them to `relatedObjects`.
>
>Watch customresourcedefinitions in the status controller so that it updates `relatedObjects` as these CRDs are created.
>
>Check the "GatewayAPIController" featuregate to determine whether to add the gatewayclasses, gateways, istios, and subscriptions resources to relatedObjects, in addition to checking the "GatewayAPI" featuregate.
>
>Before this change, the operator could add istios to `relatedObjects` even if the OSSM subscription failed to install.  By convention, an operator should only add resources to `relatedObjects` if those resources exist.


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift%2Fcluster-ingress-operator).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: CONTRIBUTOR
user: login: Miciah
created_at: 2025-05-14T19:34:50Z
body: /hold cancel
author_association: CONTRIBUTOR
user: login: openshift-ci[bot]
created_at: 2025-05-15T15:51:26Z
body: @Miciah: all tests **passed!**


[Full PR test history](https://prow.ci.openshift.org/pr-history?org=openshift&repo=cluster-ingress-operator&pr=1217). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:Miciah).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
author_association: CONTRIBUTOR
user: login: alebedev87
created_at: 2025-05-21T16:42:23Z
body: /lgtm
/approve
author_association: CONTRIBUTOR
user: login: openshift-ci[bot]
created_at: 2025-05-21T16:42:51Z
body: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/openshift/cluster-ingress-operator/pull/1217#issuecomment-2898595665" title="Approved">alebedev87</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=openshift%2Fcluster-ingress-operator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/openshift/cluster-ingress-operator/blob/master/OWNERS)~~ [alebedev87]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
author_association: CONTRIBUTOR
user: login: Miciah
created_at: 2025-05-29T01:13:28Z
body: /jira refresh
author_association: CONTRIBUTOR
user: login: openshift-ci-robot
created_at: 2025-05-29T01:13:34Z
body: @Miciah: This pull request references [Jira Issue OCPBUGS-54745](https://issues.redhat.com//browse/OCPBUGS-54745), which is valid.

<details><summary>3 validation(s) were run on this bug</summary>

* bug is open, matching expected state (open)
* bug target version (4.20.0) matches configured target version for branch (4.20.0)
* bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)</details>

No GitHub users were found matching the public email listed for the QA contact in Jira (iamin@redhat.com), skipping review request.

<details>

In response to [this](https://github.com/openshift/cluster-ingress-operator/pull/1217#issuecomment-2917955965):

>/jira refresh


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift%2Fcluster-ingress-operator).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: CONTRIBUTOR
user: login: openshift-ci-robot
created_at: 2025-05-29T01:18:04Z
body: @Miciah: [Jira Issue OCPBUGS-54745](https://issues.redhat.com//browse/OCPBUGS-54745): All pull requests linked via external trackers have merged:
 * [openshift/cluster-ingress-operator#1217](https://github.com/openshift/cluster-ingress-operator/pull/1217)

[Jira Issue OCPBUGS-54745](https://issues.redhat.com//browse/OCPBUGS-54745) has been moved to the MODIFIED state.

<details>

In response to [this](https://github.com/openshift/cluster-ingress-operator/pull/1217):

>#### status: Omit istios namespace in `relatedObjects`
>
>Omit the namespace for the istios resource in `relatedObjects` as the istios resource is cluster-scoped.
>
>
>#### status: Omit gateways namespace in `relatedObjects`
>
>Omit the namespace for the gateways resource in `relatedObjects` as Istio manages gateways in all namespaces.
>
>
>#### `getOperatorState`: Add `context` parameter
>
>Pass `ctx` from the controller's `Reconcile` method to `getOperatorState, and use it instead of `context.TODO()`.
>
>
>#### status: Conditionally add CRDs to `relatedObjects`
>
>Check whether the gatewayclasses, gateways, and istios CRDs actually exist before adding them to `relatedObjects`.
>
>Watch customresourcedefinitions in the status controller so that it updates `relatedObjects` as these CRDs are created.
>
>Check the "GatewayAPIController" featuregate to determine whether to add the gatewayclasses, gateways, istios, and subscriptions resources to relatedObjects, in addition to checking the "GatewayAPI" featuregate.
>
>Before this change, the operator could add istios to `relatedObjects` even if the OSSM subscription failed to install.  By convention, an operator should only add resources to `relatedObjects` if those resources exist.


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift%2Fcluster-ingress-operator).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: CONTRIBUTOR
user: login: openshift-bot
created_at: 2025-05-29T05:41:10Z
body: **[ART PR BUILD NOTIFIER]**

Distgit: ose-cluster-ingress-operator
This PR has been included in build [ose-cluster-ingress-operator-container-v4.20.0-202505290511.p0.g21ac32d.assembly.stream.el9](https://brewweb.engineering.redhat.com/brew/buildinfo?buildID=3667091).
All builds following this will include this PR.
author_association: CONTRIBUTOR
user: login: openshift-ci-robot
created_at: 2025-09-03T14:57:53Z
body: @Miciah: [Jira Issue OCPBUGS-54745](https://issues.redhat.com//browse/OCPBUGS-54745) is in an unrecognized state (Verified) and will not be moved to the MODIFIED state.

<details>

In response to [this](https://github.com/openshift/cluster-ingress-operator/pull/1217):

>#### status: Omit istios namespace in `relatedObjects`
>
>Omit the namespace for the istios resource in `relatedObjects` as the istios resource is cluster-scoped.
>
>
>#### status: Omit gateways namespace in `relatedObjects`
>
>Omit the namespace for the gateways resource in `relatedObjects` as Istio manages gateways in all namespaces.
>
>
>#### `getOperatorState`: Add `context` parameter
>
>Pass `ctx` from the controller's `Reconcile` method to `getOperatorState`, and use it instead of `context.TODO()`.
>
>
>#### status: Conditionally add CRDs to `relatedObjects`
>
>Check whether the gatewayclasses, gateways, and istios CRDs actually exist before adding them to `relatedObjects`.
>
>Watch customresourcedefinitions in the status controller so that it updates `relatedObjects` as these CRDs are created.
>
>Check the "GatewayAPIController" featuregate to determine whether to add the gatewayclasses, gateways, istios, and subscriptions resources to relatedObjects, in addition to checking the "GatewayAPI" featuregate.
>
>Before this change, the operator could add istios to `relatedObjects` even if the OSSM subscription failed to install.  By convention, an operator should only add resources to `relatedObjects` if those resources exist.


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift%2Fcluster-ingress-operator).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: CONTRIBUTOR