Skip to content

Conversation

@uwe-mayer
Copy link
Contributor

This updates an existing ClusterRolebinding for Greenhouse on the shoot. Where before we ignore and just checked for existence not for divergence.

@uwe-mayer uwe-mayer requested a review from a team as a code owner January 16, 2026 12:17
@github-actions
Copy link

Merging this branch will not change overall coverage

Impacted Packages Coverage Δ 🤖
github.com/cloudoperators/shoot-grafter/controller/shoot 0.00% (ø)

Coverage by file

Changed files (no unit tests)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/cloudoperators/shoot-grafter/controller/shoot/rbac.go 0.00% (ø) 0 0 0
github.com/cloudoperators/shoot-grafter/controller/shoot/shoot_controller.go 0.00% (ø) 0 0 0

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files

  • github.com/cloudoperators/shoot-grafter/controller/shoot/rbac_test.go

Comment on lines +53 to +103
// ClusterRoleBinding already exists - get it and compare
r.Info("ClusterRoleBinding already exists, comparing with desired state", "ClusterRoleBinding", clusterRoleBinding.Name, "shoot", shootName)

existingCRB := &rbacv1.ClusterRoleBinding{}
if err := shootClient.Get(ctx, client.ObjectKey{Name: clusterRoleBinding.Name}, existingCRB); err != nil {
r.Error(err, "failed to get existing ClusterRoleBinding", "ClusterRoleBinding", clusterRoleBinding.Name)
return
}

// Compare RoleRef and Subjects
needsRecreate := false

// Compare RoleRef
if existingCRB.RoleRef != clusterRoleBinding.RoleRef {
r.Info("RoleRef differs, will recreate",
"existing", fmt.Sprintf("%s/%s", existingCRB.RoleRef.Kind, existingCRB.RoleRef.Name),
"desired", fmt.Sprintf("%s/%s", clusterRoleBinding.RoleRef.Kind, clusterRoleBinding.RoleRef.Name))
needsRecreate = true
}

// Compare Subjects
// Note: This comparison assumes subjects are in the same order. If order differs, this will trigger a recreate.
if !needsRecreate && !cmp.Equal(existingCRB.Subjects, clusterRoleBinding.Subjects) {
r.Info("Subjects differ, will recreate",
"existing", existingCRB.Subjects,
"desired", clusterRoleBinding.Subjects)
needsRecreate = true
}

if needsRecreate {
r.Info("Deleting existing ClusterRoleBinding", "ClusterRoleBinding", clusterRoleBinding.Name, "shoot", shootName)
if err := shootClient.Delete(ctx, existingCRB); err != nil {
r.Error(err, "failed to delete existing ClusterRoleBinding", "ClusterRoleBinding", clusterRoleBinding.Name)
r.emitEvent(r.CareInstruction, corev1.EventTypeWarning, "RBACRecreationFailed",
fmt.Sprintf("Failed to recreate ClusterRoleBinding %s for shoot %s/%s: %v", clusterRoleBinding.Name, r.CareInstruction.Namespace, shootName, err))
return
}

r.Info("Creating new ClusterRoleBinding with correct configuration", "ClusterRoleBinding", clusterRoleBinding.Name, "shoot", shootName)
if err := shootClient.Create(ctx, clusterRoleBinding); err != nil {
r.Error(err, "failed to recreate ClusterRoleBinding", "ClusterRoleBinding", clusterRoleBinding.Name)
r.emitEvent(r.CareInstruction, corev1.EventTypeWarning, "RBACRecreationFailed",
fmt.Sprintf("Failed to recreate ClusterRoleBinding %s for shoot %s/%s: %v", clusterRoleBinding.Name, r.CareInstruction.Namespace, shootName, err))
return
}

r.Info("Successfully recreated ClusterRoleBinding", "ClusterRoleBinding", clusterRoleBinding.Name, "shoot", shootName)
r.emitEvent(r.CareInstruction, corev1.EventTypeNormal, "RBACUpdated",
fmt.Sprintf("Updated ClusterRoleBinding %s for shoot %s/%s", clusterRoleBinding.Name, r.CareInstruction.Namespace, shootName))
} else {
r.Info("ClusterRoleBinding for Greenhouse ServiceAccount already exists", "ClusterRoleBinding", clusterRoleBinding.Name)
r.Info("ClusterRoleBinding matches desired state", "ClusterRoleBinding", clusterRoleBinding.Name, "shoot", shootName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use controller-runtime's controllerutil.CreateOrUpdate here?

Copy link
Contributor

@IvoGoman IvoGoman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

// Compare Subjects
// Note: This comparison assumes subjects are in the same order. If order differs, this will trigger a recreate.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

sort subjects and pass to go-cmp to avoid un-necessary reconciliation

	opts := []cmp.Option{
		cmpopts.SortSlices(func(a, b []rbacv1.Subjects) bool {
			return a.Name < b.Name
		}),
	}
cmp.Equal(existingCRB.Subjects, clusterRoleBinding.Subjects, opts...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants