Skip to content

Commit 670d722

Browse files
committed
accessrequest controller now also adds cluster reference
1 parent 2fc9a7d commit 670d722

File tree

8 files changed

+56
-14
lines changed

8 files changed

+56
-14
lines changed

api/clusters/v1alpha1/accessrequest_types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import (
77

88
type AccessRequestSpec struct {
99
// ClusterRef is the reference to the Cluster for which access is requested.
10-
// Exactly one of clusterRef or requestRef must be set.
10+
// If set, requestRef will be ignored.
1111
// This value is immutable.
1212
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="clusterRef is immutable"
1313
// +optional
1414
ClusterRef *NamespacedObjectReference `json:"clusterRef,omitempty"`
1515

1616
// RequestRef is the reference to the ClusterRequest for whose Cluster access is requested.
17-
// Exactly one of clusterRef or requestRef must be set.
17+
// Is ignored if clusterRef is set.
1818
// This value is immutable.
1919
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="requestRef is immutable"
2020
// +optional

api/crds/manifests/clusters.openmcp.cloud_accessrequests.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ spec:
5050
clusterRef:
5151
description: |-
5252
ClusterRef is the reference to the Cluster for which access is requested.
53-
Exactly one of clusterRef or requestRef must be set.
53+
If set, requestRef will be ignored.
5454
This value is immutable.
5555
properties:
5656
name:
@@ -135,7 +135,7 @@ spec:
135135
requestRef:
136136
description: |-
137137
RequestRef is the reference to the ClusterRequest for whose Cluster access is requested.
138-
Exactly one of clusterRef or requestRef must be set.
138+
Is ignored if clusterRef is set.
139139
This value is immutable.
140140
properties:
141141
name:

docs/controller/accessrequest.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# AccessRequest Controller
22

3-
The _AccessRequest Controller_ is responsible for labelling `AccessRequest` resources with the name of the ClusterProvider that is responsible for them.
3+
The _AccessRequest Controller_ is responsible for labelling `AccessRequest` resources with the name of the ClusterProvider that is responsible for them. It also adds a label for the corresponding `ClusterProfile` and adds the cluster reference to the spec, if only the request reference is specified.
44

55
This is needed because the information, which ClusterProvider is responsible for answering the `AccessRequest` is contained in the referenced `ClusterProfile`. Depending on `AccessRequest`'s spec, a `Cluster` and potentially also a `ClusterRequest` must be fetched before the `ClusterProfile` is known, which then has to be fetched too. If multiple ClusterProviders are running in the cluster, all of them would need to fetch these resources, only for all but one of them to notice that they are not responsible and don't have to do anything.
66

@@ -16,6 +16,10 @@ ClusterProviders should only reconcile `AccessRequest` resources where both labe
1616

1717
Note that if a reconciled `AccessRequest` already has one of the labels set, but its value differs from the expected one, the controller will log an error, but not update the resource in any way, to not accidentally move the responsibility from one provider to another. This also means that `AccessRequest` resources that have only one of the labels set, and that one to a wrong value, will not be handled - this controller won't update the resource and the ClusterProvider should not pick it up because one of the labels is missing. It is therefore strongly recommended to not set the labels when creating a new `AccessRequest` resource.
1818

19+
In addition to the labels, the controller also sets `spec.clusterRef`, if only `spec.requestRef` is specified.
20+
21+
After an `AccessRequest` has been prepared this way, the ClusterProviders can easily infer which one is responsible, which `Cluster` resource this request belongs to, and which `ClusterProfile` is used by the `Cluster`, directly from the labels and spec of the `AccessRequest` resource.
22+
1923
## Configuration
2024

2125
The AccessRequest controller is run as long as `accessrequest` is included in the `--controllers` flag. It is included by default.

internal/controllers/accessrequest/controller.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,16 @@ func (r *AccessRequestReconciler) reconcile(ctx context.Context, req reconcile.R
164164
return rr
165165
}
166166
}
167+
168+
// set cluster reference, if only the request reference is set
169+
if ar.Spec.ClusterRef == nil {
170+
ar.Spec.ClusterRef = &clustersv1alpha1.NamespacedObjectReference{}
171+
ar.Spec.ClusterRef.Name = c.Name
172+
ar.Spec.ClusterRef.Namespace = c.Namespace
173+
}
174+
167175
if err := r.PlatformCluster.Client().Patch(ctx, ar, client.MergeFrom(arOld)); err != nil {
168-
rr.ReconcileError = errutils.WithReason(fmt.Errorf("error patching labels on resource '%s': %w", req.String(), err), cconst.ReasonPlatformClusterInteractionProblem)
176+
rr.ReconcileError = errutils.WithReason(fmt.Errorf("error patching resource '%s': %w", req.String(), err), cconst.ReasonPlatformClusterInteractionProblem)
169177
return rr
170178
}
171179

internal/controllers/accessrequest/controller_test.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func arReconciler(c client.Client) reconcile.Reconciler {
2626

2727
var _ = Describe("AccessRequest Controller", func() {
2828

29-
It("should add the correct provider and profile labels to the AccessRequest if a Cluster is referenced directly", func() {
29+
It("should add the correct labels to the AccessRequest if a Cluster is referenced directly", func() {
3030
env := testutils.NewEnvironmentBuilder().WithFakeClient(scheme).WithInitObjectPath("testdata", "test-01").WithReconcilerConstructor(arReconciler).Build()
3131
ar := &clustersv1alpha1.AccessRequest{}
3232
Expect(env.Client().Get(env.Ctx, ctrlutils.ObjectKey("mc-access", "bar"), ar)).To(Succeed())
@@ -38,16 +38,20 @@ var _ = Describe("AccessRequest Controller", func() {
3838
Expect(ar.Labels).To(HaveKeyWithValue(clustersv1alpha1.ProfileLabel, "default"))
3939
})
4040

41-
It("should add the correct provider and profile labels to the AccessRequest if a Cluster is referenced via a ClusterRequest", func() {
41+
It("should add the correct labels and cluster reference to the AccessRequest if a Cluster is referenced via a ClusterRequest", func() {
4242
env := testutils.NewEnvironmentBuilder().WithFakeClient(scheme).WithInitObjectPath("testdata", "test-01").WithReconcilerConstructor(arReconciler).Build()
4343
ar := &clustersv1alpha1.AccessRequest{}
4444
Expect(env.Client().Get(env.Ctx, ctrlutils.ObjectKey("mcr-access", "bar"), ar)).To(Succeed())
4545
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProviderLabel))
4646
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProfileLabel))
47+
Expect(ar.Spec.ClusterRef).To(BeNil())
4748
env.ShouldReconcile(testutils.RequestFromObject(ar))
4849
Expect(env.Client().Get(env.Ctx, client.ObjectKeyFromObject(ar), ar)).To(Succeed())
4950
Expect(ar.Labels).To(HaveKeyWithValue(clustersv1alpha1.ProviderLabel, "asdf"))
5051
Expect(ar.Labels).To(HaveKeyWithValue(clustersv1alpha1.ProfileLabel, "default"))
52+
Expect(ar.Spec.ClusterRef).ToNot(BeNil())
53+
Expect(ar.Spec.ClusterRef.Name).To(Equal("my-cluster"))
54+
Expect(ar.Spec.ClusterRef.Namespace).To(Equal("foo"))
5155
})
5256

5357
It("should fail if the AccessRequest references a ClusterRequest which is not Granted", func() {
@@ -56,9 +60,13 @@ var _ = Describe("AccessRequest Controller", func() {
5660
Expect(env.Client().Get(env.Ctx, ctrlutils.ObjectKey("mcr-access", "bar"), ar)).To(Succeed())
5761
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProviderLabel))
5862
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProfileLabel))
63+
Expect(ar.Spec.ClusterRef).To(BeNil())
5964
env.ShouldNotReconcile(testutils.RequestFromObject(ar))
6065
Expect(env.Client().Get(env.Ctx, client.ObjectKeyFromObject(ar), ar)).To(Succeed())
6166
Expect(ar.Status.Message).To(ContainSubstring("not granted"))
67+
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProviderLabel))
68+
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProfileLabel))
69+
Expect(ar.Spec.ClusterRef).To(BeNil())
6270
})
6371

