diff --git a/Makefile b/Makefile index cf528a701..1d414e0ed 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,3 @@ -### -# NOTE: this section almost matches outputs out kubebuilder v3.7.0 -### # Current Operator version VERSION ?= 5.14.0 @@ -15,13 +12,6 @@ ifeq ($(USE_IMAGE_DIGESTS), true) BUNDLE_GEN_FLAGS += --use-image-digests endif -# Set the Operator SDK version to use. By default, what is installed on the system is used. -# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit. -OPERATOR_SDK_VERSION ?= v1.32.0 - -OPM_VERSION ?= v1.23.2 -YQ_VERSION ?= v4.35.2 - # Read Grafana Image and Version from go code GRAFANA_IMAGE := $(shell grep 'GrafanaImage' controllers/config/operator_constants.go | sed 's/.*"\(.*\)".*/\1/') GRAFANA_VERSION := $(shell grep 'GrafanaVersion' controllers/config/operator_constants.go | sed 's/.*"\(.*\)".*/\1/') @@ -74,23 +64,6 @@ all: manifests test api-docs help: ## Display this help. @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) -.PHONY: yq -YQ = ./bin/yq -yq: ## Download yq locally if necessary. -ifeq (,$(wildcard $(YQ))) -ifeq (,$(shell which yq 2>/dev/null)) - @{ \ - set -e ;\ - mkdir -p $(dir $(YQ)) ;\ - OSTYPE=$(shell uname | awk '{print tolower($$0)}') && ARCH=$(shell go env GOARCH) && \ - curl -sSLo $(YQ) https://github.com/mikefarah/yq/releases/download/$(YQ_VERSION)/yq_$${OSTYPE}_$${ARCH} ;\ - chmod +x $(YQ) ;\ - } -else -YQ = $(shell which yq) -endif -endif - ##@ Development .PHONY: manifests @@ -161,6 +134,10 @@ deploy-chainsaw: manifests kustomize ## Deploy controller to the K8s cluster spe undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. $(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f - +.PHONY: start-kind +start-kind: kind ## Start kind cluster locally + @hack/kind/start-kind.sh + ##@ Build Dependencies ## Location to install dependencies to @@ -169,13 +146,22 @@ $(LOCALBIN): mkdir -p $(LOCALBIN) ## Tool Binaries +OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk KUSTOMIZE ?= $(LOCALBIN)/kustomize CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen ENVTEST ?= $(LOCALBIN)/setup-envtest +YQ = $(LOCALBIN)/yq +KIND = $(LOCALBIN)/kind ## Tool Versions +# Set the Operator SDK version to use. By default, what is installed on the system is used. +# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit. +OPERATOR_SDK_VERSION ?= v1.32.0 KUSTOMIZE_VERSION ?= v5.1.1 CONTROLLER_TOOLS_VERSION ?= v0.16.3 +OPM_VERSION ?= v1.23.2 +YQ_VERSION ?= v4.35.2 +KIND_VERSION ?= v0.24.0 KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" .PHONY: kustomize @@ -194,7 +180,6 @@ $(ENVTEST): $(LOCALBIN) test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest .PHONY: operator-sdk -OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk operator-sdk: ## Download operator-sdk locally if necessary. ifeq (,$(wildcard $(OPERATOR_SDK))) ifeq (, $(shell which operator-sdk 2>/dev/null)) @@ -210,9 +195,37 @@ OPERATOR_SDK = $(shell which operator-sdk) endif endif -### -# END OF kubebuilder SECTION -### +.PHONY: yq +yq: ## Download yq locally if necessary. +ifeq (,$(wildcard $(YQ))) +ifeq (,$(shell which yq 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(YQ)) ;\ + OSTYPE=$(shell uname | awk '{print tolower($$0)}') && ARCH=$(shell go env GOARCH) && \ + curl -sSLo $(YQ) https://github.com/mikefarah/yq/releases/download/$(YQ_VERSION)/yq_$${OSTYPE}_$${ARCH} ;\ + chmod +x $(YQ) ;\ + } +else +YQ = $(shell which yq) +endif +endif + +.PHONY: kind +kind: ## Download kind locally if necessary. +ifeq (,$(wildcard $(KIND))) +ifeq (,$(shell which kind 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(KIND)) ;\ + OSTYPE=$(shell uname | awk '{print tolower($$0)}') && ARCH=$(shell go env GOARCH) && \ + curl -sSLo $(KIND) https://github.com/kubernetes-sigs/kind/releases/download/$(KIND_VERSION)/kind-$${OSTYPE}-$${ARCH} ;\ + chmod +x $(KIND) ;\ + } +else +KIND = $(shell which kind) +endif +endif # CHANNELS define the bundle channels used in the bundle. # Add a new line here if you would like to change its default config. (E.g CHANNELS = "candidate,fast,stable") @@ -309,16 +322,14 @@ export KO_DOCKER_REPO ?= ko.local/grafana/grafana-operator export KIND_CLUSTER_NAME ?= kind-grafana export KUBECONFIG ?= ${HOME}/.kube/kind-grafana-operator -# If you want to push ko to your local Docker daemon .PHONY: ko-build-local -ko-build-local: ko +ko-build-local: ko ## Build Docker image with KO $(KO) build --sbom=none --bare -# If you want to push ko to your kind cluster .PHONY: ko-build-kind -ko-build-kind: ko - $(KO) build --sbom=none --bare - kind load docker-image $(KO_DOCKER_REPO) --name $(KIND_CLUSTER_NAME) +ko-build-kind: ko-build-local ## Build and Load Docker image into kind cluster + $(KIND) load docker-image $(KO_DOCKER_REPO) --name $(KIND_CLUSTER_NAME) + helm-docs: ifeq (, $(shell which helm-docs)) @{ \ @@ -330,9 +341,6 @@ else HELM_DOCS=$(shell which helm-docs) endif -start-kind: - @hack/kind/start-kind.sh - .PHONY: helm/docs helm/docs: helm-docs $(HELM_DOCS) diff --git a/api/v1beta1/grafanafolder_types.go b/api/v1beta1/grafanafolder_types.go index 69e0150a2..88b3ac0da 100644 --- a/api/v1beta1/grafanafolder_types.go +++ b/api/v1beta1/grafanafolder_types.go @@ -30,19 +30,26 @@ import ( // GrafanaFolderSpec defines the desired state of GrafanaFolder // +kubebuilder:validation:XValidation:rule="(has(self.parentFolderUID) && !(has(self.parentFolderRef))) || (has(self.parentFolderRef) && !(has(self.parentFolderUID))) || !(has(self.parentFolderRef) && (has(self.parentFolderUID)))", message="Only one of parentFolderUID or parentFolderRef can be set" +// +kubebuilder:validation:XValidation:rule="((!has(oldSelf.uid) && !has(self.uid)) || (has(oldSelf.uid) && has(self.uid)))", message="spec.uid is immutable" type GrafanaFolderSpec struct { + // Manually specify the UID the Folder is created with + // +optional + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="spec.uid is immutable" + CustomUID string `json:"uid,omitempty"` + + // Display name of the folder in Grafana // +optional Title string `json:"title,omitempty"` - // raw json with folder permissions + // Raw json with folder permissions, potentially exported from Grafana // +optional Permissions string `json:"permissions,omitempty"` - // selects Grafanas for import + // Selects Grafanas for import // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable" InstanceSelector *metav1.LabelSelector `json:"instanceSelector"` - // allow to import this resources from an operator in a different namespace + // Enable matching Grafana instances outside the current namespace // +optional AllowCrossNamespaceImport *bool `json:"allowCrossNamespaceImport,omitempty"` @@ -54,7 +61,7 @@ type GrafanaFolderSpec struct { // +optional ParentFolderRef string `json:"parentFolderRef,omitempty"` - // how often the folder is synced, defaults to 5m if not set + // How often the folder is synced, defaults to 5m if not set // +optional // +kubebuilder:validation:Type=string // +kubebuilder:validation:Format=duration @@ -115,6 +122,14 @@ func (in *GrafanaFolder) FolderUID() string { return in.Spec.ParentFolderUID } +// Wrapper around CustomUID or default metadata.uid +func (in *GrafanaFolder) CustomUIDOrUID() string { + if in.Spec.CustomUID != "" { + return in.Spec.CustomUID + } + return string(in.ObjectMeta.UID) +} + var _ operatorapi.FolderReferencer = (*GrafanaFolder)(nil) //+kubebuilder:object:root=true diff --git a/api/v1beta1/grafanafolder_types_test.go b/api/v1beta1/grafanafolder_types_test.go index be79fc5e3..4c931c948 100644 --- a/api/v1beta1/grafanafolder_types_test.go +++ b/api/v1beta1/grafanafolder_types_test.go @@ -39,3 +39,36 @@ func TestGrafanaFolder_GetTitle(t *testing.T) { }) } } + +func TestGrafanaFolder_GetUID(t *testing.T) { + tests := []struct { + name string + cr GrafanaFolder + want string + }{ + { + name: "No custom UID", + cr: GrafanaFolder{ + ObjectMeta: metav1.ObjectMeta{UID: "92fd2e0a-ad63-4fcf-9890-68a527cbd674"}, + }, + want: "92fd2e0a-ad63-4fcf-9890-68a527cbd674", + }, + { + name: "Custom UID", + cr: GrafanaFolder{ + ObjectMeta: metav1.ObjectMeta{UID: "92fd2e0a-ad63-4fcf-9890-68a527cbd674"}, + Spec: GrafanaFolderSpec{ + CustomUID: "custom-uid", + }, + }, + want: "custom-uid", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.cr.CustomUIDOrUID() + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/config/crd/bases/grafana.integreatly.org_grafanafolders.yaml b/config/crd/bases/grafana.integreatly.org_grafanafolders.yaml index 2cccae7a2..080826c69 100644 --- a/config/crd/bases/grafana.integreatly.org_grafanafolders.yaml +++ b/config/crd/bases/grafana.integreatly.org_grafanafolders.yaml @@ -49,11 +49,11 @@ spec: description: GrafanaFolderSpec defines the desired state of GrafanaFolder properties: allowCrossNamespaceImport: - description: allow to import this resources from an operator in a - different namespace + description: Enable matching Grafana instances outside the current + namespace type: boolean instanceSelector: - description: selects Grafanas for import + description: Selects Grafanas for import properties: matchExpressions: description: matchExpressions is a list of label selector requirements. @@ -110,17 +110,25 @@ spec: be created type: string permissions: - description: raw json with folder permissions + description: Raw json with folder permissions, potentially exported + from Grafana type: string resyncPeriod: default: 5m - description: how often the folder is synced, defaults to 5m if not + description: How often the folder is synced, defaults to 5m if not set format: duration pattern: ^([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$ type: string title: + description: Display name of the folder in Grafana + type: string + uid: + description: Manually specify the UID the Folder is created with type: string + x-kubernetes-validations: + - message: spec.uid is immutable + rule: self == oldSelf required: - instanceSelector type: object @@ -129,6 +137,9 @@ spec: rule: (has(self.parentFolderUID) && !(has(self.parentFolderRef))) || (has(self.parentFolderRef) && !(has(self.parentFolderUID))) || !(has(self.parentFolderRef) && (has(self.parentFolderUID))) + - message: spec.uid is immutable + rule: ((!has(oldSelf.uid) && !has(self.uid)) || (has(oldSelf.uid) && + has(self.uid))) status: description: GrafanaFolderStatus defines the observed state of GrafanaFolder properties: diff --git a/controllers/controller_shared.go b/controllers/controller_shared.go index 31ab88b33..e3a4cc7d4 100644 --- a/controllers/controller_shared.go +++ b/controllers/controller_shared.go @@ -82,7 +82,7 @@ func getFolderUID(ctx context.Context, k8sClient client.Client, ref operatorapi. } removeNoMatchingFolder(ref.Conditions()) - return string(folder.ObjectMeta.UID), nil + return folder.CustomUIDOrUID(), nil } func labelsSatisfyMatchExpressions(labels map[string]string, matchExpressions []metav1.LabelSelectorRequirement) bool { diff --git a/controllers/dashboard_controller.go b/controllers/dashboard_controller.go index 45ad774ba..6694cf4c9 100644 --- a/controllers/dashboard_controller.go +++ b/controllers/dashboard_controller.go @@ -699,15 +699,16 @@ func (r *GrafanaDashboardReconciler) GetFolderUID( limit := int64(1000) for { params := folders.NewGetFoldersParams().WithPage(&page).WithLimit(&limit) - resp, err := client.Folders.GetFolders(params) + + foldersResp, err := client.Folders.GetFolders(params) if err != nil { return false, "", err } - folders := resp.GetPayload() + folders := foldersResp.GetPayload() - for _, folder := range folders { - if strings.EqualFold(folder.Title, title) { - return true, folder.UID, nil + for _, remoteFolder := range folders { + if strings.EqualFold(remoteFolder.Title, title) { + return true, remoteFolder.UID, nil } } if len(folders) < int(limit) { diff --git a/controllers/grafanafolder_controller.go b/controllers/grafanafolder_controller.go index 160a917bf..ad75dc176 100644 --- a/controllers/grafanafolder_controller.go +++ b/controllers/grafanafolder_controller.go @@ -186,7 +186,7 @@ func (r *GrafanaFolderReconciler) Reconcile(ctx context.Context, req ctrl.Reques } }() - if folder.Spec.ParentFolderUID == string(folder.UID) { + if folder.Spec.ParentFolderUID == folder.CustomUIDOrUID() { setInvalidSpec(&folder.Status.Conditions, folder.Generation, "CyclicParent", "The value of parentFolderUID must not be the uid of the current folder") meta.RemoveStatusCondition(&folder.Status.Conditions, conditionFolderSynchronized) return ctrl.Result{}, fmt.Errorf("cyclic folder reference") @@ -314,7 +314,7 @@ func (r *GrafanaFolderReconciler) onFolderDeleted(ctx context.Context, namespace func (r *GrafanaFolderReconciler) onFolderCreated(ctx context.Context, grafana *grafanav1beta1.Grafana, cr *grafanav1beta1.GrafanaFolder) error { title := cr.GetTitle() - uid := string(cr.UID) + uid := cr.CustomUIDOrUID() grafanaClient, err := client2.NewGeneratedGrafanaClient(ctx, r.Client, grafana) if err != nil { @@ -413,7 +413,7 @@ func (r *GrafanaFolderReconciler) UpdateStatus(ctx context.Context, cr *grafanav // Check if the folder exists. Matches UID first and fall back to title. Title matching only works for non-nested folders func (r *GrafanaFolderReconciler) Exists(client *genapi.GrafanaHTTPAPI, cr *grafanav1beta1.GrafanaFolder) (bool, string, string, error) { title := cr.GetTitle() - uid := string(cr.UID) + uid := cr.CustomUIDOrUID() uidResp, err := client.Folders.GetFolderByUID(uid) if err == nil { @@ -429,12 +429,14 @@ func (r *GrafanaFolderReconciler) Exists(client *genapi.GrafanaHTTPAPI, cr *graf if err != nil { return false, "", "", err } - for _, folder := range foldersResp.Payload { - if strings.EqualFold(folder.Title, title) { - return true, folder.UID, folder.ParentUID, nil + folders := foldersResp.GetPayload() + + for _, remoteFolder := range folders { + if strings.EqualFold(remoteFolder.Title, title) { + return true, remoteFolder.UID, remoteFolder.ParentUID, nil } } - if len(foldersResp.Payload) < int(limit) { + if len(folders) < int(limit) { return false, "", "", nil } page++ diff --git a/deploy/helm/grafana-operator/crds/grafana.integreatly.org_grafanafolders.yaml b/deploy/helm/grafana-operator/crds/grafana.integreatly.org_grafanafolders.yaml index 2cccae7a2..080826c69 100644 --- a/deploy/helm/grafana-operator/crds/grafana.integreatly.org_grafanafolders.yaml +++ b/deploy/helm/grafana-operator/crds/grafana.integreatly.org_grafanafolders.yaml @@ -49,11 +49,11 @@ spec: description: GrafanaFolderSpec defines the desired state of GrafanaFolder properties: allowCrossNamespaceImport: - description: allow to import this resources from an operator in a - different namespace + description: Enable matching Grafana instances outside the current + namespace type: boolean instanceSelector: - description: selects Grafanas for import + description: Selects Grafanas for import properties: matchExpressions: description: matchExpressions is a list of label selector requirements. @@ -110,17 +110,25 @@ spec: be created type: string permissions: - description: raw json with folder permissions + description: Raw json with folder permissions, potentially exported + from Grafana type: string resyncPeriod: default: 5m - description: how often the folder is synced, defaults to 5m if not + description: How often the folder is synced, defaults to 5m if not set format: duration pattern: ^([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$ type: string title: + description: Display name of the folder in Grafana + type: string + uid: + description: Manually specify the UID the Folder is created with type: string + x-kubernetes-validations: + - message: spec.uid is immutable + rule: self == oldSelf required: - instanceSelector type: object @@ -129,6 +137,9 @@ spec: rule: (has(self.parentFolderUID) && !(has(self.parentFolderRef))) || (has(self.parentFolderRef) && !(has(self.parentFolderUID))) || !(has(self.parentFolderRef) && (has(self.parentFolderUID))) + - message: spec.uid is immutable + rule: ((!has(oldSelf.uid) && !has(self.uid)) || (has(oldSelf.uid) && + has(self.uid))) status: description: GrafanaFolderStatus defines the observed state of GrafanaFolder properties: diff --git a/deploy/kustomize/base/crds.yaml b/deploy/kustomize/base/crds.yaml index 9e8b9208d..e409864e6 100644 --- a/deploy/kustomize/base/crds.yaml +++ b/deploy/kustomize/base/crds.yaml @@ -1348,11 +1348,11 @@ spec: description: GrafanaFolderSpec defines the desired state of GrafanaFolder properties: allowCrossNamespaceImport: - description: allow to import this resources from an operator in a - different namespace + description: Enable matching Grafana instances outside the current + namespace type: boolean instanceSelector: - description: selects Grafanas for import + description: Selects Grafanas for import properties: matchExpressions: description: matchExpressions is a list of label selector requirements. @@ -1409,17 +1409,25 @@ spec: be created type: string permissions: - description: raw json with folder permissions + description: Raw json with folder permissions, potentially exported + from Grafana type: string resyncPeriod: default: 5m - description: how often the folder is synced, defaults to 5m if not + description: How often the folder is synced, defaults to 5m if not set format: duration pattern: ^([0-9]+(\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$ type: string title: + description: Display name of the folder in Grafana type: string + uid: + description: Manually specify the UID the Folder is created with + type: string + x-kubernetes-validations: + - message: spec.uid is immutable + rule: self == oldSelf required: - instanceSelector type: object @@ -1428,6 +1436,9 @@ spec: rule: (has(self.parentFolderUID) && !(has(self.parentFolderRef))) || (has(self.parentFolderRef) && !(has(self.parentFolderUID))) || !(has(self.parentFolderRef) && (has(self.parentFolderUID))) + - message: spec.uid is immutable + rule: ((!has(oldSelf.uid) && !has(self.uid)) || (has(oldSelf.uid) && + has(self.uid))) status: description: GrafanaFolderStatus defines the observed state of GrafanaFolder properties: diff --git a/docs/docs/api.md b/docs/docs/api.md index 7b85fe07c..5799ca3a8 100644 --- a/docs/docs/api.md +++ b/docs/docs/api.md @@ -2807,7 +2807,7 @@ GrafanaFolder is the Schema for the grafanafolders API GrafanaFolderSpec defines the desired state of GrafanaFolder

