Skip to content

Commit 82bd135

Browse files
authored
feat: auto enable registry addon in workload clusters (#1175)
**What problem does this PR solve?**: This adds a new feature gate `AutoEnableWorkloadClusterRegistry=true` that will automatically enable the registry addon on workload cluster creation when it is enabled on the management cluster. **Which issue(s) this PR fixes**: Fixes # **How Has This Been Tested?**: <!-- Please describe the tests that you ran to verify your changes. Provide output from the tests and any manual steps needed to replicate the tests. --> **Special notes for your reviewer**: <!-- Use this to provide any additional information to the reviewers. This may include: - Best way to review the PR. - Where the author wants the most review attention on. - etc. -->
1 parent d20aded commit 82bd135

File tree

13 files changed

+717
-4
lines changed

13 files changed

+717
-4
lines changed

api/v1alpha1/constants.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,6 @@ const (
3939
// DNSVariableName is the DNS external patch variable name.
4040
DNSVariableName = "dns"
4141

42-
ClusterUUIDAnnotationKey = APIGroup + "/cluster-uuid"
42+
ClusterUUIDAnnotationKey = APIGroup + "/cluster-uuid"
43+
SkipAutoEnablingWorkloadClusterRegistry = APIGroup + "/skip-auto-enabling-workload-cluster-registry"
4344
)

api/variables/json.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,20 @@ func GetClusterVariableByName(
7878
}
7979
return nil
8080
}
81+
82+
// UpdateClusterVariable updates the variable in the list of cluster variables.
83+
// If the variable does not exist, it appends it to the list.
84+
func UpdateClusterVariable(
85+
variable *clusterv1.ClusterVariable,
86+
clusterVariables []clusterv1.ClusterVariable,
87+
) []clusterv1.ClusterVariable {
88+
name := variable.Name
89+
for i := range clusterVariables {
90+
if clusterVariables[i].Name == name {
91+
clusterVariables[i] = *variable
92+
return clusterVariables
93+
}
94+
}
95+
clusterVariables = append(clusterVariables, *variable)
96+
return clusterVariables
97+
}

charts/cluster-api-runtime-extensions-nutanix/templates/webhooks.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ metadata:
88
annotations:
99
cert-manager.io/inject-ca-from: '{{ .Release.Namespace}}/{{ template "chart.name" . }}-admission-tls'
1010
webhooks:
11+
- admissionReviewVersions:
12+
- v1
13+
clientConfig:
14+
service:
15+
name: '{{ include "chart.name" . }}-admission'
16+
namespace: '{{ .Release.Namespace }}'
17+
path: /mutate-v1beta1-addons
18+
failurePolicy: Fail
19+
name: addons-defaulter.caren.nutanix.com
20+
rules:
21+
- apiGroups:
22+
- cluster.x-k8s.io
23+
apiVersions:
24+
- '*'
25+
operations:
26+
- CREATE
27+
resources:
28+
- clusters
29+
sideEffects: None
1130
- admissionReviewVersions:
1231
- v1
1332
clientConfig:

cmd/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle"
4141
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix"
4242
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options"
43+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/webhook/addons"
4344
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/webhook/cluster"
4445
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/webhook/preflight"
4546
preflightnutanix "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/webhook/preflight/nutanix"
@@ -237,6 +238,10 @@ func main() {
237238
Handler: cluster.NewValidator(mgr.GetClient(), admission.NewDecoder(mgr.GetScheme())),
238239
})
239240

