Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,65 @@ status:
name: cloud-controller-manager
resource: clusteroperators
- group: ""
name: openshift-cloud-controller-manager
name: openshift-cloud-controller-manager-operator
resource: namespaces
- group: ""
name: openshift-cloud-controller-manager-operator
name: openshift-cloud-controller-manager
resource: namespaces
- group: rbac.authorization.k8s.io
name: system:openshift:operator:cloud-controller-manager
resource: clusterroles
- group: rbac.authorization.k8s.io
name: cloud-controller-manager
resource: clusterroles
- group: rbac.authorization.k8s.io
name: cloud-node-manager
resource: clusterroles
- group: rbac.authorization.k8s.io
name: system:openshift:operator:cloud-controller-manager
resource: clusterrolebindings
- group: rbac.authorization.k8s.io
name: cloud-controller-manager
resource: clusterrolebindings
- group: rbac.authorization.k8s.io
name: cloud-node-manager
resource: clusterrolebindings
- group: rbac.authorization.k8s.io
name: system:openshift:scc:hostaccess:cloud-controller-manager-operator
resource: clusterrolebindings
- group: rbac.authorization.k8s.io
name: cluster-cloud-controller-manager
namespace: openshift-config
resource: roles
- group: rbac.authorization.k8s.io
name: cluster-cloud-controller-manager
namespace: openshift-config-managed
resource: roles
- group: rbac.authorization.k8s.io
name: cluster-cloud-controller-manager
namespace: kube-system
resource: roles
- group: rbac.authorization.k8s.io
name: cloud-controller-manager
namespace: kube-system
resource: roles
- group: rbac.authorization.k8s.io
name: cluster-cloud-controller-manager
namespace: openshift-config
resource: rolebindings
- group: rbac.authorization.k8s.io
name: cluster-cloud-controller-manager
namespace: openshift-config-managed
resource: rolebindings
- group: rbac.authorization.k8s.io
name: cluster-cloud-controller-manager
namespace: kube-system
resource: rolebindings
- group: rbac.authorization.k8s.io
name: cloud-controller-manager
namespace: kube-system
resource: rolebindings
- group: rbac.authorization.k8s.io
name: cloud-controller-manager:apiserver-authentication-reader
namespace: kube-system
resource: rolebindings
2 changes: 1 addition & 1 deletion pkg/controllers/clusteroperator_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ var _ = Describe("Cluster Operator status controller", func() {
Expect(v1helpers.FindStatusCondition(getOp.Status.Conditions, cloudControllerOwnershipCondition)).To(BeNil())

// check related objects.
Expect(getOp.Status.RelatedObjects).To(Equal(operatorController.relatedObjects()))
Expect(getOp.Status.RelatedObjects).To(Equal(operatorController.relatedObjects(context.Background())))
},
Entry("when there's no existing cluster operator nor release version", testCase{
releaseVersionEnvVariableValue: "unknown",
Expand Down
27 changes: 27 additions & 0 deletions pkg/controllers/related_objects_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package controllers

import (
"os"
"path/filepath"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
configv1 "github.com/openshift/api/config/v1"
"sigs.k8s.io/yaml"
)

var _ = Describe("relatedObjects", func() {
It("static core should stay in sync with the ClusterOperator manifest", func() {
manifestPath := filepath.Join("..", "..", "manifests", "0000_26_cloud-controller-manager-operator_60_clusteroperator.yaml")
data, err := os.ReadFile(manifestPath)
Expect(err).ToNot(HaveOccurred(), "should be able to read ClusterOperator manifest")

co := &configv1.ClusterOperator{}
Expect(yaml.Unmarshal(data, co)).To(Succeed(), "should be able to unmarshal ClusterOperator manifest")

statusClient := &ClusterOperatorStatusClient{
ManagedNamespace: DefaultManagedNamespace,
}
Expect(co.Status.RelatedObjects).To(Equal(statusClient.relatedObjectsStatic()), "Go relatedObjectsStatic() must match the static ClusterOperator manifest")
})
})
99 changes: 93 additions & 6 deletions pkg/controllers/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,101 @@ func (r *ClusterOperatorStatusClient) getOrCreateClusterOperator(ctx context.Con
return co, nil
}

func (r *ClusterOperatorStatusClient) relatedObjects() []configv1.ObjectReference {
// TBD: Add an actual set of object references from getResources method
// relatedObjectsStatic returns the platform-agnostic relatedObjects that must
// stay in sync with the ClusterOperator CVO seed manifest.
func (r *ClusterOperatorStatusClient) relatedObjectsStatic() []configv1.ObjectReference {
return []configv1.ObjectReference{
{Resource: "namespaces", Name: defaultManagementNamespace},
{Group: configv1.GroupName, Resource: "clusteroperators", Name: clusterOperatorName},
{Resource: "namespaces", Name: r.ManagedNamespace},
{Group: "", Resource: "namespaces", Name: defaultManagementNamespace},
{Group: "", Resource: "namespaces", Name: r.ManagedNamespace},
// Operator and provider ClusterRoles / ClusterRoleBindings.
{Group: "rbac.authorization.k8s.io", Resource: "clusterroles", Name: "system:openshift:operator:" + clusterOperatorName},
{Group: "rbac.authorization.k8s.io", Resource: "clusterroles", Name: clusterOperatorName},
{Group: "rbac.authorization.k8s.io", Resource: "clusterroles", Name: "cloud-node-manager"},
{Group: "rbac.authorization.k8s.io", Resource: "clusterrolebindings", Name: "system:openshift:operator:" + clusterOperatorName},
{Group: "rbac.authorization.k8s.io", Resource: "clusterrolebindings", Name: clusterOperatorName},
{Group: "rbac.authorization.k8s.io", Resource: "clusterrolebindings", Name: "cloud-node-manager"},
{Group: "rbac.authorization.k8s.io", Resource: "clusterrolebindings", Name: "system:openshift:scc:hostaccess:cloud-controller-manager-operator"},
// Foreign-namespace Roles / RoleBindings (not covered by CCCMO namespace relatedObjects).
{Group: "rbac.authorization.k8s.io", Resource: "roles", Name: "cluster-cloud-controller-manager", Namespace: "openshift-config"},
{Group: "rbac.authorization.k8s.io", Resource: "roles", Name: "cluster-cloud-controller-manager", Namespace: "openshift-config-managed"},
{Group: "rbac.authorization.k8s.io", Resource: "roles", Name: "cluster-cloud-controller-manager", Namespace: "kube-system"},
{Group: "rbac.authorization.k8s.io", Resource: "roles", Name: "cloud-controller-manager", Namespace: "kube-system"},
{Group: "rbac.authorization.k8s.io", Resource: "rolebindings", Name: "cluster-cloud-controller-manager", Namespace: "openshift-config"},
{Group: "rbac.authorization.k8s.io", Resource: "rolebindings", Name: "cluster-cloud-controller-manager", Namespace: "openshift-config-managed"},
{Group: "rbac.authorization.k8s.io", Resource: "rolebindings", Name: "cluster-cloud-controller-manager", Namespace: "kube-system"},
{Group: "rbac.authorization.k8s.io", Resource: "rolebindings", Name: "cloud-controller-manager", Namespace: "kube-system"},
{Group: "rbac.authorization.k8s.io", Resource: "rolebindings", Name: "cloud-controller-manager:apiserver-authentication-reader", Namespace: "kube-system"},
}
}

// relatedObjectsForPlatform returns cluster-scoped / foreign-NS objects from
// platform asset YAMLs. Managed-namespace Deployments/DaemonSets/Roles are omitted
// because namespace relatedObjects already gather those.
func relatedObjectsForPlatform(platform configv1.PlatformType) []configv1.ObjectReference {
switch platform {
case configv1.AWSPlatformType:
return []configv1.ObjectReference{
{Group: "admissionregistration.k8s.io", Resource: "validatingadmissionpolicies", Name: "openshift-cloud-controller-manager-cloud-provider-aws"},
{Group: "admissionregistration.k8s.io", Resource: "validatingadmissionpolicybindings", Name: "openshift-cloud-controller-manager-cloud-provider-aws"},
}
case configv1.AzurePlatformType:
return []configv1.ObjectReference{
{Group: "rbac.authorization.k8s.io", Resource: "clusterroles", Name: "azure-cloud-controller-manager"},
{Group: "rbac.authorization.k8s.io", Resource: "clusterrolebindings", Name: "cloud-controller-manager:azure-cloud-controller-manager"},
{Group: "rbac.authorization.k8s.io", Resource: "roles", Name: "azure-cloud-provider", Namespace: "kube-system"},
{Group: "rbac.authorization.k8s.io", Resource: "rolebindings", Name: "azure-cloud-provider:azure-cloud-provider", Namespace: "kube-system"},
{Group: "admissionregistration.k8s.io", Resource: "validatingadmissionpolicies", Name: "openshift-cloud-controller-manager-cloud-provider-azure-node-admission"},
{Group: "admissionregistration.k8s.io", Resource: "validatingadmissionpolicybindings", Name: "openshift-cloud-controller-manager-cloud-provider-azure-node-admission"},
{Group: "admissionregistration.k8s.io", Resource: "validatingadmissionpolicies", Name: "azure-load-balancer-tcp-idle-timeout-annotation-validation-policy"},
{Group: "admissionregistration.k8s.io", Resource: "validatingadmissionpolicybindings", Name: "azure-load-balancer-tcp-idle-timeout-validation-annotation-binding"},
}
case configv1.GCPPlatformType:
return []configv1.ObjectReference{
{Group: "rbac.authorization.k8s.io", Resource: "clusterroles", Name: "gcp-cloud-controller-manager"},
{Group: "rbac.authorization.k8s.io", Resource: "clusterrolebindings", Name: "gcp-cloud-controller-manager:cloud-provider"},
{Group: "admissionregistration.k8s.io", Resource: "validatingadmissionpolicies", Name: "network-tier-annotation-validation-policy"},
{Group: "admissionregistration.k8s.io", Resource: "validatingadmissionpolicybindings", Name: "network-tier-annotation-binding"},
}
case configv1.NutanixPlatformType:
return []configv1.ObjectReference{
{Group: "rbac.authorization.k8s.io", Resource: "clusterroles", Name: "nutanix-cloud-controller-manager"},
{Group: "rbac.authorization.k8s.io", Resource: "clusterrolebindings", Name: "nutanix-cloud-controller-manager:nutanix-cloud-controller-manager"},
}
case configv1.VSpherePlatformType:
return []configv1.ObjectReference{
{Group: "rbac.authorization.k8s.io", Resource: "clusterroles", Name: "vsphere-cloud-controller-manager"},
{Group: "rbac.authorization.k8s.io", Resource: "clusterrolebindings", Name: "vsphere-cloud-controller-manager:vsphere-cloud-controller-manager"},
{Group: "rbac.authorization.k8s.io", Resource: "clusterrolebindings", Name: "vsphere-cloud-controller-manager:cloud-controller-manager"},
}
case configv1.OpenStackPlatformType:
return []configv1.ObjectReference{
{Group: "rbac.authorization.k8s.io", Resource: "clusterroles", Name: "openstack-cloud-controller-manager"},
{Group: "rbac.authorization.k8s.io", Resource: "clusterrolebindings", Name: "openstack-cloud-controller-manager"},
{Group: "", Resource: "serviceaccounts", Name: "cloud-controller-manager", Namespace: "kube-system"},
}
default:
return nil
}
}

// relatedObjects returns the static relatedObjects plus any platform-specific
// objects derived from the Infrastructure platform type. If Infrastructure is
// missing or cannot be read, only the static core is returned.
func (r *ClusterOperatorStatusClient) relatedObjects(ctx context.Context) []configv1.ObjectReference {
objs := r.relatedObjectsStatic()

infra := &configv1.Infrastructure{}
if err := r.Get(ctx, client.ObjectKey{Name: infrastructureResourceName}, infra); err != nil {
return objs
}
if infra.Status.PlatformStatus == nil {
return objs
}

return append(objs, relatedObjectsForPlatform(infra.Status.PlatformStatus.Type)...)
}

// syncStatus applies the new condition to the ClusterOperator object.
func (r *ClusterOperatorStatusClient) syncStatus(ctx context.Context, co *configv1.ClusterOperator, conds, overrides []configv1.ClusterOperatorStatusCondition) error {
for _, c := range conds {
Expand All @@ -235,8 +321,9 @@ func (r *ClusterOperatorStatusClient) syncStatus(ctx context.Context, co *config
v1helpers.SetStatusCondition(&co.Status.Conditions, c, r.Clock)
}

if !equality.Semantic.DeepEqual(co.Status.RelatedObjects, r.relatedObjects()) {
co.Status.RelatedObjects = r.relatedObjects()
related := r.relatedObjects(ctx)
if !equality.Semantic.DeepEqual(co.Status.RelatedObjects, related) {
co.Status.RelatedObjects = related
}

return r.Status().Update(ctx, co)
Expand Down