diff --git a/addon/v1alpha1/0000_02_addon.open-cluster-management.io_addondeploymentconfigs.crd.yaml b/addon/v1alpha1/0000_02_addon.open-cluster-management.io_addondeploymentconfigs.crd.yaml index 1a39c3d3..e0c899b7 100644 --- a/addon/v1alpha1/0000_02_addon.open-cluster-management.io_addondeploymentconfigs.crd.yaml +++ b/addon/v1alpha1/0000_02_addon.open-cluster-management.io_addondeploymentconfigs.crd.yaml @@ -41,10 +41,12 @@ spec: properties: agentInstallNamespace: default: open-cluster-management-agent-addon - description: AgentInstallNamespace is the namespace where the add-on - agent should be installed on the managed cluster. + description: |- + AgentInstallNamespace is the namespace where the add-on agent should be installed on the managed cluster. + For template-type addons: set to empty string "" to use the namespace defined in the addonTemplate. + For non-template addons: defaults to "open-cluster-management-agent-addon" if not specified. maxLength: 63 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?)?$ type: string customizedVariables: description: |- diff --git a/addon/v1alpha1/types_addondeploymentconfig.go b/addon/v1alpha1/types_addondeploymentconfig.go index 1b39f89d..3fd3d013 100644 --- a/addon/v1alpha1/types_addondeploymentconfig.go +++ b/addon/v1alpha1/types_addondeploymentconfig.go @@ -54,10 +54,12 @@ type AddOnDeploymentConfigSpec struct { ProxyConfig ProxyConfig `json:"proxyConfig,omitempty"` // AgentInstallNamespace is the namespace where the add-on agent should be installed on the managed cluster. + // For template-type addons: set to empty string "" to use the namespace defined in the addonTemplate. + // For non-template addons: defaults to "open-cluster-management-agent-addon" if not specified. // +optional // +kubebuilder:default=open-cluster-management-agent-addon // +kubebuilder:validation:MaxLength=63 - // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + // +kubebuilder:validation:Pattern=^([a-z0-9]([-a-z0-9]*[a-z0-9])?)?$ AgentInstallNamespace string `json:"agentInstallNamespace,omitempty"` // ResourceRequirements specify the resources required by add-on agents. diff --git a/test/integration/api/addondeploymentconfig_test.go b/test/integration/api/addondeploymentconfig_test.go index b22a0233..850230fa 100644 --- a/test/integration/api/addondeploymentconfig_test.go +++ b/test/integration/api/addondeploymentconfig_test.go @@ -159,4 +159,99 @@ var _ = ginkgo.Describe("AddOnDeploymentConfig API test", func() { ) gomega.Expect(errors.IsInvalid(err)).To(gomega.BeTrue()) }) + + ginkgo.It("Should create a AddOnDeploymentConfig with empty agentInstallNamespace", func() { + addOnDeploymentConfig := &addonv1alpha1.AddOnDeploymentConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: addOnDeploymentConfigName, + Namespace: testNamespace, + }, + Spec: addonv1alpha1.AddOnDeploymentConfigSpec{ + AgentInstallNamespace: "", + }, + } + + _, err := hubAddonClient.AddonV1alpha1().AddOnDeploymentConfigs(testNamespace).Create( + context.TODO(), + addOnDeploymentConfig, + metav1.CreateOptions{}, + ) + gomega.Expect(err).ToNot(gomega.HaveOccurred()) + }) + + ginkgo.It("Should create a AddOnDeploymentConfig with valid agentInstallNamespace", func() { + addOnDeploymentConfig := &addonv1alpha1.AddOnDeploymentConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: addOnDeploymentConfigName, + Namespace: testNamespace, + }, + Spec: addonv1alpha1.AddOnDeploymentConfigSpec{ + AgentInstallNamespace: "my-custom-namespace", + }, + } + + _, err := hubAddonClient.AddonV1alpha1().AddOnDeploymentConfigs(testNamespace).Create( + context.TODO(), + addOnDeploymentConfig, + metav1.CreateOptions{}, + ) + gomega.Expect(err).ToNot(gomega.HaveOccurred()) + }) + + ginkgo.It("Should not create a AddOnDeploymentConfig with invalid agentInstallNamespace (starts with hyphen)", func() { + addOnDeploymentConfig := &addonv1alpha1.AddOnDeploymentConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: addOnDeploymentConfigName, + Namespace: testNamespace, + }, + Spec: addonv1alpha1.AddOnDeploymentConfigSpec{ + AgentInstallNamespace: "-invalid", + }, + } + + _, err := hubAddonClient.AddonV1alpha1().AddOnDeploymentConfigs(testNamespace).Create( + context.TODO(), + addOnDeploymentConfig, + metav1.CreateOptions{}, + ) + gomega.Expect(errors.IsInvalid(err)).To(gomega.BeTrue()) + }) + + ginkgo.It("Should not create a AddOnDeploymentConfig with invalid agentInstallNamespace (contains uppercase)", func() { + addOnDeploymentConfig := &addonv1alpha1.AddOnDeploymentConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: addOnDeploymentConfigName, + Namespace: testNamespace, + }, + Spec: addonv1alpha1.AddOnDeploymentConfigSpec{ + AgentInstallNamespace: "Invalid-Namespace", + }, + } + + _, err := hubAddonClient.AddonV1alpha1().AddOnDeploymentConfigs(testNamespace).Create( + context.TODO(), + addOnDeploymentConfig, + metav1.CreateOptions{}, + ) + gomega.Expect(errors.IsInvalid(err)).To(gomega.BeTrue()) + }) + + ginkgo.It("Should not create a AddOnDeploymentConfig with agentInstallNamespace exceeding max length", func() { + addOnDeploymentConfig := &addonv1alpha1.AddOnDeploymentConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: addOnDeploymentConfigName, + Namespace: testNamespace, + }, + Spec: addonv1alpha1.AddOnDeploymentConfigSpec{ + AgentInstallNamespace: rand.String(64), // max is 63 + }, + } + + _, err := hubAddonClient.AddonV1alpha1().AddOnDeploymentConfigs(testNamespace).Create( + context.TODO(), + addOnDeploymentConfig, + metav1.CreateOptions{}, + ) + gomega.Expect(errors.IsInvalid(err)).To(gomega.BeTrue()) + }) })