From b93e068dff267d508dabdf699603e8461248cd1c Mon Sep 17 00:00:00 2001 From: Martin Schuppert Date: Thu, 5 Oct 2023 18:30:09 +0200 Subject: [PATCH] [TLS] basic CA/ca-bundle create envtest --- .github/workflows/golangci-lint.yaml | 55 --- .github/workflows/lints.yaml | 14 + Makefile | 16 +- controllers/client/suite_test.go | 77 ---- .../core/openstackcontrolplane_controller.go | 3 + controllers/core/suite_test.go | 85 ----- go.mod | 9 +- go.sum | 13 +- tests/functional/base_test.go | 235 ++++++++++++ .../openstackclient_webhook_test.go | 71 ++++ .../openstackoperator_controller_test.go | 130 +++++++ tests/functional/suite_test.go | 350 ++++++++++++++++++ 12 files changed, 830 insertions(+), 228 deletions(-) delete mode 100644 .github/workflows/golangci-lint.yaml create mode 100644 .github/workflows/lints.yaml delete mode 100644 controllers/client/suite_test.go delete mode 100644 controllers/core/suite_test.go create mode 100644 tests/functional/base_test.go create mode 100644 tests/functional/openstackclient_webhook_test.go create mode 100644 tests/functional/openstackoperator_controller_test.go create mode 100644 tests/functional/suite_test.go diff --git a/.github/workflows/golangci-lint.yaml b/.github/workflows/golangci-lint.yaml deleted file mode 100644 index f9ac1a2e2..000000000 --- a/.github/workflows/golangci-lint.yaml +++ /dev/null @@ -1,55 +0,0 @@ -name: Golang lint, vet and unit test pipeline - -on: [push, pull_request] - -jobs: - test: - name: github (govet, golint and gotest) - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.19.x - - name: Checkout project code - uses: actions/checkout@v2 - - name: Checkout openstack-k8s-operators-ci project - uses: actions/checkout@v2 - with: - repository: openstack-k8s-operators/openstack-k8s-operators-ci - path: ./openstack-k8s-operators-ci - - name: Run govet.sh - run: ./openstack-k8s-operators-ci/test-runner/govet.sh - - name: Run golint.sh - run: ./openstack-k8s-operators-ci/test-runner/golint.sh - - name: Run gotest.sh - run: ./openstack-k8s-operators-ci/test-runner/gotest.sh - - golangci: - name: github (golangci) - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.19.x - - name: Checkout project code - uses: actions/checkout@v2 - - name: Run golangci lint - uses: golangci/golangci-lint-action@v2 - with: - version: latest - args: --timeout 5m - - operator-lint: - name: operator-lint - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.19.x - - name: Checkout project code - uses: actions/checkout@v2 - - name: Run operator-lint - run: make operator-lint diff --git a/.github/workflows/lints.yaml b/.github/workflows/lints.yaml new file mode 100644 index 000000000..15eee2371 --- /dev/null +++ b/.github/workflows/lints.yaml @@ -0,0 +1,14 @@ +name: Lints + +on: [pull_request] + +jobs: + check-go-mod-replace-lines: + name: check for replace lines in go.mod files + runs-on: ubuntu-latest + steps: + - name: Checkout project code + uses: actions/checkout@v3 + - name: check for replace lines in go.mod files + run: | + ! egrep --invert-match -e '^replace.*/apis => \./apis|^replace.*//allow-merging$' `find . -name 'go.mod'` | egrep -e 'go.mod:replace' diff --git a/Makefile b/Makefile index 37496b85e..8eb03cfec 100644 --- a/Makefile +++ b/Makefile @@ -127,8 +127,10 @@ golangci-lint: $(LOCALBIN)/golangci-lint run --fix .PHONY: test -test: manifests generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out +test: manifests generate gowork fmt vet envtest ginkgo ## Run tests. + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) -v debug --bin-dir $(LOCALBIN) use $(ENVTEST_K8S_VERSION) -p path)" \ + OPERATOR_TEMPLATES="$(PWD)/templates" \ + $(GINKGO) --trace --cover --coverpkg=../../pkg/openstack,../../pkg/openstackclient,../../pkg/util,../../controllers,../../apis/client/v1beta1,../../apis/core/v1beta1 --coverprofile cover.out --covermode=atomic ${PROC_CMD} $(GINKGO_ARGS) ./tests/... ./apis/client/... ##@ Build @@ -204,6 +206,7 @@ $(LOCALBIN): KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest +GINKGO ?= $(LOCALBIN)/ginkgo ## Tool Versions KUSTOMIZE_VERSION ?= v3.8.7 @@ -225,6 +228,11 @@ envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. $(ENVTEST): $(LOCALBIN) test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest +.PHONY: ginkgo +ginkgo: $(GINKGO) ## Download ginkgo locally if necessary. +$(GINKGO): $(LOCALBIN) + test -s $(LOCALBIN)/ginkgo || GOBIN=$(LOCALBIN) go install github.com/onsi/ginkgo/v2/ginkgo + .PHONY: bundle bundle: manifests kustomize ## Generate bundle manifests and metadata, then validate generated files. operator-sdk generate kustomize manifests -q @@ -316,9 +324,7 @@ govet: get-ci-tools GOWORK=off $(CI_TOOLS_REPO_DIR)/test-runner/govet.sh ./apis # Run go test against code -gotest: get-ci-tools - GOWORK=off $(CI_TOOLS_REPO_DIR)/test-runner/gotest.sh - GOWORK=off $(CI_TOOLS_REPO_DIR)/test-runner/gotest.sh ./apis +gotest: test # Run golangci-lint test against code golangci: get-ci-tools diff --git a/controllers/client/suite_test.go b/controllers/client/suite_test.go deleted file mode 100644 index 42e03f5bb..000000000 --- a/controllers/client/suite_test.go +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright 2023. -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 client - -import ( - "path/filepath" - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - clientv1 "github.com/openstack-k8s-operators/openstack-operator/apis/client/v1beta1" - //+kubebuilder:scaffold:imports -) - -// 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 - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecs(t, "Controller Suite") -} - -var _ = BeforeSuite(func() { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, - ErrorIfCRDPathMissing: true, - } - - var err error - // cfg is defined in this file globally. - cfg, err = testEnv.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) - - err = clientv1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - //+kubebuilder:scaffold:scheme - - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) - -}) - -var _ = AfterSuite(func() { - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) -}) diff --git a/controllers/core/openstackcontrolplane_controller.go b/controllers/core/openstackcontrolplane_controller.go index bcc4e8517..e0c589a23 100644 --- a/controllers/core/openstackcontrolplane_controller.go +++ b/controllers/core/openstackcontrolplane_controller.go @@ -20,6 +20,7 @@ import ( "context" "fmt" + certmgrv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" routev1 "github.com/openshift/api/route/v1" cinderv1 "github.com/openstack-k8s-operators/cinder-operator/api/v1beta1" glancev1 "github.com/openstack-k8s-operators/glance-operator/api/v1beta1" @@ -352,5 +353,7 @@ func (r *OpenStackControlPlaneReconciler) SetupWithManager(mgr ctrl.Manager) err Owns(&redisv1.Redis{}). Owns(&octaviav1.Octavia{}). Owns(&routev1.Route{}). + Owns(&certmgrv1.Issuer{}). + Owns(&certmgrv1.Certificate{}). Complete(r) } diff --git a/controllers/core/suite_test.go b/controllers/core/suite_test.go deleted file mode 100644 index 34cdaf35d..000000000 --- a/controllers/core/suite_test.go +++ /dev/null @@ -1,85 +0,0 @@ -/* -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 core - -/* -import ( - "path/filepath" - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - "sigs.k8s.io/controller-runtime/pkg/envtest/printer" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - corev1beta1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1" - //+kubebuilder:scaffold:imports -) - -// 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 - -func TestAPIs(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecsWithDefaultAndCustomReporters(t, - "Controller Suite", - []Reporter{printer.NewlineReporter{}}) -} - -var _ = BeforeSuite(func() { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, - ErrorIfCRDPathMissing: true, - } - - var err error - // cfg is defined in this file globally. - cfg, err = testEnv.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) - - err = corev1beta1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - //+kubebuilder:scaffold:scheme - - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) - -}, 60) - -var _ = AfterSuite(func() { - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) -}) - -*/ diff --git a/go.mod b/go.mod index e27582840..436dc0343 100644 --- a/go.mod +++ b/go.mod @@ -17,8 +17,9 @@ require ( github.com/openstack-k8s-operators/infra-operator/apis v0.3.1-0.20231018060345-8518a89de1be github.com/openstack-k8s-operators/ironic-operator/api v0.3.1-0.20231019064410-5c72e6381cbc github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20231017110713-7b1a1e54bd46 - github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231006072650-7fe7fe16bcd1 + github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231011150636-e8a0540a3c32 github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231019091705-f3aa3d057b0f + github.com/openstack-k8s-operators/lib-common/modules/test v0.3.1-0.20231011150636-e8a0540a3c32 github.com/openstack-k8s-operators/manila-operator/api v0.3.1-0.20231017114157-49522e78f991 github.com/openstack-k8s-operators/mariadb-operator/api v0.3.0 github.com/openstack-k8s-operators/neutron-operator/api v0.3.1-0.20231019125621-7c2a5a4a5186 @@ -45,8 +46,10 @@ require ( github.com/go-logr/zapr v1.2.4 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 // indirect + github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0 // indirect github.com/metal3-io/baremetal-operator/apis v0.3.1 // indirect github.com/metal3-io/baremetal-operator/pkg/hardwareutils v0.2.0 // indirect + golang.org/x/mod v0.13.0 // indirect golang.org/x/tools v0.14.0 // indirect sigs.k8s.io/gateway-api v0.6.0 // indirect ) @@ -68,7 +71,7 @@ require ( github.com/google/gnostic v0.6.9 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.3.1 github.com/gophercloud/gophercloud v1.7.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -124,3 +127,5 @@ replace github.com/openstack-k8s-operators/openstack-operator/apis => ./apis // mschuppert: map to latest commit from release-4.13 tag // must consistent within modules and service operators replace github.com/openshift/api => github.com/openshift/api v0.0.0-20230414143018-3367bc7e6ac7 //allow-merging + +replace github.com/openstack-k8s-operators/mariadb-operator/api => github.com/stuggi/mariadb-operator/api v0.0.0-20231020124743-f4336ffd2b7e diff --git a/go.sum b/go.sum index 771dda9c6..56dc54dc5 100644 --- a/go.sum +++ b/go.sum @@ -106,6 +106,8 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0 h1:VzM3TYHDgqPkettiP6I6q2jOeQFL4nrJM+UcAc4f6Fs= +github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0/go.mod h1:nqCI7aelBJU61wiBeeZWJ6oi4bJy5nrjkM6lWIMA4j0= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -153,18 +155,18 @@ github.com/openstack-k8s-operators/ironic-operator/api v0.3.1-0.20231019064410-5 github.com/openstack-k8s-operators/ironic-operator/api v0.3.1-0.20231019064410-5c72e6381cbc/go.mod h1:QJA4yh2B6lgZzrOOb0iW8JyDmB7uRT/Mokiwalca3Cw= github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20231017110713-7b1a1e54bd46 h1:EgglSFb+05sWY5Z2JivMnXT7XSdGEOqpPfnlsc0oqvE= github.com/openstack-k8s-operators/keystone-operator/api v0.3.1-0.20231017110713-7b1a1e54bd46/go.mod h1:sDYtAWryP7mF2v4XfmKdAoFquVAMts2J5PuYFV9VBQU= -github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231006072650-7fe7fe16bcd1 h1:sE/qio/WNUEng0VBmefSr46e/cq4R83payEzge/Y48U= -github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231006072650-7fe7fe16bcd1/go.mod h1:u1pqzqGNLcof95aqhLfU6xHVTD6ZTc5gWy2FE03UrZQ= +github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231011150636-e8a0540a3c32 h1:gre7NZt12iya7vLEK6j6KDYS+OD84/ydRseYa3WeuhE= +github.com/openstack-k8s-operators/lib-common/modules/certmanager v0.0.0-20231011150636-e8a0540a3c32/go.mod h1:IA9IQoz7HJ8CHhYQxhGUSmx81gOjHQaH4Tet4gh8DpU= github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231019091705-f3aa3d057b0f h1:GhwRUVLRKKCEkK06uUXTMmT/waLJQPP5kMGpN6ozbc0= github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20231019091705-f3aa3d057b0f/go.mod h1:xXAuy7HtWN4p7LF5Q+NHLkwAsKVh0KrzpnuPYIG3XaA= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.20231019091705-f3aa3d057b0f h1:UItXdH97OtXMhW+gLa/xeCTDlm/9wMy3hiGoOLlY01I= github.com/openstack-k8s-operators/lib-common/modules/openstack v0.3.1-0.20231019091705-f3aa3d057b0f/go.mod h1:+J/GuQH7/JJF8SJtWYWxgDsYlqDv+fucxwFNP+QTcKk= github.com/openstack-k8s-operators/lib-common/modules/storage v0.3.1-0.20231019091705-f3aa3d057b0f h1:WBoCIlbxWeg+hIaawVvQX/XiuEw80WHEHouw4H+0Ksk= github.com/openstack-k8s-operators/lib-common/modules/storage v0.3.1-0.20231019091705-f3aa3d057b0f/go.mod h1:baotYmNGQjRCgu/9LxjrFZzTIT2/4yLktJK8h/Fa0Ig= +github.com/openstack-k8s-operators/lib-common/modules/test v0.3.1-0.20231011150636-e8a0540a3c32 h1:JCMXaDSjy46ZaHLHb1j2uzGIy2RUmYRCsbtSPkuEUV8= +github.com/openstack-k8s-operators/lib-common/modules/test v0.3.1-0.20231011150636-e8a0540a3c32/go.mod h1:Apy5OTK60yj9cQgVZ0HcGq+CDsLDaaEydJtj8ca0IBk= github.com/openstack-k8s-operators/manila-operator/api v0.3.1-0.20231017114157-49522e78f991 h1:8bi5MJwe9jea0gtFXpUQpYeQuDo7ULEUpOCwWi8XrXY= github.com/openstack-k8s-operators/manila-operator/api v0.3.1-0.20231017114157-49522e78f991/go.mod h1:HZ2ZuXYMpLJPqg+rUy/ZlNTCA2FnNp0fkRadCL4z7WA= -github.com/openstack-k8s-operators/mariadb-operator/api v0.3.0 h1:FB0xB6whYM6W4XIncYo2mPiOJWkFsIOWtCT+UOtvOaQ= -github.com/openstack-k8s-operators/mariadb-operator/api v0.3.0/go.mod h1:xhiz5wFdKWwVM7BF/VYon4TT3NuUPXp/Pyn2hWcp0CE= github.com/openstack-k8s-operators/neutron-operator/api v0.3.1-0.20231019125621-7c2a5a4a5186 h1:pymyGAni8tJ5juel1rTbSx0sUxfjKVwM55eNSK7V5Ls= github.com/openstack-k8s-operators/neutron-operator/api v0.3.1-0.20231019125621-7c2a5a4a5186/go.mod h1:cKr0xZME9DePkWqXbyKFjNprjCeJl5WdE/Xn+lYWY7I= github.com/openstack-k8s-operators/nova-operator/api v0.3.1-0.20231019131906-d371f09abbc6 h1:sbosbVd31OagqdtMhYYKI++4PWs4KHDTfebMvegwFw0= @@ -220,6 +222,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stuggi/mariadb-operator/api v0.0.0-20231020124743-f4336ffd2b7e h1:sWTWQ6IdwcNTaK2EyCZJZgSLFq10speCBjybLQXeasY= +github.com/stuggi/mariadb-operator/api v0.0.0-20231020124743-f4336ffd2b7e/go.mod h1:xhiz5wFdKWwVM7BF/VYon4TT3NuUPXp/Pyn2hWcp0CE= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= @@ -251,6 +255,7 @@ 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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/tests/functional/base_test.go b/tests/functional/base_test.go new file mode 100644 index 000000000..bfa9eab39 --- /dev/null +++ b/tests/functional/base_test.go @@ -0,0 +1,235 @@ +/* +Copyright 2023. + +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 functional_test + +import ( + . "github.com/onsi/gomega" + + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + openstackclientv1 "github.com/openstack-k8s-operators/openstack-operator/apis/client/v1beta1" + corev1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1" +) + +type Names struct { + Namespace string + OpenStackControlplaneName types.NamespacedName + KeystoneAPIName types.NamespacedName + MemcachedName types.NamespacedName + MariaDBName types.NamespacedName + MariaDBCell1Name types.NamespacedName + RabbitMQName types.NamespacedName + RabbitMQCell1Name types.NamespacedName + ServiceAccountName types.NamespacedName + RoleName types.NamespacedName + RoleBindingName types.NamespacedName + RootCAPublicName types.NamespacedName + RootCAInternalName types.NamespacedName + SelfSignedIssuerName types.NamespacedName + CABundleName types.NamespacedName +} + +func CreateNames(openstackControlplaneName types.NamespacedName) Names { + return Names{ + Namespace: openstackControlplaneName.Namespace, + OpenStackControlplaneName: openstackControlplaneName, + RootCAPublicName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "rootca-public"}, + RootCAInternalName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "rootca-internal"}, + SelfSignedIssuerName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "selfsigned-issuer"}, + CABundleName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "combined-ca-bundle"}, + ServiceAccountName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: openstackControlplaneName.Name}, + RoleName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: openstackControlplaneName.Name + "-role"}, + RoleBindingName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: openstackControlplaneName.Name + "-rolebinding"}, + KeystoneAPIName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "keystone", + }, + MemcachedName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "memcached", + }, + MariaDBName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "openstack", + }, + MariaDBCell1Name: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "openstack-cell1", + }, + RabbitMQName: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "rabbitmq", + }, + RabbitMQCell1Name: types.NamespacedName{ + Namespace: openstackControlplaneName.Namespace, + Name: "rabbitmq-cell1", + }, + } +} + +func GetDefaultOpenStackClientSpec() map[string]interface{} { + return map[string]interface{}{} +} + +func CreateOpenStackClient(name types.NamespacedName, spec map[string]interface{}) client.Object { + + raw := map[string]interface{}{ + "apiVersion": "client.openstack.org/v1beta1", + "kind": "OpenStackClient", + "metadata": map[string]interface{}{ + "name": name.Name, + "namespace": name.Namespace, + }, + "spec": spec, + } + return th.CreateUnstructured(raw) +} + +func GetOpenStackClient(name types.NamespacedName) *openstackclientv1.OpenStackClient { + instance := &openstackclientv1.OpenStackClient{} + Eventually(func(g Gomega) { + g.Expect(k8sClient.Get(ctx, name, instance)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + return instance +} + +func CreateOpenStackControlPlane(name types.NamespacedName, spec map[string]interface{}) client.Object { + + raw := map[string]interface{}{ + "apiVersion": "core.openstack.org/v1beta1", + "kind": "OpenStackControlPlane", + "metadata": map[string]interface{}{ + "name": name.Name, + "namespace": name.Namespace, + }, + "spec": spec, + } + return th.CreateUnstructured(raw) +} + +func GetDefaultOpenStackControlPlaneSpec() map[string]interface{} { + memcachedTemplate := map[string]interface{}{ + "memcached": map[string]interface{}{ + "replicas": 1, + }, + } + rabbitTemplate := map[string]interface{}{ + names.RabbitMQName.Name: map[string]interface{}{ + "replicas": 1, + }, + names.RabbitMQCell1Name.Name: map[string]interface{}{ + "replicas": 1, + }, + } + mariadbTemplate := map[string]interface{}{ + names.MariaDBName.Name: map[string]interface{}{ + "storageRequest": "500M", + }, + names.MariaDBCell1Name.Name: map[string]interface{}{ + "storageRequest": "500M", + }, + } + keystoneTemplate := map[string]interface{}{ + "databaseInstance": names.KeystoneAPIName.Name, + "secret": "osp-secret", + } + ironicTemplate := map[string]interface{}{ + "ironicConductors": []interface{}{}, + } + + tlsTemplate := map[string]interface{}{ + //"internalEndpoints": map[string]interface{}{ + // "enabled": false, + //}, + "publicEndpoints": map[string]interface{}{ + "enabled": true, + }, + } + + return map[string]interface{}{ + "secret": "osp-secret", + "storageClass": "local-storage", + "tls": tlsTemplate, + "mariadb": map[string]interface{}{ + "enabled": true, + "templates": mariadbTemplate, + }, + "rabbitmq": map[string]interface{}{ + "enabled": true, + "templates": rabbitTemplate, + }, + "memcached": map[string]interface{}{ + "enabled": true, + "templates": memcachedTemplate, + }, + "keystone": map[string]interface{}{ + "enabled": true, + "template": keystoneTemplate, + }, + "placement": map[string]interface{}{ + "enabled": false, + }, + "glance": map[string]interface{}{ + "enabled": false, + }, + "cinder": map[string]interface{}{ + "enabled": false, + }, + "ovn": map[string]interface{}{ + "enabled": false, + }, + "neutron": map[string]interface{}{ + "enabled": false, + }, + "swift": map[string]interface{}{ + "enabled": false, + }, + "nova": map[string]interface{}{ + "enabled": false, + }, + "redis": map[string]interface{}{ + "enabled": false, + }, + "ironic": map[string]interface{}{ + "enabled": false, + "template": ironicTemplate, + }, + } +} + +func GetOpenStackControlPlane(name types.NamespacedName) *corev1.OpenStackControlPlane { + instance := &corev1.OpenStackControlPlane{} + Eventually(func(g Gomega) { + g.Expect(k8sClient.Get(ctx, name, instance)).Should(Succeed()) + }, timeout, interval).Should(Succeed()) + return instance +} diff --git a/tests/functional/openstackclient_webhook_test.go b/tests/functional/openstackclient_webhook_test.go new file mode 100644 index 000000000..1fa3eb870 --- /dev/null +++ b/tests/functional/openstackclient_webhook_test.go @@ -0,0 +1,71 @@ +/* +Copyright 2023. + +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 functional_test + +import ( + "os" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/types" + + openstackclientv1 "github.com/openstack-k8s-operators/openstack-operator/apis/client/v1beta1" +) + +var _ = Describe("OpenStackClient Webhook", func() { + + var openstackclientName types.NamespacedName + + BeforeEach(func() { + + openstackclientName = types.NamespacedName{ + Name: "foo", + Namespace: namespace, + } + + err := os.Setenv("OPERATOR_TEMPLATES", "../../templates") + Expect(err).NotTo(HaveOccurred()) + }) + + When("A OpenStackClient instance is created without container images", func() { + BeforeEach(func() { + DeferCleanup(th.DeleteInstance, CreateOpenStackClient(openstackclientName, GetDefaultOpenStackClientSpec())) + }) + + It("should have the defaults initialized by webhook", func() { + OpenStackClient := GetOpenStackClient(openstackclientName) + Expect(OpenStackClient.Spec.ContainerImage).Should(Equal( + openstackclientv1.OpenStackClientContainerImage, + )) + }) + }) + + When("A OpenStackClient instance is created with container images", func() { + BeforeEach(func() { + openstackclientSpec := GetDefaultOpenStackClientSpec() + openstackclientSpec["containerImage"] = "api-container-image" + DeferCleanup(th.DeleteInstance, CreateOpenStackClient(openstackclientName, openstackclientSpec)) + }) + + It("should use the given values", func() { + OpenStackClient := GetOpenStackClient(openstackclientName) + Expect(OpenStackClient.Spec.ContainerImage).Should(Equal( + "api-container-image", + )) + }) + }) +}) diff --git a/tests/functional/openstackoperator_controller_test.go b/tests/functional/openstackoperator_controller_test.go new file mode 100644 index 000000000..58978bdd4 --- /dev/null +++ b/tests/functional/openstackoperator_controller_test.go @@ -0,0 +1,130 @@ +/* +Copyright 2023. + +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 functional_test + +import ( + "os" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/utils/ptr" +) + +var _ = Describe("OpenStackOperator controller", func() { + BeforeEach(func() { + // lib-common uses OPERATOR_TEMPLATES env var to locate the "templates" + // directory of the operator. We need to set them othervise lib-common + // will fail to generate the ConfigMap as it does not find common.sh + err := os.Setenv("OPERATOR_TEMPLATES", "../../templates") + Expect(err).NotTo(HaveOccurred()) + }) + + When("A default OpenStackControlplane instance is created", func() { + BeforeEach(func() { + // (mschuppert) create root CA secret as there is no certmanager running. + // it is not used, just to make sure reconcile proceeds and creates the ca-bundle. + Eventually(func(g Gomega) { + th.CreateSecret( + names.RootCAPublicName, + map[string][]byte{ + "ca.crt": []byte("test"), + "tls.crt": []byte("test"), + "tls.key": []byte("test"), + }) + }, timeout, interval).Should(Succeed()) + + DeferCleanup( + th.DeleteInstance, + CreateOpenStackControlPlane(names.OpenStackControlplaneName, GetDefaultOpenStackControlPlaneSpec()), + ) + }) + + It("should have the Spec fields defaulted", func() { + OSCtlplane := GetOpenStackControlPlane(names.OpenStackControlplaneName) + Expect(OSCtlplane.Spec.Mariadb.Enabled).Should(BeTrue()) + Expect(OSCtlplane.Spec.Rabbitmq.Enabled).Should(BeTrue()) + Expect(OSCtlplane.Spec.Memcached.Enabled).Should(BeTrue()) + Expect(OSCtlplane.Spec.Keystone.Enabled).Should(BeTrue()) + Expect(OSCtlplane.Spec.TLS.PublicEndpoints.Enabled).Should(BeTrue()) + Expect(OSCtlplane.Spec.TLS.InternalEndpoints.Enabled).Should(BeFalse()) + + // mariadb exists + Eventually(func(g Gomega) { + mariadb := mariadb.GetMariaDB(names.MariaDBName) + Expect(mariadb).Should(Not(BeNil())) + }, timeout, interval).Should(Succeed()) + Eventually(func(g Gomega) { + mariadb := mariadb.GetMariaDB(names.MariaDBCell1Name) + Expect(mariadb).Should(Not(BeNil())) + }, timeout, interval).Should(Succeed()) + + // memcached exists + Eventually(func(g Gomega) { + memcached := infra.GetMemcached(names.MemcachedName) + Expect(memcached).Should(Not(BeNil())) + Expect(memcached.Spec.Replicas).Should(Equal(ptr.To[int32](1))) + }, timeout, interval).Should(Succeed()) + + // TODO rabbitmq exists + + // keystone exists + Eventually(func(g Gomega) { + keystoneAPI := keystone.GetKeystoneAPI(names.KeystoneAPIName) + Expect(keystoneAPI).Should(Not(BeNil())) + }, timeout, interval).Should(Succeed()) + }) + + It("should create selfsigned issuer and public CA and issuer", func() { + OSCtlplane := GetOpenStackControlPlane(names.OpenStackControlplaneName) + + Expect(OSCtlplane.Spec.TLS.PublicEndpoints.Enabled).Should(BeTrue()) + Expect(OSCtlplane.Spec.TLS.InternalEndpoints.Enabled).Should(BeFalse()) + + // creates selfsigned issuer + Eventually(func(g Gomega) { + crtmgr.GetIssuer(names.SelfSignedIssuerName) + }, timeout, interval).Should(Succeed()) + + // creates public root CA and issuer + Eventually(func(g Gomega) { + // ca cert + cert := crtmgr.GetCert(names.RootCAPublicName) + Expect(cert).Should(Not(BeNil())) + Expect(cert.Spec.CommonName).Should(Equal(names.RootCAPublicName.Name)) + Expect(cert.Spec.IsCA).Should(BeTrue()) + Expect(cert.Spec.IssuerRef.Name).Should(Equal(names.SelfSignedIssuerName.Name)) + Expect(cert.Spec.SecretName).Should(Equal(names.RootCAPublicName.Name)) + // issuer + issuer := crtmgr.GetIssuer(names.RootCAPublicName) + Expect(issuer).Should(Not(BeNil())) + Expect(issuer.Spec.CA.SecretName).Should(Equal(names.RootCAPublicName.Name)) + + }, timeout, interval).Should(Succeed()) + }) + + It("should create ca bundle", func() { + crtmgr.GetCert(names.RootCAPublicName) + crtmgr.GetIssuer(names.RootCAPublicName) + + Eventually(func(g Gomega) { + th.GetSecret(names.RootCAPublicName) + caBundle := th.GetSecret(names.CABundleName) + Expect(len(caBundle.Data)).Should(Equal(int(1))) + }, timeout, interval).Should(Succeed()) + }) + }) +}) diff --git a/tests/functional/suite_test.go b/tests/functional/suite_test.go new file mode 100644 index 000000000..0866bbd71 --- /dev/null +++ b/tests/functional/suite_test.go @@ -0,0 +1,350 @@ +package functional_test + +import ( + "context" + "crypto/tls" + "fmt" + "net" + "path/filepath" + "testing" + "time" + + "github.com/go-logr/logr" + "github.com/google/uuid" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "go.uber.org/zap/zapcore" + + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + certmgrv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" + routev1 "github.com/openshift/api/route/v1" + rabbitmqv2 "github.com/rabbitmq/cluster-operator/v2/api/v1beta1" + + cinderv1 "github.com/openstack-k8s-operators/cinder-operator/api/v1beta1" + glancev1 "github.com/openstack-k8s-operators/glance-operator/api/v1beta1" + heatv1 "github.com/openstack-k8s-operators/heat-operator/api/v1beta1" + horizonv1 "github.com/openstack-k8s-operators/horizon-operator/api/v1beta1" + memcachedv1 "github.com/openstack-k8s-operators/infra-operator/apis/memcached/v1beta1" + networkv1 "github.com/openstack-k8s-operators/infra-operator/apis/network/v1beta1" + redisv1 "github.com/openstack-k8s-operators/infra-operator/apis/redis/v1beta1" + ironicv1 "github.com/openstack-k8s-operators/ironic-operator/api/v1beta1" + keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1" + manilav1 "github.com/openstack-k8s-operators/manila-operator/api/v1beta1" + mariadbv1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1" + neutronv1 "github.com/openstack-k8s-operators/neutron-operator/api/v1beta1" + novav1 "github.com/openstack-k8s-operators/nova-operator/api/v1beta1" + octaviav1 "github.com/openstack-k8s-operators/octavia-operator/api/v1beta1" + openstackclientv1 "github.com/openstack-k8s-operators/openstack-operator/apis/client/v1beta1" + corev1 "github.com/openstack-k8s-operators/openstack-operator/apis/core/v1beta1" + ovnv1 "github.com/openstack-k8s-operators/ovn-operator/api/v1beta1" + placementv1 "github.com/openstack-k8s-operators/placement-operator/api/v1beta1" + swiftv1 "github.com/openstack-k8s-operators/swift-operator/api/v1beta1" + telemetryv1 "github.com/openstack-k8s-operators/telemetry-operator/api/v1beta1" + + client_ctrl "github.com/openstack-k8s-operators/openstack-operator/controllers/client" + core_ctrl "github.com/openstack-k8s-operators/openstack-operator/controllers/core" + + infra_test "github.com/openstack-k8s-operators/infra-operator/apis/test/helpers" + keystone_test "github.com/openstack-k8s-operators/keystone-operator/api/test/helpers" + certmanager_test "github.com/openstack-k8s-operators/lib-common/modules/certmanager/test/helpers" + common_test "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers" + test "github.com/openstack-k8s-operators/lib-common/modules/test" + mariadb_test "github.com/openstack-k8s-operators/mariadb-operator/api/test/helpers" + //+kubebuilder:scaffold:imports +) + +// 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 + k8sClient client.Client + testEnv *envtest.Environment + ctx context.Context + cancel context.CancelFunc + logger logr.Logger + th *common_test.TestHelper + keystone *keystone_test.TestHelper + mariadb *mariadb_test.TestHelper + infra *infra_test.TestHelper + crtmgr *certmanager_test.TestHelper + namespace string + names Names +) + +const ( + timeout = time.Second * 5 + + SecretName = "test-osp-secret" + + interval = time.Millisecond * 200 +) + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Controller Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true), func(o *zap.Options) { + o.Development = true + o.TimeEncoder = zapcore.ISO8601TimeEncoder + })) + + ctx, cancel = context.WithCancel(context.TODO()) + + routev1CRDs, err := test.GetOpenShiftCRDDir("route/v1", "../../go.mod") + Expect(err).ShouldNot(HaveOccurred()) + mariaDBCRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/mariadb-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + infraCRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/infra-operator/apis", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + cinderv1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/cinder-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + glancev1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/glance-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + heatv1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/heat-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + horizonv1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/horizon-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + ironicv1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/ironic-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + keystonev1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/keystone-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + manilav1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/manila-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + neutronv1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/neutron-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + novav1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/nova-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + octaviav1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/octavia-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + ovnv1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/ovn-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + placementv1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/placement-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + swiftv1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/swift-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + telemetryv1CRDs, err := test.GetCRDDirFromModule( + "github.com/openstack-k8s-operators/telemetry-operator/api", "../../go.mod", "bases") + Expect(err).ShouldNot(HaveOccurred()) + rabbitmqv2CRDs, err := test.GetCRDDirFromModule( + "github.com/rabbitmq/cluster-operator/v2", "../../go.mod", "config/crd/bases") + Expect(err).ShouldNot(HaveOccurred()) + certmgrv1CRDs, err := test.GetOpenShiftCRDDir("cert-manager/v1", "../../go.mod") + Expect(err).ShouldNot(HaveOccurred()) + + By("bootstrapping test environment") + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{ + filepath.Join("..", "..", "config", "crd", "bases"), + routev1CRDs, + mariaDBCRDs, + infraCRDs, + cinderv1CRDs, + glancev1CRDs, + heatv1CRDs, + horizonv1CRDs, + ironicv1CRDs, + keystonev1CRDs, + manilav1CRDs, + neutronv1CRDs, + novav1CRDs, + octaviav1CRDs, + ovnv1CRDs, + placementv1CRDs, + swiftv1CRDs, + telemetryv1CRDs, + rabbitmqv2CRDs, + certmgrv1CRDs, + }, + ErrorIfCRDPathMissing: true, + WebhookInstallOptions: envtest.WebhookInstallOptions{ + Paths: []string{filepath.Join("..", "..", "config", "webhook")}, + // NOTE(gibi): if localhost is resolved to ::1 (ipv6) then starting + // the webhook fails as it try to parse the address as ipv4 and + // failing on the colons in ::1 + LocalServingHost: "127.0.0.1", + }, + } + + // cfg is defined in this file globally. + cfg, err = testEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(cfg).NotTo(BeNil()) + + err = openstackclientv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = corev1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = routev1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = cinderv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = glancev1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = heatv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = horizonv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = memcachedv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = redisv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = ironicv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = keystonev1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = manilav1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = mariadbv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = neutronv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = novav1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = octaviav1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = ovnv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = placementv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = swiftv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = telemetryv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = rabbitmqv2.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = certmgrv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = networkv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + //+kubebuilder:scaffold:scheme + + logger = ctrl.Log.WithName("---Test---") + + k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(k8sClient).NotTo(BeNil()) + th = common_test.NewTestHelper(ctx, k8sClient, timeout, interval, logger) + Expect(th).NotTo(BeNil()) + keystone = keystone_test.NewTestHelper(ctx, k8sClient, timeout, interval, logger) + Expect(keystone).NotTo(BeNil()) + mariadb = mariadb_test.NewTestHelper(ctx, k8sClient, timeout, interval, logger) + Expect(mariadb).NotTo(BeNil()) + infra = infra_test.NewTestHelper(ctx, k8sClient, timeout, interval, logger) + Expect(infra).NotTo(BeNil()) + crtmgr = certmanager_test.NewTestHelper(ctx, k8sClient, timeout, interval, logger) + Expect(crtmgr).NotTo(BeNil()) + + // Start the controller-manager if goroutine + webhookInstallOptions := &testEnv.WebhookInstallOptions + k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{ + Scheme: scheme.Scheme, + // NOTE(gibi): disable metrics reporting in test to allow + // parallel test execution. Otherwise each instance would like to + // bind to the same port + MetricsBindAddress: "0", + Host: webhookInstallOptions.LocalServingHost, + Port: webhookInstallOptions.LocalServingPort, + CertDir: webhookInstallOptions.LocalServingCertDir, + LeaderElection: false, + }) + Expect(err).ToNot(HaveOccurred()) + + kclient, err := kubernetes.NewForConfig(cfg) + Expect(err).ToNot(HaveOccurred(), "failed to create kclient") + + err = (&openstackclientv1.OpenStackClient{}).SetupWebhookWithManager(k8sManager) + Expect(err).NotTo(HaveOccurred()) + err = (&corev1.OpenStackControlPlane{}).SetupWebhookWithManager(k8sManager) + Expect(err).NotTo(HaveOccurred()) + + openstackclientv1.SetupDefaults() + corev1.SetupDefaults() + + err = (&client_ctrl.OpenStackClientReconciler{ + Client: k8sManager.GetClient(), + Scheme: k8sManager.GetScheme(), + Kclient: kclient, + Log: ctrl.Log.WithName("controllers").WithName("OpenStackClient"), + }).SetupWithManager(k8sManager) + Expect(err).ToNot(HaveOccurred()) + + err = (&core_ctrl.OpenStackControlPlaneReconciler{ + Client: k8sManager.GetClient(), + Scheme: k8sManager.GetScheme(), + Kclient: kclient, + Log: ctrl.Log.WithName("controllers").WithName("OpenStackControlPlane"), + }).SetupWithManager(k8sManager) + Expect(err).ToNot(HaveOccurred()) + + go func() { + defer GinkgoRecover() + err = k8sManager.Start(ctx) + Expect(err).ToNot(HaveOccurred(), "failed to run manager") + }() + + // wait for the webhook server to get ready + dialer := &net.Dialer{Timeout: 10 * time.Second} + addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort) + Eventually(func() error { + conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true}) + if err != nil { + return err + } + conn.Close() + return nil + }).Should(Succeed()) +}) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + cancel() + err := testEnv.Stop() + Expect(err).NotTo(HaveOccurred()) +}) + +var _ = BeforeEach(func() { + // NOTE(gibi): We need to create a unique namespace for each test run + // as namespaces cannot be deleted in a locally running envtest. See + // https://book.kubebuilder.io/reference/envtest.html#namespace-usage-limitation + namespace = uuid.New().String() + th.CreateNamespace(namespace) + // We still request the delete of the Namespace to properly cleanup if + // we run the test in an existing cluster. + DeferCleanup(th.DeleteNamespace, namespace) + + openstackControlplaneName := types.NamespacedName{ + Namespace: namespace, + Name: uuid.New().String()[:25], + } + + names = CreateNames(openstackControlplaneName) +})