Skip to content

Commit f042545

Browse files
zhujian7claude
andauthored
Allow empty string for AgentInstallNamespace to support template namespaces (#400)
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) Signed-off-by: zhujian <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent 87a44af commit f042545

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)