-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨ Add classNamespace to topology #11352
base: main
Are you sure you want to change the base?
✨ Add classNamespace to topology #11352
Conversation
ae1cb19
to
43cb995
Compare
2bddeeb
to
352fd66
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @Danil-Grigorev! I added a small suggestion but I think this looks good.
docs/book/src/tasks/experimental-features/cluster-class/write-clusterclass.md
Outdated
Show resolved
Hide resolved
352fd66
to
bd8a56f
Compare
Thanks @Danil-Grigorev /lgtm |
LGTM label has been added. Git tree hash: c4b418743a4683ae623b3264aae7636c41ad5675
|
/assign @chrischdi |
bd8a56f
to
4bbb218
Compare
4bbb218
to
d450768
Compare
New changes are detected. LGTM label has been removed. |
bbbddcf
to
b4b6131
Compare
api/v1beta1/cluster_types.go
Outdated
@@ -509,6 +509,14 @@ type Topology struct { | |||
// The name of the ClusterClass object to create the topology. | |||
Class string `json:"class"` | |||
|
|||
// The namespace of the ClusterClass object to create the topology. | |||
// Empty namespace assumes the namespace of the cluster object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if we should default to current namespace ...
Pros: it is explicit and consistent to what we do for other references
Cons: it add "noises" to the containing struct while we don't have a clean nesting yet
A compromise might be to keep it empty for now and start defaulting when we will introduce a nested struct
@JoelSpeed opinions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The namespace of the object can never change, so, defaulting this value to the current namespace would make sense, and make the API explicit. I can't foresee us ever, in the future, wanting to default this to a specific namespace, as we have no concept of a core namespace.
That said, I could see a use case where a cluster admin wants to default this field themselves. In the future they could leverage MutatingAdmissionPolicy to set the namespace always to a certain namespace where they keep their classes. Could defaulting this (since it would have to be a webhook, or MAP) then cause interference with any logic the cluster admin has there? They'd have to make sure that their defaulting went before ours 🤔
I think I would err on the side here, or not defaulting it and just explaining that the empty namespace means that the namespace of the cluster is leveraged, as it is now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me, thx for the explanation Joel!
|
||
<h1>Cluster rebase across namespaces</h1> | ||
|
||
Changing `classNamespace` is not supported in rebase procedure, while chanding `class` reference to a different `ClusterClass` from the same namespace performs regular `Cluster` rebase procedure. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be I'm wrong, but I did not found a place where we are enforcing "Changing classNamespace
is not supported".
Also, out of curiosity, why are we introducing this limitation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That’s mainly due to tests performed on that operation locally. It seems when changing classNamespace
, many referenced template components change namespace too, as they have to preserve ownership references, and instead of rebase
performing minimal modifications of the resource, it has to switch resources entirely. This seemed as a larger scope change.
I’ll add a validation on the field modifications.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks clarification
It would be great if we can add the same note as a godoc explanation for check above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I composed a clarification message on the field. It seems there is no need for additional tests as TestLocalObjectTemplatesAreCompatible
is already covering template namespace changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added another comment already but I didn't see validation for this. To be honest I'm really wondering what's going on here. Rebase across namespaces shouldn't lead to problems
What do you mean with: "it has to switch resources entirely"?
@@ -380,12 +380,19 @@ func (webhook *ClusterClass) getClustersUsingClusterClass(ctx context.Context, c | |||
clusters := &clusterv1.ClusterList{} | |||
err := webhook.Client.List(ctx, clusters, | |||
client.MatchingFields{index.ClusterClassNameField: clusterClass.Name}, | |||
client.InNamespace(clusterClass.Namespace), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking a little bit more about this, I think we change this index so performance in the webhook are optimized and also the resulting code will be more readable (both here and in clusterClassToCluster)
@@ -371,7 +370,9 @@ func (r *Reconciler) clusterClassToCluster(ctx context.Context, o client.Object) | |||
// create a request for each of the clusters. | |||
requests := []ctrl.Request{} | |||
for i := range clusterList.Items { | |||
requests = append(requests, ctrl.Request{NamespacedName: util.ObjectKey(&clusterList.Items[i])}) | |||
if clusterList.Items[i].GetInfrastructureNamespace() == clusterClass.Namespace { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note for self: this seems still open no matter if it reports outdated
c581444
to
3639364
Compare
docs/book/src/tasks/experimental-features/cluster-class/write-clusterclass.md
Outdated
Show resolved
Hide resolved
docs/book/src/tasks/experimental-features/cluster-class/write-clusterclass.md
Outdated
Show resolved
Hide resolved
@chrischdi @fabriziopandini Can I get another review? All comments are addressed here. |
902e582
to
2730042
Compare
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Signed-off-by: Danil-Grigorev <[email protected]>
Signed-off-by: Danil-Grigorev <[email protected]>
Signed-off-by: Danil-Grigorev <[email protected]>
Signed-off-by: Danil-Grigorev <[email protected]>
Signed-off-by: Danil-Grigorev <[email protected]>
Signed-off-by: Danil-Grigorev <[email protected]>
Signed-off-by: Danil-Grigorev <[email protected]>
Signed-off-by: Danil-Grigorev <[email protected]>
Signed-off-by: Danil-Grigorev <[email protected]>
Co-authored-by: Christian Schlotter <[email protected]>
Signed-off-by: Danil-Grigorev <[email protected]>
eb540d6
to
03780fe
Compare
Signed-off-by: Danil-Grigorev <[email protected]>
03780fe
to
1ae95a5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for working on this and thx for the patience. Sorry for the delay
@@ -517,6 +518,15 @@ type Topology struct { | |||
// The name of the ClusterClass object to create the topology. | |||
Class string `json:"class"` | |||
|
|||
// The namespace of the ClusterClass object to create the topology. Empty namespace assumes the namespace of the cluster object. | |||
// Class namespace changes are not supported by the rebase procedure, as different CC namespace uses namespace-local templates. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this limitation.
Example:
Before rebase: CC1 in test1 namespace referencing templates in test1 namespace
After rebase: CC2 in test2 namespace referencing templates in test2 namespace
Why doesn't this work?
EDIT: I also didn't find anything in our webhook that blocks changing the namespace, maybe this godoc comment is just outdated
Related: #11352 (comment)
@@ -517,6 +518,15 @@ type Topology struct { | |||
// The name of the ClusterClass object to create the topology. | |||
Class string `json:"class"` | |||
|
|||
// The namespace of the ClusterClass object to create the topology. Empty namespace assumes the namespace of the cluster object. | |||
// Class namespace changes are not supported by the rebase procedure, as different CC namespace uses namespace-local templates. | |||
// Cluster templates namespace modification is not allowed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is Cluster templates referring to? To me this comment is mostly confusing to be honest
// Class namespace changes are not supported by the rebase procedure, as different CC namespace uses namespace-local templates. | ||
// Cluster templates namespace modification is not allowed. | ||
// +optional | ||
// +kubebuilder:validation:MinLength=1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't MinLength=1
conflict with "Empty namespace assumes the namespace of the cluster object"?
I assume valid values are / should be:
- not set => which is what "empty namespace" is referring to
- set to a string with length between 1 and 253
Not valid:
- setting it to an empty string ("")
If I'm correct, maybe we should simply update the comment above to: "If namespace is not set we assume the namespace of the Cluster object"
P.S. I'm aware that when an end user sets the classNamespace field to "", the field will be removed by our mutating webhook on the Cluster object (because of the omitempty) and then passes the OpenAPI schema validation. Nonetheless it's probably cleaner to use "not set" vs. "empty string" (also because empty string is forbidden by the OpenAPI schema)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was originally a suggestion from Joel. Cross-referencing it here for the context: #11352 (comment) I validated it, and it works great. Typically an ””
value will be stored on the resource if it is once set (even via a controller), but here it blocks the round trip on API server via MinLength
and falls back to +optional
, removing the field, thus making it use class metadata.namespace
instead.
This is what allowed to add defaulting of the value in the E2E tests followup, suggested in #11395 (comment), allowing to greatly reduce templates duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. Can we modify the comment to say "If the namespace is empty or not set ..." ?
// +optional | ||
// +kubebuilder:validation:MinLength=1 | ||
// +kubebuilder:validation:MaxLength=253 | ||
// +kubebuilder:validation:Pattern="^[a-z0-9](?:[-a-z0-9]*[a-z0-9])?(?:\\.[a-z0-9](?:[-a-z0-9]*[a-z0-9])?)*$" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there's a specific place where we got this regex from, let's please mention it (I guess it's sort of the "standard" regexp to validate Kubernetes object names?)
@@ -380,12 +380,19 @@ func (webhook *ClusterClass) getClustersUsingClusterClass(ctx context.Context, c | |||
clusters := &clusterv1.ClusterList{} | |||
err := webhook.Client.List(ctx, clusters, | |||
client.MatchingFields{index.ClusterClassNameField: clusterClass.Name}, | |||
client.InNamespace(clusterClass.Namespace), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I'm following the discussion (but I also don't know the previous version of the code).
But I was also wondering why we don't simply use one index (e.g. ClusterClassRefField) that has the format namespace/name?
As ClusterClassNameField index is always used together with the ClusterClassNamespaceField index I don't see the need to maintain two indices.
What this PR does / why we need it:
Adding
classNamespace
variable to the cluster topology, which allows to point to a ClusterClass in a different namespace. This field is dormant, and is used for differentiation only.Which issue(s) this PR fixes (optional, in
fixes #<issue number>(, fixes #<issue_number>, ...)
format, will close the issue(s) when PR gets merged):Related to #5673
/area clusterclass