6472
It("should fail if the AccessRequest references an unknown Cluster or ClusterRequest", func() {
@@ -72,15 +80,21 @@ var _ = Describe("AccessRequest Controller", func() {
7280
Expect(env.Client().Get(env.Ctx, client.ObjectKeyFromObject(ar), ar)).To(Succeed())
7381
Expect(ar.Status.Reason).To(Equal(cconst.ReasonInvalidReference))
7482
Expect(ar.Status.Message).To(ContainSubstring("not found"))
83+
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProviderLabel))
84+
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProfileLabel))
7585

7686
ar = &clustersv1alpha1.AccessRequest{}
7787
Expect(env.Client().Get(env.Ctx, ctrlutils.ObjectKey("mcr-access", "bar"), ar)).To(Succeed())
7888
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProviderLabel))
7989
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProfileLabel))
90+
Expect(ar.Spec.ClusterRef).To(BeNil())
8091
env.ShouldNotReconcile(testutils.RequestFromObject(ar))
8192
Expect(env.Client().Get(env.Ctx, client.ObjectKeyFromObject(ar), ar)).To(Succeed())
8293
Expect(ar.Status.Reason).To(Equal(cconst.ReasonInvalidReference))
8394
Expect(ar.Status.Message).To(ContainSubstring("not found"))
95+
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProviderLabel))
96+
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProfileLabel))
97+
Expect(ar.Spec.ClusterRef).To(BeNil())
8498
})
8599

