Skip to content
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

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

Danil-Grigorev
Copy link
Member

@Danil-Grigorev Danil-Grigorev commented Oct 30, 2024

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

@k8s-ci-robot k8s-ci-robot added area/clusterclass Issues or PRs related to clusterclass cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Oct 30, 2024
@Danil-Grigorev Danil-Grigorev changed the title Add classNamespace to topology ✨ Add classNamespace to topology Oct 30, 2024
@Danil-Grigorev Danil-Grigorev force-pushed the class-namespace-addition branch 2 times, most recently from ae1cb19 to 43cb995 Compare October 30, 2024 11:59
@k8s-ci-robot k8s-ci-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Oct 30, 2024
@Danil-Grigorev Danil-Grigorev force-pushed the class-namespace-addition branch 2 times, most recently from 2bddeeb to 352fd66 Compare October 30, 2024 15:20
Copy link
Contributor

@salasberryfin salasberryfin left a 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.

@Danil-Grigorev Danil-Grigorev force-pushed the class-namespace-addition branch from 352fd66 to bd8a56f Compare October 31, 2024 09:51
@salasberryfin
Copy link
Contributor

Thanks @Danil-Grigorev

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Oct 31, 2024
@k8s-ci-robot
Copy link
Contributor

LGTM label has been added.

Git tree hash: c4b418743a4683ae623b3264aae7636c41ad5675

@salasberryfin
Copy link
Contributor

/assign @chrischdi

@Danil-Grigorev Danil-Grigorev changed the title ✨ Add classNamespace to topology [WIP] ✨ Add classNamespace to topology Oct 31, 2024
@k8s-ci-robot k8s-ci-robot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Oct 31, 2024
@Danil-Grigorev Danil-Grigorev force-pushed the class-namespace-addition branch from bd8a56f to 4bbb218 Compare October 31, 2024 18:34
@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Oct 31, 2024
@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Oct 31, 2024
@Danil-Grigorev Danil-Grigorev force-pushed the class-namespace-addition branch from 4bbb218 to d450768 Compare October 31, 2024 18:44
@Danil-Grigorev Danil-Grigorev changed the title [WIP] ✨ Add classNamespace to topology ✨ Add classNamespace to topology Oct 31, 2024
@k8s-ci-robot
Copy link
Contributor

New changes are detected. LGTM label has been removed.

@Danil-Grigorev Danil-Grigorev force-pushed the class-namespace-addition branch from bbbddcf to b4b6131 Compare November 27, 2024 21:25
@@ -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.
Copy link
Member

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?

Copy link
Contributor

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.

Copy link
Member

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!

api/v1beta1/cluster_types.go Show resolved Hide resolved
api/v1beta1/cluster_types.go Outdated Show resolved Hide resolved

<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.
Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Member

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

Copy link
Member Author

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.

Copy link
Member

@sbueringer sbueringer Jan 10, 2025

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),
Copy link
Member

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 {
Copy link
Member

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

@Danil-Grigorev Danil-Grigorev force-pushed the class-namespace-addition branch 4 times, most recently from c581444 to 3639364 Compare December 4, 2024 13:28
@Danil-Grigorev
Copy link
Member Author

@chrischdi @fabriziopandini Can I get another review? All comments are addressed here.

@Danil-Grigorev Danil-Grigorev force-pushed the class-namespace-addition branch from 902e582 to 2730042 Compare January 7, 2025 19:49
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please ask for approval from chrischdi. For more information see the Code Review Process.

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 /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@Danil-Grigorev Danil-Grigorev force-pushed the class-namespace-addition branch 2 times, most recently from eb540d6 to 03780fe Compare January 9, 2025 21:05
Signed-off-by: Danil-Grigorev <[email protected]>
@Danil-Grigorev Danil-Grigorev force-pushed the class-namespace-addition branch from 03780fe to 1ae95a5 Compare January 9, 2025 21:07
Copy link
Member

@sbueringer sbueringer left a 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.
Copy link
Member

@sbueringer sbueringer Jan 10, 2025

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.
Copy link
Member

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
Copy link
Member

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)

Copy link
Member Author

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.

Copy link
Member

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])?)*$"
Copy link
Member

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),
Copy link
Member

@sbueringer sbueringer Jan 10, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/clusterclass Issues or PRs related to clusterclass cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.