- Validations:
  • (has(self.parentFolderUID) && !(has(self.parentFolderRef))) || (has(self.parentFolderRef) && !(has(self.parentFolderUID))) || !(has(self.parentFolderRef) && (has(self.parentFolderUID))): Only one of parentFolderUID or parentFolderRef can be set
  • + Validations:
  • (has(self.parentFolderUID) && !(has(self.parentFolderRef))) || (has(self.parentFolderRef) && !(has(self.parentFolderUID))) || !(has(self.parentFolderRef) && (has(self.parentFolderUID))): Only one of parentFolderUID or parentFolderRef can be set
  • ((!has(oldSelf.uid) && !has(self.uid)) || (has(oldSelf.uid) && has(self.uid))): spec.uid is immutable
  • false @@ -2841,7 +2841,7 @@ GrafanaFolderSpec defines the desired state of GrafanaFolder instanceSelector object - selects Grafanas for import
    + Selects Grafanas for import

    Validations:
  • self == oldSelf: Value is immutable
  • @@ -2850,7 +2850,7 @@ GrafanaFolderSpec defines the desired state of GrafanaFolder allowCrossNamespaceImport boolean - allow to import this resources from an operator in a different namespace
    + Enable matching Grafana instances outside the current namespace
    false @@ -2871,14 +2871,14 @@ GrafanaFolderSpec defines the desired state of GrafanaFolder permissions string - raw json with folder permissions
    + Raw json with folder permissions, potentially exported from Grafana
    false resyncPeriod string - how often the folder is synced, defaults to 5m if not set
    + How often the folder is synced, defaults to 5m if not set

    Format: duration
    Default: 5m
    @@ -2888,7 +2888,16 @@ GrafanaFolderSpec defines the desired state of GrafanaFolder title string + Display name of the folder in Grafana
    + + false + + uid + string + + Manually specify the UID the Folder is created with

    + Validations:
  • self == oldSelf: spec.uid is immutable
  • false @@ -2900,7 +2909,7 @@ GrafanaFolderSpec defines the desired state of GrafanaFolder -selects Grafanas for import +Selects Grafanas for import diff --git a/hack/kind/start-kind.sh b/hack/kind/start-kind.sh index e9507f5e7..f8cb5ec85 100755 --- a/hack/kind/start-kind.sh +++ b/hack/kind/start-kind.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +KIND=${KIND:-kind} KIND_CLUSTER_NAME=${KIND_CLUSTER_NAME:-kind-grafana} KUBECONFIG=${KUBECONFIG:-~/.kube/kind-grafana-operator} CRD_NS=${CRD_NS:-grafana-crds} @@ -6,19 +7,19 @@ CRD_NS=${CRD_NS:-grafana-crds} set -eu # Find the script directory -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) # Make sure there is no current cluster echo "Delete existing cluster" -kind --kubeconfig="${KUBECONFIG}" delete cluster --name "${KIND_CLUSTER_NAME}" \ - || echo "There was no existing cluster" +${KIND} --kubeconfig="${KUBECONFIG}" delete cluster --name "${KIND_CLUSTER_NAME}" || + echo "There was no existing cluster" # Start kind cluster echo "" echo "###############################" echo "# 1. Start kind cluster #" echo "###############################" -kind --kubeconfig "${KUBECONFIG}" create cluster \ +${KIND} --kubeconfig "${KUBECONFIG}" create cluster \ --name "${KIND_CLUSTER_NAME}" \ --wait 120s \ --config="${SCRIPT_DIR}/resources/cluster.yaml" @@ -34,10 +35,10 @@ echo "###############################" kubectl --kubeconfig="${KUBECONFIG}" \ apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml kubectl --kubeconfig="${KUBECONFIG}" \ - -n ingress-nginx \ - wait deploy ingress-nginx-controller \ - --for condition=Available \ - --timeout=90s + -n ingress-nginx \ + wait deploy ingress-nginx-controller \ + --for condition=Available \ + --timeout=90s # Will install the CRD:s echo ""