241+
mgr.GetWebhookServer().Register("/mutate-v1beta1-addons", &webhook.Admission{
242+
Handler: addons.NewDefaulter(mgr.GetClient(), admission.NewDecoder(mgr.GetScheme())),
243+
})
244+
240245
mgr.GetWebhookServer().Register("/preflight-v1beta1-cluster", &webhook.Admission{
241246
Handler: preflight.New(mgr.GetClient(), admission.NewDecoder(mgr.GetScheme()),
242247
[]preflight.Checker{

docs/content/addons/registry.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@ spec:
3131
registry: {}
3232
```
3333
34+
## Registry in the workload cluster
35+
36+
When the registry is enabled in the management cluster, it can also be automatically enabled in the workload cluster.
37+
To enable this behavior, set the following feature gate on the controller:
38+
39+
```text
40+
--feature-gates=AutoEnableWorkloadClusterRegistry=true
41+
```
42+
43+
It is also possible to disable this behavior by setting the following annotation on the Cluster resource:
44+
45+
```yaml
46+
annotations:
47+
caren.nutanix.com/skip-auto-enabling-workload-cluster-registry: "true"
48+
```
49+
3450
## Registry Certificate
3551
3652
1. A root CA Certificate is deployed in the provider's namespace.

pkg/feature/feature.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ import (
77
"k8s.io/component-base/featuregate"
88
)
99

10+
const AutoEnableWorkloadClusterRegistry featuregate.Feature = "AutoEnableWorkloadClusterRegistry"
11+
1012
// defaultFeatureGates returns all known feature gates.
1113
// To add a new feature, define a key for it above and add it here. The features will be
1214
// available throughout the codebase.
1315
func defaultFeatureGates() map[featuregate.Feature]featuregate.FeatureSpec {
14-
return map[featuregate.Feature]featuregate.FeatureSpec{}
16+
return map[featuregate.Feature]featuregate.FeatureSpec{
17+
AutoEnableWorkloadClusterRegistry: {Default: false, PreRelease: featuregate.Alpha},
18+
}
1519
}

pkg/feature/gates.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ var (
2020
// featuregatetesting "k8s.io/component-base/featuregate/testing"
2121
// featuregatetesting.SetFeatureGateDuringTest(
2222
// t,
23-
// features.Gates,
24-
// features.<FeatureName>,
23+
// feature.Gates,
24+
// feature.<FeatureName>,
2525
// <value>,
2626
// )()
2727
MutableGates featuregate.MutableFeatureGate = featuregate.NewFeatureGate()

pkg/webhook/addons/defaulter.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2025 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package addons
5+
6+
import (
7+
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
8+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
9+
10+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/feature"
11+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/webhook/addons/registry"
12+
)
13+
14+
func NewDefaulter(client ctrlclient.Client, decoder admission.Decoder) admission.Handler {
15+
return admission.MultiMutatingHandler(
16+
allHandlers(client, decoder)...,
17+
)
18+
}
19+
20+
// allHandlers returns a list of all defaulter handlers that should be registered,
21+
// including any feature-gated handlers.
22+
func allHandlers(
23+
client ctrlclient.Client, decoder admission.Decoder,
24+
) []admission.Handler {
25+
var handlers []admission.Handler
26+
if feature.Gates.Enabled(feature.AutoEnableWorkloadClusterRegistry) {
27+
handlers = append(handlers, registry.NewWorkloadClusterAutoEnabler(client, decoder).Defaulter())
28+
}
29+
return handlers
30+
}

pkg/webhook/addons/defaulter_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2025 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package addons
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
featuregatetesting "k8s.io/component-base/featuregate/testing"
11+
12+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/feature"
13+
)
14+
15+
// Test_allHandlers is a crude test to ensure handlers are only registered when the feature gate is enabled.
16+
func Test_allHandlers(t *testing.T) {
17+
handlers := allHandlers(nil, nil)
18+
assert.Empty(t, handlers)
19+
20+
// Enable the feature gates and test again.
21+
featuregatetesting.SetFeatureGateDuringTest(
22+
t,
23+
feature.Gates,
24+
feature.AutoEnableWorkloadClusterRegistry,
25+
true,
26+
)
27+
handlers = allHandlers(nil, nil)
28+
assert.Len(t, handlers, 1)
29+
}

pkg/webhook/addons/doc.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright 2025 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// +kubebuilder:webhook:path=/mutate-v1beta1-addons,mutating=true,failurePolicy=fail,groups="cluster.x-k8s.io",resources=clusters,verbs=create,versions=*,name=addons-defaulter.caren.nutanix.com,admissionReviewVersions=v1,sideEffects=None
5+
package addons

0 commit comments

Comments
 (0)