From 8950d62d247165c858a737d5b21314aaaff5d4d3 Mon Sep 17 00:00:00 2001 From: Zorian Motso Date: Wed, 9 Oct 2024 12:08:47 +0300 Subject: [PATCH] feat: Add ConfigMap creation for Stage (#78) Implement automatic creation of a ConfigMap for each Stage. This ConfigMap will be used to store Stage variables. --- controllers/stage/chain/factory.go | 1 + controllers/stage/chain/put_configmap.go | 69 ++++++++++++++ controllers/stage/chain/put_configmap_test.go | 91 +++++++++++++++++++ .../03-assert-cdpipeline-and-stages.yaml | 12 +++ 4 files changed, 173 insertions(+) create mode 100644 controllers/stage/chain/put_configmap.go create mode 100644 controllers/stage/chain/put_configmap_test.go diff --git a/controllers/stage/chain/factory.go b/controllers/stage/chain/factory.go index 42e4281..d894052 100644 --- a/controllers/stage/chain/factory.go +++ b/controllers/stage/chain/factory.go @@ -56,6 +56,7 @@ func CreateChain(ctx context.Context, c client.Client, stage *cdPipeApi.Stage) ( AddApplicationSetGenerators{ applicationSetManager: argocd.NewArgoApplicationSetManager(c), }, + NewPutConfigMap(c), ) return ch, nil diff --git a/controllers/stage/chain/put_configmap.go b/controllers/stage/chain/put_configmap.go new file mode 100644 index 0000000..e3b3b06 --- /dev/null +++ b/controllers/stage/chain/put_configmap.go @@ -0,0 +1,69 @@ +package chain + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + k8sErrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + cdPipeApi "github.com/epam/edp-cd-pipeline-operator/v2/api/v1" +) + +type PutConfigMap struct { + k8sClient client.Client +} + +func NewPutConfigMap(k8sClient client.Client) *PutConfigMap { + return &PutConfigMap{k8sClient: k8sClient} +} + +func (h *PutConfigMap) ServeRequest(ctx context.Context, stage *cdPipeApi.Stage) error { + log := ctrl.LoggerFrom(ctx) + + log.Info("Start putting ConfigMap", "configMapName", stage.Name) + + cm := &corev1.ConfigMap{} + + err := h.k8sClient.Get( + ctx, + types.NamespacedName{ + Namespace: stage.Namespace, + Name: stage.Name, + }, + cm, + ) + if err != nil && !k8sErrors.IsNotFound(err) { + return fmt.Errorf("failed to get ConfigMap: %w", err) + } + + if err == nil { + log.Info("ConfigMap already exists") + + return nil + } + + cm = &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: stage.Name, + Namespace: stage.Namespace, + }, + } + + if err = controllerutil.SetControllerReference(stage, cm, h.k8sClient.Scheme()); err != nil { + return fmt.Errorf("failed to set controller reference: %w", err) + } + + if err = h.k8sClient.Create(ctx, cm); err != nil { + return fmt.Errorf("failed to create ConfigMap: %w", err) + } + + log.Info("ConfigMap has been created") + + return nil +} diff --git a/controllers/stage/chain/put_configmap_test.go b/controllers/stage/chain/put_configmap_test.go new file mode 100644 index 0000000..e57fd0e --- /dev/null +++ b/controllers/stage/chain/put_configmap_test.go @@ -0,0 +1,91 @@ +package chain + +import ( + "context" + "testing" + + "github.com/go-logr/logr" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + cdPipeApi "github.com/epam/edp-cd-pipeline-operator/v2/api/v1" +) + +func TestPutConfigMap_ServeRequest(t *testing.T) { + t.Parallel() + + scheme := runtime.NewScheme() + require.NoError(t, corev1.AddToScheme(scheme)) + require.NoError(t, cdPipeApi.AddToScheme(scheme)) + + tests := []struct { + name string + stage *cdPipeApi.Stage + client func(t *testing.T) client.Client + wantErr require.ErrorAssertionFunc + want func(t *testing.T, stage *cdPipeApi.Stage, cl client.Client) + }{ + { + name: "create configmap successfully", + stage: &cdPipeApi.Stage{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pipe-dev", + Namespace: "default", + }, + }, + client: func(t *testing.T) client.Client { + return fake.NewClientBuilder().WithScheme(scheme).Build() + }, + wantErr: require.NoError, + want: func(t *testing.T, stage *cdPipeApi.Stage, cl client.Client) { + cm := &corev1.ConfigMap{} + require.NoError(t, cl.Get( + context.Background(), + client.ObjectKey{Namespace: stage.Namespace, Name: stage.Name}, + cm, + )) + }, + }, + { + name: "configmap already exists", + stage: &cdPipeApi.Stage{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pipe-dev", + Namespace: "default", + }, + }, + client: func(t *testing.T) client.Client { + return fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects( + &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pipe-dev", + Namespace: "default", + }, + }, + ). + Build() + }, + wantErr: require.NoError, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cl := tt.client(t) + h := NewPutConfigMap(cl) + + tt.wantErr(t, h.ServeRequest(ctrl.LoggerInto(context.Background(), logr.Discard()), tt.stage)) + + if tt.want != nil { + tt.want(t, tt.stage, cl) + } + }) + } +} diff --git a/tests/e2e/capsule-feature/03-assert-cdpipeline-and-stages.yaml b/tests/e2e/capsule-feature/03-assert-cdpipeline-and-stages.yaml index 225033f..016f779 100644 --- a/tests/e2e/capsule-feature/03-assert-cdpipeline-and-stages.yaml +++ b/tests/e2e/capsule-feature/03-assert-cdpipeline-and-stages.yaml @@ -302,3 +302,15 @@ spec: targetRevision: >- {{ if eq .versionType "edp" }}build/{{ .imageTag }}{{ else }}{{ .imageTag }}{{ end }} + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: mypipeline-dev + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: mypipeline-qa