diff --git a/api/v1beta1/spec.go b/api/v1beta1/spec.go index 841f3ecc..5dd2a72d 100644 --- a/api/v1beta1/spec.go +++ b/api/v1beta1/spec.go @@ -138,6 +138,13 @@ type ValueFrom struct { // - ConfigMap/Secret // +kubebuilder:validation:Enum=ConfigMap;Secret Kind string `json:"kind"` + + // Optional indicates that the referenced resource is not mandatory. + // If set to true and the resource is not found, the error will be ignored, + // and Sveltos will continue processing other ValueFroms. + // +kubebuilder:default:=false + // +optional + Optional bool `json:"optional,omitempty"` } type RegistryCredentialsConfig struct { @@ -485,6 +492,13 @@ type KustomizationRef struct { // +optional Path string `json:"path,omitempty"` + // Optional indicates that the referenced resource is not mandatory. + // If set to true and the resource is not found, the error will be ignored, + // and Sveltos will continue processing other ValueFroms. + // +kubebuilder:default:=false + // +optional + Optional bool `json:"optional,omitempty"` + // TargetNamespace sets or overrides the namespace in the // kustomization.yaml file. // +kubebuilder:validation:MinLength=1 @@ -559,6 +573,13 @@ type TemplateResourceRef struct { // Identifier is how the resource will be referred to in the // template Identifier string `json:"identifier"` + + // Optional indicates that the referenced resource is not mandatory. + // If set to true and the resource is not found, the error will be ignored, + // and Sveltos will continue processing other TemplateResourceRefs. + // +kubebuilder:default:=false + // +optional + Optional bool `json:"optional,omitempty"` } type PolicyRef struct { @@ -592,6 +613,13 @@ type PolicyRef struct { // +kubebuilder:default:=Remote // +optional DeploymentType DeploymentType `json:"deploymentType,omitempty"` + + // Optional indicates that the referenced resource is not mandatory. + // If set to true and the resource is not found, the error will be ignored, + // and Sveltos will continue processing other PolicyRefs. + // +kubebuilder:default:=false + // +optional + Optional bool `json:"optional,omitempty"` } type DriftExclusion struct { diff --git a/config/crd/bases/config.projectsveltos.io_clusterprofiles.yaml b/config/crd/bases/config.projectsveltos.io_clusterprofiles.yaml index 1a6d4bcf..6deff0a6 100644 --- a/config/crd/bases/config.projectsveltos.io_clusterprofiles.yaml +++ b/config/crd/bases/config.projectsveltos.io_clusterprofiles.yaml @@ -584,6 +584,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -656,6 +663,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean path: description: |- Path to the directory containing the kustomization.yaml file, or the @@ -732,6 +746,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -872,6 +893,13 @@ spec: For Profile namespace must be left empty. Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other PolicyRefs. + type: boolean path: description: |- Path to the directory containing the YAML files. @@ -945,6 +973,13 @@ spec: Identifier is how the resource will be referred to in the template type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other TemplateResourceRefs. + type: boolean resource: description: |- Resource references a Kubernetes instance in the management diff --git a/config/crd/bases/config.projectsveltos.io_clustersummaries.yaml b/config/crd/bases/config.projectsveltos.io_clustersummaries.yaml index fe24c3c7..6b9142d4 100644 --- a/config/crd/bases/config.projectsveltos.io_clustersummaries.yaml +++ b/config/crd/bases/config.projectsveltos.io_clustersummaries.yaml @@ -622,6 +622,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -694,6 +701,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean path: description: |- Path to the directory containing the kustomization.yaml file, or the @@ -770,6 +784,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -910,6 +931,13 @@ spec: For Profile namespace must be left empty. Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other PolicyRefs. + type: boolean path: description: |- Path to the directory containing the YAML files. @@ -983,6 +1011,13 @@ spec: Identifier is how the resource will be referred to in the template type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other TemplateResourceRefs. + type: boolean resource: description: |- Resource references a Kubernetes instance in the management diff --git a/config/crd/bases/config.projectsveltos.io_profiles.yaml b/config/crd/bases/config.projectsveltos.io_profiles.yaml index b11a981f..b7fad91c 100644 --- a/config/crd/bases/config.projectsveltos.io_profiles.yaml +++ b/config/crd/bases/config.projectsveltos.io_profiles.yaml @@ -584,6 +584,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -656,6 +663,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean path: description: |- Path to the directory containing the kustomization.yaml file, or the @@ -732,6 +746,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -872,6 +893,13 @@ spec: For Profile namespace must be left empty. Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other PolicyRefs. + type: boolean path: description: |- Path to the directory containing the YAML files. @@ -945,6 +973,13 @@ spec: Identifier is how the resource will be referred to in the template type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other TemplateResourceRefs. + type: boolean resource: description: |- Resource references a Kubernetes instance in the management diff --git a/controllers/clustersummary_controller.go b/controllers/clustersummary_controller.go index 4e89b58a..ee0e20e3 100644 --- a/controllers/clustersummary_controller.go +++ b/controllers/clustersummary_controller.go @@ -933,6 +933,9 @@ func (r *ClusterSummaryReconciler) getKustomizationRefReferences(ctx context.Con valuesFromReferences, err := getKustomizationValueFrom(ctx, clusterSummaryScope, kr) if err != nil { + if kr.Optional { + continue + } return nil, err } currentReferences.Append(valuesFromReferences) diff --git a/controllers/handlers_utils.go b/controllers/handlers_utils.go index ca835117..e1cd3c35 100644 --- a/controllers/handlers_utils.go +++ b/controllers/handlers_utils.go @@ -1174,6 +1174,9 @@ func collectReferencedObjects(ctx context.Context, controlClusterClient client.C msg := fmt.Sprintf("Referenced resource: %s %s/%s does not exist", reference.Kind, reference.Namespace, name) logger.V(logs.LogInfo).Info(msg) + if reference.Optional { + continue + } return nil, nil, &NonRetriableError{Message: msg} } return nil, nil, err @@ -1917,15 +1920,11 @@ func getValuesFrom(ctx context.Context, c client.Client, clusterSummary *configv if valuesFrom[i].Kind == string(libsveltosv1beta1.ConfigMapReferencedResourceKind) { configMap, err := getConfigMap(ctx, c, types.NamespacedName{Namespace: namespace, Name: name}) if err != nil { - msg := fmt.Sprintf("failed to get ConfigMap %s/%s", namespace, name) - logger.V(logs.LogInfo).Info(fmt.Sprintf("%s: %v", msg, err)) - if apierrors.IsNotFound(err) { - msg := fmt.Sprintf("Referenced resource: %s %s/%s does not exist", - libsveltosv1beta1.ConfigMapReferencedResourceKind, namespace, name) - logger.V(logs.LogInfo).Info(msg) - return nil, nil, &NonRetriableError{Message: msg} + err = handleReferenceError(err, valuesFrom[i].Kind, namespace, name, valuesFrom[i].Optional, logger) + if err == nil { + continue } - return nil, nil, fmt.Errorf("%s: %w", msg, err) + return nil, nil, err } if instantiateTemplate(configMap, logger) { @@ -1948,15 +1947,11 @@ func getValuesFrom(ctx context.Context, c client.Client, clusterSummary *configv } else if valuesFrom[i].Kind == string(libsveltosv1beta1.SecretReferencedResourceKind) { secret, err := getSecret(ctx, c, types.NamespacedName{Namespace: namespace, Name: name}) if err != nil { - msg := fmt.Sprintf("failed to get Secret %s/%s", namespace, name) - logger.V(logs.LogInfo).Info(fmt.Sprintf("%s: %v", msg, err)) - if apierrors.IsNotFound(err) { - msg := fmt.Sprintf("Referenced resource: %s %s/%s does not exist", - libsveltosv1beta1.SecretReferencedResourceKind, namespace, name) - logger.V(logs.LogInfo).Info(msg) - return nil, nil, &NonRetriableError{Message: msg} + err = handleReferenceError(err, valuesFrom[i].Kind, namespace, name, valuesFrom[i].Optional, logger) + if err == nil { + continue } - return nil, nil, fmt.Errorf("%s: %w", msg, err) + return nil, nil, err } if instantiateTemplate(secret, logger) { for key, value := range secret.Data { @@ -1981,6 +1976,24 @@ func getValuesFrom(ctx context.Context, c client.Client, clusterSummary *configv return template, nonTemplate, nil } +func handleReferenceError(err error, kind, namespace, name string, optional bool, + logger logr.Logger) error { + + msg := fmt.Sprintf("Referenced resource: %s %s/%s", kind, namespace, name) + + if apierrors.IsNotFound(err) { + msg += " does not exist" + logger.V(logs.LogInfo).Info(msg) + if optional { + return nil + } + return &NonRetriableError{Message: msg} + } + + logger.V(logs.LogInfo).Info(fmt.Sprintf("%s: %v", msg, err)) + return fmt.Errorf("%s: %w", msg, err) +} + func addToMap(m map[string]string, key, value string) { // Check if the key exists in the map if existingValue, ok := m[key]; ok { diff --git a/controllers/templateresourcedef_utils.go b/controllers/templateresourcedef_utils.go index f9634156..fa703c9a 100644 --- a/controllers/templateresourcedef_utils.go +++ b/controllers/templateresourcedef_utils.go @@ -79,7 +79,7 @@ func collectTemplateResourceRefs(ctx context.Context, clusterSummary *configv1be var u *unstructured.Unstructured u, err = dr.Get(ctx, ref.Resource.Name, metav1.GetOptions{}) if err != nil { - if apierrors.IsNotFound(err) { + if apierrors.IsNotFound(err) && ref.Optional { continue } return nil, err diff --git a/go.mod b/go.mod index d1f295b6..5ef53d8a 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/onsi/ginkgo/v2 v2.23.4 github.com/onsi/gomega v1.37.0 github.com/pkg/errors v0.9.1 - github.com/projectsveltos/libsveltos v0.53.1-0.20250506070210-ef75a78e70a1 + github.com/projectsveltos/libsveltos v0.53.1-0.20250508204842-3ec81919e31d github.com/prometheus/client_golang v1.22.0 github.com/spf13/pflag v1.0.6 github.com/yuin/gopher-lua v1.1.1 diff --git a/go.sum b/go.sum index 44b7fdb1..42537717 100644 --- a/go.sum +++ b/go.sum @@ -329,8 +329,8 @@ github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= -github.com/projectsveltos/libsveltos v0.53.1-0.20250506070210-ef75a78e70a1 h1:62mLgYOrZiqhMD6vc8JcndMs8obZpq+tfvNePsi774Y= -github.com/projectsveltos/libsveltos v0.53.1-0.20250506070210-ef75a78e70a1/go.mod h1:sqZMoHeBgXY6cMIRrByGsdZxpOmwdK+p/H3G81yZ6q0= +github.com/projectsveltos/libsveltos v0.53.1-0.20250508204842-3ec81919e31d h1:JcGfM5vYF+mWaR1xz7qDn0O0UNPqdzb/bBWJanwSamU= +github.com/projectsveltos/libsveltos v0.53.1-0.20250508204842-3ec81919e31d/go.mod h1:sqZMoHeBgXY6cMIRrByGsdZxpOmwdK+p/H3G81yZ6q0= github.com/projectsveltos/lua-utils/glua-json v0.0.0-20250301182851-e4fbb9fd7ff7 h1:KdDtBEJPgavOHlut1gq2i6bFm5dgoNHNsOUC8oe2hK4= github.com/projectsveltos/lua-utils/glua-json v0.0.0-20250301182851-e4fbb9fd7ff7/go.mod h1:AIzg+JWbfrFWazyM5Ka2fX69r9aFr3+o2Mvn9SfKDYU= github.com/projectsveltos/lua-utils/glua-runes v0.0.0-20250301182851-e4fbb9fd7ff7 h1:kZzOx+XTEfCRjxw1yACuGhFSyS7ybP/NNJFAZYNARCk= diff --git a/manifest/manifest.yaml b/manifest/manifest.yaml index ca69b6ed..a2878483 100644 --- a/manifest/manifest.yaml +++ b/manifest/manifest.yaml @@ -979,6 +979,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -1051,6 +1058,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean path: description: |- Path to the directory containing the kustomization.yaml file, or the @@ -1127,6 +1141,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -1267,6 +1288,13 @@ spec: For Profile namespace must be left empty. Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other PolicyRefs. + type: boolean path: description: |- Path to the directory containing the YAML files. @@ -1340,6 +1368,13 @@ spec: Identifier is how the resource will be referred to in the template type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other TemplateResourceRefs. + type: boolean resource: description: |- Resource references a Kubernetes instance in the management @@ -2634,6 +2669,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -2706,6 +2748,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean path: description: |- Path to the directory containing the kustomization.yaml file, or the @@ -2782,6 +2831,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -2922,6 +2978,13 @@ spec: For Profile namespace must be left empty. Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other PolicyRefs. + type: boolean path: description: |- Path to the directory containing the YAML files. @@ -2995,6 +3058,13 @@ spec: Identifier is how the resource will be referred to in the template type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other TemplateResourceRefs. + type: boolean resource: description: |- Resource references a Kubernetes instance in the management @@ -3891,6 +3961,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -3963,6 +4040,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean path: description: |- Path to the directory containing the kustomization.yaml file, or the @@ -4039,6 +4123,13 @@ spec: For Profile namespace must be left empty. The Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other ValueFroms. + type: boolean required: - kind - name @@ -4179,6 +4270,13 @@ spec: For Profile namespace must be left empty. Profile namespace will be used. Namespace can be expressed as a template and instantiate using any cluster field. type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other PolicyRefs. + type: boolean path: description: |- Path to the directory containing the YAML files. @@ -4252,6 +4350,13 @@ spec: Identifier is how the resource will be referred to in the template type: string + optional: + default: false + description: |- + Optional indicates that the referenced resource is not mandatory. + If set to true and the resource is not found, the error will be ignored, + and Sveltos will continue processing other TemplateResourceRefs. + type: boolean resource: description: |- Resource references a Kubernetes instance in the management diff --git a/test/fv/autoscaler_test.go b/test/fv/autoscaler_test.go index e7d1b935..eb0aa186 100644 --- a/test/fv/autoscaler_test.go +++ b/test/fv/autoscaler_test.go @@ -126,6 +126,7 @@ var _ = Describe("Feature", func() { Name: autoscaler, }, Identifier: "AutoscalerSecret", + Optional: true, }, } currentClusterProfile.Spec.PolicyRefs = []configv1beta1.PolicyRef{ diff --git a/test/fv/optional_referenced_resource_test.go b/test/fv/optional_referenced_resource_test.go new file mode 100644 index 00000000..485e7957 --- /dev/null +++ b/test/fv/optional_referenced_resource_test.go @@ -0,0 +1,142 @@ +/* +Copyright 2025. projectsveltos.io. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package fv_test + +import ( + "context" + "fmt" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + configv1beta1 "github.com/projectsveltos/addon-controller/api/v1beta1" + "github.com/projectsveltos/addon-controller/controllers" + libsveltosv1beta1 "github.com/projectsveltos/libsveltos/api/v1beta1" +) + +var _ = Describe("Feature", func() { + const ( + namePrefix = "optional-ref-resources-" + ) + + var ( + namespace = `kind: Namespace +apiVersion: v1 +metadata: + name: %s` + ) + + It("When referenced resource is marked as optional, Sveltos keeps deploying if resource is not found", Label("NEW-FV"), func() { + Byf("Create a ClusterProfile matching Cluster %s/%s", kindWorkloadCluster.Namespace, kindWorkloadCluster.Name) + clusterProfile := getClusterProfile(namePrefix, map[string]string{key: value}) + clusterProfile.Spec.SyncMode = configv1beta1.SyncModeContinuous + maxConsecutiveFailures := uint(3) + clusterProfile.Spec.MaxConsecutiveFailures = &maxConsecutiveFailures + Expect(k8sClient.Create(context.TODO(), clusterProfile)).To(Succeed()) + + verifyClusterProfileMatches(clusterProfile) + + verifyClusterSummary(controllers.ClusterProfileLabelName, + clusterProfile.Name, &clusterProfile.Spec, kindWorkloadCluster.Namespace, kindWorkloadCluster.Name) + + configMapNs := randomString() + Byf("Create configMap's namespace %s", configMapNs) + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapNs, + }, + } + Expect(k8sClient.Create(context.TODO(), ns)).To(Succeed()) + + Byf("Create a configMap with resources to deploy") + resourceNamespace := randomString() + configMap := createConfigMapWithPolicy(configMapNs, namePrefix+randomString(), + fmt.Sprintf(namespace, resourceNamespace)) + Expect(k8sClient.Create(context.TODO(), configMap)).To(Succeed()) + currentConfigMap := &corev1.ConfigMap{} + Expect(k8sClient.Get(context.TODO(), + types.NamespacedName{Namespace: configMap.Namespace, Name: configMap.Name}, currentConfigMap)).To(Succeed()) + + Byf("Update ClusterProfile %s to deploy helm charts and referencing ConfigMap %s/%s", + clusterProfile.Name, configMap.Namespace, configMap.Name) + currentClusterProfile := &configv1beta1.ClusterProfile{} + Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Name: clusterProfile.Name}, + currentClusterProfile)).To(Succeed()) + + currentClusterProfile.Spec.HelmCharts = []configv1beta1.HelmChart{ + { + RepositoryURL: "https://prometheus-community.github.io/helm-charts", + RepositoryName: "prometheus-community", + ChartName: "prometheus-community/prometheus", + ChartVersion: "25.24.0", + ReleaseName: "prometheus", + ReleaseNamespace: "prometheus", + HelmChartAction: configv1beta1.HelmChartActionInstall, + ValuesFrom: []configv1beta1.ValueFrom{ + { + Kind: string(libsveltosv1beta1.ConfigMapReferencedResourceKind), + Namespace: namespace, + Name: randomString(), // this wont exist but it is marked as optional + Optional: true, + }, + }, + }, + } + + currentClusterProfile.Spec.PolicyRefs = []configv1beta1.PolicyRef{ + { + Kind: string(libsveltosv1beta1.ConfigMapReferencedResourceKind), + Namespace: configMap.Namespace, + Name: configMap.Name, + }, + { + Kind: string(libsveltosv1beta1.ConfigMapReferencedResourceKind), + Namespace: configMap.Namespace, + Name: randomString(), // this wont exist but it is marked as optional + Optional: true, + }, + } + + Expect(k8sClient.Update(context.TODO(), currentClusterProfile)).To(Succeed()) + + clusterSummary := verifyClusterSummary(controllers.ClusterProfileLabelName, + currentClusterProfile.Name, ¤tClusterProfile.Spec, + kindWorkloadCluster.Namespace, kindWorkloadCluster.Name) + + charts := []configv1beta1.Chart{ + {ReleaseName: "prometheus", ChartVersion: "25.24.0", Namespace: "prometheus"}, + } + + verifyClusterConfiguration(configv1beta1.ClusterProfileKind, clusterProfile.Name, + clusterSummary.Spec.ClusterNamespace, clusterSummary.Spec.ClusterName, configv1beta1.FeatureHelm, + nil, charts) + + policies := []policy{ + {kind: "Namespace", name: resourceNamespace, namespace: "", group: ""}, + } + + verifyClusterConfiguration(configv1beta1.ClusterProfileKind, clusterProfile.Name, + clusterSummary.Spec.ClusterNamespace, clusterSummary.Spec.ClusterName, configv1beta1.FeatureResources, + policies, nil) + + deleteClusterProfile(clusterProfile) + }) +})