86100
It("should add the respective other label if either provider or profile label is already set", func() {
@@ -109,22 +123,26 @@ var _ = Describe("AccessRequest Controller", func() {
109123
env := testutils.NewEnvironmentBuilder().WithFakeClient(scheme).WithInitObjectPath("testdata", "test-05").WithReconcilerConstructor(arReconciler).Build()
110124

111125
ar := &clustersv1alpha1.AccessRequest{}
112-
Expect(env.Client().Get(env.Ctx, ctrlutils.ObjectKey("mc-access-provider", "bar"), ar)).To(Succeed())
126+
Expect(env.Client().Get(env.Ctx, ctrlutils.ObjectKey("mcr-access-provider", "bar"), ar)).To(Succeed())
113127
Expect(ar.Labels).To(HaveKey(clustersv1alpha1.ProviderLabel))
114128
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProfileLabel))
129+
Expect(ar.Spec.ClusterRef).To(BeNil())
115130
env.ShouldReconcile(testutils.RequestFromObject(ar))
116131
Expect(env.Client().Get(env.Ctx, client.ObjectKeyFromObject(ar), ar)).To(Succeed())
117132
Expect(ar.Labels).ToNot(HaveKeyWithValue(clustersv1alpha1.ProviderLabel, "asdf"))
118133
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProfileLabel))
134+
Expect(ar.Spec.ClusterRef).To(BeNil())
119135

120136
ar = &clustersv1alpha1.AccessRequest{}
121-
Expect(env.Client().Get(env.Ctx, ctrlutils.ObjectKey("mc-access-profile", "bar"), ar)).To(Succeed())
137+
Expect(env.Client().Get(env.Ctx, ctrlutils.ObjectKey("mcr-access-profile", "bar"), ar)).To(Succeed())
122138
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProviderLabel))
123139
Expect(ar.Labels).To(HaveKey(clustersv1alpha1.ProfileLabel))
140+
Expect(ar.Spec.ClusterRef).To(BeNil())
124141
env.ShouldReconcile(testutils.RequestFromObject(ar))
125142
Expect(env.Client().Get(env.Ctx, client.ObjectKeyFromObject(ar), ar)).To(Succeed())
126143
Expect(ar.Labels).ToNot(HaveKey(clustersv1alpha1.ProviderLabel))
127144
Expect(ar.Labels).ToNot(HaveKeyWithValue(clustersv1alpha1.ProfileLabel, "default"))
145+
Expect(ar.Spec.ClusterRef).To(BeNil())
128146
})
129147

130148
})

internal/controllers/accessrequest/testdata/test-05/accessrequest-profile.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
apiVersion: clusters.openmcp.cloud/v1alpha1
22
kind: AccessRequest
33
metadata:
4-
name: mc-access-profile
4+
name: mcr-access-profile
55
namespace: bar
66
labels:
77
profile.clusters.openmcp.cloud: wrong
88
spec:
9-
clusterRef:
9+
requestRef:
1010
name: my-cluster
1111
namespace: foo
1212
permissions:

internal/controllers/accessrequest/testdata/test-05/accessrequest-provider.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
apiVersion: clusters.openmcp.cloud/v1alpha1
22
kind: AccessRequest
33
metadata:
4-
name: mc-access-provider
4+
name: mcr-access-provider
55
namespace: bar
66
labels:
77
provider.clusters.openmcp.cloud: wrong
88
spec:
9-
clusterRef:
9+
requestRef:
1010
name: my-cluster
1111
namespace: foo
1212
permissions:
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
apiVersion: clusters.openmcp.cloud/v1alpha1
2+
kind: ClusterRequest
3+
metadata:
4+
name: my-cluster
5+
namespace: foo
6+
spec:
7+
purpose: test
8+
status:
9+
phase: Granted
10+
cluster:
11+
name: my-cluster
12+
namespace: foo

0 commit comments

Comments
 (0)