From f515dc9b6c935232e82d0f29cf1cda6b2d5eb049 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Mon, 8 Jul 2024 17:03:43 +0200 Subject: [PATCH 01/12] fix: Use provided rest config --- controllers/base_template_reconciler.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/controllers/base_template_reconciler.go b/controllers/base_template_reconciler.go index cd4d48c..c6f1a66 100644 --- a/controllers/base_template_reconciler.go +++ b/controllers/base_template_reconciler.go @@ -11,7 +11,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" @@ -33,10 +32,7 @@ type BaseTemplateReconciler struct { } func (r *BaseTemplateReconciler) getClientForObjects(serviceAccountName string, objNamespace string) (client.Client, error) { - restConfig, err := config.GetConfig() - if err != nil { - return nil, err - } + restConfig := rest.CopyConfig(r.Manager.GetConfig()) name := "default" if serviceAccountName != "" { From b0c2f62c2071532db4dfa275cda13b6db032abba Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Mon, 8 Jul 2024 17:04:10 +0200 Subject: [PATCH 02/12] tests: Add initial ObjectHandler tests --- controllers/objecttemplate_controller_test.go | 322 ++++++++++++++++++ controllers/suite_test.go | 141 +++++++- 2 files changed, 454 insertions(+), 9 deletions(-) create mode 100644 controllers/objecttemplate_controller_test.go diff --git a/controllers/objecttemplate_controller_test.go b/controllers/objecttemplate_controller_test.go new file mode 100644 index 0000000..c155b75 --- /dev/null +++ b/controllers/objecttemplate_controller_test.go @@ -0,0 +1,322 @@ +/* +Copyright 2022. + +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 controllers + +import ( + "fmt" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "math/rand/v2" + client2 "sigs.k8s.io/controller-runtime/pkg/client" + "time" + + templatesv1alpha1 "github.com/kluctl/template-controller/api/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func buildTestConfigMap(name string, namespace string, data map[string]string) *unstructured.Unstructured { + m := map[string]any{} + for k, v := range data { + m[k] = v + } + return &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]any{ + "name": name, + "namespace": namespace, + }, + "data": m, + }, + } +} + +func buildTestSecret(name string, namespace string, data map[string]string) *unstructured.Unstructured { + m := map[string]any{} + for k, v := range data { + m[k] = v + } + return &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": "v1", + "kind": "Secret", + "metadata": map[string]any{ + "name": name, + "namespace": namespace, + }, + "stringData": m, + }, + } +} + +func buildObjectTemplate(name string, namespace string, matrixEntries []*templatesv1alpha1.MatrixEntry, templates []templatesv1alpha1.Template) *templatesv1alpha1.ObjectTemplate { + t := &templatesv1alpha1.ObjectTemplate{ + TypeMeta: metav1.TypeMeta{ + APIVersion: templatesv1alpha1.GroupVersion.String(), + Kind: "ObjectTemplate", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: templatesv1alpha1.ObjectTemplateSpec{ + Interval: metav1.Duration{Duration: time.Second}, + Matrix: matrixEntries, + Templates: templates, + }, + } + return t +} + +func buildMatrixListEntry(name string) *templatesv1alpha1.MatrixEntry { + return &templatesv1alpha1.MatrixEntry{ + Name: name, + List: []runtime.RawExtension{ + { + Raw: []byte(`{"k1": 1, "k2": 2}`), + }, + }, + } +} + +func buildMatrixObjectEntry(name string, objName string, objNamespace string, objKind string, jsonPath string, expandLists bool) *templatesv1alpha1.MatrixEntry { + var jsonPathPtr *string + if jsonPath != "" { + jsonPathPtr = &jsonPath + } + return &templatesv1alpha1.MatrixEntry{ + Name: name, + Object: &templatesv1alpha1.MatrixEntryObject{ + Ref: templatesv1alpha1.ObjectRef{ + APIVersion: "v1", + Kind: objKind, + Name: objName, + Namespace: objNamespace, + }, + JsonPath: jsonPathPtr, + ExpandLists: expandLists, + }, + } +} + +func updateObjectTemplate(key client2.ObjectKey, fn func(t *templatesv1alpha1.ObjectTemplate)) { + t := getObjectTemplate(key) + fn(t) + err := k8sClient.Update(ctx, t, client2.FieldOwner("tests")) + Expect(err).To(Succeed()) +} + +func triggerReconcile(key client2.ObjectKey) { + updateObjectTemplate(key, func(t *templatesv1alpha1.ObjectTemplate) { + t.Spec.Interval.Duration += time.Millisecond + }) +} + +func waitUntiReconciled(key client2.ObjectKey, timeout time.Duration) { + Eventually(func() bool { + t := getObjectTemplate(key) + if t == nil { + return false + } + c := getReadyCondition(t.GetConditions()) + if c == nil { + return false + } + return c.ObservedGeneration == t.Generation + }, timeout, time.Millisecond*250).Should(BeTrue()) +} + +func getObjectTemplate(key client2.ObjectKey) *templatesv1alpha1.ObjectTemplate { + var t templatesv1alpha1.ObjectTemplate + err := k8sClient.Get(ctx, key, &t) + if err != nil { + return nil + } + return &t +} + +func assertAppliedConfigMaps(key client2.ObjectKey, keys ...client2.ObjectKey) { + t := getObjectTemplate(key) + Expect(t).ToNot(BeNil()) + + var found []client2.ObjectKey + for _, as := range t.Status.AppliedResources { + if as.Success { + found = append(found, client2.ObjectKey{Name: as.Ref.Name, Namespace: as.Ref.Namespace}) + } + } + + Expect(found).To(ConsistOf(keys)) +} + +func assertFailedConfigMaps(key client2.ObjectKey, keys ...client2.ObjectKey) { + t := getObjectTemplate(key) + Expect(t).ToNot(BeNil()) + + var found []client2.ObjectKey + for _, as := range t.Status.AppliedResources { + if !as.Success { + found = append(found, client2.ObjectKey{Name: as.Ref.Name, Namespace: as.Ref.Namespace}) + } + } + + Expect(found).To(ConsistOf(keys)) +} + +func assertFailedConfigMap(key client2.ObjectKey, cmKey client2.ObjectKey, errStr string) { + t := getObjectTemplate(key) + Expect(t).ToNot(BeNil()) + for _, as := range t.Status.AppliedResources { + if !as.Success && as.Ref.Name == cmKey.Name && as.Ref.Namespace == cmKey.Namespace { + Expect(as.Error).To(ContainSubstring(errStr)) + return + } + } + Expect(false).To(BeTrue()) +} + +var _ = Describe("ObjectTemplate controller", func() { + const ( + timeout = time.Second * 1000 + duration = time.Second * 10 + interval = time.Millisecond * 250 + ) + + Context("Template without permissions to write object", func() { + ns := fmt.Sprintf("test-%d", rand.Int64()) + + key := client2.ObjectKey{Name: "t1", Namespace: ns} + cmKey := client2.ObjectKey{Name: "cm1", Namespace: ns} + + t := buildObjectTemplate(key.Name, key.Namespace, + []*templatesv1alpha1.MatrixEntry{buildMatrixListEntry("m1")}, + []templatesv1alpha1.Template{ + {Object: buildTestConfigMap(cmKey.Name, cmKey.Namespace, map[string]string{ + "k1": `{{ matrix.m1.k1 + matrix.m1.k2 }}`, + })}, + }) + + It("Should fail initially", func() { + createNamespace(ns) + createServiceAccount("default", ns) + + Expect(k8sClient.Create(ctx, t)).Should(Succeed()) + waitUntiReconciled(key, timeout) + + Consistently(func() error { + return k8sClient.Get(ctx, cmKey, &v1.ConfigMap{}) + }, "2s").Should(MatchError("configmaps \"cm1\" not found")) + + assertFailedConfigMaps(key, cmKey) + }) + It("Should succeed when RBAC is added", func() { + createRoleWithBinding("default", ns, []string{"configmaps"}) + + triggerReconcile(key) + waitUntiReconciled(key, timeout) + + assertAppliedConfigMaps(key, cmKey) + + var cm v1.ConfigMap + err := k8sClient.Get(ctx, cmKey, &cm) + Expect(err).To(Succeed()) + + Expect(cm.Data).To(Equal(map[string]string{ + "k1": "3", + })) + }) + It("Should fail with non-existing SA", func() { + updateObjectTemplate(key, func(t *templatesv1alpha1.ObjectTemplate) { + t.Spec.ServiceAccountName = "non-existent" + }) + waitUntiReconciled(key, timeout) + + assertFailedConfigMap(key, cmKey, "configmaps \"cm1\" is forbidden") + }) + It("Should succeed after the SA is being created", func() { + createServiceAccount("non-existent", ns) + createRoleWithBinding("non-existent", ns, []string{"configmaps"}) + triggerReconcile(key) + waitUntiReconciled(key, timeout) + assertAppliedConfigMaps(key, cmKey) + }) + }) + Context("Template without permissions to read matrix object", func() { + ns := fmt.Sprintf("test-%d", rand.Int64()) + + key := client2.ObjectKey{Name: "t1", Namespace: ns} + cmKey := client2.ObjectKey{Name: "cm1", Namespace: ns} + + It("Should fail initially", func() { + createNamespace(ns) + createServiceAccount("default", ns) + createRoleWithBinding("default", ns, []string{"configmaps"}) + + t := buildObjectTemplate(key.Name, key.Namespace, + []*templatesv1alpha1.MatrixEntry{ + buildMatrixObjectEntry("m1", "m1", ns, "Secret", "", false), + }, + []templatesv1alpha1.Template{ + {Object: buildTestConfigMap(cmKey.Name, cmKey.Namespace, map[string]string{ + "k1": `{{ matrix.m1.k1 + matrix.m1.k2 }}`, + })}, + }) + + err := k8sClient.Create(ctx, buildTestSecret("m1", ns, map[string]string{ + "k1": "1", + "k2": "2", + })) + Expect(err).To(Succeed()) + + Expect(k8sClient.Create(ctx, t)).Should(Succeed()) + waitUntiReconciled(key, timeout) + + t2 := getObjectTemplate(key) + c := getReadyCondition(t2.GetConditions()) + Expect(c.Status).To(Equal(metav1.ConditionFalse)) + Expect(c.Message).To(ContainSubstring("secrets \"m1\" is forbidden")) + }) + It("Should succeed when RBAC is created", func() { + createRoleWithBinding("default", ns, []string{"secrets"}) + triggerReconcile(key) + waitUntiReconciled(key, timeout) + assertAppliedConfigMaps(key, cmKey) + }) + It("Should fail with non-existing SA", func() { + updateObjectTemplate(key, func(t *templatesv1alpha1.ObjectTemplate) { + t.Spec.ServiceAccountName = "non-existent" + }) + waitUntiReconciled(key, timeout) + + t2 := getObjectTemplate(key) + c := getReadyCondition(t2.GetConditions()) + Expect(c.Status).To(Equal(metav1.ConditionFalse)) + Expect(c.Message).To(ContainSubstring("secrets \"m1\" is forbidden")) + }) + It("Should succeed after the SA is being created", func() { + createServiceAccount("non-existent", ns) + createRoleWithBinding("non-existent", ns, []string{"configmaps"}) + triggerReconcile(key) + waitUntiReconciled(key, timeout) + assertAppliedConfigMaps(key, cmKey) + }) + }) +}) diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 450ed23..01c2b27 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -17,10 +17,19 @@ limitations under the License. package controllers import ( + "context" + "fmt" + corev1 "k8s.io/api/core/v1" + v12 "k8s.io/api/rbac/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "math/rand/v2" + "os" + "path" "path/filepath" + ctrl "sigs.k8s.io/controller-runtime" "testing" - . "github.com/onsi/ginkgo" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "k8s.io/client-go/kubernetes/scheme" @@ -37,21 +46,28 @@ import ( // These tests use Ginkgo (BDD-style Go testing framework). Refer to // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. -var cfg *rest.Config -var k8sClient client.Client -var testEnv *envtest.Environment +var ( + cfg *rest.Config + k8sClient client.Client // You'll be using this client in your tests. + testEnv *envtest.Environment + ctx context.Context + cancel context.CancelFunc -func TestAPIs(t *testing.T) { + kubeconfigName = "template-controller-tests.kubeconfig" + kubeconfigPath string +) + +func TestControllers(t *testing.T) { RegisterFailHandler(Fail) - RunSpecsWithDefaultAndCustomReporters(t, - "Controller Suite", - []Reporter{}) + RunSpecs(t, "Controller Suite") } var _ = BeforeSuite(func() { logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + ctx, cancel = context.WithCancel(context.TODO()) + By("bootstrapping test environment") testEnv = &envtest.Environment{ CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, @@ -69,14 +85,121 @@ var _ = BeforeSuite(func() { //+kubebuilder:scaffold:scheme + user, err := testEnv.AddUser(envtest.User{Name: "default", Groups: []string{"system:masters"}}, &rest.Config{}) + Expect(err).NotTo(HaveOccurred()) + + kcfg, err := user.KubeConfig() + Expect(err).NotTo(HaveOccurred()) + + kubeconfigPath = path.Join(os.TempDir(), kubeconfigName) + err = os.WriteFile(kubeconfigPath, kcfg, 0600) + Expect(err).To(Succeed()) + + _, _ = fmt.Fprintf(GinkgoWriter, "kubeconfig: %s\n", kubeconfigPath) + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) Expect(err).NotTo(HaveOccurred()) Expect(k8sClient).NotTo(BeNil()) -}, 60) + k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{ + Scheme: scheme.Scheme, + }) + Expect(err).ToNot(HaveOccurred()) + + err = (&ObjectTemplateReconciler{ + BaseTemplateReconciler: BaseTemplateReconciler{ + Client: k8sManager.GetClient(), + Scheme: k8sManager.GetScheme(), + FieldManager: "template-controller", + }, + }).SetupWithManager(k8sManager, 1) + Expect(err).ToNot(HaveOccurred()) + + go func() { + defer GinkgoRecover() + err = k8sManager.Start(ctx) + Expect(err).ToNot(HaveOccurred(), "failed to run manager") + }() + +}) var _ = AfterSuite(func() { + cancel() By("tearing down the test environment") err := testEnv.Stop() Expect(err).NotTo(HaveOccurred()) + + if kubeconfigPath != "" { + _ = os.Remove(kubeconfigPath) + } }) + +func createNamespace(name string) { + ns := corev1.Namespace{ + ObjectMeta: v1.ObjectMeta{ + Name: name, + }, + } + err := k8sClient.Create(ctx, &ns) + Expect(err).To(Succeed()) +} + +func createServiceAccount(saName string, saNamespace string) { + sa := corev1.ServiceAccount{ + ObjectMeta: v1.ObjectMeta{ + Name: saName, + Namespace: saNamespace, + }, + } + err := k8sClient.Create(ctx, &sa) + Expect(err).To(Succeed()) +} + +func createRoleWithBinding(saName string, saNamespace string, resources []string) { + roleName := fmt.Sprintf("role-%s-%d", saName, rand.Int64()) + + role := v12.Role{ + ObjectMeta: v1.ObjectMeta{ + Name: roleName, + Namespace: saNamespace, + }, + Rules: []v12.PolicyRule{ + { + Verbs: []string{"*"}, + APIGroups: []string{"", "*"}, + Resources: resources, + }, + }, + } + roleBinding := v12.RoleBinding{ + ObjectMeta: v1.ObjectMeta{ + Name: roleName, + Namespace: saNamespace, + }, + Subjects: []v12.Subject{ + { + Kind: "ServiceAccount", + Name: saName, + Namespace: saNamespace, + }, + }, + RoleRef: v12.RoleRef{ + Kind: "Role", + Name: roleName, + }, + } + + err := k8sClient.Create(ctx, &role) + Expect(err).To(Succeed()) + err = k8sClient.Create(ctx, &roleBinding) + Expect(err).To(Succeed()) +} + +func getReadyCondition(conditions []v1.Condition) *v1.Condition { + for _, c := range conditions { + if c.Type == "Ready" { + return &c + } + } + return nil +} From 3b4f38d9a7b07e4e6bac64e45e89d8e88aece94d Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Mon, 8 Jul 2024 22:09:32 +0200 Subject: [PATCH 03/12] ci: Add tests workflow --- .github/workflows/tests.yml | 91 +++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..35736ab --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,91 @@ +name: tests + +on: + push: + branches: + - main + - release-v* + pull_request: + branches: + - main + +jobs: + generate-checks: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-go@v5 + with: + go-version: '1.22' + - uses: actions/cache@v4 + with: + path: | + ~/go/pkg/mod + ~/.cache/go-build + key: generate-check-go-${{ runner.os }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + generate-check-go-${{ runner.os }}- + - name: Verify generated source is up-to-date + run: | + make generate + if [ ! -z "$(git status --porcelain)" ]; then + echo "make generate must be invoked and the result committed" + git status + git diff + exit 1 + fi + - name: Verify generated manifests are up-to-date + run: | + make manifests + if [ ! -z "$(git status --porcelain)" ]; then + echo "make manifests must be invoked and the result committed" + git status + git diff + exit 1 + fi + - name: Verify generated api-docs are up-to-date + run: | + make api-docs + if [ ! -z "$(git status --porcelain)" ]; then + echo "make api-docs must be invoked and the result committed" + git status + git diff + exit 1 + fi + - name: Verify go.mod and go.sum are clean + run: | + go mod tidy + if [ ! -z "$(git status --porcelain)" ]; then + echo "go mod tidy must be invoked and the result committed" + git status + git diff + exit 1 + fi + + tests: + runs-on: ubuntu-22.04 + name: tests + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version: '1.22' + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - uses: actions/cache@v4 + with: + path: | + ~/go/pkg/mod + ~/.cache/go-build + key: tests-go-${{ runner.os }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + tests-go-${{ runner.os }}- + - name: Run tests + shell: bash + run: | + make test From e82793c6126831764e77d270c6dd52a6af71fb26 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Mon, 8 Jul 2024 22:14:03 +0200 Subject: [PATCH 04/12] chore: Run make manifests --- config/crd/bases/templates.kluctl.io_githubcomments.yaml | 2 +- config/crd/bases/templates.kluctl.io_gitlabcomments.yaml | 2 +- config/crd/bases/templates.kluctl.io_gitprojectors.yaml | 2 +- .../crd/bases/templates.kluctl.io_listgithubpullrequests.yaml | 2 +- .../crd/bases/templates.kluctl.io_listgitlabmergerequests.yaml | 2 +- config/crd/bases/templates.kluctl.io_objecttemplates.yaml | 2 +- config/crd/bases/templates.kluctl.io_texttemplates.yaml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/config/crd/bases/templates.kluctl.io_githubcomments.yaml b/config/crd/bases/templates.kluctl.io_githubcomments.yaml index 63f3bec..2b15523 100644 --- a/config/crd/bases/templates.kluctl.io_githubcomments.yaml +++ b/config/crd/bases/templates.kluctl.io_githubcomments.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.15.0 name: githubcomments.templates.kluctl.io spec: group: templates.kluctl.io diff --git a/config/crd/bases/templates.kluctl.io_gitlabcomments.yaml b/config/crd/bases/templates.kluctl.io_gitlabcomments.yaml index a949152..2f77822 100644 --- a/config/crd/bases/templates.kluctl.io_gitlabcomments.yaml +++ b/config/crd/bases/templates.kluctl.io_gitlabcomments.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.15.0 name: gitlabcomments.templates.kluctl.io spec: group: templates.kluctl.io diff --git a/config/crd/bases/templates.kluctl.io_gitprojectors.yaml b/config/crd/bases/templates.kluctl.io_gitprojectors.yaml index 326c81b..6e60993 100644 --- a/config/crd/bases/templates.kluctl.io_gitprojectors.yaml +++ b/config/crd/bases/templates.kluctl.io_gitprojectors.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.15.0 name: gitprojectors.templates.kluctl.io spec: group: templates.kluctl.io diff --git a/config/crd/bases/templates.kluctl.io_listgithubpullrequests.yaml b/config/crd/bases/templates.kluctl.io_listgithubpullrequests.yaml index cb44c48..4702ff1 100644 --- a/config/crd/bases/templates.kluctl.io_listgithubpullrequests.yaml +++ b/config/crd/bases/templates.kluctl.io_listgithubpullrequests.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.15.0 name: listgithubpullrequests.templates.kluctl.io spec: group: templates.kluctl.io diff --git a/config/crd/bases/templates.kluctl.io_listgitlabmergerequests.yaml b/config/crd/bases/templates.kluctl.io_listgitlabmergerequests.yaml index 2f0e151..26f49d4 100644 --- a/config/crd/bases/templates.kluctl.io_listgitlabmergerequests.yaml +++ b/config/crd/bases/templates.kluctl.io_listgitlabmergerequests.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.15.0 name: listgitlabmergerequests.templates.kluctl.io spec: group: templates.kluctl.io diff --git a/config/crd/bases/templates.kluctl.io_objecttemplates.yaml b/config/crd/bases/templates.kluctl.io_objecttemplates.yaml index f62c90b..8163bde 100644 --- a/config/crd/bases/templates.kluctl.io_objecttemplates.yaml +++ b/config/crd/bases/templates.kluctl.io_objecttemplates.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.15.0 name: objecttemplates.templates.kluctl.io spec: group: templates.kluctl.io diff --git a/config/crd/bases/templates.kluctl.io_texttemplates.yaml b/config/crd/bases/templates.kluctl.io_texttemplates.yaml index 67ed7c4..104bf83 100644 --- a/config/crd/bases/templates.kluctl.io_texttemplates.yaml +++ b/config/crd/bases/templates.kluctl.io_texttemplates.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.14.0 + controller-gen.kubebuilder.io/version: v0.15.0 name: texttemplates.templates.kluctl.io spec: group: templates.kluctl.io From 49451cd7d4fd96f072c27b7433aecdabe5623d90 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Mon, 8 Jul 2024 22:15:09 +0200 Subject: [PATCH 05/12] ci: Use verbose mode when running tests --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index eaba057..e2cd290 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ vet: ## Run go vet against code. .PHONY: test test: manifests generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out --ginkgo.v ##@ Build From cee3c2c0f67f12f44fcf2f67ea9559b09fc6586b Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Mon, 8 Jul 2024 23:57:40 +0200 Subject: [PATCH 06/12] fix: Stop using pointers as list elements when not really necessary --- api/v1alpha1/objecttemplate_types.go | 2 +- api/v1alpha1/texttemplate_types.go | 2 +- api/v1alpha1/zz_generated.deepcopy.go | 16 ++++--------- controllers/objecttemplate_controller_test.go | 14 +++++------ docs/api/template-controller.md | 24 ++++++++++++------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/api/v1alpha1/objecttemplate_types.go b/api/v1alpha1/objecttemplate_types.go index adaa87e..f4e7e53 100644 --- a/api/v1alpha1/objecttemplate_types.go +++ b/api/v1alpha1/objecttemplate_types.go @@ -50,7 +50,7 @@ type ObjectTemplateSpec struct { // Matrix specifies the input matrix // +required - Matrix []*MatrixEntry `json:"matrix"` + Matrix []MatrixEntry `json:"matrix"` // Templates specifies a list of templates to render and deploy // +required diff --git a/api/v1alpha1/texttemplate_types.go b/api/v1alpha1/texttemplate_types.go index 6c980ce..988eade 100644 --- a/api/v1alpha1/texttemplate_types.go +++ b/api/v1alpha1/texttemplate_types.go @@ -33,7 +33,7 @@ type TextTemplateSpec struct { ServiceAccountName string `json:"serviceAccountName,omitempty"` // +optional - Inputs []*TextTemplateInput `json:"inputs,omitempty"` + Inputs []TextTemplateInput `json:"inputs,omitempty"` // +optional Template *string `json:"template,omitempty"` diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 1b2ab65..d852af4 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -987,13 +987,9 @@ func (in *ObjectTemplateSpec) DeepCopyInto(out *ObjectTemplateSpec) { out.Interval = in.Interval if in.Matrix != nil { in, out := &in.Matrix, &out.Matrix - *out = make([]*MatrixEntry, len(*in)) + *out = make([]MatrixEntry, len(*in)) for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(MatrixEntry) - (*in).DeepCopyInto(*out) - } + (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.Templates != nil { @@ -1221,13 +1217,9 @@ func (in *TextTemplateSpec) DeepCopyInto(out *TextTemplateSpec) { *out = *in if in.Inputs != nil { in, out := &in.Inputs, &out.Inputs - *out = make([]*TextTemplateInput, len(*in)) + *out = make([]TextTemplateInput, len(*in)) for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(TextTemplateInput) - (*in).DeepCopyInto(*out) - } + (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.Template != nil { diff --git a/controllers/objecttemplate_controller_test.go b/controllers/objecttemplate_controller_test.go index c155b75..0610d31 100644 --- a/controllers/objecttemplate_controller_test.go +++ b/controllers/objecttemplate_controller_test.go @@ -67,7 +67,7 @@ func buildTestSecret(name string, namespace string, data map[string]string) *uns } } -func buildObjectTemplate(name string, namespace string, matrixEntries []*templatesv1alpha1.MatrixEntry, templates []templatesv1alpha1.Template) *templatesv1alpha1.ObjectTemplate { +func buildObjectTemplate(name string, namespace string, matrixEntries []templatesv1alpha1.MatrixEntry, templates []templatesv1alpha1.Template) *templatesv1alpha1.ObjectTemplate { t := &templatesv1alpha1.ObjectTemplate{ TypeMeta: metav1.TypeMeta{ APIVersion: templatesv1alpha1.GroupVersion.String(), @@ -86,8 +86,8 @@ func buildObjectTemplate(name string, namespace string, matrixEntries []*templat return t } -func buildMatrixListEntry(name string) *templatesv1alpha1.MatrixEntry { - return &templatesv1alpha1.MatrixEntry{ +func buildMatrixListEntry(name string) templatesv1alpha1.MatrixEntry { + return templatesv1alpha1.MatrixEntry{ Name: name, List: []runtime.RawExtension{ { @@ -97,12 +97,12 @@ func buildMatrixListEntry(name string) *templatesv1alpha1.MatrixEntry { } } -func buildMatrixObjectEntry(name string, objName string, objNamespace string, objKind string, jsonPath string, expandLists bool) *templatesv1alpha1.MatrixEntry { +func buildMatrixObjectEntry(name string, objName string, objNamespace string, objKind string, jsonPath string, expandLists bool) templatesv1alpha1.MatrixEntry { var jsonPathPtr *string if jsonPath != "" { jsonPathPtr = &jsonPath } - return &templatesv1alpha1.MatrixEntry{ + return templatesv1alpha1.MatrixEntry{ Name: name, Object: &templatesv1alpha1.MatrixEntryObject{ Ref: templatesv1alpha1.ObjectRef{ @@ -207,7 +207,7 @@ var _ = Describe("ObjectTemplate controller", func() { cmKey := client2.ObjectKey{Name: "cm1", Namespace: ns} t := buildObjectTemplate(key.Name, key.Namespace, - []*templatesv1alpha1.MatrixEntry{buildMatrixListEntry("m1")}, + []templatesv1alpha1.MatrixEntry{buildMatrixListEntry("m1")}, []templatesv1alpha1.Template{ {Object: buildTestConfigMap(cmKey.Name, cmKey.Namespace, map[string]string{ "k1": `{{ matrix.m1.k1 + matrix.m1.k2 }}`, @@ -271,7 +271,7 @@ var _ = Describe("ObjectTemplate controller", func() { createRoleWithBinding("default", ns, []string{"configmaps"}) t := buildObjectTemplate(key.Name, key.Namespace, - []*templatesv1alpha1.MatrixEntry{ + []templatesv1alpha1.MatrixEntry{ buildMatrixObjectEntry("m1", "m1", ns, "Secret", "", false), }, []templatesv1alpha1.Template{ diff --git a/docs/api/template-controller.md b/docs/api/template-controller.md index ecd4a02..d3937e3 100644 --- a/docs/api/template-controller.md +++ b/docs/api/template-controller.md @@ -1971,6 +1971,10 @@ string

MatrixEntry

+

+(Appears on: +ObjectTemplateSpec) +

@@ -2242,8 +2246,8 @@ bool @@ -2353,8 +2357,8 @@ bool @@ -2669,8 +2673,8 @@ when reconciling this TextTemplate. If omitted, the “default” servic @@ -2723,6 +2727,10 @@ TextTemplateStatus

TextTemplateInput

+

+(Appears on: +TextTemplateSpec) +

matrix
- -[]*github.com/kluctl/template-controller/api/v1alpha1.MatrixEntry + +[]MatrixEntry
matrix
- -[]*github.com/kluctl/template-controller/api/v1alpha1.MatrixEntry + +[]MatrixEntry
inputs
- -[]*github.com/kluctl/template-controller/api/v1alpha1.TextTemplateInput + +[]TextTemplateInput
@@ -2849,8 +2857,8 @@ when reconciling this TextTemplate. If omitted, the “default” servic From 44660af8e24d225c5c56b0e1281f8acf2cfcd2c3 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 9 Jul 2024 00:40:42 +0200 Subject: [PATCH 07/12] chore: Run go mod tidy --- go.mod | 8 ++++---- go.sum | 49 ------------------------------------------------- 2 files changed, 4 insertions(+), 53 deletions(-) diff --git a/go.mod b/go.mod index 6122f27..950f373 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/kluctl/go-jinja2 v0.0.0-20240619083358-c137395943eb github.com/kluctl/kluctl/lib v0.0.0-20240708111940-7d9465ba9662 github.com/ohler55/ojg v1.22.1 - github.com/onsi/ginkgo v1.16.5 + github.com/onsi/ginkgo/v2 v2.19.0 github.com/onsi/gomega v1.33.1 github.com/xanzy/go-gitlab v0.106.0 golang.org/x/oauth2 v0.21.0 @@ -50,6 +50,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.22.0 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -57,6 +58,7 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -76,8 +78,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/nxadm/tail v1.4.11 // indirect - github.com/onsi/ginkgo/v2 v2.19.0 // indirect github.com/otiai10/copy v1.14.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -102,10 +102,10 @@ require ( golang.org/x/term v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.22.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect diff --git a/go.sum b/go.sum index c93e64a..1fcb119 100644 --- a/go.sum +++ b/go.sum @@ -39,9 +39,6 @@ github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0 github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I= @@ -76,8 +73,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= @@ -86,20 +81,10 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -126,7 +111,6 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= @@ -173,20 +157,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= -github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/ohler55/ojg v1.22.1 h1:MvUieaWTwksoYk47GYyP9kzXIAkxHYX6rxeLjUEeq/8= github.com/ohler55/ojg v1.22.1/go.mod h1:gQhDVpQLqrmnd2eqGAvJtn+NfKoYJbe/A4Sj3/Vro4o= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= @@ -225,7 +199,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= @@ -257,11 +230,9 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -273,7 +244,6 @@ golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -281,24 +251,17 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -326,7 +289,6 @@ golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= @@ -338,29 +300,18 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From dd4085af85aadf4a14ff49d817305881287adde8 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 9 Jul 2024 10:06:00 +0200 Subject: [PATCH 08/12] ci: Use go-version-file instead of go-version --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 35736ab..aeb1d21 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,7 +19,7 @@ jobs: fetch-depth: 0 - uses: actions/setup-go@v5 with: - go-version: '1.22' + go-version-file: go.mod - uses: actions/cache@v4 with: path: | @@ -73,7 +73,7 @@ jobs: uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: '1.22' + go-version-file: go.mod - uses: actions/setup-python@v5 with: python-version: '3.11' From 9c62dfb0a284267b94ff48037b1b3393b7f49aa7 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 9 Jul 2024 10:07:03 +0200 Subject: [PATCH 09/12] tests: Use typed objects when possible --- controllers/objecttemplate_controller_test.go | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/controllers/objecttemplate_controller_test.go b/controllers/objecttemplate_controller_test.go index 0610d31..0367cf6 100644 --- a/controllers/objecttemplate_controller_test.go +++ b/controllers/objecttemplate_controller_test.go @@ -31,40 +31,40 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func buildTestConfigMap(name string, namespace string, data map[string]string) *unstructured.Unstructured { - m := map[string]any{} - for k, v := range data { - m[k] = v - } +func toUnstructured(o client.Object) *unstructured.Unstructured { + m, err := runtime.DefaultUnstructuredConverter.ToUnstructured(o) + Expect(err).To(Succeed()) return &unstructured.Unstructured{ - Object: map[string]any{ - "apiVersion": "v1", - "kind": "ConfigMap", - "metadata": map[string]any{ - "name": name, - "namespace": namespace, - }, - "data": m, - }, + Object: m, } } +func buildTestConfigMap(name string, namespace string, data map[string]string) *unstructured.Unstructured { + return toUnstructured(&v1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "ConfigMap", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Data: data, + }) +} + func buildTestSecret(name string, namespace string, data map[string]string) *unstructured.Unstructured { - m := map[string]any{} - for k, v := range data { - m[k] = v - } - return &unstructured.Unstructured{ - Object: map[string]any{ - "apiVersion": "v1", - "kind": "Secret", - "metadata": map[string]any{ - "name": name, - "namespace": namespace, - }, - "stringData": m, + return toUnstructured(&v1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", }, - } + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + StringData: data, + }) } func buildObjectTemplate(name string, namespace string, matrixEntries []templatesv1alpha1.MatrixEntry, templates []templatesv1alpha1.Template) *templatesv1alpha1.ObjectTemplate { From 31c2568ef2485faab6106773fcb521ea1947a39e Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 9 Jul 2024 10:07:18 +0200 Subject: [PATCH 10/12] tests: Don't use client2 alias --- controllers/objecttemplate_controller_test.go | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/controllers/objecttemplate_controller_test.go b/controllers/objecttemplate_controller_test.go index 0367cf6..a9998f8 100644 --- a/controllers/objecttemplate_controller_test.go +++ b/controllers/objecttemplate_controller_test.go @@ -22,7 +22,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "math/rand/v2" - client2 "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client" "time" templatesv1alpha1 "github.com/kluctl/template-controller/api/v1alpha1" @@ -117,20 +117,20 @@ func buildMatrixObjectEntry(name string, objName string, objNamespace string, ob } } -func updateObjectTemplate(key client2.ObjectKey, fn func(t *templatesv1alpha1.ObjectTemplate)) { +func updateObjectTemplate(key client.ObjectKey, fn func(t *templatesv1alpha1.ObjectTemplate)) { t := getObjectTemplate(key) fn(t) - err := k8sClient.Update(ctx, t, client2.FieldOwner("tests")) + err := k8sClient.Update(ctx, t, client.FieldOwner("tests")) Expect(err).To(Succeed()) } -func triggerReconcile(key client2.ObjectKey) { +func triggerReconcile(key client.ObjectKey) { updateObjectTemplate(key, func(t *templatesv1alpha1.ObjectTemplate) { t.Spec.Interval.Duration += time.Millisecond }) } -func waitUntiReconciled(key client2.ObjectKey, timeout time.Duration) { +func waitUntiReconciled(key client.ObjectKey, timeout time.Duration) { Eventually(func() bool { t := getObjectTemplate(key) if t == nil { @@ -144,7 +144,7 @@ func waitUntiReconciled(key client2.ObjectKey, timeout time.Duration) { }, timeout, time.Millisecond*250).Should(BeTrue()) } -func getObjectTemplate(key client2.ObjectKey) *templatesv1alpha1.ObjectTemplate { +func getObjectTemplate(key client.ObjectKey) *templatesv1alpha1.ObjectTemplate { var t templatesv1alpha1.ObjectTemplate err := k8sClient.Get(ctx, key, &t) if err != nil { @@ -153,35 +153,35 @@ func getObjectTemplate(key client2.ObjectKey) *templatesv1alpha1.ObjectTemplate return &t } -func assertAppliedConfigMaps(key client2.ObjectKey, keys ...client2.ObjectKey) { +func assertAppliedConfigMaps(key client.ObjectKey, keys ...client.ObjectKey) { t := getObjectTemplate(key) Expect(t).ToNot(BeNil()) - var found []client2.ObjectKey + var found []client.ObjectKey for _, as := range t.Status.AppliedResources { if as.Success { - found = append(found, client2.ObjectKey{Name: as.Ref.Name, Namespace: as.Ref.Namespace}) + found = append(found, client.ObjectKey{Name: as.Ref.Name, Namespace: as.Ref.Namespace}) } } Expect(found).To(ConsistOf(keys)) } -func assertFailedConfigMaps(key client2.ObjectKey, keys ...client2.ObjectKey) { +func assertFailedConfigMaps(key client.ObjectKey, keys ...client.ObjectKey) { t := getObjectTemplate(key) Expect(t).ToNot(BeNil()) - var found []client2.ObjectKey + var found []client.ObjectKey for _, as := range t.Status.AppliedResources { if !as.Success { - found = append(found, client2.ObjectKey{Name: as.Ref.Name, Namespace: as.Ref.Namespace}) + found = append(found, client.ObjectKey{Name: as.Ref.Name, Namespace: as.Ref.Namespace}) } } Expect(found).To(ConsistOf(keys)) } -func assertFailedConfigMap(key client2.ObjectKey, cmKey client2.ObjectKey, errStr string) { +func assertFailedConfigMap(key client.ObjectKey, cmKey client.ObjectKey, errStr string) { t := getObjectTemplate(key) Expect(t).ToNot(BeNil()) for _, as := range t.Status.AppliedResources { @@ -203,8 +203,8 @@ var _ = Describe("ObjectTemplate controller", func() { Context("Template without permissions to write object", func() { ns := fmt.Sprintf("test-%d", rand.Int64()) - key := client2.ObjectKey{Name: "t1", Namespace: ns} - cmKey := client2.ObjectKey{Name: "cm1", Namespace: ns} + key := client.ObjectKey{Name: "t1", Namespace: ns} + cmKey := client.ObjectKey{Name: "cm1", Namespace: ns} t := buildObjectTemplate(key.Name, key.Namespace, []templatesv1alpha1.MatrixEntry{buildMatrixListEntry("m1")}, @@ -262,8 +262,8 @@ var _ = Describe("ObjectTemplate controller", func() { Context("Template without permissions to read matrix object", func() { ns := fmt.Sprintf("test-%d", rand.Int64()) - key := client2.ObjectKey{Name: "t1", Namespace: ns} - cmKey := client2.ObjectKey{Name: "cm1", Namespace: ns} + key := client.ObjectKey{Name: "t1", Namespace: ns} + cmKey := client.ObjectKey{Name: "cm1", Namespace: ns} It("Should fail initially", func() { createNamespace(ns) From fa92d68c7c78496761b2e10b33997c7340342976 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 9 Jul 2024 10:07:25 +0200 Subject: [PATCH 11/12] tests: Remove temporary kubeconfig --- controllers/suite_test.go | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 01c2b27..fee7660 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -23,8 +23,6 @@ import ( v12 "k8s.io/api/rbac/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "math/rand/v2" - "os" - "path" "path/filepath" ctrl "sigs.k8s.io/controller-runtime" "testing" @@ -52,9 +50,6 @@ var ( testEnv *envtest.Environment ctx context.Context cancel context.CancelFunc - - kubeconfigName = "template-controller-tests.kubeconfig" - kubeconfigPath string ) func TestControllers(t *testing.T) { @@ -85,18 +80,6 @@ var _ = BeforeSuite(func() { //+kubebuilder:scaffold:scheme - user, err := testEnv.AddUser(envtest.User{Name: "default", Groups: []string{"system:masters"}}, &rest.Config{}) - Expect(err).NotTo(HaveOccurred()) - - kcfg, err := user.KubeConfig() - Expect(err).NotTo(HaveOccurred()) - - kubeconfigPath = path.Join(os.TempDir(), kubeconfigName) - err = os.WriteFile(kubeconfigPath, kcfg, 0600) - Expect(err).To(Succeed()) - - _, _ = fmt.Fprintf(GinkgoWriter, "kubeconfig: %s\n", kubeconfigPath) - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) Expect(err).NotTo(HaveOccurred()) Expect(k8sClient).NotTo(BeNil()) @@ -128,10 +111,6 @@ var _ = AfterSuite(func() { By("tearing down the test environment") err := testEnv.Stop() Expect(err).NotTo(HaveOccurred()) - - if kubeconfigPath != "" { - _ = os.Remove(kubeconfigPath) - } }) func createNamespace(name string) { From f0f5e34509b3f6ac412f9c2ff47d6313f4d0fbed Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 9 Jul 2024 10:09:37 +0200 Subject: [PATCH 12/12] tests: Move utility functions into own source file --- controllers/objecttemplate_controller_test.go | 164 ---------------- controllers/utils_test.go | 175 ++++++++++++++++++ 2 files changed, 175 insertions(+), 164 deletions(-) create mode 100644 controllers/utils_test.go diff --git a/controllers/objecttemplate_controller_test.go b/controllers/objecttemplate_controller_test.go index a9998f8..07bd82b 100644 --- a/controllers/objecttemplate_controller_test.go +++ b/controllers/objecttemplate_controller_test.go @@ -19,8 +19,6 @@ package controllers import ( "fmt" v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" "math/rand/v2" "sigs.k8s.io/controller-runtime/pkg/client" "time" @@ -31,168 +29,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func toUnstructured(o client.Object) *unstructured.Unstructured { - m, err := runtime.DefaultUnstructuredConverter.ToUnstructured(o) - Expect(err).To(Succeed()) - return &unstructured.Unstructured{ - Object: m, - } -} - -func buildTestConfigMap(name string, namespace string, data map[string]string) *unstructured.Unstructured { - return toUnstructured(&v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ConfigMap", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Data: data, - }) -} - -func buildTestSecret(name string, namespace string, data map[string]string) *unstructured.Unstructured { - return toUnstructured(&v1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - StringData: data, - }) -} - -func buildObjectTemplate(name string, namespace string, matrixEntries []templatesv1alpha1.MatrixEntry, templates []templatesv1alpha1.Template) *templatesv1alpha1.ObjectTemplate { - t := &templatesv1alpha1.ObjectTemplate{ - TypeMeta: metav1.TypeMeta{ - APIVersion: templatesv1alpha1.GroupVersion.String(), - Kind: "ObjectTemplate", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: templatesv1alpha1.ObjectTemplateSpec{ - Interval: metav1.Duration{Duration: time.Second}, - Matrix: matrixEntries, - Templates: templates, - }, - } - return t -} - -func buildMatrixListEntry(name string) templatesv1alpha1.MatrixEntry { - return templatesv1alpha1.MatrixEntry{ - Name: name, - List: []runtime.RawExtension{ - { - Raw: []byte(`{"k1": 1, "k2": 2}`), - }, - }, - } -} - -func buildMatrixObjectEntry(name string, objName string, objNamespace string, objKind string, jsonPath string, expandLists bool) templatesv1alpha1.MatrixEntry { - var jsonPathPtr *string - if jsonPath != "" { - jsonPathPtr = &jsonPath - } - return templatesv1alpha1.MatrixEntry{ - Name: name, - Object: &templatesv1alpha1.MatrixEntryObject{ - Ref: templatesv1alpha1.ObjectRef{ - APIVersion: "v1", - Kind: objKind, - Name: objName, - Namespace: objNamespace, - }, - JsonPath: jsonPathPtr, - ExpandLists: expandLists, - }, - } -} - -func updateObjectTemplate(key client.ObjectKey, fn func(t *templatesv1alpha1.ObjectTemplate)) { - t := getObjectTemplate(key) - fn(t) - err := k8sClient.Update(ctx, t, client.FieldOwner("tests")) - Expect(err).To(Succeed()) -} - -func triggerReconcile(key client.ObjectKey) { - updateObjectTemplate(key, func(t *templatesv1alpha1.ObjectTemplate) { - t.Spec.Interval.Duration += time.Millisecond - }) -} - -func waitUntiReconciled(key client.ObjectKey, timeout time.Duration) { - Eventually(func() bool { - t := getObjectTemplate(key) - if t == nil { - return false - } - c := getReadyCondition(t.GetConditions()) - if c == nil { - return false - } - return c.ObservedGeneration == t.Generation - }, timeout, time.Millisecond*250).Should(BeTrue()) -} - -func getObjectTemplate(key client.ObjectKey) *templatesv1alpha1.ObjectTemplate { - var t templatesv1alpha1.ObjectTemplate - err := k8sClient.Get(ctx, key, &t) - if err != nil { - return nil - } - return &t -} - -func assertAppliedConfigMaps(key client.ObjectKey, keys ...client.ObjectKey) { - t := getObjectTemplate(key) - Expect(t).ToNot(BeNil()) - - var found []client.ObjectKey - for _, as := range t.Status.AppliedResources { - if as.Success { - found = append(found, client.ObjectKey{Name: as.Ref.Name, Namespace: as.Ref.Namespace}) - } - } - - Expect(found).To(ConsistOf(keys)) -} - -func assertFailedConfigMaps(key client.ObjectKey, keys ...client.ObjectKey) { - t := getObjectTemplate(key) - Expect(t).ToNot(BeNil()) - - var found []client.ObjectKey - for _, as := range t.Status.AppliedResources { - if !as.Success { - found = append(found, client.ObjectKey{Name: as.Ref.Name, Namespace: as.Ref.Namespace}) - } - } - - Expect(found).To(ConsistOf(keys)) -} - -func assertFailedConfigMap(key client.ObjectKey, cmKey client.ObjectKey, errStr string) { - t := getObjectTemplate(key) - Expect(t).ToNot(BeNil()) - for _, as := range t.Status.AppliedResources { - if !as.Success && as.Ref.Name == cmKey.Name && as.Ref.Namespace == cmKey.Namespace { - Expect(as.Error).To(ContainSubstring(errStr)) - return - } - } - Expect(false).To(BeTrue()) -} - var _ = Describe("ObjectTemplate controller", func() { const ( timeout = time.Second * 1000 diff --git a/controllers/utils_test.go b/controllers/utils_test.go new file mode 100644 index 0000000..0a12ba7 --- /dev/null +++ b/controllers/utils_test.go @@ -0,0 +1,175 @@ +package controllers + +import ( + templatesv1alpha1 "github.com/kluctl/template-controller/api/v1alpha1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "time" + + . "github.com/onsi/gomega" +) + +func toUnstructured(o client.Object) *unstructured.Unstructured { + m, err := runtime.DefaultUnstructuredConverter.ToUnstructured(o) + Expect(err).To(Succeed()) + return &unstructured.Unstructured{ + Object: m, + } +} + +func buildTestConfigMap(name string, namespace string, data map[string]string) *unstructured.Unstructured { + return toUnstructured(&v1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "ConfigMap", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Data: data, + }) +} + +func buildTestSecret(name string, namespace string, data map[string]string) *unstructured.Unstructured { + return toUnstructured(&v1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + StringData: data, + }) +} + +func buildObjectTemplate(name string, namespace string, matrixEntries []templatesv1alpha1.MatrixEntry, templates []templatesv1alpha1.Template) *templatesv1alpha1.ObjectTemplate { + t := &templatesv1alpha1.ObjectTemplate{ + TypeMeta: metav1.TypeMeta{ + APIVersion: templatesv1alpha1.GroupVersion.String(), + Kind: "ObjectTemplate", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: templatesv1alpha1.ObjectTemplateSpec{ + Interval: metav1.Duration{Duration: time.Second}, + Matrix: matrixEntries, + Templates: templates, + }, + } + return t +} + +func buildMatrixListEntry(name string) templatesv1alpha1.MatrixEntry { + return templatesv1alpha1.MatrixEntry{ + Name: name, + List: []runtime.RawExtension{ + { + Raw: []byte(`{"k1": 1, "k2": 2}`), + }, + }, + } +} + +func buildMatrixObjectEntry(name string, objName string, objNamespace string, objKind string, jsonPath string, expandLists bool) templatesv1alpha1.MatrixEntry { + var jsonPathPtr *string + if jsonPath != "" { + jsonPathPtr = &jsonPath + } + return templatesv1alpha1.MatrixEntry{ + Name: name, + Object: &templatesv1alpha1.MatrixEntryObject{ + Ref: templatesv1alpha1.ObjectRef{ + APIVersion: "v1", + Kind: objKind, + Name: objName, + Namespace: objNamespace, + }, + JsonPath: jsonPathPtr, + ExpandLists: expandLists, + }, + } +} + +func updateObjectTemplate(key client.ObjectKey, fn func(t *templatesv1alpha1.ObjectTemplate)) { + t := getObjectTemplate(key) + fn(t) + err := k8sClient.Update(ctx, t, client.FieldOwner("tests")) + Expect(err).To(Succeed()) +} + +func triggerReconcile(key client.ObjectKey) { + updateObjectTemplate(key, func(t *templatesv1alpha1.ObjectTemplate) { + t.Spec.Interval.Duration += time.Millisecond + }) +} + +func waitUntiReconciled(key client.ObjectKey, timeout time.Duration) { + Eventually(func() bool { + t := getObjectTemplate(key) + if t == nil { + return false + } + c := getReadyCondition(t.GetConditions()) + if c == nil { + return false + } + return c.ObservedGeneration == t.Generation + }, timeout, time.Millisecond*250).Should(BeTrue()) +} + +func getObjectTemplate(key client.ObjectKey) *templatesv1alpha1.ObjectTemplate { + var t templatesv1alpha1.ObjectTemplate + err := k8sClient.Get(ctx, key, &t) + if err != nil { + return nil + } + return &t +} + +func assertAppliedConfigMaps(key client.ObjectKey, keys ...client.ObjectKey) { + t := getObjectTemplate(key) + Expect(t).ToNot(BeNil()) + + var found []client.ObjectKey + for _, as := range t.Status.AppliedResources { + if as.Success { + found = append(found, client.ObjectKey{Name: as.Ref.Name, Namespace: as.Ref.Namespace}) + } + } + + Expect(found).To(ConsistOf(keys)) +} + +func assertFailedConfigMaps(key client.ObjectKey, keys ...client.ObjectKey) { + t := getObjectTemplate(key) + Expect(t).ToNot(BeNil()) + + var found []client.ObjectKey + for _, as := range t.Status.AppliedResources { + if !as.Success { + found = append(found, client.ObjectKey{Name: as.Ref.Name, Namespace: as.Ref.Namespace}) + } + } + + Expect(found).To(ConsistOf(keys)) +} + +func assertFailedConfigMap(key client.ObjectKey, cmKey client.ObjectKey, errStr string) { + t := getObjectTemplate(key) + Expect(t).ToNot(BeNil()) + for _, as := range t.Status.AppliedResources { + if !as.Success && as.Ref.Name == cmKey.Name && as.Ref.Namespace == cmKey.Namespace { + Expect(as.Error).To(ContainSubstring(errStr)) + return + } + } + Expect(false).To(BeTrue()) +}
inputs
- -[]*github.com/kluctl/template-controller/api/v1alpha1.TextTemplateInput + +[]TextTemplateInput