Skip to content

Commit d2a6c8c

Browse files
zhujian7claude
andcommitted
Allow empty string for AgentInstallNamespace to support template namespaces
This change updates the AgentInstallNamespace field validation pattern to allow empty strings, enabling template-type addons to use the namespace defined in their addonTemplate. Key changes: - Updated validation pattern from ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ to ^([a-z0-9]([-a-z0-9]*[a-z0-9])?)?$ to allow empty strings - Added documentation clarifying behavior for template vs non-template addons - Regenerated CRD manifests - Added comprehensive integration tests for validation This allows users to explicitly set agentInstallNamespace to "" to use their template's namespace, while maintaining backward compatibility with the default "open-cluster-management-agent-addon" namespace. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> Signed-off-by: zhujian <[email protected]>
1 parent 87a44af commit d2a6c8c

File tree

3 files changed

+103
-4
lines changed

3 files changed

+103
-4
lines changed

addon/v1alpha1/0000_02_addon.open-cluster-management.io_addondeploymentconfigs.crd.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ spec:
4141
properties:
4242
agentInstallNamespace:
4343
default: open-cluster-management-agent-addon
44-
description: AgentInstallNamespace is the namespace where the add-on
45-
agent should be installed on the managed cluster.
44+
description: |-
45+
AgentInstallNamespace is the namespace where the add-on agent should be installed on the managed cluster.
46+
For template-type addons: set to empty string "" to use the namespace defined in the addonTemplate.
47+
For non-template addons: defaults to "open-cluster-management-agent-addon" if not specified.
4648
maxLength: 63
47-
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
49+
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?)?$
4850
type: string
4951
customizedVariables:
5052
description: |-

addon/v1alpha1/types_addondeploymentconfig.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,12 @@ type AddOnDeploymentConfigSpec struct {
5454
ProxyConfig ProxyConfig `json:"proxyConfig,omitempty"`
5555

5656
// AgentInstallNamespace is the namespace where the add-on agent should be installed on the managed cluster.
57+
// For template-type addons: set to empty string "" to use the namespace defined in the addonTemplate.
58+
// For non-template addons: defaults to "open-cluster-management-agent-addon" if not specified.
5759
// +optional
5860
// +kubebuilder:default=open-cluster-management-agent-addon
5961
// +kubebuilder:validation:MaxLength=63
60-
// +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
62+
// +kubebuilder:validation:Pattern=^([a-z0-9]([-a-z0-9]*[a-z0-9])?)?$
6163
AgentInstallNamespace string `json:"agentInstallNamespace,omitempty"`
6264

6365
// ResourceRequirements specify the resources required by add-on agents.

test/integration/api/addondeploymentconfig_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,99 @@ var _ = ginkgo.Describe("AddOnDeploymentConfig API test", func() {
159159
)
160160
gomega.Expect(errors.IsInvalid(err)).To(gomega.BeTrue())
161161
})
162+
163+
ginkgo.It("Should create a AddOnDeploymentConfig with empty agentInstallNamespace", func() {
164+
addOnDeploymentConfig := &addonv1alpha1.AddOnDeploymentConfig{
165+
ObjectMeta: metav1.ObjectMeta{
166+
Name: addOnDeploymentConfigName,
167+
Namespace: testNamespace,
168+
},
169+
Spec: addonv1alpha1.AddOnDeploymentConfigSpec{
170+
AgentInstallNamespace: "",
171+
},
172+
}
173+
174+
_, err := hubAddonClient.AddonV1alpha1().AddOnDeploymentConfigs(testNamespace).Create(
175+
context.TODO(),
176+
addOnDeploymentConfig,
177+
metav1.CreateOptions{},
178+
)
179+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
180+
})
181+
182+
ginkgo.It("Should create a AddOnDeploymentConfig with valid agentInstallNamespace", func() {
183+
addOnDeploymentConfig := &addonv1alpha1.AddOnDeploymentConfig{
184+
ObjectMeta: metav1.ObjectMeta{
185+
Name: addOnDeploymentConfigName,
186+
Namespace: testNamespace,
187+
},
188+
Spec: addonv1alpha1.AddOnDeploymentConfigSpec{
189+
AgentInstallNamespace: "my-custom-namespace",
190+
},
191+
}
192+
193+
_, err := hubAddonClient.AddonV1alpha1().AddOnDeploymentConfigs(testNamespace).Create(
194+
context.TODO(),
195+
addOnDeploymentConfig,
196+
metav1.CreateOptions{},
197+
)
198+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
199+
})
200+
201+
ginkgo.It("Should not create a AddOnDeploymentConfig with invalid agentInstallNamespace (starts with hyphen)", func() {
202+
addOnDeploymentConfig := &addonv1alpha1.AddOnDeploymentConfig{
203+
ObjectMeta: metav1.ObjectMeta{
204+
Name: addOnDeploymentConfigName,
205+
Namespace: testNamespace,
206+
},
207+
Spec: addonv1alpha1.AddOnDeploymentConfigSpec{
208+
AgentInstallNamespace: "-invalid",
209+
},
210+
}
211+
212+
_, err := hubAddonClient.AddonV1alpha1().AddOnDeploymentConfigs(testNamespace).Create(
213+
context.TODO(),
214+
addOnDeploymentConfig,
215+
metav1.CreateOptions{},
216+
)
217+
gomega.Expect(errors.IsInvalid(err)).To(gomega.BeTrue())
218+
})
219+
220+
ginkgo.It("Should not create a AddOnDeploymentConfig with invalid agentInstallNamespace (contains uppercase)", func() {
221+
addOnDeploymentConfig := &addonv1alpha1.AddOnDeploymentConfig{
222+
ObjectMeta: metav1.ObjectMeta{
223+
Name: addOnDeploymentConfigName,
224+
Namespace: testNamespace,
225+
},
226+
Spec: addonv1alpha1.AddOnDeploymentConfigSpec{
227+
AgentInstallNamespace: "Invalid-Namespace",
228+
},
229+
}
230+
231+
_, err := hubAddonClient.AddonV1alpha1().AddOnDeploymentConfigs(testNamespace).Create(
232+
context.TODO(),
233+
addOnDeploymentConfig,
234+
metav1.CreateOptions{},
235+
)
236+
gomega.Expect(errors.IsInvalid(err)).To(gomega.BeTrue())
237+
})
238+
239+
ginkgo.It("Should not create a AddOnDeploymentConfig with agentInstallNamespace exceeding max length", func() {
240+
addOnDeploymentConfig := &addonv1alpha1.AddOnDeploymentConfig{
241+
ObjectMeta: metav1.ObjectMeta{
242+
Name: addOnDeploymentConfigName,
243+
Namespace: testNamespace,
244+
},
245+
Spec: addonv1alpha1.AddOnDeploymentConfigSpec{
246+
AgentInstallNamespace: rand.String(64), // max is 63
247+
},
248+
}
249+
250+
_, err := hubAddonClient.AddonV1alpha1().AddOnDeploymentConfigs(testNamespace).Create(
251+
context.TODO(),
252+
addOnDeploymentConfig,
253+
metav1.CreateOptions{},
254+
)
255+
gomega.Expect(errors.IsInvalid(err)).To(gomega.BeTrue())
256+
})
162257
})

0 commit comments

Comments
 (0)