diff --git a/controllers/classifier_deployer.go b/controllers/classifier_deployer.go index 909b329..39755e7 100644 --- a/controllers/classifier_deployer.go +++ b/controllers/classifier_deployer.go @@ -41,6 +41,7 @@ import ( "sigs.k8s.io/cluster-api/util" "sigs.k8s.io/cluster-api/util/annotations" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/yaml" "github.com/projectsveltos/classifier/controllers/keymanager" "github.com/projectsveltos/classifier/pkg/agent" @@ -494,6 +495,7 @@ func deploySveltosAgentWithKubeconfigInCluster(ctx context.Context, c client.Cli patches, err := getSveltosAgentPatches(ctx, c, logger) if err != nil { + logger.V(logs.LogInfo).Error(err, "failed to get patches") return err } @@ -1855,7 +1857,75 @@ func removeSveltosAgentFromManagementCluster(ctx context.Context, return nil } -func getSveltosAgentPatches(ctx context.Context, c client.Client, +func getPatchesFromConfigMap(configMap *corev1.ConfigMap, logger logr.Logger, +) ([]libsveltosv1beta1.Patch, error) { + + patches := make([]libsveltosv1beta1.Patch, 0) + for k := range configMap.Data { + patch := &libsveltosv1beta1.Patch{} + err := yaml.Unmarshal([]byte(configMap.Data[k]), patch) + if err != nil { + logger.V(logs.LogInfo).Error(err, "failed to marshal unstructured object") + return nil, err + } + + if patch.Patch == "" { + return nil, fmt.Errorf("ConfigMap %s: content of key %s is not a Patch", + configMap.Name, k) + } + + if patch.Target == nil { + patch.Target = &libsveltosv1beta1.PatchSelector{ + Kind: "Deployment", + Group: "apps", + } + } + + patches = append(patches, *patch) + } + + return patches, nil +} + +func getSveltosAgentPatchesNew(ctx context.Context, c client.Client, + logger logr.Logger) ([]libsveltosv1beta1.Patch, error) { + + configMapName := getSveltosAgentConfigMap() + configMap := &corev1.ConfigMap{} + if configMapName != "" { + err := c.Get(ctx, + types.NamespacedName{Namespace: projectsveltos, Name: configMapName}, + configMap) + if err != nil { + logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to get ConfigMap %s: %v", + configMapName, err)) + return nil, err + } + } + + return getPatchesFromConfigMap(configMap, logger) +} + +func getSveltosApplierPatchesNew(ctx context.Context, c client.Client, + logger logr.Logger) ([]libsveltosv1beta1.Patch, error) { + + configMapName := getSveltosApplierConfigMap() + configMap := &corev1.ConfigMap{} + if configMapName != "" { + err := c.Get(ctx, + types.NamespacedName{Namespace: projectsveltos, Name: configMapName}, + configMap) + if err != nil { + logger.V(logs.LogInfo).Info(fmt.Sprintf("failed to get ConfigMap %s: %v", + configMapName, err)) + return nil, err + } + } + + return getPatchesFromConfigMap(configMap, logger) +} + +func getSveltosAgentPatchesOld(ctx context.Context, c client.Client, logger logr.Logger) ([]libsveltosv1beta1.Patch, error) { patches := make([]libsveltosv1beta1.Patch, 0) @@ -1887,7 +1957,7 @@ func getSveltosAgentPatches(ctx context.Context, c client.Client, return patches, nil } -func getSveltosApplierPatches(ctx context.Context, c client.Client, +func getSveltosApplierPatchesOld(ctx context.Context, c client.Client, logger logr.Logger) ([]libsveltosv1beta1.Patch, error) { patches := make([]libsveltosv1beta1.Patch, 0) @@ -1919,6 +1989,28 @@ func getSveltosApplierPatches(ctx context.Context, c client.Client, return patches, nil } +func getSveltosAgentPatches(ctx context.Context, c client.Client, + logger logr.Logger) ([]libsveltosv1beta1.Patch, error) { + + patches, err := getSveltosAgentPatchesNew(ctx, c, logger) + if err == nil { + return patches, nil + } + + return getSveltosAgentPatchesOld(ctx, c, logger) +} + +func getSveltosApplierPatches(ctx context.Context, c client.Client, + logger logr.Logger) ([]libsveltosv1beta1.Patch, error) { + + patches, err := getSveltosApplierPatchesNew(ctx, c, logger) + if err == nil { + return patches, nil + } + + return getSveltosApplierPatchesOld(ctx, c, logger) +} + func addTemplateSpecLabels(u *unstructured.Unstructured, lbls map[string]string) (*unstructured.Unstructured, error) { var deployment appsv1.Deployment err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.UnstructuredContent(), &deployment) diff --git a/controllers/classifier_deployer_test.go b/controllers/classifier_deployer_test.go index 45c9826..b8de43c 100644 --- a/controllers/classifier_deployer_test.go +++ b/controllers/classifier_deployer_test.go @@ -665,6 +665,235 @@ var _ = Describe("Classifier Deployer", func() { return true }, timeout, pollingInterval).Should(BeTrue()) }) + + It("getSveltosAgentPatches reads post render patches from ConfigMap", func() { + cmYAML := `apiVersion: v1 +data: + deployment-patch: |- + patch: |- + - op: replace + path: /spec/template/spec/containers/0/resources/requests/cpu + value: 500m + - op: replace + path: /spec/template/spec/containers/0/resources/requests/memory + value: 512Mi + - op: replace + path: /spec/template/spec/containers/0/resources/limits/cpu + value: 500m + - op: replace + path: /spec/template/spec/containers/0/resources/limits/memory + value: 1024Mi + target: + kind: Deployment + name: sveltos-agent-manager + namespace: projectsveltos + clusterrole-patch: |- + patch: |- + - op: remove + path: /rules + target: + kind: ClusterRole + name: sveltos-agent-manager-role +kind: ConfigMap +metadata: + name: sveltos-agent-config + namespace: projectsveltos` + + cm, err := deployer.GetUnstructured([]byte(cmYAML), logger) + Expect(err).To(BeNil()) + + initObjects := []client.Object{} + for i := range cm { + initObjects = append(initObjects, cm[i]) + } + + c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjects...).Build() + + controllers.SetSveltosAgentConfigMap("sveltos-agent-config") + patches, err := controllers.GetSveltosAgentPatches(context.TODO(), c, logger) + Expect(err).To(BeNil()) + Expect(len(patches)).To(Equal(2)) + controllers.SetSveltosAgentConfigMap("") + + verifyPatches(patches) + }) + + It("getSveltosApplierPatches reads post render patches from ConfigMap", func() { + cmYAML := `apiVersion: v1 +data: + deployment-patch: |- + patch: |- + - op: replace + path: /spec/template/spec/containers/0/resources/requests/cpu + value: 500m + - op: replace + path: /spec/template/spec/containers/0/resources/requests/memory + value: 512Mi + target: + kind: Deployment + name: sveltos-applier-manager + namespace: projectsveltos + clusterrole-patch: |- + patch: |- + - op: remove + path: /rules + target: + kind: ClusterRole + name: sveltos-applier-manager-role +kind: ConfigMap +metadata: + name: sveltos-applier-config + namespace: projectsveltos` + + cm, err := deployer.GetUnstructured([]byte(cmYAML), logger) + Expect(err).To(BeNil()) + + initObjects := []client.Object{} + for i := range cm { + initObjects = append(initObjects, cm[i]) + } + + c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjects...).Build() + + controllers.SetSveltosApplierConfigMap("sveltos-applier-config") + patches, err := controllers.GetSveltosApplierPatches(context.TODO(), c, logger) + Expect(err).To(BeNil()) + Expect(len(patches)).To(Equal(2)) + controllers.SetSveltosApplierConfigMap("") + + verifyPatches(patches) + }) + + It("getSveltosAgentPatches with Strategic Merge Patch", func() { + cmYAML := `apiVersion: v1 +data: + deployment-spec-patch: |- + patch: |- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: "sveltos-ag*" + spec: + template: + spec: + containers: + - name: manager + resources: + requests: + memory: 256Mi + target: + kind: Deployment + group: apps + name: "sveltos-ag*" +kind: ConfigMap +metadata: + name: sveltos-agent-config + namespace: projectsveltos` + + cm, err := deployer.GetUnstructured([]byte(cmYAML), logger) + Expect(err).To(BeNil()) + + initObjects := []client.Object{} + for i := range cm { + initObjects = append(initObjects, cm[i]) + } + + c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjects...).Build() + + controllers.SetSveltosAgentConfigMap("sveltos-agent-config") + patches, err := controllers.GetSveltosAgentPatches(context.TODO(), c, logger) + Expect(err).To(BeNil()) + Expect(len(patches)).To(Equal(1)) + Expect(patches[0].Target.Kind).To(Equal("Deployment")) + Expect(patches[0].Patch).ToNot(BeEmpty()) + controllers.SetSveltosAgentConfigMap("") + }) + + It("getSveltosAgentPatches reads old post render patches from ConfigMap", func() { + cmYAML := `apiVersion: v1 +data: + deployment-patch: |- + image-patch: |- + - op: replace + path: /spec/template/spec/containers/0/image + value: registry.ciroos.ai/samay/third-party-images/projectsveltos/sveltos-agent:f2d27fef1-251024102029-amd64 + - op: add + path: /spec/template/spec/imagePullSecrets + value: + - name: regcred + - op: replace + path: /spec/template/spec/containers/0/resources/requests/cpu + value: 500m + - op: replace + path: /spec/template/spec/containers/0/resources/requests/memory + value: 512Mi + - op: replace + path: /spec/template/spec/containers/0/resources/limits/cpu + value: 500m + - op: replace + path: /spec/template/spec/containers/0/resources/limits/memory + value: 1024Mi +kind: ConfigMap +metadata: + name: sveltos-agent-config-old + namespace: projectsveltos` + + cm, err := deployer.GetUnstructured([]byte(cmYAML), logger) + Expect(err).To(BeNil()) + + initObjects := []client.Object{} + for i := range cm { + initObjects = append(initObjects, cm[i]) + } + + c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjects...).Build() + + controllers.SetSveltosAgentConfigMap("sveltos-agent-config-old") + patches, err := controllers.GetSveltosAgentPatches(context.TODO(), c, logger) + Expect(err).To(BeNil()) + Expect(len(patches)).To(Equal(1)) + controllers.SetSveltosAgentConfigMap("") + }) + + It("getSveltosAgentPatches with old Strategic Merge Patch", func() { + cmYAML := `apiVersion: v1 +data: + patch: |- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: "sveltos-ag*" + spec: + template: + spec: + containers: + - name: manager + resources: + requests: + memory: 256Mi +kind: ConfigMap +metadata: + name: sveltos-agent-config-old + namespace: projectsveltos` + + cm, err := deployer.GetUnstructured([]byte(cmYAML), logger) + Expect(err).To(BeNil()) + + initObjects := []client.Object{} + for i := range cm { + initObjects = append(initObjects, cm[i]) + } + + c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjects...).Build() + + controllers.SetSveltosAgentConfigMap("sveltos-agent-config-old") + patches, err := controllers.GetSveltosAgentPatches(context.TODO(), c, logger) + Expect(err).To(BeNil()) + Expect(len(patches)).To(Equal(1)) + Expect(patches[0].Target.Kind).To(Equal("Deployment")) + Expect(patches[0].Patch).ToNot(BeEmpty()) + controllers.SetSveltosAgentConfigMap("") + }) }) func prepareCluster() *clusterv1.Cluster { @@ -775,3 +1004,21 @@ func verifyLabels(currentLabels, expectedLabels map[string]string) bool { return true } + +func verifyPatches(patches []libsveltosv1beta1.Patch) { + found := false + for i := range patches { + if patches[i].Target.Kind == "Deployment" { + found = true + } + } + Expect(found).To(BeTrue()) + + found = false + for i := range patches { + if patches[i].Target.Kind == "ClusterRole" { + found = true + } + } + Expect(found).To(BeTrue()) +} diff --git a/controllers/export_test.go b/controllers/export_test.go index 180af42..1f86a69 100644 --- a/controllers/export_test.go +++ b/controllers/export_test.go @@ -38,6 +38,8 @@ var ( RemoveSveltosAgentFromManagementCluster = removeSveltosAgentFromManagementCluster GetSveltosAgentLabels = getSveltosAgentLabels GetSveltosAgentNamespace = getSveltosAgentNamespace + GetSveltosAgentPatches = getSveltosAgentPatches + GetSveltosApplierPatches = getSveltosApplierPatches CreateAccessRequest = createAccessRequest GetAccessRequestName = getAccessRequestName diff --git a/pkg/agent/sveltos-applier.go b/pkg/agent/sveltos-applier.go index 0b61fec..2bde4a9 100644 --- a/pkg/agent/sveltos-applier.go +++ b/pkg/agent/sveltos-applier.go @@ -117,7 +117,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace - image: docker.io/projectsveltos/sveltos-applier@sha256:e42404bcb3db4b0f472fe21f7dd19f3206f9f31481b0dddbfb28825e70af8861 + image: docker.io/projectsveltos/sveltos-applier@sha256:4c89caeed4eb7b719ac5da9a2e6ae35a4a294112418db89eba8a74b85874747d livenessProbe: failureThreshold: 3 httpGet: diff --git a/pkg/agent/sveltos-applier.yaml b/pkg/agent/sveltos-applier.yaml index 9281f42..327f65f 100644 --- a/pkg/agent/sveltos-applier.yaml +++ b/pkg/agent/sveltos-applier.yaml @@ -99,7 +99,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace - image: docker.io/projectsveltos/sveltos-applier@sha256:e42404bcb3db4b0f472fe21f7dd19f3206f9f31481b0dddbfb28825e70af8861 + image: docker.io/projectsveltos/sveltos-applier@sha256:4c89caeed4eb7b719ac5da9a2e6ae35a4a294112418db89eba8a74b85874747d livenessProbe: failureThreshold: 3 httpGet: diff --git a/test/pullmode-sveltosapplier.yaml b/test/pullmode-sveltosapplier.yaml index c40b399..1fcfed9 100644 --- a/test/pullmode-sveltosapplier.yaml +++ b/test/pullmode-sveltosapplier.yaml @@ -99,7 +99,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace - image: docker.io/projectsveltos/sveltos-applier@sha256:e42404bcb3db4b0f472fe21f7dd19f3206f9f31481b0dddbfb28825e70af8861 + image: docker.io/projectsveltos/sveltos-applier@sha256:4c89caeed4eb7b719ac5da9a2e6ae35a4a294112418db89eba8a74b85874747d livenessProbe: failureThreshold: 3 httpGet: