diff --git a/README.md b/README.md index e9b0b6c7..49e2f2e3 100644 --- a/README.md +++ b/README.md @@ -39,27 +39,38 @@ See all targets with `make help` ### QuickStart Demonstration 1. Get an API token exoscale.com -1. `export EXOSCALE_API_KEY=` -1. `export EXOSCALE_API_SECRET=` -1. `make local-install` +2. `export EXOSCALE_API_KEY=` +3. `export EXOSCALE_API_SECRET=` +4. `make local-install` ### Kubernetes Webhook Troubleshooting The provider comes with mutating and validation admission webhook server. -To test and troubleshoot the webhooks on the cluster, simply apply your changes with `kubectl`. +1. `make local-debug` -1. To debug the webhook in an IDE, we need to generate certificates: +2. Set the right host ip: ```bash - make webhook-cert + HOSTIP=$(docker inspect kindev-control-plane | jq '.[0].NetworkSettings.Networks.kind.Gateway') # On kind MacOS/Windows + HOSTIP=host.docker.internal # On Docker Desktop distributions + HOSTIP=host.lima.internal # On Lima backed Docker distributions + For Linux users: `ip -4 addr show dev docker0 | grep inet | awk -F' ' '{print $2}' | awk -F'/' '{print $1}'` ``` -2. Start the operator in your IDE with `WEBHOOK_TLS_CERT_DIR` environment set to `.kind`. - -3. Send an admission request sample of the spec: + +3. Get an Exoscale API secret and key and create the following secret: + ```bash + EXOSCALE_API_KEY= + EXOSCALE_API_SECRET= + kubectl -n crossplane-system create secret generic api-secret-1 --from-literal=EXOSCALE_API_KEY="$EXOSCALE_API_KEY" --from-literal=EXOSCALE_API_SECRET="$EXOSCALE_API_SECRET" + ``` +4. Run the debug target: ```bash - # send an admission request - curl -k -v -H "Content-Type: application/json" --data @samples/admission.k8s.io_admissionreview.json https://localhost:9443/validate-exoscale-crossplane-io-v1-iamkey + make webhook-debug -e webhook_service_name=$HOSTIP ``` +5. Run the operator from IDE in debug mode with env variable: + ```bash + WEBHOOK_TLS_CERT_DIR=.kind # or full path if does not work + ``` ### Crossplane Provider Mechanics diff --git a/generate_sample.go b/generate_sample.go index b5bbb93a..93a7463e 100644 --- a/generate_sample.go +++ b/generate_sample.go @@ -299,7 +299,6 @@ func newKafkaSample() *exoscalev1.Kafka { }, IPFilter: exoscalev1.IPFilter{"0.0.0.0/0"}, }, - Version: "3.2", KafkaSettings: runtime.RawExtension{Raw: []byte(`{"connections_max_idle_ms": 60000}`)}, }, }, diff --git a/operator/kafkacontroller/webhook.go b/operator/kafkacontroller/webhook.go index 72ab64d0..4763af14 100644 --- a/operator/kafkacontroller/webhook.go +++ b/operator/kafkacontroller/webhook.go @@ -63,7 +63,7 @@ func (v *Validator) validateCreateWithExoClient(ctx context.Context, obj runtime err = v.validateVersion(ctx, obj, *availableVersions) if err != nil { - return err + return fmt.Errorf("invalid version, allowed versions are %v: %w", *availableVersions, err) } } diff --git a/package/package.mk b/package/package.mk index ae92ecf8..d38ded52 100644 --- a/package/package.mk +++ b/package/package.mk @@ -17,7 +17,7 @@ $(up_bin):export VERSION=v0.30.0 $(up_bin): | $(go_bin) curl -sL "https://cli.upbound.io" | sh @mv up $@ - $(up_bin) --version + $(up_bin) version .PHONY: package package: ## All-in-one packaging and releasing @@ -28,7 +28,7 @@ package-provider-local: export CONTROLLER_IMG = $(CONTAINER_IMG) package-provider-local: $(crossplane_bin) generate-go ## Build Crossplane package for local installation in kind-cluster @rm -rf package/*.xpkg @yq e '.spec.controller.image=strenv(CONTROLLER_IMG)' $(package_dir)/crossplane.yaml.template > $(package_dir)/crossplane.yaml - @$(crossplane_bin) build provider -f $(package_dir) + @$(crossplane_bin) xpkg build -f $(package_dir) @echo Package file: $$(ls $(package_dir)/*.xpkg) .PHONY: package-provider @@ -41,12 +41,12 @@ package-provider: $(up_bin) generate-go build-docker ## Build Crossplane package .PHONY: .local-package-push .local-package-push: pkg_file = $(shell ls $(package_dir)/*.xpkg) .local-package-push: $(crossplane_bin) package-provider-local - $(crossplane_bin) push provider -f $(pkg_file) $(LOCAL_PACKAGE_IMG) + $(crossplane_bin) xpkg push -f $(pkg_file) $(LOCAL_PACKAGE_IMG) .PHONY: .ghcr-package-push .ghcr-package-push: pkg_file = $(package_dir)/provider-exoscale.xpkg .ghcr-package-push: $(crossplane_bin) package-provider - $(crossplane_bin) push provider -f $(pkg_file) $(GHCR_PACKAGE_IMG) + $(crossplane_bin) xpkg push -f $(pkg_file) $(GHCR_PACKAGE_IMG) .PHONY: .upbound-package-push .upbound-package-push: pkg_file = $(package_dir)/provider-exoscale.xpkg diff --git a/test/local.mk b/test/local.mk index 4e858ffe..6d091d8a 100644 --- a/test/local.mk +++ b/test/local.mk @@ -5,12 +5,16 @@ registry_sentinel = $(kind_dir)/registry_sentinel local-install: export KUBECONFIG = $(KIND_KUBECONFIG) # for ControllerConfig: local-install: export INTERNAL_PACKAGE_IMG = registry.registry-system.svc.cluster.local:5000/$(PROJECT_OWNER)/$(PROJECT_NAME)/package:$(IMG_TAG) -local-install: kind-load-image crossplane-setup registry-setup .local-package-push ## Install Operator in local cluster +local-install: local-debug ## Install Operator in local cluster yq e '.spec.metadata.annotations."local.dev/installed"="$(shell date)"' test/controllerconfig-exoscale.yaml | kubectl apply -f - yq e '.spec.package=strenv(INTERNAL_PACKAGE_IMG)' test/provider-exoscale.yaml | kubectl apply -f - kubectl wait --for condition=Healthy provider.pkg.crossplane.io/provider-exoscale --timeout 60s kubectl -n crossplane-system wait --for condition=Ready $$(kubectl -n crossplane-system get pods -o name -l pkg.crossplane.io/provider=provider-exoscale) --timeout 60s +.PHONY: local-debug +local-debug: export KUBECONFIG = $(KIND_KUBECONFIG) +local-debug: kind-load-image crossplane-setup registry-setup .local-package-push ## Install Operator in local cluster + .PHONY: crossplane-setup crossplane-setup: $(crossplane_sentinel) ## Installs Crossplane in kind cluster. @@ -95,18 +99,6 @@ webhook_key = $(kind_dir)/tls.key webhook_cert = $(kind_dir)/tls.crt webhook_service_name = provider-exocale.crossplane-system.svc -# Generate webhook certificates. -# This is only relevant when running in IDE with debugger. -# When installed as a provider, Crossplane handles the certificate generation. -.PHONY: webhook-cert -webhook-cert: $(webhook_cert) ## Generate webhook certificates for out-of-cluster debugging in an IDE - -$(webhook_key): - openssl req -x509 -newkey rsa:4096 -nodes -keyout $@ --noout -days 3650 -subj "/CN=$(webhook_service_name)" -addext "subjectAltName = DNS:$(webhook_service_name)" - -$(webhook_cert): $(webhook_key) - openssl req -x509 -key $(webhook_key) -nodes -out $@ -days 3650 -subj "/CN=$(webhook_service_name)" -addext "subjectAltName = DNS:$(webhook_service_name)" - ### ### E2E Tests ### with KUTTL (https://kuttl.dev) @@ -148,3 +140,41 @@ run-single-e2e: $(kuttl_bin) $(mc_bin) local-install provider-config ## Run spec echo "no kubeconfig found"; \ fi rm -f $(kuttl_bin) $(mc_bin) + +.PHONY: webhook-debug +webhook_service_name = host.docker.internal + +webhook-debug: export KUBECONFIG = $(KIND_KUBECONFIG) +webhook-debug: $(webhook_cert) ## Creates certificates, patches the webhook registrations and applies everything to the given kube cluster +webhook-debug: + kubectl apply -f package/crds/ + kubectl apply -f package/webhook/manifests.yaml + kubectl apply -f samples/exoscale.crossplane.io_providerconfig.yaml + kubectl apply -f samples/lab-provider-keys-exo.yaml + cabundle=$$(cat $(kind_dir)/tls.crt | base64) && \ + kubectl annotate validatingwebhookconfigurations.admissionregistration.k8s.io validating-webhook-configuration kubectl.kubernetes.io/last-applied-configuration- && \ + kubectl annotate validatingwebhookconfigurations.admissionregistration.k8s.io validating-webhook-configuration cert-manager.io/inject-ca-from- && \ + kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io validating-webhook-configuration -oyaml | \ + yq e "with(.webhooks[]; .clientConfig.caBundle = \"$$cabundle\") | with(.webhooks[]; .clientConfig.url = \"https://$(webhook_service_name):9443\" + .clientConfig.service.path) | with(.webhooks[]; del(.clientConfig.service))" | \ + kubectl replace -f - && \ + kubectl annotate validatingwebhookconfigurations.admissionregistration.k8s.io validating-webhook-configuration kubectl.kubernetes.io/last-applied-configuration- + +# Generate webhook certificates. +# This is only relevant when debugging. +# Component-appcat installs a proper certificate for this. +.PHONY: webhook-cert +webhook-cert: $(webhook_cert) ## Generate webhook certificates for out-of-cluster debugging in an IDE + +$(webhook_key): + ipsan="" && \ + if [[ $(webhook_service_name) =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$$ ]]; then \ + ipsan=", IP:$(webhook_service_name)"; \ + fi; \ + openssl req -x509 -newkey rsa:4096 -nodes -keyout $@ --noout -days 3650 -subj "/CN=$(webhook_service_name)" -addext "subjectAltName = DNS:$(webhook_service_name)$$ipsan" + +$(webhook_cert): $(webhook_key) + ipsan="" && \ + if [[ $(webhook_service_name) =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$$ ]]; then \ + ipsan=", IP:$(webhook_service_name)"; \ + fi; \ + openssl req -x509 -key $(webhook_key) -nodes -out $@ -days 3650 -subj "/CN=$(webhook_service_name)" -addext "subjectAltName = DNS:$(webhook_service_name)$$ipsan"