diff --git a/.envrc.sample b/.envrc.sample index e39f4a2bf..506e15820 100644 --- a/.envrc.sample +++ b/.envrc.sample @@ -5,7 +5,7 @@ export SSH_KEY_NAME=my-caph-ssh-key export HCLOUD_REGION=fsn1 export CONTROL_PLANE_MACHINE_COUNT=1 export WORKER_MACHINE_COUNT=1 -export KUBERNETES_VERSION=v1.31.6 +export KUBERNETES_VERSION=v1.33.6 export HCLOUD_CONTROL_PLANE_MACHINE_TYPE=cpx31 export HCLOUD_WORKER_MACHINE_TYPE=cpx31 export SSH_KEY=$HOME/.ssh/my-caph-ssh-key.pub diff --git a/.github/actions/e2e/action.yaml b/.github/actions/e2e/action.yaml index 915171e61..59b0b2516 100644 --- a/.github/actions/e2e/action.yaml +++ b/.github/actions/e2e/action.yaml @@ -58,9 +58,9 @@ runs: - name: Prepull the pre-built image shell: bash - run: docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${TAG} + run: docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${CAPH_CONTAINER_TAG} env: - TAG: ${{ steps.meta.outputs.version }} + CAPH_CONTAINER_TAG: ${{ steps.meta.outputs.version }} - name: Get HCLOUD_TOKEN # sets env.HCLOUD_TOKEN uses: hetznercloud/tps-action@dee5dd2546322c28ed8f74b910189066e8b6f31a # main @@ -71,14 +71,14 @@ runs: CI: "true" REGISTRY: ${{ env.REGISTRY }} IMAGE_NAME: ${{ env.IMAGE_NAME }} - TAG: ${{ steps.meta.outputs.version }} + CAPH_CONTAINER_TAG: ${{ steps.meta.outputs.version }} HCLOUD_TOKEN: ${{ env.HCLOUD_TOKEN }} HETZNER_ROBOT_USER: ${{ inputs.e2e_robot_user }} HETZNER_ROBOT_PASSWORD: ${{ inputs.e2e_robot_password }} HETZNER_SSH_PUB: ${{ inputs.e2e_ssh_pub }} HETZNER_SSH_PRIV: ${{ inputs.e2e_ssh_priv }} SKIP_IMAGE_BUILD: "1" - CAPH_LATEST_VERSION: "v1.0.1" + CAPH_LATEST_VERSION: "v1.0.7" run: make ${{ inputs.e2e_make_target }} - name: Upload artifact diff --git a/.github/actions/test-release/action.yaml b/.github/actions/test-release/action.yaml index c7a340671..79f77a8b1 100644 --- a/.github/actions/test-release/action.yaml +++ b/.github/actions/test-release/action.yaml @@ -25,7 +25,7 @@ runs: - name: Test Release shell: bash env: - TAG: ${{ steps.meta.outputs.version }} + CAPH_CONTAINER_TAG: ${{ steps.meta.outputs.version }} run: make test-release - name: Upload artifact diff --git a/.github/workflows/main-promote-builder-image.yml b/.github/workflows/main-promote-builder-image.yml index 83cd7128e..fc8e6d700 100644 --- a/.github/workflows/main-promote-builder-image.yml +++ b/.github/workflows/main-promote-builder-image.yml @@ -25,4 +25,4 @@ jobs: env: PASSWORD: ${{ secrets.GITHUB_TOKEN }} USERNAME: ${{ github.actor }} - run: make builder-image-promote-latest \ No newline at end of file + run: make builder-image-promote-latest diff --git a/.github/workflows/schedule-scan-image.yml b/.github/workflows/schedule-scan-image.yml index 3753d2b3f..391610f91 100644 --- a/.github/workflows/schedule-scan-image.yml +++ b/.github/workflows/schedule-scan-image.yml @@ -25,4 +25,4 @@ jobs: env: TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} TRIVY_USERNAME: ${{ github.actor }} - run: make verify-container-images \ No newline at end of file + run: make verify-container-images diff --git a/.gitignore b/.gitignore index 58bdd299e..aa51bc41b 100644 --- a/.gitignore +++ b/.gitignore @@ -62,7 +62,7 @@ resp.json # release artifacts out _releasenotes -templates/cluster-templates/cluster-template* +/generated/v1* # Helm .helm diff --git a/Makefile b/Makefile index 132fb6c32..b7f473ba8 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ MGT_CLUSTER_KUBECONFIG ?= ".mgt-cluster-kubeconfig.yaml" # Kubebuilder. # go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest # The command `setup-envtest list` shows the available versions. -export KUBEBUILDER_ENVTEST_KUBERNETES_VERSION ?= 1.31.0 +export KUBEBUILDER_ENVTEST_KUBERNETES_VERSION ?= 1.33.0 ##@ Binaries ############ @@ -92,67 +92,65 @@ export KUBEBUILDER_ENVTEST_KUBERNETES_VERSION ?= 1.31.0 KUSTOMIZE := $(abspath $(TOOLS_BIN_DIR)/kustomize) kustomize: $(KUSTOMIZE) ## Build a local copy of kustomize $(KUSTOMIZE): # Build kustomize from tools folder. - go install sigs.k8s.io/kustomize/kustomize/v4@v4.5.7 + go install sigs.k8s.io/kustomize/kustomize/v5@v5.8.0 TILT := $(abspath $(TOOLS_BIN_DIR)/tilt) tilt: $(TILT) ## Build a local copy of tilt $(TILT): @mkdir -p $(TOOLS_BIN_DIR) - MINIMUM_TILT_VERSION=0.33.3 hack/ensure-tilt.sh - -ENVSUBST := $(abspath $(TOOLS_BIN_DIR)/envsubst) -envsubst: $(ENVSUBST) ## Build a local copy of envsubst -$(ENVSUBST): # Build envsubst from tools folder. - go install github.com/drone/envsubst/v2/cmd/envsubst@latest + MINIMUM_TILT_VERSION=0.35.2 hack/ensure-tilt.sh SETUP_ENVTEST := $(abspath $(TOOLS_BIN_DIR)/setup-envtest) + +.PHONY: setup-envtest setup-envtest: $(SETUP_ENVTEST) ## Build a local copy of setup-envtest $(SETUP_ENVTEST): # Build setup-envtest from tools folder. - go install sigs.k8s.io/controller-runtime/tools/setup-envtest@v0.0.0-20250310021545-f80bc5dbf8f7 + go install sigs.k8s.io/controller-runtime/tools/setup-envtest@v0.0.0-20251126220622-4b46eb04d57f CTLPTL := $(abspath $(TOOLS_BIN_DIR)/ctlptl) ctlptl: $(CTLPTL) ## Build a local copy of ctlptl $(CTLPTL): - go install github.com/tilt-dev/ctlptl/cmd/ctlptl@v0.8.25 + go install github.com/tilt-dev/ctlptl/cmd/ctlptl@v0.8.43 CLUSTERCTL := $(abspath $(TOOLS_BIN_DIR)/clusterctl) clusterctl: $(CLUSTERCTL) ## Build a local copy of clusterctl $(CLUSTERCTL): - go install sigs.k8s.io/cluster-api/cmd/clusterctl@v1.10.7 + go install sigs.k8s.io/cluster-api/cmd/clusterctl@v1.10.9 HCLOUD := $(abspath $(TOOLS_BIN_DIR)/hcloud) hcloud: $(HCLOUD) ## Build a local copy of hcloud $(HCLOUD): - curl -sSL https://github.com/hetznercloud/cli/releases/download/v1.43.1/hcloud-$$(go env GOOS)-$$(go env GOARCH).tar.gz | tar xz -C $(TOOLS_BIN_DIR) hcloud + curl -sSL https://github.com/hetznercloud/cli/releases/download/v1.57.0/hcloud-$$(go env GOOS)-$$(go env GOARCH).tar.gz | tar xz -C $(TOOLS_BIN_DIR) hcloud chmod a+rx $(HCLOUD) KIND := $(abspath $(TOOLS_BIN_DIR)/kind) kind: $(KIND) ## Build a local copy of kind $(KIND): - go install sigs.k8s.io/kind@v0.23.0 + go install sigs.k8s.io/kind@v0.30.0 KUBECTL := $(abspath $(TOOLS_BIN_DIR)/kubectl) -kubectl: $(KUBECTL) ## Build a local copy of kubectl +kubectl: $(TOOLS_BIN_DIR) $(KUBECTL) ## Build a local copy of kubectl $(KUBECTL): - curl -fsSL "https://dl.k8s.io/release/v1.31.6/bin/$$(go env GOOS)/$$(go env GOARCH)/kubectl" -o $(KUBECTL) + mkdir -p $(TOOLS_BIN_DIR) + curl -fsSL "https://dl.k8s.io/release/v1.33.6/bin/$$(go env GOOS)/$$(go env GOARCH)/kubectl" -o $(KUBECTL) chmod a+rx $(KUBECTL) go-binsize-treemap := $(abspath $(TOOLS_BIN_DIR)/go-binsize-treemap) go-binsize-treemap: $(go-binsize-treemap) # Build go-binsize-treemap from tools folder. $(go-binsize-treemap): - go install github.com/nikolaydubina/go-binsize-treemap@v0.2.0 + go install github.com/nikolaydubina/go-binsize-treemap@v0.2.3 go-cover-treemap := $(abspath $(TOOLS_BIN_DIR)/go-cover-treemap) go-cover-treemap: $(go-cover-treemap) # Build go-cover-treemap from tools folder. $(go-cover-treemap): - go install github.com/nikolaydubina/go-cover-treemap@v1.3.0 + go install github.com/nikolaydubina/go-cover-treemap@v1.5.0 GOTESTSUM := $(abspath $(TOOLS_BIN_DIR)/gotestsum) gotestsum: $(GOTESTSUM) # Build gotestsum from tools folder. $(GOTESTSUM): - go install gotest.tools/gotestsum@v1.11.0 + go install gotest.tools/gotestsum@v1.13.0 -all-tools: $(GOTESTSUM) $(go-cover-treemap) $(go-binsize-treemap) $(KIND) $(KUBECTL) $(CLUSTERCTL) $(CTLPTL) $(SETUP_ENVTEST) $(ENVSUBST) $(KUSTOMIZE) ## Install all tools required for development +all-tools: $(GOTESTSUM) $(go-cover-treemap) $(go-binsize-treemap) $(KIND) $(KUBECTL) $(CLUSTERCTL) $(CTLPTL) $(SETUP_ENVTEST) $(KUSTOMIZE) ## Install all tools required for development echo 'done' ##@ Development @@ -178,6 +176,9 @@ wait-and-get-secret: $(KUBECTL) ./hack/ensure-env-variables.sh CLUSTER_NAME # Wait for the kubeconfig to become available. rm -f $(WORKER_CLUSTER_KUBECONFIG) + @echo + @echo "You can use 'make watch' to get an overview" + @echo ${TIMEOUT} --foreground 5m bash -c "while ! $(KUBECTL) get secrets | grep $(CLUSTER_NAME)-kubeconfig; do sleep 1; done" # Get kubeconfig and store it locally. ./hack/get-kubeconfig-of-workload-cluster.sh @@ -204,76 +205,45 @@ else KUBECONFIG=$(WORKER_CLUSTER_KUBECONFIG) helm upgrade --install ccm syself/ccm-hetzner --version 2.0.1 \ --namespace kube-system \ --set privateNetwork.enabled=$(PRIVATE_NETWORK) + @echo @echo 'run "kubectl --kubeconfig=$(WORKER_CLUSTER_KUBECONFIG) ..." to work with the new target cluster' + @echo + @echo "Use 'make watch' to get an overview of the resources, events and logs" + @echo endif add-ssh-pub-key: - ./hack/ensure-env-variables.sh HCLOUD_TOKEN SSH_KEY SSH_KEY_NAME - SSH_KEY_CONTENT=$$(cat $(SSH_KEY)) ; \ - curl -sS \ - -X POST \ - -H "Authorization: Bearer $${HCLOUD_TOKEN}" \ - -H "Content-Type: application/json" \ - -d '{"labels":{},"name":"${SSH_KEY_NAME}","public_key":"'"$${SSH_KEY_CONTENT}"'"}' \ - 'https://api.hetzner.cloud/v1/ssh_keys' + ./hack/ensure-ssh-key-in-hcloud.sh env-vars-for-wl-cluster: @./hack/ensure-env-variables.sh CLUSTER_NAME CONTROL_PLANE_MACHINE_COUNT HCLOUD_CONTROL_PLANE_MACHINE_TYPE \ HCLOUD_REGION SSH_KEY_NAME HCLOUD_WORKER_MACHINE_TYPE KUBERNETES_VERSION WORKER_MACHINE_COUNT -create-workload-cluster-hcloud: env-vars-for-wl-cluster $(KUSTOMIZE) $(ENVSUBST) install-crds ## Creates a workload-cluster. +create-workload-cluster-hcloud: env-vars-for-wl-cluster $(KUSTOMIZE) install-crds ## Creates a workload-cluster. # Create workload Cluster. ./hack/ensure-env-variables.sh HCLOUD_TOKEN - $(KUBECTL) create secret generic $(INFRA_PROVIDER) --from-literal=hcloud=$(HCLOUD_TOKEN) --save-config --dry-run=client -o yaml | $(KUBECTL) apply -f - - $(KUSTOMIZE) build templates/cluster-templates/hcloud --load-restrictor LoadRestrictionsNone > templates/cluster-templates/cluster-template-hcloud.yaml - cat templates/cluster-templates/cluster-template-hcloud.yaml | $(ENVSUBST) - | $(KUBECTL) apply -f - - $(MAKE) wait-and-get-secret - $(MAKE) install-cilium-in-wl-cluster - $(MAKE) install-ccm-in-wl-cluster + ./hack/create-workload-cluster.sh v1beta1 hcloud -create-workload-cluster-hcloud-network: env-vars-for-wl-cluster $(KUSTOMIZE) $(ENVSUBST) ## Creates a workload-cluster. +create-workload-cluster-hcloud-network: env-vars-for-wl-cluster $(KUSTOMIZE) ## Creates a workload-cluster. # Create workload Cluster. ./hack/ensure-env-variables.sh HCLOUD_TOKEN - $(KUBECTL) create secret generic $(INFRA_PROVIDER) --from-literal=hcloud=$(HCLOUD_TOKEN) --save-config --dry-run=client -o yaml | $(KUBECTL) apply -f - - $(KUSTOMIZE) build templates/cluster-templates/hcloud-network --load-restrictor LoadRestrictionsNone > templates/cluster-templates/cluster-template-hcloud-network.yaml - cat templates/cluster-templates/cluster-template-hcloud-network.yaml | $(ENVSUBST) - | $(KUBECTL) apply -f - - $(MAKE) wait-and-get-secret - $(MAKE) install-cilium-in-wl-cluster - $(MAKE) install-ccm-in-wl-cluster PRIVATE_NETWORK=true + ./hack/create-workload-cluster.sh v1beta1 hcloud-network # Use that, if you want to test hcloud control-planes, hcloud worker and bm worker. -create-workload-cluster-hetzner-hcloud-control-plane: env-vars-for-wl-cluster $(KUSTOMIZE) $(ENVSUBST) ## Creates a workload-cluster. +create-workload-cluster-hetzner-hcloud-control-plane: env-vars-for-wl-cluster $(KUSTOMIZE) ## Creates a workload-cluster. # Create workload Cluster. ./hack/ensure-env-variables.sh HCLOUD_TOKEN HETZNER_ROBOT_USER HETZNER_ROBOT_PASSWORD HETZNER_SSH_PRIV_PATH HETZNER_SSH_PUB_PATH SSH_KEY_NAME - $(KUBECTL) create secret generic $(INFRA_PROVIDER) --from-literal=hcloud=$(HCLOUD_TOKEN) --from-literal=robot-user=$(HETZNER_ROBOT_USER) --from-literal=robot-password=$(HETZNER_ROBOT_PASSWORD) --save-config --dry-run=client -o yaml | $(KUBECTL) apply -f - - $(KUBECTL) create secret generic robot-ssh --from-literal=sshkey-name=$(SSH_KEY_NAME) --from-file=ssh-privatekey=${HETZNER_SSH_PRIV_PATH} --from-file=ssh-publickey=${HETZNER_SSH_PUB_PATH} --save-config --dry-run=client -o yaml | $(KUBECTL) apply -f - - $(KUSTOMIZE) build templates/cluster-templates/$(INFRA_PROVIDER)-hcloud-control-planes --load-restrictor LoadRestrictionsNone > templates/cluster-templates/cluster-template-$(INFRA_PROVIDER)-hcloud-control-planes.yaml - cat templates/cluster-templates/cluster-template-$(INFRA_PROVIDER)-hcloud-control-planes.yaml | $(ENVSUBST) - | $(KUBECTL) apply -f - - $(MAKE) wait-and-get-secret - $(MAKE) install-cilium-in-wl-cluster - $(MAKE) install-ccm-in-wl-cluster + ./hack/create-workload-cluster.sh --robot v1beta1 hetzner-hcloud-control-planes -create-workload-cluster-hetzner-baremetal-control-plane: env-vars-for-wl-cluster $(KUSTOMIZE) $(ENVSUBST) ## Creates a workload-cluster. +create-workload-cluster-hetzner-baremetal-control-plane: env-vars-for-wl-cluster $(KUSTOMIZE) ## Creates a workload-cluster. # Create workload Cluster. ./hack/ensure-env-variables.sh HCLOUD_TOKEN HETZNER_ROBOT_USER HETZNER_ROBOT_PASSWORD HETZNER_SSH_PRIV_PATH HETZNER_SSH_PUB_PATH SSH_KEY_NAME - $(KUBECTL) create secret generic $(INFRA_PROVIDER) --from-literal=hcloud=$(HCLOUD_TOKEN) --from-literal=robot-user=$(HETZNER_ROBOT_USER) --from-literal=robot-password=$(HETZNER_ROBOT_PASSWORD) --save-config --dry-run=client -o yaml | $(KUBECTL) apply -f - - $(KUBECTL) create secret generic robot-ssh --from-literal=sshkey-name=$(SSH_KEY_NAME) --from-file=ssh-privatekey=${HETZNER_SSH_PRIV_PATH} --from-file=ssh-publickey=${HETZNER_SSH_PUB_PATH} --save-config --dry-run=client -o yaml | $(KUBECTL) apply -f - - $(KUSTOMIZE) build templates/cluster-templates/$(INFRA_PROVIDER)-baremetal-control-planes --load-restrictor LoadRestrictionsNone > templates/cluster-templates/cluster-template-$(INFRA_PROVIDER)-baremetal-control-planes.yaml - cat templates/cluster-templates/cluster-template-$(INFRA_PROVIDER)-baremetal-control-planes.yaml | $(ENVSUBST) - | $(KUBECTL) apply -f - - $(MAKE) wait-and-get-secret - $(MAKE) install-cilium-in-wl-cluster - $(MAKE) install-ccm-in-wl-cluster + ./hack/create-workload-cluster.sh --robot v1beta1 hetzner-baremetal-control-plane -create-workload-cluster-hetzner-baremetal-control-plane-remediation: env-vars-for-wl-cluster $(KUSTOMIZE) $(ENVSUBST) ## Creates a workload-cluster. +create-workload-cluster-hetzner-baremetal-control-plane-remediation: env-vars-for-wl-cluster $(KUSTOMIZE) ## Creates a workload-cluster. # Create workload Cluster. ./hack/ensure-env-variables.sh HCLOUD_TOKEN HETZNER_ROBOT_USER HETZNER_ROBOT_PASSWORD HETZNER_SSH_PRIV_PATH HETZNER_SSH_PUB_PATH SSH_KEY_NAME - $(KUBECTL) create secret generic $(INFRA_PROVIDER) --from-literal=hcloud=$(HCLOUD_TOKEN) --from-literal=robot-user=$(HETZNER_ROBOT_USER) --from-literal=robot-password=$(HETZNER_ROBOT_PASSWORD) --save-config --dry-run=client -o yaml | $(KUBECTL) apply -f - - $(KUBECTL) create secret generic robot-ssh --from-literal=sshkey-name=$(SSH_KEY_NAME) --from-file=ssh-privatekey=${HETZNER_SSH_PRIV_PATH} --from-file=ssh-publickey=${HETZNER_SSH_PUB_PATH} --save-config --dry-run=client -o yaml | $(KUBECTL) apply -f - - $(KUSTOMIZE) build templates/cluster-templates/$(INFRA_PROVIDER)-baremetal-control-planes-remediation --load-restrictor LoadRestrictionsNone > templates/cluster-templates/cluster-template-$(INFRA_PROVIDER)-baremetal-control-planes-remediation.yaml - cat templates/cluster-templates/cluster-template-$(INFRA_PROVIDER)-baremetal-control-planes-remediation.yaml | $(ENVSUBST) - | $(KUBECTL) apply -f - - $(MAKE) wait-and-get-secret - $(MAKE) install-cilium-in-wl-cluster - $(MAKE) install-ccm-in-wl-cluster + ./hack/create-workload-cluster.sh --robot v1beta1 hetzner-baremetal-control-plane-remediation move-to-workload-cluster: $(CLUSTERCTL) $(CLUSTERCTL) init --kubeconfig=$(WORKER_CLUSTER_KUBECONFIG) --core cluster-api --bootstrap kubeadm --control-plane kubeadm --infrastructure $(INFRA_PROVIDER) @@ -289,13 +259,18 @@ delete-workload-cluster: ## Deletes the example workload Kubernetes cluster ${TIMEOUT} --foreground 15m bash -c "while $(KUBECTL) get cluster | grep $(NAME); do sleep 1; done" @echo 'Cluster deleted' -create-mgt-cluster: $(CLUSTERCTL) $(KUBECTL) cluster ## Start a mgt-cluster with the latest version of all capi components and the infra provider. +create-mgt-cluster: $(CLUSTERCTL) $(KUBECTL) cluster ## Start a mgt-cluster with the latest **released** version of all capi components and the infra provider. $(CLUSTERCTL) init --core cluster-api --bootstrap kubeadm --control-plane kubeadm --infrastructure $(INFRA_PROVIDER) $(KUBECTL) create secret generic $(INFRA_PROVIDER) --from-literal=hcloud=$(HCLOUD_TOKEN) --save-config --dry-run=client -o yaml | $(KUBECTL) apply -f - $(KUBECTL) patch secret $(INFRA_PROVIDER) -p '{"metadata":{"labels":{"clusterctl.cluster.x-k8s.io/move":""}}}' + @echo + @echo "Your next step, for example:" + @echo " ./hack/update-operator-dev-deployment.sh to install the caph code of the git repo into the mgt-cluster" + @echo "then you could create a wl-cluster:" + @echo " make create-workload-cluster-hetzner-hcloud-control-plane" .PHONY: cluster -cluster: $(CTLPTL) $(KUBECTL) ## Creates kind-dev Cluster +cluster: $(CTLPTL) $(KUBECTL) ## Creates kind-dev management cluster @# Fail early: Test if HCLOUD_TOKEN is valid. Background: After Tilt started, changing .envrc has no effect for processes @# started via Tilt. That's why this should fail early. @curl -fsS -H "Authorization: Bearer $$HCLOUD_TOKEN" 'https://api.hetzner.cloud/v1/ssh_keys' > /dev/null || (echo "HCLOUD_TOKEN is invalid (might help: ./hack/ci-e2e-get-token.sh and update .envrc)"; exit 1) @@ -363,9 +338,9 @@ $(RELEASE_NOTES_DIR): .PHONY: test-release test-release: - @# TAG: caph container image tag. For PRs this is pr-NNNN - ./hack/ensure-env-variables.sh TAG - $(MAKE) set-manifest-image MANIFEST_IMG=$(IMAGE_PREFIX)/$(STAGING_IMAGE) MANIFEST_TAG=$(TAG) + @# CAPH_CONTAINER_TAG: caph container image tag. For PRs this is pr-NNNN + ./hack/ensure-env-variables.sh CAPH_CONTAINER_TAG + $(MAKE) set-manifest-image MANIFEST_IMG=$(IMAGE_PREFIX)/$(STAGING_IMAGE) MANIFEST_TAG=$(CAPH_CONTAINER_TAG) $(MAKE) set-manifest-pull-policy PULL_POLICY=IfNotPresent $(MAKE) release-manifests @@ -469,15 +444,16 @@ test-unit: $(SETUP_ENVTEST) $(GOTESTSUM) ## Run unit and integration tests .PHONY: e2e-image e2e-image: ## Build the e2e manager image - ./hack/ensure-env-variables.sh TAG - docker build --pull --build-arg ARCH=$(ARCH) --build-arg LDFLAGS="$(LDFLAGS)" -t $(IMAGE_PREFIX)/$(STAGING_IMAGE):$(TAG) -f images/$(INFRA_SHORT)/Dockerfile . + ./hack/ensure-env-variables.sh CAPH_CONTAINER_TAG + docker build --pull --build-arg ARCH=$(ARCH) --build-arg LDFLAGS="$(LDFLAGS)" -t $(IMAGE_PREFIX)/$(STAGING_IMAGE):$(CAPH_CONTAINER_TAG) -f images/$(INFRA_SHORT)/Dockerfile . .PHONY: e2e-conf-file e2e-conf-file: $(E2E_CONF_FILE) -$(E2E_CONF_FILE): $(ENVSUBST) $(E2E_CONF_FILE_SOURCE) ./hack/create-e2e-conf-file.sh - CAPH_LATEST_VERSION=$(CAPH_LATEST_VERSION) ENVSUBST=$(ENVSUBST) \ +$(E2E_CONF_FILE): $(E2E_CONF_FILE_SOURCE) ./hack/create-e2e-conf-file.sh + CAPH_LATEST_VERSION=$(CAPH_LATEST_VERSION) \ E2E_CONF_FILE_SOURCE=$(E2E_CONF_FILE_SOURCE) \ E2E_CONF_FILE=$(E2E_CONF_FILE) \ + CLUSTERCTL=$(CLUSTERCTL) \ ./hack/create-e2e-conf-file.sh .PHONY: test-e2e @@ -648,12 +624,12 @@ generate-api-ci: generate-manifests generate-go-deepcopy fi cluster-templates: $(KUSTOMIZE) - $(KUSTOMIZE) build templates/cluster-templates/hcloud --load-restrictor LoadRestrictionsNone > templates/cluster-templates/cluster-template.yaml - $(KUSTOMIZE) build templates/cluster-templates/hcloud --load-restrictor LoadRestrictionsNone > templates/cluster-templates/cluster-template-hcloud.yaml - $(KUSTOMIZE) build templates/cluster-templates/hcloud-network --load-restrictor LoadRestrictionsNone > templates/cluster-templates/cluster-template-hcloud-network.yaml - $(KUSTOMIZE) build templates/cluster-templates/hetzner-hcloud-control-planes --load-restrictor LoadRestrictionsNone > templates/cluster-templates/cluster-template-hetzner-hcloud-control-planes.yaml - $(KUSTOMIZE) build templates/cluster-templates/hetzner-baremetal-control-planes --load-restrictor LoadRestrictionsNone > templates/cluster-templates/cluster-template-hetzner-baremetal-control-planes.yaml - $(KUSTOMIZE) build templates/cluster-templates/hetzner-baremetal-control-planes-remediation --load-restrictor LoadRestrictionsNone > templates/cluster-templates/cluster-template-hetzner-baremetal-control-planes-remediation.yaml + $(KUSTOMIZE) build templates/cluster-templates/hcloud --load-restrictor LoadRestrictionsNone > generated/cluster-template.yaml + $(KUSTOMIZE) build templates/cluster-templates/hcloud --load-restrictor LoadRestrictionsNone > generated/cluster-template-hcloud.yaml + $(KUSTOMIZE) build templates/cluster-templates/hcloud-network --load-restrictor LoadRestrictionsNone > generated/cluster-template-hcloud-network.yaml + $(KUSTOMIZE) build templates/cluster-templates/hetzner-hcloud-control-planes --load-restrictor LoadRestrictionsNone > generated/cluster-template-hetzner-hcloud-control-planes.yaml + $(KUSTOMIZE) build templates/cluster-templates/hetzner-baremetal-control-planes --load-restrictor LoadRestrictionsNone > generated/cluster-template-hetzner-baremetal-control-planes.yaml + $(KUSTOMIZE) build templates/cluster-templates/hetzner-baremetal-control-planes-remediation --load-restrictor LoadRestrictionsNone > generated/cluster-template-hetzner-baremetal-control-planes-remediation.yaml ##@ Format ########## @@ -809,7 +785,7 @@ builder-image-push: ## Build $(INFRA_SHORT)-builder to a new version. For more i test: test-unit ## Runs all unit and integration tests. .PHONY: tilt-up -tilt-up: env-vars-for-wl-cluster $(ENVSUBST) $(KUBECTL) $(KUSTOMIZE) $(TILT) cluster ## Start a mgt-cluster & Tilt. Installs the CRDs and deploys the controllers +tilt-up: env-vars-for-wl-cluster $(KUBECTL) $(KUSTOMIZE) $(TILT) cluster ## Start a mgt-cluster & Tilt. Installs the CRDs and deploys the controllers @mkdir -p .tiltbuild EXP_CLUSTER_RESOURCE_SET=true $(TILT) up --port=10351 diff --git a/Tiltfile b/Tiltfile index 6da211b61..041a9f1f5 100644 --- a/Tiltfile +++ b/Tiltfile @@ -3,13 +3,15 @@ load("ext://uibutton", "cmd_button", "location") load("ext://restart_process", "docker_build_with_restart") kustomize_cmd = "./hack/tools/bin/kustomize" -envsubst_cmd = "./hack/tools/bin/envsubst" +clusterctl_cmd = "./hack/tools/bin/clusterctl" tools_bin = "./hack/tools/bin" -#Add tools to path +# Add tools to path os.putenv("PATH", os.getenv("PATH") + ":" + tools_bin) -update_settings(k8s_upsert_timeout_secs = 60) # on first tilt up, often can take longer than 30 seconds +update_settings( + k8s_upsert_timeout_secs=60 +) # on first tilt up, often can take longer than 30 seconds # set defaults settings = { @@ -20,7 +22,7 @@ settings = { "deploy_observability": False, "preload_images_for_kind": True, "kind_cluster_name": "caph", - "capi_version": "v1.8.10", + "capi_version": "v1.10.9", "cabpt_version": "v0.5.6", "cacppt_version": "v0.4.11", "cert_manager_version": "v1.11.0", @@ -29,15 +31,16 @@ settings = { "--log-level=debug", ], }, - "kustomize_substitutions": { - }, + "kustomize_substitutions": {}, } # global settings -settings.update(read_yaml( - "tilt-settings.yaml", - default = {}, -)) +settings.update( + read_yaml( + "tilt-settings.yaml", + default={}, + ) +) if settings.get("trigger_mode") == "manual": trigger_mode(TRIGGER_MODE_MANUAL) @@ -48,37 +51,61 @@ if "allowed_contexts" in settings: if "default_registry" in settings: default_registry(settings.get("default_registry")) + # deploy CAPI def deploy_capi(): version = settings.get("capi_version") - capi_uri = "https://github.com/kubernetes-sigs/cluster-api/releases/download/{}/cluster-api-components.yaml".format(version) - cmd = "curl -sSL {} | {} | kubectl apply -f -".format(capi_uri, envsubst_cmd) - local(cmd, quiet = True) + capi_uri = "https://github.com/kubernetes-sigs/cluster-api/releases/download/{}/cluster-api-components.yaml".format( + version + ) + cmd = "curl -sSL {} | {} generate yaml | kubectl apply -f -".format( + capi_uri, clusterctl_cmd + ) + local(cmd, quiet=True) if settings.get("extra_args"): extra_args = settings.get("extra_args") if extra_args.get("core"): core_extra_args = extra_args.get("core") if core_extra_args: for namespace in ["capi-system", "capi-webhook-system"]: - patch_args_with_extra_args(namespace, "capi-controller-manager", core_extra_args) + patch_args_with_extra_args( + namespace, "capi-controller-manager", core_extra_args + ) if extra_args.get("kubeadm-bootstrap"): kb_extra_args = extra_args.get("kubeadm-bootstrap") if kb_extra_args: - patch_args_with_extra_args("capi-kubeadm-bootstrap-system", "capi-kubeadm-bootstrap-controller-manager", kb_extra_args) + patch_args_with_extra_args( + "capi-kubeadm-bootstrap-system", + "capi-kubeadm-bootstrap-controller-manager", + kb_extra_args, + ) def patch_args_with_extra_args(namespace, name, extra_args): - args_str = str(local("kubectl get deployments {} -n {} -o jsonpath='{{.spec.template.spec.containers[0].args}}'".format(name, namespace))) + args_str = str( + local( + "kubectl get deployments {} -n {} -o jsonpath='{{.spec.template.spec.containers[0].args}}'".format( + name, namespace + ) + ) + ) args_to_add = [arg for arg in extra_args if arg not in args_str] if args_to_add: args = args_str[1:-1].split() args.extend(args_to_add) - patch = [{ - "op": "replace", - "path": "/spec/template/spec/containers/0/args", - "value": args, - }] - local("kubectl patch deployment {} -n {} --type json -p='{}'".format(name, namespace, str(encode_json(patch)).replace("\n", ""))) + patch = [ + { + "op": "replace", + "path": "/spec/template/spec/containers/0/args", + "value": args, + } + ] + local( + "kubectl patch deployment {} -n {} --type json -p='{}'".format( + name, namespace, str(encode_json(patch)).replace("\n", "") + ) + ) + # Users may define their own Tilt customizations in tilt.d. This directory is excluded from git and these files will # not be checked in to version control. @@ -87,18 +114,27 @@ def include_user_tilt_files(): for f in user_tiltfiles: include(f) -def append_arg_for_container_in_deployment(yaml_stream, name, namespace, contains_image_name, args): + +def append_arg_for_container_in_deployment( + yaml_stream, name, namespace, contains_image_name, args +): for item in yaml_stream: - if item["kind"] == "Deployment" and item.get("metadata").get("name") == name and item.get("metadata").get("namespace") == namespace: + if ( + item["kind"] == "Deployment" + and item.get("metadata").get("name") == name + and item.get("metadata").get("namespace") == namespace + ): containers = item.get("spec").get("template").get("spec").get("containers") for container in containers: if contains_image_name in container.get("name"): container.get("args").extend(args) + def fixup_yaml_empty_arrays(yaml_str): yaml_str = yaml_str.replace("conditions: null", "conditions: []") return yaml_str.replace("storedVersions: null", "storedVersions: []") + def set_env_variables(): substitutions = settings.get("kustomize_substitutions", {}) print(substitutions) @@ -106,6 +142,7 @@ def set_env_variables(): for key, val in arr: os.putenv(key, val) + ## This should have the same versions as the Dockerfile tilt_dockerfile_header = """ FROM gcr.io/distroless/base:debug as tilt @@ -116,6 +153,7 @@ COPY installimage.tgz . COPY manager . """ + # Build CAPH and add feature gates def caph(): # yaml = str(kustomizesub("./hack/observability")) # build an observable kind deployment by default @@ -126,7 +164,13 @@ def caph(): hetzner_extra_args = settings.get("extra_args").get("hetzner") if hetzner_extra_args: yaml_dict = decode_yaml_stream(yaml) - append_arg_for_container_in_deployment(yaml_dict, "caph-controller-manager", "caph-system", "manager", hetzner_extra_args) + append_arg_for_container_in_deployment( + yaml_dict, + "caph-controller-manager", + "caph-system", + "manager", + hetzner_extra_args, + ) yaml = str(encode_yaml_stream(yaml_dict)) yaml = fixup_yaml_empty_arrays(yaml) @@ -135,17 +179,19 @@ def caph(): # Set up a local_resource build of the provider's manager binary. # Forge the build command - ldflags = "-extldflags \"-static\" " + str(local("hack/version.sh")).rstrip("\n") + ldflags = '-extldflags "-static" ' + str(local("hack/version.sh")).rstrip("\n") build_env = "CGO_ENABLED=0 GOOS=linux GOARCH=amd64" - build_cmd = "{build_env} go build -ldflags '{ldflags}' -o .tiltbuild/manager".format( - build_env = build_env, - ldflags = ldflags, + build_cmd = ( + "{build_env} go build -ldflags '{ldflags}' -o .tiltbuild/manager".format( + build_env=build_env, + ldflags=ldflags, + ) ) local_resource( "manager", - cmd = "mkdir -p .tiltbuild; " + build_cmd, - deps = ["api", "config", "controllers", "pkg", "go.mod", "go.sum", "main.go"], - labels = ["CAPH"], + cmd="mkdir -p .tiltbuild; " + build_cmd, + deps=["api", "config", "controllers", "pkg", "go.mod", "go.sum", "main.go"], + labels=["CAPH"], ) entrypoint = ["/manager"] @@ -156,22 +202,22 @@ def caph(): # Set up an image build for the provider. The live update configuration syncs the output from the local_resource # build into the container. docker_build_with_restart( - ref = "ghcr.io/syself/caph-staging", - context = "./.tiltbuild/", - dockerfile_contents = tilt_dockerfile_header, - target = "tilt", - entrypoint = entrypoint, - only = ["manager", "installimage.tgz"], - live_update = [ + ref="ghcr.io/syself/caph-staging", + context="./.tiltbuild/", + dockerfile_contents=tilt_dockerfile_header, + target="tilt", + entrypoint=entrypoint, + only=["manager", "installimage.tgz"], + live_update=[ sync(".tiltbuild/manager", "/manager"), ], - ignore = ["templates"], + ignore=["templates"], ) k8s_yaml(blob(yaml)) - k8s_resource(workload = "caph-controller-manager", labels = ["CAPH"]) + k8s_resource(workload="caph-controller-manager", labels=["CAPH"]) k8s_resource( - objects = [ + objects=[ "caph-system:namespace", "hetznerbaremetalhosts.infrastructure.cluster.x-k8s.io:customresourcedefinition", "hetznerbaremetalmachines.infrastructure.cluster.x-k8s.io:customresourcedefinition", @@ -193,67 +239,105 @@ def caph(): "caph-selfsigned-issuer:issuer", "caph-validating-webhook-configuration:validatingwebhookconfiguration", ], - new_name = "caph-misc", - labels = ["CAPH"], + new_name="caph-misc", + labels=["CAPH"], ) if os.path.exists("baremetalhosts.yaml"): k8s_custom_deploy( "baremetal-hosts", - deps = ["caph-controller-manager", "caph-misc"], - apply_cmd = "kubectl apply -f baremetalhosts.yaml 1>&2", - delete_cmd = "kubectl delete -f baremetalhosts.yaml", + deps=["caph-controller-manager", "caph-misc"], + apply_cmd="kubectl apply -f baremetalhosts.yaml 1>&2", + delete_cmd="kubectl delete -f baremetalhosts.yaml", ) k8s_resource( "baremetal-hosts", - labels = ["CAPH"], - resource_deps = ["caph-controller-manager", "caph-misc"], + labels=["CAPH"], + resource_deps=["caph-controller-manager", "caph-misc"], ) + def base64_encode(to_encode): - encode_blob = local("echo '{}' | tr -d '\n' | base64 - | tr -d '\n'".format(to_encode), quiet = True) + encode_blob = local( + "echo '{}' | tr -d '\n' | base64 - | tr -d '\n'".format(to_encode), quiet=True + ) return str(encode_blob) + def base64_encode_file(path_to_encode): - encode_blob = local("cat {} | tr -d '\n' | base64 - | tr -d '\n'".format(path_to_encode), quiet = True) + encode_blob = local( + "cat {} | tr -d '\n' | base64 - | tr -d '\n'".format(path_to_encode), quiet=True + ) return str(encode_blob) + def read_file_from_path(path_to_read): - str_blob = local("cat {} | tr -d '\n'".format(path_to_read), quiet = True) + str_blob = local("cat {} | tr -d '\n'".format(path_to_read), quiet=True) return str(str_blob) + def base64_decode(to_decode): - decode_blob = local("echo '{}' | base64 --decode -".format(to_decode), quiet = True) + decode_blob = local("echo '{}' | base64 --decode -".format(to_decode), quiet=True) return str(decode_blob) -def ensure_envsubst(): - if not os.path.exists(envsubst_cmd): - local("make {}".format(os.path.abspath(envsubst_cmd))) + +def ensure_clusterctl(): + if not os.path.exists(clusterctl_cmd): + local("make {}".format(os.path.abspath(clusterctl_cmd))) + def ensure_kustomize(): if not os.path.exists(kustomize_cmd): local("make {}".format(os.path.abspath(kustomize_cmd))) + def kustomizesub(folder): - yaml = local("hack/kustomize-sub.sh {}".format(folder), quiet = True) + yaml = local("hack/kustomize-sub.sh {}".format(folder), quiet=True) return yaml + def waitforsystem(): - local("kubectl wait --for=condition=ready --timeout=300s pod --all -n capi-kubeadm-bootstrap-system") - local("kubectl wait --for=condition=ready --timeout=300s pod --all -n capi-kubeadm-control-plane-system") + local( + "kubectl wait --for=condition=ready --timeout=300s pod --all -n capi-kubeadm-bootstrap-system" + ) + local( + "kubectl wait --for=condition=ready --timeout=300s pod --all -n capi-kubeadm-control-plane-system" + ) local("kubectl wait --for=condition=ready --timeout=300s pod --all -n capi-system") + def deploy_observability(): - k8s_yaml(blob(str(local("{} build {}".format(kustomize_cmd, "./hack/observability/"), quiet = True)))) + k8s_yaml( + blob( + str( + local( + "{} build {}".format(kustomize_cmd, "./hack/observability/"), + quiet=True, + ) + ) + ) + ) + + k8s_resource( + workload="promtail", + extra_pod_selectors=[{"app": "promtail"}], + labels=["observability"], + ) + k8s_resource( + workload="loki", extra_pod_selectors=[{"app": "loki"}], labels=["observability"] + ) + k8s_resource( + workload="grafana", + port_forwards="3000", + extra_pod_selectors=[{"app": "grafana"}], + labels=["observability"], + ) - k8s_resource(workload = "promtail", extra_pod_selectors = [{"app": "promtail"}], labels = ["observability"]) - k8s_resource(workload = "loki", extra_pod_selectors = [{"app": "loki"}], labels = ["observability"]) - k8s_resource(workload = "grafana", port_forwards = "3000", extra_pod_selectors = [{"app": "grafana"}], labels = ["observability"]) ############################## # Actual work happens here ############################## -ensure_envsubst() +ensure_clusterctl() ensure_kustomize() include_user_tilt_files() @@ -275,51 +359,54 @@ caph() waitforsystem() cmd_button( - "Create Hcloud Cluster", - argv = ["make", "create-workload-cluster-hcloud"], - location = location.NAV, - icon_name = "switch_access_shortcut_outlined", - text = "Create Hcloud Cluster", + "Create HCloud Cluster", + argv=["make", "create-workload-cluster-hcloud"], + location=location.NAV, + icon_name="switch_access_shortcut_outlined", + text="Create Hcloud Cluster", ) cmd_button( "Create Hcloud Cluster Private Network", - argv = ["make", "create-workload-cluster-hcloud-network"], - location = location.NAV, - icon_name = "switch_access_shortcut_add_outlined", - text = "Create Hcloud Cluster Private Network", + argv=["make", "create-workload-cluster-hcloud-network"], + location=location.NAV, + icon_name="switch_access_shortcut_add_outlined", + text="Create Hcloud Cluster Private Network", ) cmd_button( "Create Baremetal Cluster - with hcloud control-planes", - argv = ["make", "create-workload-cluster-hetzner-hcloud-control-plane"], - location = location.NAV, - icon_name = "dns_outline", - text = "Create Baremetal Cluster - with hcloud control-planes", + argv=["make", "create-workload-cluster-hetzner-hcloud-control-plane"], + location=location.NAV, + icon_name="dns_outline", + text="Create Baremetal Cluster - with hcloud control-planes", ) cmd_button( "Create Hetzner Cluster - with baremetal control-planes", - argv = ["make", "create-workload-cluster-hetzner-baremetal-control-plane"], - location = location.NAV, - icon_name = "storage", - text = "Create Hetzner Cluster - with baremetal control-planes", + argv=["make", "create-workload-cluster-hetzner-baremetal-control-plane"], + location=location.NAV, + icon_name="storage", + text="Create Hetzner Cluster - with baremetal control-planes", ) cmd_button( "Create Hetzner Cluster - with baremetal control-planes - remediation", - argv = ["make", "create-workload-cluster-hetzner-baremetal-control-plane-remediation"], - location = location.NAV, - icon_name = "dvr", - text = "Create Hetzner Cluster - remediation - baremetal control-planes", + argv=[ + "make", + "create-workload-cluster-hetzner-baremetal-control-plane-remediation", + ], + location=location.NAV, + icon_name="dvr", + text="Create Hetzner Cluster - remediation - baremetal control-planes", ) cmd_button( "Delete Cluster", - argv = ["make", "delete-workload-cluster"], - location = location.NAV, - icon_name = "cloud_download", - text = "Delete Cluster", + argv=["make", "delete-workload-cluster"], + location=location.NAV, + icon_name="cloud_download", + text="Delete Cluster", ) diff --git a/config/crd/patches/webhook_in_hcloudmachines.yaml b/config/crd/patches/webhook_in_hcloudmachines.yaml index 646afc54c..792c16501 100644 --- a/config/crd/patches/webhook_in_hcloudmachines.yaml +++ b/config/crd/patches/webhook_in_hcloudmachines.yaml @@ -9,8 +9,8 @@ spec: webhook: clientConfig: service: - namespace: system - name: webhook-service + namespace: caph-system + name: caph-webhook-service path: /convert conversionReviewVersions: - v1 diff --git a/config/crd/patches/webhook_in_hcloudmachinetemplates.yaml b/config/crd/patches/webhook_in_hcloudmachinetemplates.yaml index e0bcc1506..2e2b2fdf5 100644 --- a/config/crd/patches/webhook_in_hcloudmachinetemplates.yaml +++ b/config/crd/patches/webhook_in_hcloudmachinetemplates.yaml @@ -9,8 +9,8 @@ spec: webhook: clientConfig: service: - namespace: system - name: webhook-service + namespace: caph-system + name: caph-webhook-service path: /convert conversionReviewVersions: - v1 diff --git a/config/crd/patches/webhook_in_hcloudremediations.yaml b/config/crd/patches/webhook_in_hcloudremediations.yaml index 6fd585251..4b20e56c3 100644 --- a/config/crd/patches/webhook_in_hcloudremediations.yaml +++ b/config/crd/patches/webhook_in_hcloudremediations.yaml @@ -9,8 +9,8 @@ spec: webhook: clientConfig: service: - namespace: system - name: webhook-service + namespace: caph-system + name: caph-webhook-service path: /convert conversionReviewVersions: - v1 diff --git a/config/crd/patches/webhook_in_hcloudremediationtemplates.yaml b/config/crd/patches/webhook_in_hcloudremediationtemplates.yaml index 0d852fc72..96492283a 100644 --- a/config/crd/patches/webhook_in_hcloudremediationtemplates.yaml +++ b/config/crd/patches/webhook_in_hcloudremediationtemplates.yaml @@ -9,8 +9,8 @@ spec: webhook: clientConfig: service: - namespace: system - name: webhook-service + namespace: caph-system + name: caph-webhook-service path: /convert conversionReviewVersions: - v1 diff --git a/config/crd/patches/webhook_in_hetznerbaremetalhosts.yaml b/config/crd/patches/webhook_in_hetznerbaremetalhosts.yaml index cf131d522..fd0e7210e 100644 --- a/config/crd/patches/webhook_in_hetznerbaremetalhosts.yaml +++ b/config/crd/patches/webhook_in_hetznerbaremetalhosts.yaml @@ -9,8 +9,8 @@ spec: webhook: clientConfig: service: - namespace: system - name: webhook-service + namespace: caph-system + name: caph-webhook-service path: /convert conversionReviewVersions: - v1 diff --git a/config/crd/patches/webhook_in_hetznerbaremetalmachines.yaml b/config/crd/patches/webhook_in_hetznerbaremetalmachines.yaml index 8e8bc412a..50d2c2f70 100644 --- a/config/crd/patches/webhook_in_hetznerbaremetalmachines.yaml +++ b/config/crd/patches/webhook_in_hetznerbaremetalmachines.yaml @@ -9,8 +9,8 @@ spec: webhook: clientConfig: service: - namespace: system - name: webhook-service + namespace: caph-system + name: caph-webhook-service path: /convert conversionReviewVersions: - v1 diff --git a/config/crd/patches/webhook_in_hetznerbaremetalmachinetemplates.yaml b/config/crd/patches/webhook_in_hetznerbaremetalmachinetemplates.yaml index 635cbfba2..de2be56ee 100644 --- a/config/crd/patches/webhook_in_hetznerbaremetalmachinetemplates.yaml +++ b/config/crd/patches/webhook_in_hetznerbaremetalmachinetemplates.yaml @@ -9,8 +9,8 @@ spec: webhook: clientConfig: service: - namespace: system - name: webhook-service + namespace: caph-system + name: caph-webhook-service path: /convert conversionReviewVersions: - v1 diff --git a/config/crd/patches/webhook_in_hetznerbaremetalremediations.yaml b/config/crd/patches/webhook_in_hetznerbaremetalremediations.yaml index 631ffb141..eb0d7b5b9 100644 --- a/config/crd/patches/webhook_in_hetznerbaremetalremediations.yaml +++ b/config/crd/patches/webhook_in_hetznerbaremetalremediations.yaml @@ -9,8 +9,8 @@ spec: webhook: clientConfig: service: - namespace: system - name: webhook-service + namespace: caph-system + name: caph-webhook-service path: /convert conversionReviewVersions: - v1 diff --git a/config/crd/patches/webhook_in_hetznerbaremetalremediationtemplates.yaml b/config/crd/patches/webhook_in_hetznerbaremetalremediationtemplates.yaml index 6703e44e1..1a514faf8 100644 --- a/config/crd/patches/webhook_in_hetznerbaremetalremediationtemplates.yaml +++ b/config/crd/patches/webhook_in_hetznerbaremetalremediationtemplates.yaml @@ -9,8 +9,8 @@ spec: webhook: clientConfig: service: - namespace: system - name: webhook-service + namespace: caph-system + name: caph-webhook-service path: /convert conversionReviewVersions: - v1 diff --git a/config/crd/patches/webhook_in_hetznerclusters.yaml b/config/crd/patches/webhook_in_hetznerclusters.yaml index db6498a37..c1cfc4781 100644 --- a/config/crd/patches/webhook_in_hetznerclusters.yaml +++ b/config/crd/patches/webhook_in_hetznerclusters.yaml @@ -9,8 +9,8 @@ spec: webhook: clientConfig: service: - namespace: system - name: webhook-service + namespace: caph-system + name: caph-webhook-service path: /convert conversionReviewVersions: - v1 diff --git a/config/crd/patches/webhook_in_hetznerclustertemplates.yaml b/config/crd/patches/webhook_in_hetznerclustertemplates.yaml index a3f1a2498..7ac4396cc 100644 --- a/config/crd/patches/webhook_in_hetznerclustertemplates.yaml +++ b/config/crd/patches/webhook_in_hetznerclustertemplates.yaml @@ -9,8 +9,8 @@ spec: webhook: clientConfig: service: - namespace: system - name: webhook-service + namespace: caph-system + name: caph-webhook-service path: /convert conversionReviewVersions: - v1 diff --git a/docs/caph/01-getting-started/01-introduction.md b/docs/caph/01-getting-started/01-introduction.md index 3c21f1d26..744a9ba62 100644 --- a/docs/caph/01-getting-started/01-introduction.md +++ b/docs/caph/01-getting-started/01-introduction.md @@ -19,28 +19,34 @@ It is recommended that you have at least a basic understanding of Cluster API be This provider's versions are compatible with the following versions of Cluster API: -| | CAPI `v1beta1` (`v1.7.x`) | CAPI `v1beta1` (`v1.8.x`) | -| ------------------------------------ | ------------------------- | ------------------------- | -| Hetzner Provider `v1.0.0-beta.34-43` | ✅ | ❌ | -| Hetzner Provider `v1.0.0` | ✅ | ✅ | -| Hetzner Provider `v1.0.1` | ✅ | ✅ | +| CAPI Version | Hetzner Provider `v1.0.x` | Hetzner Provider `v1.1.x` | +| --------------------------------------------------------------------------------------------------------- | ------------------------- | ------------------------- | +| `v1.8.x` | ✅ | ❔ | +| `v1.9.x` | ✅ | ❔ | +| `v1.10.x` | ✅ | ✅ | +| `v1.11.x` [start of beta2](https://cluster-api.sigs.k8s.io/developer/providers/migrations/v1.10-to-v1.11) | ❌ | ✅ | +| `v1.12.x` | ❌ | ✅ | This provider's versions can install and manage the following versions of Kubernetes: -| | Hetzner Provider `v1.0.x` | -| ----------------- | ------------------------- | -| Kubernetes 1.28.x | ✅ | -| Kubernetes 1.29.x | ✅ | -| Kubernetes 1.30.x | ✅ | -| Kubernetes 1.31.x | ✅ | +| | Hetzner Provider `v1.0.x` | Hetzner Provider `v1.1.x` | +| ----------------- | ------------------------- | ------------------------- | +| Kubernetes 1.31.x | ✅ | ❌ | +| Kubernetes 1.32.x | ✅ | ✅ | +| Kubernetes 1.33.x | ✅ | ✅ | +| Kubernetes 1.34.x | ❔ | ✅ | Test status: - ✅ tested -- ❔ should work, but we weren't able to test it +- ❔ should work Each version of Cluster API for Hetzner will attempt to support at least two Kubernetes versions. +**NOTE:** As the versioning for this project is tied to the versioning of Cluster API, future +modifications to this policy may be made to more closely align with other providers in the Cluster +API ecosystem. + {% callout %} As the versioning for this project is tied to the versioning of Cluster API, future modifications to this policy may be made to more closely align with other providers in the Cluster API ecosystem. diff --git a/docs/caph/01-getting-started/02-quickstart/02-management-cluster-setup.md b/docs/caph/01-getting-started/02-quickstart/02-management-cluster-setup.md index 17079bc81..f22455cfa 100644 --- a/docs/caph/01-getting-started/02-quickstart/02-management-cluster-setup.md +++ b/docs/caph/01-getting-started/02-quickstart/02-management-cluster-setup.md @@ -78,8 +78,8 @@ For a specific version, use the `--infrastructure hetzner:vX.X.X` flag with the ```shell export SSH_KEY_NAME="" export HCLOUD_REGION="fsn1" -export HCLOUD_CONTROL_PLANE_MACHINE_TYPE=cpx31 -export HCLOUD_WORKER_MACHINE_TYPE=cpx31 +export HCLOUD_CONTROL_PLANE_MACHINE_TYPE=cpx32 +export HCLOUD_WORKER_MACHINE_TYPE=cpx32 ``` - **SSH_KEY_NAME**: The SSH Key name you loaded in HCloud. diff --git a/docs/caph/01-getting-started/02-quickstart/03-creating-a-workload-cluster.md b/docs/caph/01-getting-started/02-quickstart/03-creating-a-workload-cluster.md index 7e2b4bf5b..dddd06772 100644 --- a/docs/caph/01-getting-started/02-quickstart/03-creating-a-workload-cluster.md +++ b/docs/caph/01-getting-started/02-quickstart/03-creating-a-workload-cluster.md @@ -11,7 +11,7 @@ The `clusterctl generate cluster` command returns a YAML template for creating a It generates a YAML file named `my-cluster.yaml` with a predefined list of Cluster API objects (`Cluster`, `Machines`, `MachineDeployments`, etc.) to be deployed in the current namespace. ```shell -clusterctl generate cluster my-cluster --kubernetes-version v1.31.6 --control-plane-machine-count=3 --worker-machine-count=3 > my-cluster.yaml +clusterctl generate cluster my-cluster --kubernetes-version v1.33.6 --control-plane-machine-count=3 --worker-machine-count=3 > my-cluster.yaml ``` {% callout %} diff --git a/docs/caph/01-getting-started/03-preparation.md b/docs/caph/01-getting-started/03-preparation.md index 18cf70931..6a7819f6f 100644 --- a/docs/caph/01-getting-started/03-preparation.md +++ b/docs/caph/01-getting-started/03-preparation.md @@ -74,9 +74,9 @@ export CLUSTER_NAME="my-cluster" export HCLOUD_REGION="fsn1" export CONTROL_PLANE_MACHINE_COUNT=3 export WORKER_MACHINE_COUNT=3 -export KUBERNETES_VERSION=1.31.6 -export HCLOUD_CONTROL_PLANE_MACHINE_TYPE=cpx31 -export HCLOUD_WORKER_MACHINE_TYPE=cpx31 +export KUBERNETES_VERSION=1.33.6 +export HCLOUD_CONTROL_PLANE_MACHINE_TYPE=cpx32 +export HCLOUD_WORKER_MACHINE_TYPE=cpx32 ``` - SSH_KEY_NAME: The SSH Key name you loaded in HCloud. @@ -96,7 +96,7 @@ Required Variables: Optional Variables: - CLUSTER_NAME (defaults to hetzner-cluster) - CONTROL_PLANE_MACHINE_COUNT (defaults to 3) - - KUBERNETES_VERSION (defaults to 1.31.6) + - KUBERNETES_VERSION (defaults to 1.33.6) - WORKER_MACHINE_COUNT (defaults to 3) ``` diff --git a/docs/caph/02-topics/04-upgrading-caph.md b/docs/caph/02-topics/04-upgrading-caph.md index b2eed9c5d..45ae006da 100644 --- a/docs/caph/02-topics/04-upgrading-caph.md +++ b/docs/caph/02-topics/04-upgrading-caph.md @@ -61,7 +61,7 @@ NAME NAMESPACE TYPE bootstrap-kubeadm capi-kubeadm-bootstrap-system BootstrapProvider v1.8.0 v1.8.4 control-plane-kubeadm capi-kubeadm-control-plane-system ControlPlaneProvider v1.8.0 v1.8.4 cluster-api capi-system CoreProvider v1.8.0 v1.8.4 -infrastructure-hetzner caph-system InfrastructureProvider v1.0.1 Already up to date +infrastructure-hetzner caph-system InfrastructureProvider v1.0.7 Already up to date You can now apply the upgrade by executing the following command: @@ -114,13 +114,13 @@ You can find the latest version of CAPH here: ```shell -$ clusterctl upgrade apply --infrastructure=hetzner:v1.0.1 +$ clusterctl upgrade apply --infrastructure=hetzner:v1.0.7 Checking cert-manager version... Cert-manager is already up to date Performing upgrade... Scaling down Provider="infrastructure-hetzner" Version="" Namespace="caph-system" Deleting Provider="infrastructure-hetzner" Version="" Namespace="caph-system" -Installing Provider="infrastructure-hetzner" Version="v1.0.1" TargetNamespace="caph-system" +Installing Provider="infrastructure-hetzner" Version="v1.0.7" TargetNamespace="caph-system" ``` After the upgrade, you'll notice the new pod spinning up the `caph-system` namespace. @@ -133,7 +133,7 @@ caph-controller-manager-85fcb6ffcb-4sj6d 1/1 Running 0 79s {% callout %} -Please note that `clusterctl` doesn't support pre-release of GitHub by default so if you want to use a pre-release, you'll have to specify the version such as `hetzner:v1.0.1` +Please note that `clusterctl` doesn't support pre-release of GitHub by default so if you want to use a pre-release, you'll have to specify the version such as `hetzner:v1.0.7` {% /callout %} diff --git a/docs/caph/02-topics/05-baremetal/02-management-cluster.md b/docs/caph/02-topics/05-baremetal/02-management-cluster.md index f6cc870df..783df7b80 100644 --- a/docs/caph/02-topics/05-baremetal/02-management-cluster.md +++ b/docs/caph/02-topics/05-baremetal/02-management-cluster.md @@ -44,7 +44,7 @@ Required Variables: Optional Variables: - CLUSTER_NAME (defaults to my-cluster) - CONTROL_PLANE_MACHINE_COUNT (defaults to 3) - - KUBERNETES_VERSION (defaults to v1.31.6) + - KUBERNETES_VERSION (defaults to v1.33.6) - WORKER_MACHINE_COUNT (defaults to 3) ``` @@ -60,10 +60,10 @@ clusterctl init --infrastructure hetzner Fetching providers Installing cert-manager Version="v1.14.2" Waiting for cert-manager to be available... -Installing Provider="cluster-api" Version="v1.8.10" TargetNamespace="capi-system" -Installing Provider="bootstrap-kubeadm" Version="v1.8.10" TargetNamespace="capi-kubeadm-bootstrap-system" -Installing Provider="control-plane-kubeadm" Version="v1.8.10" TargetNamespace="capi-kubeadm-control-plane-system" -Installing Provider="infrastructure-hetzner" Version="v1.0.1" TargetNamespace="caph-system" +Installing Provider="cluster-api" Version="v1.10.9" TargetNamespace="capi-system" +Installing Provider="bootstrap-kubeadm" Version="v1.10.9" TargetNamespace="capi-kubeadm-bootstrap-system" +Installing Provider="control-plane-kubeadm" Version="v1.10.9" TargetNamespace="capi-kubeadm-control-plane-system" +Installing Provider="infrastructure-hetzner" Version="v1.0.7" TargetNamespace="caph-system" Your management cluster has been initialized successfully! diff --git a/docs/caph/02-topics/05-baremetal/03-creating-workload-cluster.md b/docs/caph/02-topics/05-baremetal/03-creating-workload-cluster.md index e0811a7a8..a53c01e08 100644 --- a/docs/caph/02-topics/05-baremetal/03-creating-workload-cluster.md +++ b/docs/caph/02-topics/05-baremetal/03-creating-workload-cluster.md @@ -118,14 +118,14 @@ NAMESPACE NAME CLUSTERCLASS PHASE AGE VERSION default my-cluster Provisioned 10h $ kubectl get machines -A NAMESPACE NAME CLUSTER NODENAME PROVIDERID PHASE AGE VERSION -default my-cluster-control-plane-6m6zf my-cluster my-cluster-control-plane-84hsn hcloud://45443706 Running 10h v1.31.6 -default my-cluster-control-plane-m6frm my-cluster my-cluster-control-plane-hvl5d hcloud://45443651 Running 10h v1.31.6 -default my-cluster-control-plane-qwsq6 my-cluster my-cluster-control-plane-ss9kc hcloud://45443746 Running 10h v1.31.6 -default my-cluster-md-0-2xgj5-c5bhc my-cluster my-cluster-md-0-6xttr hcloud://45443694 Running 10h v1.31.6 -default my-cluster-md-0-2xgj5-rbnbw my-cluster my-cluster-md-0-fdq9l hcloud://45443693 Running 10h v1.31.6 -default my-cluster-md-0-2xgj5-tl2jr my-cluster my-cluster-md-0-59cgw hcloud://45443692 Running 10h v1.31.6 -default my-cluster-md-1-cp2fd-7nld7 my-cluster bm-my-cluster-md-1-d7526 hcloud://bm-2317525 Running 9h v1.31.6 -default my-cluster-md-1-cp2fd-n74sm my-cluster bm-my-cluster-md-1-l5dnr hcloud://bm-2105469 Running 10h v1.31.6 +default my-cluster-control-plane-6m6zf my-cluster my-cluster-control-plane-84hsn hcloud://45443706 Running 10h v1.33.6 +default my-cluster-control-plane-m6frm my-cluster my-cluster-control-plane-hvl5d hcloud://45443651 Running 10h v1.33.6 +default my-cluster-control-plane-qwsq6 my-cluster my-cluster-control-plane-ss9kc hcloud://45443746 Running 10h v1.33.6 +default my-cluster-md-0-2xgj5-c5bhc my-cluster my-cluster-md-0-6xttr hcloud://45443694 Running 10h v1.33.6 +default my-cluster-md-0-2xgj5-rbnbw my-cluster my-cluster-md-0-fdq9l hcloud://45443693 Running 10h v1.33.6 +default my-cluster-md-0-2xgj5-tl2jr my-cluster my-cluster-md-0-59cgw hcloud://45443692 Running 10h v1.33.6 +default my-cluster-md-1-cp2fd-7nld7 my-cluster bm-my-cluster-md-1-d7526 hcloud://bm-2317525 Running 9h v1.33.6 +default my-cluster-md-1-cp2fd-n74sm my-cluster bm-my-cluster-md-1-l5dnr hcloud://bm-2105469 Running 10h v1.33.6 ``` Please note that hcloud servers are prefixed with `hcloud://` and baremetal servers are prefixed with `hcloud://bm-`. diff --git a/docs/caph/03-reference/03-hcloud-machine-template.md b/docs/caph/03-reference/03-hcloud-machine-template.md index 8062a0e8f..deec42887 100644 --- a/docs/caph/03-reference/03-hcloud-machine-template.md +++ b/docs/caph/03-reference/03-hcloud-machine-template.md @@ -12,7 +12,7 @@ In `HCloudMachineTemplate` you can define all important properties for `HCloudMa | Key | Type | Default | Required | Description | | ------------------------------------------ | ---------- | --------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `template.spec.providerID` | `string` | | no | ProviderID set by controller | -| `template.spec.type` | `string` | | yes | Desired server type of server in Hetzner's Cloud API. Example: cpx11 | +| `template.spec.type` | `string` | | yes | Desired server type of server in Hetzner's Cloud API. Example: cpx22 | | `template.spec.imageName` | `string` | | yes | Specifies desired image of server. ImageName can reference an image uploaded to Hetzner API in two ways: either directly as name of an image, or as label of an image (see [here](/docs/caph/02-topics/03-node-image.md) for more details) | | `template.spec.sshKeys` | `object` | | no | SSHKeys that are scoped to this machine | | `template.spec.sshKeys.hcloud` | `[]object` | | no | SSH keys for HCloud | diff --git a/docs/caph/04-developers/01-development-guide.md b/docs/caph/04-developers/01-development-guide.md index b08bdce18..3c0090c4e 100644 --- a/docs/caph/04-developers/01-development-guide.md +++ b/docs/caph/04-developers/01-development-guide.md @@ -60,11 +60,23 @@ To access the Tilt UI, please go to: `http://localhost:10351` {% /callout %} -Once your kind management cluster is up and running, you can deploy a workload cluster. This could be done through the Tilt UI by pressing one of the buttons in the top right corner, e.g., **"Create Workload Cluster"**. This triggers the `make create-workload-cluster` command, which uses the environment variables (we defined in the .envrc) and the cluster-template. Additionally, it installs cilium as CNI. +Once your kind management cluster is up and running, you can deploy a workload cluster. This could +be done through the Tilt UI by pressing one of the buttons in the top right corner, e.g., **"Create +HCloud Cluster"**, if you want to start a HCloud only cluster, or **"Create Baremetal Cluster - with +hcloud control-planes"**, if you want to use baremetal worker. -If you update the API in some way, you need to run `make generate` to generate everything related to kubebuilder and the CRDs. +The buttons are defined in +[Tiltfile](https://github.com/syself/cluster-api-provider-hetzner/blob/main/Tiltfile). There you see +the corresponding makefile targets, if you prefer to use the command line. -To tear down the workload cluster, press the **"Delete Workload Cluster"** button. After a few minutes, the resources should be deleted. +You can use `make watch` to get an overview. It shows continously: + +- infrastructure resources in your mgt-cluster +- logs of caph and capi controller +- events + +To tear down the workload cluster, press the **"Delete Workload Cluster"** button. After a few +minutes, the resources should be deleted. To tear down the kind cluster, use: @@ -115,12 +127,13 @@ that. A common way to run one particular unit-test is like this: ```shell -reset; ginkgo run --focus "foo" ./controllers/... | ./hack/filter-caph-controller-manager-logs.py - +reset; DEBUG=1 ginkgo run --focus "foo" ./controllers/... | ./hack/filter-caph-controller-manager-logs.py - ``` Explanation: - `reset`: Reset the terminal so you can scroll back to the first line of output easily. +- `DEBUG=1`: Set log-level to "debug". - `ginkgo run --focus "foo" ./controllers/...`: Run tests in the controllers directory, but only those whose `It("...")` contains "foo". - `./hack/filter-caph-controller-manager-logs.py -`: Filter the output to avoid being overwhelmed. diff --git a/docs/caph/04-developers/02-tilt.md b/docs/caph/04-developers/02-tilt.md index 8e58308f0..bb5df6ffb 100644 --- a/docs/caph/04-developers/02-tilt.md +++ b/docs/caph/04-developers/02-tilt.md @@ -17,7 +17,7 @@ solution. "deploy_observability": False, "preload_images_for_kind": True, "kind_cluster_name": "caph", -"capi_version": "v1.8.10", +"capi_version": "v1.10.9", "cabpt_version": "v0.5.5", "cacppt_version": "v0.4.10", "cert_manager_version": "v1.11.0", @@ -25,9 +25,9 @@ solution. "HCLOUD_REGION": "fsn1", "CONTROL_PLANE_MACHINE_COUNT": "3", "WORKER_MACHINE_COUNT": "3", - "KUBERNETES_VERSION": "v1.31.6", - "HCLOUD_CONTROL_PLANE_MACHINE_TYPE": "cpx31", - "HCLOUD_WORKER_MACHINE_TYPE": "cpx31", + "KUBERNETES_VERSION": "v1.33.6", + "HCLOUD_CONTROL_PLANE_MACHINE_TYPE": "cpx32", + "HCLOUD_WORKER_MACHINE_TYPE": "cpx32", "CLUSTER_NAME": "test", "HETZNER_SSH_PUB_PATH": "~/.ssh/test", "HETZNER_SSH_PRIV_PATH": "~/.ssh/test", @@ -43,5 +43,5 @@ solution. | `deploy_observability` | `bool` | `false` | no | If true, installs grafana, loki and promtail in the dev cluster. Grafana UI will be accessible via a link in the tilt console. Important! This feature requires the `helm` command to be available in the user's path | | `preload_images_for_kind` | `bool` | `true` | no | If set to true, uses `kind load docker-image` to preload images into a kind cluster | | `kind_cluster_name` | `[]object` | `"caph"` | no | The name of the kind cluster to use when preloading images | -| `capi_version` | `string` | `"v1.8.10"` | no | Version of CAPI | +| `capi_version` | `string` | `"v1.10.9"` | no | Version of CAPI | | `cert_manager_version` | `string` | `"v1.11.0"` | no | Version of cert manager | diff --git a/docs/caph/04-developers/03-releasing.md b/docs/caph/04-developers/03-releasing.md index 28fe19235..6aa2b5498 100644 --- a/docs/caph/04-developers/03-releasing.md +++ b/docs/caph/04-developers/03-releasing.md @@ -11,7 +11,7 @@ description: Documentation on the CAPH release process, describing the necessary - `git switch main` - `git pull` - Have a look at the current (old) version: [Github Releases](https://github.com/syself/cluster-api-provider-hetzner/releases) - - `export RELEASE_TAG=` (eg. `export RELEASE_TAG=v1.0.1`) + - `export RELEASE_TAG=` (eg. `export RELEASE_TAG=v1.0.7`) - `git tag -a ${RELEASE_TAG} -m ${RELEASE_TAG}` 2. Push the tag to the GitHub repository. {% callout %} diff --git a/go.mod b/go.mod index 54664f1fe..30e736793 100644 --- a/go.mod +++ b/go.mod @@ -29,8 +29,8 @@ require ( k8s.io/klog/v2 v2.130.1 k8s.io/kubectl v0.32.7 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 - sigs.k8s.io/cluster-api v1.10.4 - sigs.k8s.io/cluster-api/test v1.10.4 + sigs.k8s.io/cluster-api v1.10.9 + sigs.k8s.io/cluster-api/test v1.10.9 sigs.k8s.io/controller-runtime v0.20.4 sigs.k8s.io/kind v0.29.0 ) @@ -70,7 +70,7 @@ require ( github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/go-viper/mapstructure/v2 v2.3.0 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobuffalo/flect v1.0.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect diff --git a/go.sum b/go.sum index 3dffbacb9..099ab0ca1 100644 --- a/go.sum +++ b/go.sum @@ -44,8 +44,8 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/coredns/caddy v1.1.1 h1:2eYKZT7i6yxIfGP3qLJoJ7HAsDJqYB+X68g4NYjSrE0= github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= -github.com/coredns/corefile-migration v1.0.26 h1:xiiEkVB1Dwolb24pkeDUDBfygV9/XsOSq79yFCrhptY= -github.com/coredns/corefile-migration v1.0.26/go.mod h1:56DPqONc3njpVPsdilEnfijCwNGC3/kTJLl7i7SPavY= +github.com/coredns/corefile-migration v1.0.29 h1:g4cPYMXXDDs9uLE2gFYrJaPBuUAR07eEMGyh9JBE13w= +github.com/coredns/corefile-migration v1.0.29/go.mod h1:56DPqONc3njpVPsdilEnfijCwNGC3/kTJLl7i7SPavY= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= @@ -100,8 +100,8 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= 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/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= -github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4= github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -406,10 +406,10 @@ k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= -sigs.k8s.io/cluster-api v1.10.4 h1:5mdyWLGbbwOowWrjqM/J9N600QnxTohu5J1/1YR6g7c= -sigs.k8s.io/cluster-api v1.10.4/go.mod h1:68GJs286ZChsncp+TxYNj/vhy2NWokiPtH4+SA0afs0= -sigs.k8s.io/cluster-api/test v1.10.4 h1:1CJp7yjh2XazaPFtZzxSby9Gip2yjW0dNxyyHR7VjDk= -sigs.k8s.io/cluster-api/test v1.10.4/go.mod h1:n2LsLQxc4RSLDjUXhgzquSTagZTJpUcY7uwtQtCRmaY= +sigs.k8s.io/cluster-api v1.10.9 h1:6vjjs4a8kF5oP+t6JqHGDIjyP36ZLgqAU+8EVGjmPyE= +sigs.k8s.io/cluster-api v1.10.9/go.mod h1:IHnO3HR8ta0yK1S2SyI2qKpcrZNsyOdArwRjUfnJwnc= +sigs.k8s.io/cluster-api/test v1.10.9 h1:bf5X9VKwTdOqrZIuKnEOABVcbAXlEZbWec+rBS+mkWo= +sigs.k8s.io/cluster-api/test v1.10.9/go.mod h1:ehnxLYJn73nn/0NM0x6dJgdYa04ZWwqn7T5xcvwRwYg= sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= diff --git a/hack/ci-e2e-capi.sh b/hack/ci-e2e-capi.sh index df0e941af..4c510b042 100755 --- a/hack/ci-e2e-capi.sh +++ b/hack/ci-e2e-capi.sh @@ -42,14 +42,14 @@ echo "+ run tests!" IMAGE_PREFIX="${IMAGE_PREFIX:-ghcr.io/syself}" -if [[ -z "${TAG:-}" ]]; then +if [[ -z "${CAPH_CONTAINER_TAG:-}" ]]; then echo - echo "Error: Missing TAG environment variable" + echo "Error: Missing CAPH_CONTAINER_TAG environment variable" echo "This is the caph container image tag for the image." echo "For PRs this is pr-NNNN" echo "Use the following command to set the environment variable:" echo " gh pr view --json number --jq .number" - echo "Then: export TAG=pr-NNNN" + echo "Then: export CAPH_CONTAINER_TAG=pr-NNNN" echo exit 1 fi diff --git a/hack/create-e2e-conf-file.sh b/hack/create-e2e-conf-file.sh index 61c585948..8c8354af0 100755 --- a/hack/create-e2e-conf-file.sh +++ b/hack/create-e2e-conf-file.sh @@ -17,16 +17,16 @@ trap 'echo "ERROR: A command has failed. Exiting the script. Line was ($0:$LINENO): $(sed -n "${LINENO}p" "$0")"; exit 3' ERR set -Eeuo pipefail -./hack/ensure-env-variables.sh CAPH_LATEST_VERSION ENVSUBST E2E_CONF_FILE_SOURCE E2E_CONF_FILE TAG +./hack/ensure-env-variables.sh CAPH_LATEST_VERSION E2E_CONF_FILE_SOURCE E2E_CONF_FILE CAPH_CONTAINER_TAG -if [[ -z "${TAG:-}" ]]; then +if [[ -z "${CAPH_CONTAINER_TAG:-}" ]]; then echo - echo "Error: Missing TAG environment variable" + echo "Error: Missing CAPH_CONTAINER_TAG environment variable" echo "This is the caph container image tag for the image." echo "For PRs this is pr-NNNN" echo "Use the following command to set the environment variable:" echo " gh pr view --json number --jq .number" - echo "Then: export TAG=pr-NNNN" + echo "Then: export CAPH_CONTAINER_TAG=pr-NNNN" echo exit 1 fi @@ -38,4 +38,4 @@ make release-manifests git restore config echo "# Created from $E2E_CONF_FILE_SOURCE by $0" >"$E2E_CONF_FILE" -$ENVSUBST <"$E2E_CONF_FILE_SOURCE" >>"$E2E_CONF_FILE" +$CLUSTERCTL generate yaml <"$E2E_CONF_FILE_SOURCE" >>"$E2E_CONF_FILE" diff --git a/hack/create-workload-cluster.sh b/hack/create-workload-cluster.sh new file mode 100755 index 000000000..6a85953ce --- /dev/null +++ b/hack/create-workload-cluster.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash +# Copyright 2022 The Kubernetes Authors. +# +# 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. + +# Bash Strict Mode: https://github.com/guettli/bash-strict-mode +trap 'echo -e "\n🤷 🚨 🔥 Warning: A command has failed. Exiting the script. Line was ($0:$LINENO): $(sed -n "${LINENO}p" "$0" 2>/dev/null || true) 🔥 🚨 🤷 "; exit 3' ERR +set -Eeuo pipefail + +ROBOT= +while [[ $# -gt 0 ]]; do + case "$1" in + --robot) + ROBOT=1 + shift + ;; + *) + break + ;; + esac +done + +if [[ $# -ne 2 ]]; then + echo "Usage: $0 [--robot] API_VERSION NAME" + exit 1 +fi + +API_VERSION="$1" +case "$API_VERSION" in +v1beta1 | v1beta2) ;; +*) + echo "Error: API_VERSION must be v1beta1 or v1beta2" + exit 1 + ;; +esac + +if [[ -z "${HCLOUD_TOKEN:-}" ]]; then + echo "Error: HCLOUD_TOKEN environment variable is not set or empty." + exit 2 +fi +NAME="$2" + +BIN=./hack/tools/bin + +if [[ ! -e "$BIN"/kubectl ]]; then + make kubectl +fi + +if [[ ! -e "$BIN"/kustomize ]]; then + make kustomize +fi + +hack/ensure-ssh-key-in-hcloud.py + +secret_args=( + create secret generic hetzner + --from-literal=hcloud="$HCLOUD_TOKEN" +) + +if [[ -n $ROBOT ]]; then + if [[ -z "${HETZNER_ROBOT_USER:-}" || -z "${HETZNER_ROBOT_PASSWORD:-}" ]]; then + echo "Error: HETZNER_ROBOT_USER/HETZNER_ROBOT_PASSWORD must be set when using --robot." + exit 2 + fi + secret_args+=(--from-literal=robot-user="$HETZNER_ROBOT_USER") + secret_args+=(--from-literal=robot-password="$HETZNER_ROBOT_PASSWORD") +fi + +"$BIN"/kubectl "${secret_args[@]}" \ + --save-config --dry-run=client -o yaml | "$BIN"/kubectl apply -f - + +if [[ -n $ROBOT ]]; then + + "$BIN"/kubectl create secret generic robot-ssh \ + --from-literal=sshkey-name="$SSH_KEY_NAME" \ + --from-file=ssh-privatekey="$HETZNER_SSH_PRIV_PATH" \ + --from-file=ssh-publickey="$HETZNER_SSH_PUB_PATH" \ + --save-config --dry-run=client -o yaml | "$BIN"/kubectl apply -f - + +fi + +TEMPLATE_DIR=templates/cluster-templates/"$API_VERSION"/"$NAME" +if [[ ! -e $TEMPLATE_DIR ]]; then + echo "$TEMPLATE_DIR does not exist. Check NAME argument of this script." + exit 1 +fi + +mkdir -p generated/"$API_VERSION" + +if [[ -z $CLUSTER_NAME ]]; then + echo "CLUSTER_NAME not set" + exit 1 +fi +UNIQ="$API_VERSION/$NAME--$CLUSTER_NAME" +"$BIN"/kustomize build templates/cluster-templates/"$API_VERSION/$NAME" \ + --load-restrictor LoadRestrictionsNone >>generated/"$UNIQ"--kustomized.yaml + +"$BIN"/clusterctl generate yaml --from generated/"$UNIQ"--kustomized.yaml \ + >generated/"$UNIQ"--rendered.yaml +echo "Created generated/$UNIQ--rendered.yaml" + +echo "Applying manifests" +"$BIN"/kubectl apply --validate=true -f generated/"$UNIQ"--rendered.yaml + +make wait-and-get-secret +make install-cilium-in-wl-cluster +make install-ccm-in-wl-cluster diff --git a/hack/ensure-ssh-key-in-hcloud.py b/hack/ensure-ssh-key-in-hcloud.py new file mode 100755 index 000000000..f18c210f8 --- /dev/null +++ b/hack/ensure-ssh-key-in-hcloud.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 + +# Copyright 2025 The Kubernetes Authors. +# +# 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. + +""" +Ensure that the given SSH key exists in Hetzner Cloud with the expected content. +If the key already exists and the public key matches, the script exits 0. +If the key exists but the content differs, the script fails. +Otherwise it creates the key via the Hetzner API. +""" + +from __future__ import annotations + +import json +import os +import sys +import urllib.error +import urllib.parse +import urllib.request + + +def env_or_exit(name: str, example: str) -> str: + value = os.environ.get(name) + if not value: + print(f"{name} not set. Example: {example}", file=sys.stderr) + sys.exit(1) + return value + + +def read_ssh_key(path: str) -> str: + try: + with open(path, "r", encoding="utf-8") as fp: + return fp.read().strip() + except OSError as err: + print(f"failed to read SSH key {path}: {err}", file=sys.stderr) + sys.exit(1) + + +def hetzner_request( + url: str, token: str, method: str = "GET", payload: bytes | None = None +) -> dict[str, object]: + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + } + request = urllib.request.Request(url, data=payload, headers=headers, method=method) + try: + with urllib.request.urlopen(request) as response: + body = response.read() + except urllib.error.HTTPError as err: + body = err.read() + print(body.decode("utf-8", errors="ignore"), file=sys.stderr) + sys.exit(1) + except urllib.error.URLError as err: + print(f"failed to reach Hetzner API: {err}", file=sys.stderr) + sys.exit(1) + + try: + return json.loads(body) + except json.JSONDecodeError as err: + print(f"failed to parse Hetzner API response: {err}", file=sys.stderr) + sys.exit(1) + + +def main() -> None: + ssh_key_path = env_or_exit( + "SSH_KEY", "path to a public key (e.g. $HOME/.ssh/shared-2024-07-08.pub)" + ) + ssh_name = env_or_exit("SSH_KEY_NAME", "shared-2024-07-08") + hcloud_token = env_or_exit("HCLOUD_TOKEN", "your Hetzner API token") + + public_key = read_ssh_key(ssh_key_path) + + # remove trailing docstring, just use the first to words: + public_key = " ".join(public_key.split()[0:2]) + + encoded_name = urllib.parse.quote_plus(ssh_name) + url = f"https://api.hetzner.cloud/v1/ssh_keys?name={encoded_name}" + + data = hetzner_request(url, hcloud_token) + ssh_keys = data.get("ssh_keys", []) + assert isinstance(ssh_keys, list), "ssh_keys is not a list" + + if ssh_keys: + existing = ssh_keys[0].get("public_key", "").strip() + if existing == public_key: + print(f"ok: SSH key {ssh_name} already exists with identical content.") + sys.exit(0) + print( + f"error: SSH key {ssh_name} already exists with different public key data.", + file=sys.stderr, + ) + sys.exit(1) + + payload = json.dumps( + {"labels": {}, "name": ssh_name, "public_key": public_key} + ).encode("utf-8") + hetzner_request( + "https://api.hetzner.cloud/v1/ssh_keys", + hcloud_token, + method="POST", + payload=payload, + ) + print("SSH key created.") + + +if __name__ == "__main__": + main() diff --git a/hack/filter-caph-controller-manager-logs.py b/hack/filter-caph-controller-manager-logs.py index 907743766..787c29e8d 100755 --- a/hack/filter-caph-controller-manager-logs.py +++ b/hack/filter-caph-controller-manager-logs.py @@ -55,7 +55,11 @@ r"^Random Seed: \d+", ] -rows_to_trigger_test_filter = ["Running Suite:"] +# if this string appears, then rows_to_skip_for_tests will be added to rows_to_skip. +rows_to_trigger_test_filter_regex = [ + "Running Suite:", + r"^\[\d+\] .* Suite - \d+/\d+ specs", +] # List of fixed-strings. rows_to_skip = [ @@ -77,6 +81,7 @@ '"All workers finished"', '"Shutdown signal received, waiting for all workers to finish"', "'statusCode': 200, 'method': 'GET', 'url': 'https://robot-ws.your-server.de", + '"Update to resource changes significant fields, will enqueue event"', ] rows_to_skip_for_tests = [ @@ -115,6 +120,10 @@ '"HetznerCluster is not available yet"', '"Unable to write event (broadcaster is shut down)"', '"Unable to write event (may retry after sleeping)"', + '"Caches populated"', + '"Listing and watching"', + '"Starting reflector"', + '"Stopping reflector"', ] @@ -151,13 +160,14 @@ def read_logs(fd): def write_line(line): + global filtering_test_data ascii_line = ansi_pattern.sub("", line) - for r in rows_to_trigger_test_filter: - if r in ascii_line: - global filtering_test_data - filtering_test_data = True - rows_to_skip.extend(rows_to_skip_for_tests) - + if not filtering_test_data: + for r in rows_to_trigger_test_filter_regex: + if re.match(r, ascii_line): + filtering_test_data = True + rows_to_skip.extend(rows_to_skip_for_tests) + break for r in rows_to_skip: if r in ascii_line: return @@ -229,4 +239,7 @@ def handle_line(line): if __name__ == "__main__": - main() + try: + main() + except KeyboardInterrupt: + sys.exit(0) diff --git a/hack/get-kubeconfig-of-workload-cluster.sh b/hack/get-kubeconfig-of-workload-cluster.sh index 339deec52..522b36407 100755 --- a/hack/get-kubeconfig-of-workload-cluster.sh +++ b/hack/get-kubeconfig-of-workload-cluster.sh @@ -16,12 +16,25 @@ set -euo pipefail +CLUSTER_NAME=${CLUSTER_NAME:-} +CLUSTER_NAMESPACE=${CLUSTER_NAMESPACE:-} + +if [ -z "$CLUSTER_NAME" ]; then + # Pick the first cluster found if none is provided explicitly. + CLUSTER_NAME=$(kubectl get clusters -A -o jsonpath='{.items[0].metadata.name}') + CLUSTER_NAMESPACE=$(kubectl get clusters -A -o jsonpath='{.items[0].metadata.namespace}') +fi + if [ -z "$CLUSTER_NAME" ]; then - echo "env var CLUSTER_NAME is missing. Failed to get kubeconfig of workload cluster" + echo "env var CLUSTER_NAME is missing and no clusters found. Failed to get kubeconfig of workload cluster" exit 1 fi + +# Default to the Cluster namespace when not provided. +CLUSTER_NAMESPACE=${CLUSTER_NAMESPACE:-default} + kubeconfig=".workload-cluster-kubeconfig.yaml" -new_content="$(kubectl get secrets "${CLUSTER_NAME}-kubeconfig" -ojsonpath='{.data.value}' | base64 -d)" +new_content="$(kubectl -n "$CLUSTER_NAMESPACE" get secrets "${CLUSTER_NAME}-kubeconfig" -ojsonpath='{.data.value}' | base64 -d)" if [ -z "$new_content" ]; then echo "failed to get kubeconfig of workload cluster" diff --git a/hack/kind-dev.sh b/hack/kind-dev.sh index 213b7b7b4..6b34a284b 100755 --- a/hack/kind-dev.sh +++ b/hack/kind-dev.sh @@ -14,16 +14,20 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -o errexit -set -o pipefail -set -x +# Bash Strict Mode: https://github.com/guettli/bash-strict-mode +trap 'echo -e "\n🤷 🚨 🔥 Warning: A command has failed. Exiting the script. Line was ($0:$LINENO): $(sed -n "${LINENO}p" "$0" 2>/dev/null || true) 🔥 🚨 🤷 "; exit 3' ERR +set -Eeuo pipefail # See `crane ls ghcr.io/fluxcd/kindest/node` for available versions -K8S_VERSION=v1.31.5 +K8S_VERSION=v1.33.0 REPO_ROOT=$(git rev-parse --show-toplevel) cd "${REPO_ROOT}" || exit 1 +if [[ ! -e $REPO_ROOT/hack/tools/bin/ctlptl ]]; then + make ctlptl +fi + # Creates a kind cluster with the ctlptl tool https://github.com/tilt-dev/ctlptl ctlptl_kind-cluster-with-registry() { @@ -62,4 +66,4 @@ ctlptl_kind-cluster-with-registry caph ${K8S_VERSION} echo "" echo "" echo "" -echo "Cluster is ready - you can now tilt up!" +echo "Cluster is ready. Next: 'make tilt-up' or 'make create-mgt-cluster'" diff --git a/hack/kustomize-sub.sh b/hack/kustomize-sub.sh index e4e1098a0..b66be39f4 100755 --- a/hack/kustomize-sub.sh +++ b/hack/kustomize-sub.sh @@ -18,4 +18,4 @@ set -o nounset set -o pipefail root=$(dirname "${BASH_SOURCE[0]}") -$root/tools/bin/kustomize build $1 | $root/tools/bin/envsubst \ No newline at end of file +"$root"/tools/bin/kustomize build "$1" | "$root"/tools/bin/clusterctl generate yaml diff --git a/hack/output-for-watch.sh b/hack/output-for-watch.sh index 972afe39b..700aba064 100755 --- a/hack/output-for-watch.sh +++ b/hack/output-for-watch.sh @@ -37,7 +37,7 @@ kubectl get clusters -A print_heading machines: -kubectl -n org-testing get machines \ +kubectl get machines -A \ -o custom-columns='NAME:.metadata.name,NODENAME:.status.nodeRef.name,IP:.status.addresses[?(@.type=="ExternalIP")].address,PROVIDERID:.spec.providerID,PHASE:.status.phase,VERSION:.spec.version' print_heading hcloudmachine: diff --git a/hack/test-unit.sh b/hack/test-unit.sh index 79e4f2f86..6f7324b99 100755 --- a/hack/test-unit.sh +++ b/hack/test-unit.sh @@ -28,6 +28,14 @@ KUBEBUILDER_ASSETS=$(./hack/tools/bin/setup-envtest use --use-env \ --bin-dir "$PWD/hack/tools/bin" -p path \ "$KUBEBUILDER_ENVTEST_KUBERNETES_VERSION") +if [[ ! -e $KUBEBUILDER_ASSETS ]]; then + echo "$KUBEBUILDER_ASSETS does not exist. Check our setup." + echo "Maybe env var wrong: KUBEBUILDER_ASSETS=$KUBEBUILDER_ASSETS" + echo "Maybe this helps:" + echo " rm -rf hack/tools/bin/setup-envtest" + echo " make setup-envtest" + exit 1 +fi export KUBEBUILDER_ASSETS mkdir -p .coverage diff --git a/hack/update-operator-dev-deployment.sh b/hack/update-operator-dev-deployment.sh index dc1f7298c..47cb7ef74 100755 --- a/hack/update-operator-dev-deployment.sh +++ b/hack/update-operator-dev-deployment.sh @@ -60,7 +60,7 @@ if ! kubectl cluster-info >/dev/null; then fi current_context=$(kubectl config current-context) -if ! echo "$current_context" | grep -P '.*-admin@.*-mgt-cluster'; then +if ! echo "$current_context" | grep -P '.*-admin@.*-mgt-cluster|kind-'; then echo "The script refuses to update because the current context is: $current_context" echo "Expecting something like foo-mgt-cluster-admin@foo-mgt-cluster with 'foo' being a short version of your name" exit 1 diff --git a/images/builder/Dockerfile b/images/builder/Dockerfile index 6614257bd..ba3b6f091 100644 --- a/images/builder/Dockerfile +++ b/images/builder/Dockerfile @@ -68,9 +68,6 @@ RUN apt-get update && \ yamlfixer-opt-nc==${YAMLFIXER_VERSION} -# Install controller-gen (current version) -RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.18.0 - # Install controller-gen (current version) RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.18.0 diff --git a/templates/cluster-templates/hcloud-network/kustomization.yaml b/templates/cluster-templates/hcloud-network/kustomization.yaml deleted file mode 100644 index dd1756ac4..000000000 --- a/templates/cluster-templates/hcloud-network/kustomization.yaml +++ /dev/null @@ -1,14 +0,0 @@ -bases: - - ../bases/capi-cluster-kubeadm.yaml - - ../bases/hcloud-hetznerCluster-network.yaml - - ../bases/hcloud-kcp-ubuntu.yaml - - ../bases/hcloud-mt-control-plane-ubuntu.yaml - - ../bases/hcloud-mhc-control-plane.yaml - - ../bases/hcloud-md-0-kubeadm.yaml - - ../bases/kct-md-0-ubuntu.yaml - - ../bases/hcloud-mt-md-0-ubuntu.yaml - - ../bases/hcloud-mhc-md-0.yaml -patchesStrategicMerge: - - ../bases/hcloud-hetznerCluster-placementGroup_patch.yaml - - ../bases/hcloud-mt-control-plane-placementGroup_patch.yaml - - ../bases/hcloud-mt-md-0-placementGroup_patch.yaml diff --git a/templates/cluster-templates/hcloud/kustomization.yaml b/templates/cluster-templates/hcloud/kustomization.yaml deleted file mode 100644 index dce0dafe0..000000000 --- a/templates/cluster-templates/hcloud/kustomization.yaml +++ /dev/null @@ -1,15 +0,0 @@ -bases: - - ../bases/capi-cluster-kubeadm.yaml - - ../bases/hcloud-hetznerCluster.yaml - - ../bases/hcloud-kcp-ubuntu.yaml - - ../bases/hcloud-mt-control-plane-ubuntu.yaml - - ../bases/hcloud-mhc-control-plane.yaml - - ../bases/hcloud-md-0-kubeadm.yaml - - ../bases/kct-md-0-ubuntu.yaml - - ../bases/hcloud-mt-md-0-ubuntu.yaml - - ../bases/hcloud-mhc-md-0.yaml - -patchesStrategicMerge: - - ../bases/hcloud-hetznerCluster-placementGroup_patch.yaml - - ../bases/hcloud-mt-control-plane-placementGroup_patch.yaml - - ../bases/hcloud-mt-md-0-placementGroup_patch.yaml diff --git a/templates/cluster-templates/hetzner-baremetal-control-planes-remediation/kustomization.yaml b/templates/cluster-templates/hetzner-baremetal-control-planes-remediation/kustomization.yaml deleted file mode 100644 index decd57c48..000000000 --- a/templates/cluster-templates/hetzner-baremetal-control-planes-remediation/kustomization.yaml +++ /dev/null @@ -1,17 +0,0 @@ -resources: - - ../bases/capi-cluster-kubeadm.yaml - - ../bases/hetzner-hetznerCluster.yaml - - ../bases/hetznerbaremetal-kcp-ubuntu.yaml - - ../bases/hetznerbaremetal-mt-control-plane-ubuntu.yaml - - ../bases/hetznerbaremetal-mhc-rt-control-plane.yaml - - ../bases/hcloud-md-0-kubeadm.yaml - - ../bases/kct-md-0-ubuntu.yaml - - ../bases/hcloud-mt-md-0-ubuntu.yaml - - ../bases/hcloud-mhc-md-0.yaml - - ../bases/hetznerbaremetal-md-1-kubeadm.yaml - - md-1 - - ../bases/hetznerbaremetal-mt-md-1-ubuntu.yaml - - ../bases/hetznerbaremetal-mhc-rt-md-1.yaml -patchesStrategicMerge: - - ../bases/hcloud-hetznerCluster-placementGroup_patch.yaml - - ../bases/hcloud-mt-md-0-placementGroup_patch.yaml diff --git a/templates/cluster-templates/hetzner-baremetal-control-planes/kustomization.yaml b/templates/cluster-templates/hetzner-baremetal-control-planes/kustomization.yaml deleted file mode 100644 index 2037b4d97..000000000 --- a/templates/cluster-templates/hetzner-baremetal-control-planes/kustomization.yaml +++ /dev/null @@ -1,17 +0,0 @@ -resources: - - ../bases/capi-cluster-kubeadm.yaml - - ../bases/hetzner-hetznerCluster.yaml - - ../bases/hetznerbaremetal-kcp-ubuntu.yaml - - ../bases/hetznerbaremetal-mt-control-plane-ubuntu.yaml - - ../bases/hetznerbaremetal-mhc-control-plane.yaml - - ../bases/hcloud-md-0-kubeadm.yaml - - ../bases/kct-md-0-ubuntu.yaml - - ../bases/hcloud-mt-md-0-ubuntu.yaml - - ../bases/hcloud-mhc-md-0.yaml - - ../bases/hetznerbaremetal-md-1-kubeadm.yaml - - md-1 - - ../bases/hetznerbaremetal-mt-md-1-ubuntu.yaml - - ../bases/hetznerbaremetal-mhc-md-1.yaml -patchesStrategicMerge: - - ../bases/hcloud-hetznerCluster-placementGroup_patch.yaml - - ../bases/hcloud-mt-md-0-placementGroup_patch.yaml diff --git a/templates/cluster-templates/hetzner-hcloud-control-planes/kustomization.yaml b/templates/cluster-templates/hetzner-hcloud-control-planes/kustomization.yaml deleted file mode 100644 index 531755661..000000000 --- a/templates/cluster-templates/hetzner-hcloud-control-planes/kustomization.yaml +++ /dev/null @@ -1,18 +0,0 @@ -resources: - - ../bases/capi-cluster-kubeadm.yaml - - ../bases/hetzner-hetznerCluster.yaml - - ../bases/hcloud-kcp-ubuntu.yaml - - ../bases/hcloud-mt-control-plane-ubuntu.yaml - - ../bases/hcloud-mhc-control-plane.yaml - - ../bases/hcloud-md-0-kubeadm.yaml - - ../bases/kct-md-0-ubuntu.yaml - - ../bases/hcloud-mt-md-0-ubuntu.yaml - - ../bases/hcloud-mhc-md-0.yaml - - ../bases/hetznerbaremetal-md-1-kubeadm.yaml - - md-1 - - ../bases/hetznerbaremetal-mt-md-1-ubuntu.yaml - - ../bases/hetznerbaremetal-mhc-md-1.yaml -patchesStrategicMerge: - - ../bases/hcloud-hetznerCluster-placementGroup_patch.yaml - - ../bases/hcloud-mt-control-plane-placementGroup_patch.yaml - - ../bases/hcloud-mt-md-0-placementGroup_patch.yaml diff --git a/templates/cluster-templates/bases/capi-cluster-kubeadm.yaml b/templates/cluster-templates/v1beta1/bases/capi-cluster-kubeadm.yaml similarity index 100% rename from templates/cluster-templates/bases/capi-cluster-kubeadm.yaml rename to templates/cluster-templates/v1beta1/bases/capi-cluster-kubeadm.yaml diff --git a/templates/cluster-templates/bases/hcloud-hetznerCluster-network.yaml b/templates/cluster-templates/v1beta1/bases/hcloud-hetznerCluster-network.yaml similarity index 100% rename from templates/cluster-templates/bases/hcloud-hetznerCluster-network.yaml rename to templates/cluster-templates/v1beta1/bases/hcloud-hetznerCluster-network.yaml diff --git a/templates/cluster-templates/bases/hcloud-hetznerCluster-placementGroup_patch.yaml b/templates/cluster-templates/v1beta1/bases/hcloud-hetznerCluster-placementGroup_patch.yaml similarity index 100% rename from templates/cluster-templates/bases/hcloud-hetznerCluster-placementGroup_patch.yaml rename to templates/cluster-templates/v1beta1/bases/hcloud-hetznerCluster-placementGroup_patch.yaml diff --git a/templates/cluster-templates/bases/hcloud-hetznerCluster.yaml b/templates/cluster-templates/v1beta1/bases/hcloud-hetznerCluster.yaml similarity index 100% rename from templates/cluster-templates/bases/hcloud-hetznerCluster.yaml rename to templates/cluster-templates/v1beta1/bases/hcloud-hetznerCluster.yaml diff --git a/templates/cluster-templates/bases/hcloud-kcp-ubuntu.yaml b/templates/cluster-templates/v1beta1/bases/hcloud-kcp-ubuntu.yaml similarity index 100% rename from templates/cluster-templates/bases/hcloud-kcp-ubuntu.yaml rename to templates/cluster-templates/v1beta1/bases/hcloud-kcp-ubuntu.yaml diff --git a/templates/cluster-templates/bases/hcloud-md-0-kubeadm.yaml b/templates/cluster-templates/v1beta1/bases/hcloud-md-0-kubeadm.yaml similarity index 100% rename from templates/cluster-templates/bases/hcloud-md-0-kubeadm.yaml rename to templates/cluster-templates/v1beta1/bases/hcloud-md-0-kubeadm.yaml diff --git a/templates/cluster-templates/bases/hcloud-mhc-control-plane.yaml b/templates/cluster-templates/v1beta1/bases/hcloud-mhc-control-plane.yaml similarity index 100% rename from templates/cluster-templates/bases/hcloud-mhc-control-plane.yaml rename to templates/cluster-templates/v1beta1/bases/hcloud-mhc-control-plane.yaml diff --git a/templates/cluster-templates/bases/hcloud-mhc-md-0.yaml b/templates/cluster-templates/v1beta1/bases/hcloud-mhc-md-0.yaml similarity index 100% rename from templates/cluster-templates/bases/hcloud-mhc-md-0.yaml rename to templates/cluster-templates/v1beta1/bases/hcloud-mhc-md-0.yaml diff --git a/templates/cluster-templates/bases/hcloud-mt-control-plane-placementGroup_patch.yaml b/templates/cluster-templates/v1beta1/bases/hcloud-mt-control-plane-placementGroup_patch.yaml similarity index 100% rename from templates/cluster-templates/bases/hcloud-mt-control-plane-placementGroup_patch.yaml rename to templates/cluster-templates/v1beta1/bases/hcloud-mt-control-plane-placementGroup_patch.yaml diff --git a/templates/cluster-templates/bases/hcloud-mt-control-plane-ubuntu.yaml b/templates/cluster-templates/v1beta1/bases/hcloud-mt-control-plane-ubuntu.yaml similarity index 100% rename from templates/cluster-templates/bases/hcloud-mt-control-plane-ubuntu.yaml rename to templates/cluster-templates/v1beta1/bases/hcloud-mt-control-plane-ubuntu.yaml diff --git a/templates/cluster-templates/bases/hcloud-mt-md-0-placementGroup_patch.yaml b/templates/cluster-templates/v1beta1/bases/hcloud-mt-md-0-placementGroup_patch.yaml similarity index 100% rename from templates/cluster-templates/bases/hcloud-mt-md-0-placementGroup_patch.yaml rename to templates/cluster-templates/v1beta1/bases/hcloud-mt-md-0-placementGroup_patch.yaml diff --git a/templates/cluster-templates/bases/hcloud-mt-md-0-ubuntu.yaml b/templates/cluster-templates/v1beta1/bases/hcloud-mt-md-0-ubuntu.yaml similarity index 100% rename from templates/cluster-templates/bases/hcloud-mt-md-0-ubuntu.yaml rename to templates/cluster-templates/v1beta1/bases/hcloud-mt-md-0-ubuntu.yaml diff --git a/templates/cluster-templates/bases/hetzner-hetznerCluster.yaml b/templates/cluster-templates/v1beta1/bases/hetzner-hetznerCluster.yaml similarity index 100% rename from templates/cluster-templates/bases/hetzner-hetznerCluster.yaml rename to templates/cluster-templates/v1beta1/bases/hetzner-hetznerCluster.yaml diff --git a/templates/cluster-templates/bases/hetznerbaremetal-kcp-ubuntu.yaml b/templates/cluster-templates/v1beta1/bases/hetznerbaremetal-kcp-ubuntu.yaml similarity index 100% rename from templates/cluster-templates/bases/hetznerbaremetal-kcp-ubuntu.yaml rename to templates/cluster-templates/v1beta1/bases/hetznerbaremetal-kcp-ubuntu.yaml diff --git a/templates/cluster-templates/bases/hetznerbaremetal-md-1-kubeadm.yaml b/templates/cluster-templates/v1beta1/bases/hetznerbaremetal-md-1-kubeadm.yaml similarity index 100% rename from templates/cluster-templates/bases/hetznerbaremetal-md-1-kubeadm.yaml rename to templates/cluster-templates/v1beta1/bases/hetznerbaremetal-md-1-kubeadm.yaml diff --git a/templates/cluster-templates/bases/hetznerbaremetal-mhc-control-plane.yaml b/templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mhc-control-plane.yaml similarity index 100% rename from templates/cluster-templates/bases/hetznerbaremetal-mhc-control-plane.yaml rename to templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mhc-control-plane.yaml diff --git a/templates/cluster-templates/bases/hetznerbaremetal-mhc-md-1.yaml b/templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mhc-md-1.yaml similarity index 100% rename from templates/cluster-templates/bases/hetznerbaremetal-mhc-md-1.yaml rename to templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mhc-md-1.yaml diff --git a/templates/cluster-templates/bases/hetznerbaremetal-mhc-rt-control-plane.yaml b/templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mhc-rt-control-plane.yaml similarity index 100% rename from templates/cluster-templates/bases/hetznerbaremetal-mhc-rt-control-plane.yaml rename to templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mhc-rt-control-plane.yaml diff --git a/templates/cluster-templates/bases/hetznerbaremetal-mhc-rt-md-1.yaml b/templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mhc-rt-md-1.yaml similarity index 100% rename from templates/cluster-templates/bases/hetznerbaremetal-mhc-rt-md-1.yaml rename to templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mhc-rt-md-1.yaml diff --git a/templates/cluster-templates/bases/hetznerbaremetal-mt-control-plane-ubuntu.yaml b/templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mt-control-plane-ubuntu.yaml similarity index 100% rename from templates/cluster-templates/bases/hetznerbaremetal-mt-control-plane-ubuntu.yaml rename to templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mt-control-plane-ubuntu.yaml diff --git a/templates/cluster-templates/bases/hetznerbaremetal-mt-md-1-ubuntu.yaml b/templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mt-md-1-ubuntu.yaml similarity index 100% rename from templates/cluster-templates/bases/hetznerbaremetal-mt-md-1-ubuntu.yaml rename to templates/cluster-templates/v1beta1/bases/hetznerbaremetal-mt-md-1-ubuntu.yaml diff --git a/templates/cluster-templates/bases/kct-md-0-ubuntu.yaml b/templates/cluster-templates/v1beta1/bases/kct-md-0-ubuntu.yaml similarity index 100% rename from templates/cluster-templates/bases/kct-md-0-ubuntu.yaml rename to templates/cluster-templates/v1beta1/bases/kct-md-0-ubuntu.yaml diff --git a/templates/cluster-templates/cluster-class-topology-example.yaml b/templates/cluster-templates/v1beta1/cluster-class-topology-example.yaml similarity index 99% rename from templates/cluster-templates/cluster-class-topology-example.yaml rename to templates/cluster-templates/v1beta1/cluster-class-topology-example.yaml index e883b3abc..79dcb4be7 100644 --- a/templates/cluster-templates/cluster-class-topology-example.yaml +++ b/templates/cluster-templates/v1beta1/cluster-class-topology-example.yaml @@ -48,7 +48,7 @@ spec: - name: region value: hel1 # - name: hcloudControlPlaneMachineType - # value: cpx31 + # value: cpx32 # - name: hcloudControlPlaneMachineImageName # value: ubuntu-24.04 - name: hcloudControlPlanePlacementGroupName diff --git a/templates/cluster-templates/cluster-class.yaml b/templates/cluster-templates/v1beta1/cluster-class.yaml similarity index 100% rename from templates/cluster-templates/cluster-class.yaml rename to templates/cluster-templates/v1beta1/cluster-class.yaml diff --git a/templates/cluster-templates/v1beta1/hcloud-network/kustomization.yaml b/templates/cluster-templates/v1beta1/hcloud-network/kustomization.yaml new file mode 100644 index 000000000..38a24444a --- /dev/null +++ b/templates/cluster-templates/v1beta1/hcloud-network/kustomization.yaml @@ -0,0 +1,16 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- ../bases/capi-cluster-kubeadm.yaml +- ../bases/hcloud-hetznerCluster-network.yaml +- ../bases/hcloud-kcp-ubuntu.yaml +- ../bases/hcloud-mt-control-plane-ubuntu.yaml +- ../bases/hcloud-mhc-control-plane.yaml +- ../bases/hcloud-md-0-kubeadm.yaml +- ../bases/kct-md-0-ubuntu.yaml +- ../bases/hcloud-mt-md-0-ubuntu.yaml +- ../bases/hcloud-mhc-md-0.yaml +patches: +- path: ../bases/hcloud-hetznerCluster-placementGroup_patch.yaml +- path: ../bases/hcloud-mt-control-plane-placementGroup_patch.yaml +- path: ../bases/hcloud-mt-md-0-placementGroup_patch.yaml diff --git a/templates/cluster-templates/v1beta1/hcloud/kustomization.yaml b/templates/cluster-templates/v1beta1/hcloud/kustomization.yaml new file mode 100644 index 000000000..69d944e73 --- /dev/null +++ b/templates/cluster-templates/v1beta1/hcloud/kustomization.yaml @@ -0,0 +1,16 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- ../bases/capi-cluster-kubeadm.yaml +- ../bases/hcloud-hetznerCluster.yaml +- ../bases/hcloud-kcp-ubuntu.yaml +- ../bases/hcloud-mt-control-plane-ubuntu.yaml +- ../bases/hcloud-mhc-control-plane.yaml +- ../bases/hcloud-md-0-kubeadm.yaml +- ../bases/kct-md-0-ubuntu.yaml +- ../bases/hcloud-mt-md-0-ubuntu.yaml +- ../bases/hcloud-mhc-md-0.yaml +patches: +- path: ../bases/hcloud-hetznerCluster-placementGroup_patch.yaml +- path: ../bases/hcloud-mt-control-plane-placementGroup_patch.yaml +- path: ../bases/hcloud-mt-md-0-placementGroup_patch.yaml diff --git a/templates/cluster-templates/v1beta1/hetzner-baremetal-control-planes-remediation/kustomization.yaml b/templates/cluster-templates/v1beta1/hetzner-baremetal-control-planes-remediation/kustomization.yaml new file mode 100644 index 000000000..efb1e57fa --- /dev/null +++ b/templates/cluster-templates/v1beta1/hetzner-baremetal-control-planes-remediation/kustomization.yaml @@ -0,0 +1,19 @@ +resources: +- ../bases/capi-cluster-kubeadm.yaml +- ../bases/hetzner-hetznerCluster.yaml +- ../bases/hetznerbaremetal-kcp-ubuntu.yaml +- ../bases/hetznerbaremetal-mt-control-plane-ubuntu.yaml +- ../bases/hetznerbaremetal-mhc-rt-control-plane.yaml +- ../bases/hcloud-md-0-kubeadm.yaml +- ../bases/kct-md-0-ubuntu.yaml +- ../bases/hcloud-mt-md-0-ubuntu.yaml +- ../bases/hcloud-mhc-md-0.yaml +- ../bases/hetznerbaremetal-md-1-kubeadm.yaml +- md-1 +- ../bases/hetznerbaremetal-mt-md-1-ubuntu.yaml +- ../bases/hetznerbaremetal-mhc-rt-md-1.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +patches: +- path: ../bases/hcloud-hetznerCluster-placementGroup_patch.yaml +- path: ../bases/hcloud-mt-md-0-placementGroup_patch.yaml diff --git a/templates/cluster-templates/hetzner-baremetal-control-planes-remediation/md-1/kustomization.yaml b/templates/cluster-templates/v1beta1/hetzner-baremetal-control-planes-remediation/md-1/kustomization.yaml similarity index 100% rename from templates/cluster-templates/hetzner-baremetal-control-planes-remediation/md-1/kustomization.yaml rename to templates/cluster-templates/v1beta1/hetzner-baremetal-control-planes-remediation/md-1/kustomization.yaml diff --git a/templates/cluster-templates/v1beta1/hetzner-baremetal-control-planes/kustomization.yaml b/templates/cluster-templates/v1beta1/hetzner-baremetal-control-planes/kustomization.yaml new file mode 100644 index 000000000..ac856720c --- /dev/null +++ b/templates/cluster-templates/v1beta1/hetzner-baremetal-control-planes/kustomization.yaml @@ -0,0 +1,19 @@ +resources: +- ../bases/capi-cluster-kubeadm.yaml +- ../bases/hetzner-hetznerCluster.yaml +- ../bases/hetznerbaremetal-kcp-ubuntu.yaml +- ../bases/hetznerbaremetal-mt-control-plane-ubuntu.yaml +- ../bases/hetznerbaremetal-mhc-control-plane.yaml +- ../bases/hcloud-md-0-kubeadm.yaml +- ../bases/kct-md-0-ubuntu.yaml +- ../bases/hcloud-mt-md-0-ubuntu.yaml +- ../bases/hcloud-mhc-md-0.yaml +- ../bases/hetznerbaremetal-md-1-kubeadm.yaml +- md-1 +- ../bases/hetznerbaremetal-mt-md-1-ubuntu.yaml +- ../bases/hetznerbaremetal-mhc-md-1.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +patches: +- path: ../bases/hcloud-hetznerCluster-placementGroup_patch.yaml +- path: ../bases/hcloud-mt-md-0-placementGroup_patch.yaml diff --git a/templates/cluster-templates/hetzner-baremetal-control-planes/md-1/kustomization.yaml b/templates/cluster-templates/v1beta1/hetzner-baremetal-control-planes/md-1/kustomization.yaml similarity index 100% rename from templates/cluster-templates/hetzner-baremetal-control-planes/md-1/kustomization.yaml rename to templates/cluster-templates/v1beta1/hetzner-baremetal-control-planes/md-1/kustomization.yaml diff --git a/templates/cluster-templates/v1beta1/hetzner-hcloud-control-planes/kustomization.yaml b/templates/cluster-templates/v1beta1/hetzner-hcloud-control-planes/kustomization.yaml new file mode 100644 index 000000000..7c04d6a8c --- /dev/null +++ b/templates/cluster-templates/v1beta1/hetzner-hcloud-control-planes/kustomization.yaml @@ -0,0 +1,20 @@ +resources: +- ../bases/capi-cluster-kubeadm.yaml +- ../bases/hetzner-hetznerCluster.yaml +- ../bases/hcloud-kcp-ubuntu.yaml +- ../bases/hcloud-mt-control-plane-ubuntu.yaml +- ../bases/hcloud-mhc-control-plane.yaml +- ../bases/hcloud-md-0-kubeadm.yaml +- ../bases/kct-md-0-ubuntu.yaml +- ../bases/hcloud-mt-md-0-ubuntu.yaml +- ../bases/hcloud-mhc-md-0.yaml +- ../bases/hetznerbaremetal-md-1-kubeadm.yaml +- md-1 +- ../bases/hetznerbaremetal-mt-md-1-ubuntu.yaml +- ../bases/hetznerbaremetal-mhc-md-1.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +patches: +- path: ../bases/hcloud-hetznerCluster-placementGroup_patch.yaml +- path: ../bases/hcloud-mt-control-plane-placementGroup_patch.yaml +- path: ../bases/hcloud-mt-md-0-placementGroup_patch.yaml diff --git a/templates/cluster-templates/hetzner-hcloud-control-planes/md-1/kustomization.yaml b/templates/cluster-templates/v1beta1/hetzner-hcloud-control-planes/md-1/kustomization.yaml similarity index 100% rename from templates/cluster-templates/hetzner-hcloud-control-planes/md-1/kustomization.yaml rename to templates/cluster-templates/v1beta1/hetzner-hcloud-control-planes/md-1/kustomization.yaml diff --git a/test/e2e/config/hetzner.yaml b/test/e2e/config/hetzner.yaml index f60c6e313..f666c5c6f 100644 --- a/test/e2e/config/hetzner.yaml +++ b/test/e2e/config/hetzner.yaml @@ -135,23 +135,23 @@ providers: variables: # Upgrade Test - KUBERNETES_VERSION_MANAGEMENT: "v1.31.6" - KUBERNETES_VERSION: "${KUBERNETES_VERSION:-v1.31.6}" - KUBERNETES_VERSION_UPGRADE_FROM: "v1.30.10" - KUBERNETES_VERSION_UPGRADE_TO: "v1.31.6" + KUBERNETES_VERSION_MANAGEMENT: "v1.33.6" + KUBERNETES_VERSION: "${KUBERNETES_VERSION:-v1.33.6}" + KUBERNETES_VERSION_UPGRADE_FROM: "v1.32.10" + KUBERNETES_VERSION_UPGRADE_TO: "v1.33.6" CONTROL_PLANE_MACHINE_TEMPLATE_UPGRADE_TO: "k8s-upgrade-control-plane" WORKERS_MACHINE_TEMPLATE_UPGRADE_TO: "k8s-upgrade-worker" KUBERNETES_IMAGE_UPGRADE_FROM: ${KUBERNETES_IMAGE_UPGRADE_FROM:-} KUBERNETES_IMAGE_UPGRADE_TO: ${KUBERNETES_IMAGE_UPGRADE_TO:-} - ETCD_VERSION_UPGRADE_TO: "3.5.12-0" - COREDNS_VERSION_UPGRADE_TO: "v1.11.1" + ETCD_VERSION_UPGRADE_TO: "3.5.24-0" + COREDNS_VERSION_UPGRADE_TO: "v1.12.0" IP_FAMILY: "IPv4" # NOTE: INIT_WITH_BINARY and INIT_WITH_KUBERNETES_VERSION are only used by the clusterctl upgrade test to initialize # the management cluster to be upgraded. - INIT_WITH_BINARY: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.8.10/clusterctl-linux-amd64" + INIT_WITH_BINARY: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.10.9/clusterctl-linux-amd64" INIT_WITH_PROVIDERS_CONTRACT: "v1beta1" - INIT_WITH_KUBERNETES_VERSION: "v1.31.6" + INIT_WITH_KUBERNETES_VERSION: "v1.33.6" INIT_WITH_INFRASTRUCTURE_PROVIDER_VERSION: ${CAPH_LATEST_VERSION} # Cluster Addons @@ -178,8 +178,8 @@ variables: HETZNER_SSH_PRIV: "secret" SSH_KEY_NAME: "shared-2024-07-08" HCLOUD_REGION: "nbg1" - HCLOUD_CONTROL_PLANE_MACHINE_TYPE: cpx31 - HCLOUD_WORKER_MACHINE_TYPE: cpx21 + HCLOUD_CONTROL_PLANE_MACHINE_TYPE: cpx32 + HCLOUD_WORKER_MACHINE_TYPE: cpx22 REDACT_LOG_SCRIPT: "../../hack/log/redact.sh" intervals: diff --git a/vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml b/vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml index ec1680b3a..bda962566 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml +++ b/vendor/github.com/go-viper/mapstructure/v2/.golangci.yaml @@ -37,3 +37,12 @@ formatters: - standard - default - localmodule + gofmt: + simplify: true + rewrite-rules: + - pattern: interface{} + replacement: any + + exclusions: + paths: + - internal/ diff --git a/vendor/github.com/go-viper/mapstructure/v2/README.md b/vendor/github.com/go-viper/mapstructure/v2/README.md index bc4be08e6..45db71975 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/README.md +++ b/vendor/github.com/go-viper/mapstructure/v2/README.md @@ -1,7 +1,7 @@ # mapstructure [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/go-viper/mapstructure/ci.yaml?style=flat-square)](https://github.com/go-viper/mapstructure/actions/workflows/ci.yaml) -[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/mod/github.com/go-viper/mapstructure) +[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/mod/github.com/go-viper/mapstructure/v2) ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/go-viper/mapstructure?style=flat-square&color=61CFDD) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-viper/mapstructure/badge?style=flat-square)](https://deps.dev/go/github.com%252Fgo-viper%252Fmapstructure%252Fv2) diff --git a/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go b/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go index 57c6de69d..a852a0a04 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go +++ b/vendor/github.com/go-viper/mapstructure/v2/decode_hooks.go @@ -13,7 +13,7 @@ import ( "time" ) -// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns +// typedDecodeHook takes a raw DecodeHookFunc (an any) and turns // it into the proper DecodeHookFunc type, such as DecodeHookFuncType. func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { // Create variables here so we can reference them with the reflect pkg @@ -23,7 +23,7 @@ func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { // Fill in the variables into this interface and the rest is done // automatically using the reflect package. - potential := []interface{}{f1, f2, f3} + potential := []any{f1, f2, f3} v := reflect.ValueOf(h) vt := v.Type() @@ -37,25 +37,25 @@ func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { return nil } -// cachedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns +// cachedDecodeHook takes a raw DecodeHookFunc (an any) and turns // it into a closure to be used directly // if the type fails to convert we return a closure always erroring to keep the previous behaviour -func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Value) (interface{}, error) { +func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Value) (any, error) { switch f := typedDecodeHook(raw).(type) { case DecodeHookFuncType: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return func(from reflect.Value, to reflect.Value) (any, error) { return f(from.Type(), to.Type(), from.Interface()) } case DecodeHookFuncKind: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return func(from reflect.Value, to reflect.Value) (any, error) { return f(from.Kind(), to.Kind(), from.Interface()) } case DecodeHookFuncValue: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return func(from reflect.Value, to reflect.Value) (any, error) { return f(from, to) } default: - return func(from reflect.Value, to reflect.Value) (interface{}, error) { + return func(from reflect.Value, to reflect.Value) (any, error) { return nil, errors.New("invalid decode hook signature") } } @@ -67,7 +67,7 @@ func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Va func DecodeHookExec( raw DecodeHookFunc, from reflect.Value, to reflect.Value, -) (interface{}, error) { +) (any, error) { switch f := typedDecodeHook(raw).(type) { case DecodeHookFuncType: return f(from.Type(), to.Type(), from.Interface()) @@ -86,11 +86,11 @@ func DecodeHookExec( // The composed funcs are called in order, with the result of the // previous transformation. func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { - cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(fs)) + cached := make([]func(from reflect.Value, to reflect.Value) (any, error), 0, len(fs)) for _, f := range fs { cached = append(cached, cachedDecodeHook(f)) } - return func(f reflect.Value, t reflect.Value) (interface{}, error) { + return func(f reflect.Value, t reflect.Value) (any, error) { var err error data := f.Interface() @@ -114,13 +114,13 @@ func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { // OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned. // If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages. func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc { - cached := make([]func(from reflect.Value, to reflect.Value) (interface{}, error), 0, len(ff)) + cached := make([]func(from reflect.Value, to reflect.Value) (any, error), 0, len(ff)) for _, f := range ff { cached = append(cached, cachedDecodeHook(f)) } - return func(a, b reflect.Value) (interface{}, error) { + return func(a, b reflect.Value) (any, error) { var allErrs string - var out interface{} + var out any var err error for _, c := range cached { @@ -143,8 +143,8 @@ func StringToSliceHookFunc(sep string) DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -161,14 +161,37 @@ func StringToSliceHookFunc(sep string) DecodeHookFunc { } } +// StringToWeakSliceHookFunc brings back the old (pre-v2) behavior of [StringToSliceHookFunc]. +// +// As of mapstructure v2.0.0 [StringToSliceHookFunc] checks if the return type is a string slice. +// This function removes that check. +func StringToWeakSliceHookFunc(sep string) DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data any, + ) (any, error) { + if f.Kind() != reflect.String || t.Kind() != reflect.Slice { + return data, nil + } + + raw := data.(string) + if raw == "" { + return []string{}, nil + } + + return strings.Split(raw, sep), nil + } +} + // StringToTimeDurationHookFunc returns a DecodeHookFunc that converts // strings to time.Duration. func StringToTimeDurationHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -177,7 +200,29 @@ func StringToTimeDurationHookFunc() DecodeHookFunc { } // Convert it by parsing - return time.ParseDuration(data.(string)) + d, err := time.ParseDuration(data.(string)) + + return d, wrapTimeParseDurationError(err) + } +} + +// StringToTimeLocationHookFunc returns a DecodeHookFunc that converts +// strings to *time.Location. +func StringToTimeLocationHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data any, + ) (any, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(time.Local) { + return data, nil + } + d, err := time.LoadLocation(data.(string)) + + return d, wrapTimeParseLocationError(err) } } @@ -187,8 +232,8 @@ func StringToURLHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -197,7 +242,9 @@ func StringToURLHookFunc() DecodeHookFunc { } // Convert it by parsing - return url.Parse(data.(string)) + u, err := url.Parse(data.(string)) + + return u, wrapUrlError(err) } } @@ -207,8 +254,8 @@ func StringToIPHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -219,7 +266,7 @@ func StringToIPHookFunc() DecodeHookFunc { // Convert it by parsing ip := net.ParseIP(data.(string)) if ip == nil { - return net.IP{}, fmt.Errorf("failed parsing ip %v", data) + return net.IP{}, fmt.Errorf("failed parsing ip") } return ip, nil @@ -232,8 +279,8 @@ func StringToIPNetHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -243,7 +290,7 @@ func StringToIPNetHookFunc() DecodeHookFunc { // Convert it by parsing _, net, err := net.ParseCIDR(data.(string)) - return net, err + return net, wrapNetParseError(err) } } @@ -253,8 +300,8 @@ func StringToTimeHookFunc(layout string) DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -263,7 +310,9 @@ func StringToTimeHookFunc(layout string) DecodeHookFunc { } // Convert it by parsing - return time.Parse(layout, data.(string)) + ti, err := time.Parse(layout, data.(string)) + + return ti, wrapTimeParseError(err) } } @@ -275,8 +324,8 @@ func StringToTimeHookFunc(layout string) DecodeHookFunc { func WeaklyTypedHook( f reflect.Kind, t reflect.Kind, - data interface{}, -) (interface{}, error) { + data any, +) (any, error) { dataVal := reflect.ValueOf(data) switch t { case reflect.String: @@ -305,17 +354,17 @@ func WeaklyTypedHook( } func RecursiveStructToMapHookFunc() DecodeHookFunc { - return func(f reflect.Value, t reflect.Value) (interface{}, error) { + return func(f reflect.Value, t reflect.Value) (any, error) { if f.Kind() != reflect.Struct { return f.Interface(), nil } - var i interface{} = struct{}{} + var i any = struct{}{} if t.Type() != reflect.TypeOf(&i).Elem() { return f.Interface(), nil } - m := make(map[string]interface{}) + m := make(map[string]any) t.Set(reflect.ValueOf(m)) return f.Interface(), nil @@ -329,8 +378,8 @@ func TextUnmarshallerHookFunc() DecodeHookFuncType { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -356,8 +405,8 @@ func StringToNetIPAddrHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -366,7 +415,9 @@ func StringToNetIPAddrHookFunc() DecodeHookFunc { } // Convert it by parsing - return netip.ParseAddr(data.(string)) + addr, err := netip.ParseAddr(data.(string)) + + return addr, wrapNetIPParseAddrError(err) } } @@ -376,8 +427,8 @@ func StringToNetIPAddrPortHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -386,7 +437,9 @@ func StringToNetIPAddrPortHookFunc() DecodeHookFunc { } // Convert it by parsing - return netip.ParseAddrPort(data.(string)) + addrPort, err := netip.ParseAddrPort(data.(string)) + + return addrPort, wrapNetIPParseAddrPortError(err) } } @@ -396,8 +449,8 @@ func StringToNetIPPrefixHookFunc() DecodeHookFunc { return func( f reflect.Type, t reflect.Type, - data interface{}, - ) (interface{}, error) { + data any, + ) (any, error) { if f.Kind() != reflect.String { return data, nil } @@ -406,7 +459,9 @@ func StringToNetIPPrefixHookFunc() DecodeHookFunc { } // Convert it by parsing - return netip.ParsePrefix(data.(string)) + prefix, err := netip.ParsePrefix(data.(string)) + + return prefix, wrapNetIPParsePrefixError(err) } } @@ -439,178 +494,182 @@ func StringToBasicTypeHookFunc() DecodeHookFunc { // StringToInt8HookFunc returns a DecodeHookFunc that converts // strings to int8. func StringToInt8HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Int8 { return data, nil } // Convert it by parsing i64, err := strconv.ParseInt(data.(string), 0, 8) - return int8(i64), err + return int8(i64), wrapStrconvNumError(err) } } // StringToUint8HookFunc returns a DecodeHookFunc that converts // strings to uint8. func StringToUint8HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Uint8 { return data, nil } // Convert it by parsing u64, err := strconv.ParseUint(data.(string), 0, 8) - return uint8(u64), err + return uint8(u64), wrapStrconvNumError(err) } } // StringToInt16HookFunc returns a DecodeHookFunc that converts // strings to int16. func StringToInt16HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Int16 { return data, nil } // Convert it by parsing i64, err := strconv.ParseInt(data.(string), 0, 16) - return int16(i64), err + return int16(i64), wrapStrconvNumError(err) } } // StringToUint16HookFunc returns a DecodeHookFunc that converts // strings to uint16. func StringToUint16HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Uint16 { return data, nil } // Convert it by parsing u64, err := strconv.ParseUint(data.(string), 0, 16) - return uint16(u64), err + return uint16(u64), wrapStrconvNumError(err) } } // StringToInt32HookFunc returns a DecodeHookFunc that converts // strings to int32. func StringToInt32HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Int32 { return data, nil } // Convert it by parsing i64, err := strconv.ParseInt(data.(string), 0, 32) - return int32(i64), err + return int32(i64), wrapStrconvNumError(err) } } // StringToUint32HookFunc returns a DecodeHookFunc that converts // strings to uint32. func StringToUint32HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Uint32 { return data, nil } // Convert it by parsing u64, err := strconv.ParseUint(data.(string), 0, 32) - return uint32(u64), err + return uint32(u64), wrapStrconvNumError(err) } } // StringToInt64HookFunc returns a DecodeHookFunc that converts // strings to int64. func StringToInt64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Int64 { return data, nil } // Convert it by parsing - return strconv.ParseInt(data.(string), 0, 64) + i64, err := strconv.ParseInt(data.(string), 0, 64) + return int64(i64), wrapStrconvNumError(err) } } // StringToUint64HookFunc returns a DecodeHookFunc that converts // strings to uint64. func StringToUint64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Uint64 { return data, nil } // Convert it by parsing - return strconv.ParseUint(data.(string), 0, 64) + u64, err := strconv.ParseUint(data.(string), 0, 64) + return uint64(u64), wrapStrconvNumError(err) } } // StringToIntHookFunc returns a DecodeHookFunc that converts // strings to int. func StringToIntHookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Int { return data, nil } // Convert it by parsing i64, err := strconv.ParseInt(data.(string), 0, 0) - return int(i64), err + return int(i64), wrapStrconvNumError(err) } } // StringToUintHookFunc returns a DecodeHookFunc that converts // strings to uint. func StringToUintHookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Uint { return data, nil } // Convert it by parsing u64, err := strconv.ParseUint(data.(string), 0, 0) - return uint(u64), err + return uint(u64), wrapStrconvNumError(err) } } // StringToFloat32HookFunc returns a DecodeHookFunc that converts // strings to float32. func StringToFloat32HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Float32 { return data, nil } // Convert it by parsing f64, err := strconv.ParseFloat(data.(string), 32) - return float32(f64), err + return float32(f64), wrapStrconvNumError(err) } } // StringToFloat64HookFunc returns a DecodeHookFunc that converts // strings to float64. func StringToFloat64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Float64 { return data, nil } // Convert it by parsing - return strconv.ParseFloat(data.(string), 64) + f64, err := strconv.ParseFloat(data.(string), 64) + return f64, wrapStrconvNumError(err) } } // StringToBoolHookFunc returns a DecodeHookFunc that converts // strings to bool. func StringToBoolHookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Bool { return data, nil } // Convert it by parsing - return strconv.ParseBool(data.(string)) + b, err := strconv.ParseBool(data.(string)) + return b, wrapStrconvNumError(err) } } @@ -629,26 +688,27 @@ func StringToRuneHookFunc() DecodeHookFunc { // StringToComplex64HookFunc returns a DecodeHookFunc that converts // strings to complex64. func StringToComplex64HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Complex64 { return data, nil } // Convert it by parsing c128, err := strconv.ParseComplex(data.(string), 64) - return complex64(c128), err + return complex64(c128), wrapStrconvNumError(err) } } // StringToComplex128HookFunc returns a DecodeHookFunc that converts // strings to complex128. func StringToComplex128HookFunc() DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { + return func(f reflect.Type, t reflect.Type, data any) (any, error) { if f.Kind() != reflect.String || t.Kind() != reflect.Complex128 { return data, nil } // Convert it by parsing - return strconv.ParseComplex(data.(string), 128) + c128, err := strconv.ParseComplex(data.(string), 128) + return c128, wrapStrconvNumError(err) } } diff --git a/vendor/github.com/go-viper/mapstructure/v2/errors.go b/vendor/github.com/go-viper/mapstructure/v2/errors.go index 31a3edfb0..07d31c22a 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/errors.go +++ b/vendor/github.com/go-viper/mapstructure/v2/errors.go @@ -1,8 +1,14 @@ package mapstructure import ( + "errors" "fmt" + "net" + "net/url" "reflect" + "strconv" + "strings" + "time" ) // Error interface is implemented by all errors emitted by mapstructure. @@ -72,3 +78,167 @@ func (e *UnconvertibleTypeError) Error() string { } func (*UnconvertibleTypeError) mapstructure() {} + +func wrapStrconvNumError(err error) error { + if err == nil { + return nil + } + + if err, ok := err.(*strconv.NumError); ok { + return &strconvNumError{Err: err} + } + + return err +} + +type strconvNumError struct { + Err *strconv.NumError +} + +func (e *strconvNumError) Error() string { + return "strconv." + e.Err.Func + ": " + e.Err.Err.Error() +} + +func (e *strconvNumError) Unwrap() error { return e.Err } + +func wrapUrlError(err error) error { + if err == nil { + return nil + } + + if err, ok := err.(*url.Error); ok { + return &urlError{Err: err} + } + + return err +} + +type urlError struct { + Err *url.Error +} + +func (e *urlError) Error() string { + return fmt.Sprintf("%s", e.Err.Err) +} + +func (e *urlError) Unwrap() error { return e.Err } + +func wrapNetParseError(err error) error { + if err == nil { + return nil + } + + if err, ok := err.(*net.ParseError); ok { + return &netParseError{Err: err} + } + + return err +} + +type netParseError struct { + Err *net.ParseError +} + +func (e *netParseError) Error() string { + return "invalid " + e.Err.Type +} + +func (e *netParseError) Unwrap() error { return e.Err } + +func wrapTimeParseError(err error) error { + if err == nil { + return nil + } + + if err, ok := err.(*time.ParseError); ok { + return &timeParseError{Err: err} + } + + return err +} + +type timeParseError struct { + Err *time.ParseError +} + +func (e *timeParseError) Error() string { + if e.Err.Message == "" { + return fmt.Sprintf("parsing time as %q: cannot parse as %q", e.Err.Layout, e.Err.LayoutElem) + } + + return "parsing time " + e.Err.Message +} + +func (e *timeParseError) Unwrap() error { return e.Err } + +func wrapNetIPParseAddrError(err error) error { + if err == nil { + return nil + } + + if errMsg := err.Error(); strings.HasPrefix(errMsg, "ParseAddr") { + errPieces := strings.Split(errMsg, ": ") + + return fmt.Errorf("ParseAddr: %s", errPieces[len(errPieces)-1]) + } + + return err +} + +func wrapNetIPParseAddrPortError(err error) error { + if err == nil { + return nil + } + + errMsg := err.Error() + if strings.HasPrefix(errMsg, "invalid port ") { + return errors.New("invalid port") + } else if strings.HasPrefix(errMsg, "invalid ip:port ") { + return errors.New("invalid ip:port") + } + + return err +} + +func wrapNetIPParsePrefixError(err error) error { + if err == nil { + return nil + } + + if errMsg := err.Error(); strings.HasPrefix(errMsg, "netip.ParsePrefix") { + errPieces := strings.Split(errMsg, ": ") + + return fmt.Errorf("netip.ParsePrefix: %s", errPieces[len(errPieces)-1]) + } + + return err +} + +func wrapTimeParseDurationError(err error) error { + if err == nil { + return nil + } + + errMsg := err.Error() + if strings.HasPrefix(errMsg, "time: unknown unit ") { + return errors.New("time: unknown unit") + } else if strings.HasPrefix(errMsg, "time: ") { + idx := strings.LastIndex(errMsg, " ") + + return errors.New(errMsg[:idx]) + } + + return err +} + +func wrapTimeParseLocationError(err error) error { + if err == nil { + return nil + } + errMsg := err.Error() + if strings.Contains(errMsg, "unknown time zone") || strings.HasPrefix(errMsg, "time: unknown format") { + return fmt.Errorf("invalid time zone format: %w", err) + } + + return err +} diff --git a/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go b/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go index 4b738a3a9..7c35bce02 100644 --- a/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go +++ b/vendor/github.com/go-viper/mapstructure/v2/mapstructure.go @@ -1,5 +1,5 @@ // Package mapstructure exposes functionality to convert one arbitrary -// Go type into another, typically to convert a map[string]interface{} +// Go type into another, typically to convert a map[string]any // into a native Go structure. // // The Go structure can be arbitrarily complex, containing slices, @@ -54,8 +54,8 @@ // // This would require an input that looks like below: // -// map[string]interface{}{ -// "person": map[string]interface{}{"name": "alice"}, +// map[string]any{ +// "person": map[string]any{"name": "alice"}, // } // // If your "person" value is NOT nested, then you can append ",squash" to @@ -68,7 +68,7 @@ // // Now the following input would be accepted: // -// map[string]interface{}{ +// map[string]any{ // "name": "alice", // } // @@ -79,7 +79,7 @@ // // Will be decoded into a map: // -// map[string]interface{}{ +// map[string]any{ // "name": "alice", // } // @@ -95,18 +95,18 @@ // // You can also use the ",remain" suffix on your tag to collect all unused // values in a map. The field with this tag MUST be a map type and should -// probably be a "map[string]interface{}" or "map[interface{}]interface{}". +// probably be a "map[string]any" or "map[any]any". // See example below: // // type Friend struct { // Name string -// Other map[string]interface{} `mapstructure:",remain"` +// Other map[string]any `mapstructure:",remain"` // } // // Given the input below, Other would be populated with the other // values that weren't used (everything but "name"): // -// map[string]interface{}{ +// map[string]any{ // "name": "bob", // "address": "123 Maple St.", // } @@ -161,7 +161,7 @@ // // Using this map as input: // -// map[string]interface{}{ +// map[string]any{ // "private": "I will be ignored", // "Public": "I made it through!", // } @@ -204,19 +204,19 @@ import ( // we started with Kinds and then realized Types were the better solution, // but have a promise to not break backwards compat so we now support // both. -type DecodeHookFunc interface{} +type DecodeHookFunc any // DecodeHookFuncType is a DecodeHookFunc which has complete information about // the source and target types. -type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error) +type DecodeHookFuncType func(reflect.Type, reflect.Type, any) (any, error) // DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the // source and target types. -type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) +type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, any) (any, error) // DecodeHookFuncValue is a DecodeHookFunc which has complete access to both the source and target // values. -type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (interface{}, error) +type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (any, error) // DecoderConfig is the configuration that is used to create a new decoder // and allows customization of various aspects of decoding. @@ -287,7 +287,7 @@ type DecoderConfig struct { // Result is a pointer to the struct that will contain the decoded // value. - Result interface{} + Result any // The tag name that mapstructure reads for field names. This // defaults to "mapstructure" @@ -319,7 +319,7 @@ type DecoderConfig struct { // up the most basic Decoder. type Decoder struct { config *DecoderConfig - cachedDecodeHook func(from reflect.Value, to reflect.Value) (interface{}, error) + cachedDecodeHook func(from reflect.Value, to reflect.Value) (any, error) } // Metadata contains information about decoding a structure that @@ -340,7 +340,7 @@ type Metadata struct { // Decode takes an input structure and uses reflection to translate it to // the output structure. output must be a pointer to a map or struct. -func Decode(input interface{}, output interface{}) error { +func Decode(input any, output any) error { config := &DecoderConfig{ Metadata: nil, Result: output, @@ -356,7 +356,7 @@ func Decode(input interface{}, output interface{}) error { // WeakDecode is the same as Decode but is shorthand to enable // WeaklyTypedInput. See DecoderConfig for more info. -func WeakDecode(input, output interface{}) error { +func WeakDecode(input, output any) error { config := &DecoderConfig{ Metadata: nil, Result: output, @@ -373,7 +373,7 @@ func WeakDecode(input, output interface{}) error { // DecodeMetadata is the same as Decode, but is shorthand to // enable metadata collection. See DecoderConfig for more info. -func DecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { +func DecodeMetadata(input any, output any, metadata *Metadata) error { config := &DecoderConfig{ Metadata: metadata, Result: output, @@ -390,7 +390,7 @@ func DecodeMetadata(input interface{}, output interface{}, metadata *Metadata) e // WeakDecodeMetadata is the same as Decode, but is shorthand to // enable both WeaklyTypedInput and metadata collection. See // DecoderConfig for more info. -func WeakDecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { +func WeakDecodeMetadata(input any, output any, metadata *Metadata) error { config := &DecoderConfig{ Metadata: metadata, Result: output, @@ -457,7 +457,7 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) { // Decode decodes the given raw interface to the target pointer specified // by the configuration. -func (d *Decoder) Decode(input interface{}) error { +func (d *Decoder) Decode(input any) error { err := d.decode("", input, reflect.ValueOf(d.config.Result).Elem()) // Retain some of the original behavior when multiple errors ocurr @@ -470,7 +470,7 @@ func (d *Decoder) Decode(input interface{}) error { } // isNil returns true if the input is nil or a typed nil pointer. -func isNil(input interface{}) bool { +func isNil(input any) bool { if input == nil { return true } @@ -479,7 +479,7 @@ func isNil(input interface{}) bool { } // Decodes an unknown data type into a specific reflection value. -func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error { +func (d *Decoder) decode(name string, input any, outVal reflect.Value) error { var ( inputVal = reflect.ValueOf(input) outputKind = getKind(outVal) @@ -516,10 +516,10 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e // Hooks need a valid inputVal, so reset it to zero value of outVal type. switch outputKind { case reflect.Struct, reflect.Map: - var mapVal map[string]interface{} + var mapVal map[string]any inputVal = reflect.ValueOf(mapVal) // create nil map pointer case reflect.Slice, reflect.Array: - var sliceVal []interface{} + var sliceVal []any inputVal = reflect.ValueOf(sliceVal) // create nil slice pointer default: inputVal = reflect.Zero(outVal.Type()) @@ -583,7 +583,7 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e // This decodes a basic type (bool, int, string, etc.) and sets the // value to "data" of that type. -func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeBasic(name string, data any, val reflect.Value) error { if val.IsValid() && val.Elem().IsValid() { elem := val.Elem() @@ -640,7 +640,7 @@ func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) return nil } -func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeString(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) @@ -693,7 +693,7 @@ func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) return nil } -func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeInt(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) dataType := dataVal.Type() @@ -724,7 +724,7 @@ func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) er return newDecodeError(name, &ParseError{ Expected: val, Value: data, - Err: err, + Err: wrapStrconvNumError(err), }) } case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": @@ -748,7 +748,7 @@ func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) er return nil } -func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeUint(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) dataType := dataVal.Type() @@ -795,7 +795,7 @@ func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) e return newDecodeError(name, &ParseError{ Expected: val, Value: data, - Err: err, + Err: wrapStrconvNumError(err), }) } case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": @@ -805,7 +805,7 @@ func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) e return newDecodeError(name, &ParseError{ Expected: val, Value: data, - Err: err, + Err: wrapStrconvNumError(err), }) } val.SetUint(i) @@ -819,7 +819,7 @@ func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) e return nil } -func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeBool(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) @@ -842,7 +842,7 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) e return newDecodeError(name, &ParseError{ Expected: val, Value: data, - Err: err, + Err: wrapStrconvNumError(err), }) } default: @@ -855,7 +855,7 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) e return nil } -func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeFloat(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) dataType := dataVal.Type() @@ -886,7 +886,7 @@ func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) return newDecodeError(name, &ParseError{ Expected: val, Value: data, - Err: err, + Err: wrapStrconvNumError(err), }) } case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": @@ -910,7 +910,7 @@ func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) return nil } -func (d *Decoder) decodeComplex(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeComplex(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataKind := getKind(dataVal) @@ -927,7 +927,7 @@ func (d *Decoder) decodeComplex(name string, data interface{}, val reflect.Value return nil } -func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeMap(name string, data any, val reflect.Value) error { valType := val.Type() valKeyType := valType.Key() valElemType := valType.Elem() @@ -1176,7 +1176,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re return nil } -func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) (bool, error) { +func (d *Decoder) decodePtr(name string, data any, val reflect.Value) (bool, error) { // If the input data is nil, then we want to just set the output // pointer to be nil as well. isNil := data == nil @@ -1223,7 +1223,7 @@ func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) (b return false, nil } -func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeFunc(name string, data any, val reflect.Value) error { // Create an element of the concrete (non pointer) type and decode // into that. Then set the value of the pointer to this type. dataVal := reflect.Indirect(reflect.ValueOf(data)) @@ -1237,7 +1237,7 @@ func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) e return nil } -func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeSlice(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataValKind := dataVal.Kind() valType := val.Type() @@ -1259,7 +1259,7 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) return nil } // Create slice of maps of other sizes - return d.decodeSlice(name, []interface{}{data}, val) + return d.decodeSlice(name, []any{data}, val) case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8: return d.decodeSlice(name, []byte(dataVal.String()), val) @@ -1268,7 +1268,7 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) // and "lift" it into it. i.e. a string becomes a string slice. default: // Just re-try this function with data as a slice. - return d.decodeSlice(name, []interface{}{data}, val) + return d.decodeSlice(name, []any{data}, val) } } @@ -1311,7 +1311,7 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) return errors.Join(errs...) } -func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeArray(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) dataValKind := dataVal.Kind() valType := val.Type() @@ -1336,7 +1336,7 @@ func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) // and "lift" it into it. i.e. a string becomes a string array. default: // Just re-try this function with data as a slice. - return d.decodeArray(name, []interface{}{data}, val) + return d.decodeArray(name, []any{data}, val) } } @@ -1372,7 +1372,7 @@ func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) return errors.Join(errs...) } -func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error { +func (d *Decoder) decodeStruct(name string, data any, val reflect.Value) error { dataVal := reflect.Indirect(reflect.ValueOf(data)) // If the type of the value to write to and the data match directly, @@ -1393,7 +1393,7 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) // as an intermediary. // Make a new map to hold our result - mapType := reflect.TypeOf((map[string]interface{})(nil)) + mapType := reflect.TypeOf((map[string]any)(nil)) mval := reflect.MakeMap(mapType) // Creating a pointer to a map so that other methods can completely @@ -1424,13 +1424,13 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e } dataValKeys := make(map[reflect.Value]struct{}) - dataValKeysUnused := make(map[interface{}]struct{}) + dataValKeysUnused := make(map[any]struct{}) for _, dataValKey := range dataVal.MapKeys() { dataValKeys[dataValKey] = struct{}{} dataValKeysUnused[dataValKey.Interface()] = struct{}{} } - targetValKeysUnused := make(map[interface{}]struct{}) + targetValKeysUnused := make(map[any]struct{}) var errs []error @@ -1583,7 +1583,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e // we put the unused keys directly into the remain field. if remainField != nil && len(dataValKeysUnused) > 0 { // Build a map of only the unused values - remain := map[interface{}]interface{}{} + remain := map[any]any{} for key := range dataValKeysUnused { remain[key] = dataVal.MapIndex(reflect.ValueOf(key)).Interface() } diff --git a/vendor/modules.txt b/vendor/modules.txt index 88871bef8..6b58eed96 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -178,7 +178,7 @@ github.com/go-openapi/swag # github.com/go-task/slim-sprig/v3 v3.0.0 ## explicit; go 1.20 github.com/go-task/slim-sprig/v3 -# github.com/go-viper/mapstructure/v2 v2.3.0 +# github.com/go-viper/mapstructure/v2 v2.4.0 ## explicit; go 1.18 github.com/go-viper/mapstructure/v2 github.com/go-viper/mapstructure/v2/internal/errors @@ -1267,7 +1267,7 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/metrics sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client -# sigs.k8s.io/cluster-api v1.10.4 +# sigs.k8s.io/cluster-api v1.10.9 ## explicit; go 1.23.0 sigs.k8s.io/cluster-api/api/addons/v1beta1 sigs.k8s.io/cluster-api/api/v1beta1 @@ -1352,7 +1352,7 @@ sigs.k8s.io/cluster-api/util/topology sigs.k8s.io/cluster-api/util/version sigs.k8s.io/cluster-api/util/yaml sigs.k8s.io/cluster-api/version -# sigs.k8s.io/cluster-api/test v1.10.4 +# sigs.k8s.io/cluster-api/test v1.10.9 ## explicit; go 1.23.0 sigs.k8s.io/cluster-api/test/e2e sigs.k8s.io/cluster-api/test/e2e/internal/log diff --git a/vendor/sigs.k8s.io/cluster-api/cmd/clusterctl/client/config/cert_manager_client.go b/vendor/sigs.k8s.io/cluster-api/cmd/clusterctl/client/config/cert_manager_client.go index 2389bc0d4..f63127412 100644 --- a/vendor/sigs.k8s.io/cluster-api/cmd/clusterctl/client/config/cert_manager_client.go +++ b/vendor/sigs.k8s.io/cluster-api/cmd/clusterctl/client/config/cert_manager_client.go @@ -29,7 +29,7 @@ const ( CertManagerConfigKey = "cert-manager" // CertManagerDefaultVersion defines the default cert-manager version to be used by clusterctl. - CertManagerDefaultVersion = "v1.18.1" + CertManagerDefaultVersion = "v1.19.1" // CertManagerDefaultURL defines the default cert-manager repository url to be used by clusterctl. // NOTE: At runtime CertManagerDefaultVersion may be replaced with the diff --git a/vendor/sigs.k8s.io/cluster-api/internal/runtime/client/client.go b/vendor/sigs.k8s.io/cluster-api/internal/runtime/client/client.go index 3d4619fed..374d708dd 100644 --- a/vendor/sigs.k8s.io/cluster-api/internal/runtime/client/client.go +++ b/vendor/sigs.k8s.io/cluster-api/internal/runtime/client/client.go @@ -52,6 +52,7 @@ import ( runtimemetrics "sigs.k8s.io/cluster-api/internal/runtime/metrics" runtimeregistry "sigs.k8s.io/cluster-api/internal/runtime/registry" "sigs.k8s.io/cluster-api/util" + "sigs.k8s.io/cluster-api/util/cache" ) type errCallingExtensionHandler error @@ -60,6 +61,8 @@ const defaultDiscoveryTimeout = 10 * time.Second // Options are creation options for a Client. type Options struct { + CertFile string // Path of the PEM-encoded client certificate. + KeyFile string // Path of the PEM-encoded client key. Catalog *runtimecatalog.Catalog Registry runtimeregistry.ExtensionRegistry Client ctrlclient.Client @@ -68,18 +71,52 @@ type Options struct { // New returns a new Client. func New(options Options) runtimeclient.Client { return &client{ - catalog: options.Catalog, - registry: options.Registry, - client: options.Client, + certFile: options.CertFile, + keyFile: options.KeyFile, + catalog: options.Catalog, + registry: options.Registry, + client: options.Client, + httpClientsCache: cache.New[httpClientEntry](24 * time.Hour), } } var _ runtimeclient.Client = &client{} type client struct { - catalog *runtimecatalog.Catalog - registry runtimeregistry.ExtensionRegistry - client ctrlclient.Client + certFile string + keyFile string + catalog *runtimecatalog.Catalog + registry runtimeregistry.ExtensionRegistry + client ctrlclient.Client + httpClientsCache cache.Cache[httpClientEntry] +} + +type httpClientEntry struct { + // Note: caData and hostName are the variable parts in the TLSConfig + // for an http.Client that is used to call runtime extensions. + caData []byte + hostName string + + client *http.Client +} + +func newHTTPClientEntry(hostName string, caData []byte, client *http.Client) httpClientEntry { + return httpClientEntry{ + hostName: hostName, + caData: caData, + client: client, + } +} + +func newHTTPClientEntryKey(hostName string, caData []byte) string { + return httpClientEntry{ + hostName: hostName, + caData: caData, + }.Key() +} + +func (r httpClientEntry) Key() string { + return fmt.Sprintf("%s/%s", r.hostName, string(r.caData)) } func (c *client) WarmUp(extensionConfigList *runtimev1.ExtensionConfigList) error { @@ -99,6 +136,11 @@ func (c *client) Discover(ctx context.Context, extensionConfig *runtimev1.Extens return nil, errors.Wrapf(err, "failed to discover extension %q: failed to compute GVH of hook", extensionConfig.Name) } + httpClient, err := c.getHTTPClient(extensionConfig.Spec.ClientConfig) + if err != nil { + return nil, errors.Wrapf(err, "failed to discover extension %q: failed to get http client", extensionConfig.Name) + } + request := &runtimehooksv1.DiscoveryRequest{} response := &runtimehooksv1.DiscoveryResponse{} opts := &httpCallOptions{ @@ -107,6 +149,7 @@ func (c *client) Discover(ctx context.Context, extensionConfig *runtimev1.Extens registrationGVH: hookGVH, hookGVH: hookGVH, timeout: defaultDiscoveryTimeout, + httpClient: httpClient, } if err := httpCall(ctx, request, response, opts); err != nil { return nil, errors.Wrapf(err, "failed to discover extension %q", extensionConfig.Name) @@ -328,6 +371,11 @@ func (c *client) CallExtension(ctx context.Context, hook runtimecatalog.Hook, fo } } + httpClient, err := c.getHTTPClient(registration.ClientConfig) + if err != nil { + return errors.Wrapf(err, "failed to call extension handler %q: failed to get http client", name) + } + httpOpts := &httpCallOptions{ catalog: c.catalog, config: registration.ClientConfig, @@ -335,6 +383,7 @@ func (c *client) CallExtension(ctx context.Context, hook runtimecatalog.Hook, fo hookGVH: hookGVH, name: strings.TrimSuffix(registration.Name, "."+registration.ExtensionConfigName), timeout: timeoutDuration, + httpClient: httpClient, } err = httpCall(ctx, request, response, httpOpts) if err != nil { @@ -378,6 +427,48 @@ func (c *client) CallExtension(ctx context.Context, hook runtimecatalog.Hook, fo return nil } +func (c *client) getHTTPClient(config runtimev1.ClientConfig) (*http.Client, error) { + // Note: we are passing an empty gvh and "" as name because the only relevant part of the url + // for this function is the Hostname, which derives from config (ghv and name are appended to the path). + extensionURL, err := urlForExtension(config, runtimecatalog.GroupVersionHook{}, "") + if err != nil { + return nil, err + } + + if cacheEntry, ok := c.httpClientsCache.Has(newHTTPClientEntryKey(extensionURL.Hostname(), config.CABundle)); ok { + return cacheEntry.client, nil + } + + httpClient, err := createHTTPClient(c.certFile, c.keyFile, config.CABundle, extensionURL.Hostname()) + if err != nil { + return nil, err + } + + c.httpClientsCache.Add(newHTTPClientEntry(extensionURL.Hostname(), config.CABundle, httpClient)) + return httpClient, nil +} + +func createHTTPClient(certFile, keyFile string, caData []byte, hostName string) (*http.Client, error) { + httpClient := &http.Client{} + tlsConfig, err := transport.TLSConfigFor(&transport.Config{ + TLS: transport.TLSConfig{ + CertFile: certFile, + KeyFile: keyFile, + CAData: caData, + ServerName: hostName, + }, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to create tls config") + } + + // This also adds http2 + httpClient.Transport = utilnet.SetTransportDefaults(&http.Transport{ + TLSClientConfig: tlsConfig, + }) + return httpClient, nil +} + // cloneAndAddSettings creates a new request object and adds settings to it. func cloneAndAddSettings(request runtimehooksv1.RequestObject, registrationSettings map[string]string) runtimehooksv1.RequestObject { // Merge the settings from registration with the settings in the request. @@ -402,6 +493,7 @@ type httpCallOptions struct { hookGVH runtimecatalog.GroupVersionHook name string timeout time.Duration + httpClient *http.Client } func httpCall(ctx context.Context, request, response runtime.Object, opts *httpCallOptions) error { @@ -480,23 +572,8 @@ func httpCall(ctx context.Context, request, response runtime.Object, opts *httpC return errors.Wrap(err, "http call failed: failed to create http request") } - // Use client-go's transport.TLSConfigureFor to ensure good defaults for tls - client := http.DefaultClient - tlsConfig, err := transport.TLSConfigFor(&transport.Config{ - TLS: transport.TLSConfig{ - CAData: opts.config.CABundle, - ServerName: extensionURL.Hostname(), - }, - }) - if err != nil { - return errors.Wrap(err, "http call failed: failed to create tls config") - } - // This also adds http2 - client.Transport = utilnet.SetTransportDefaults(&http.Transport{ - TLSClientConfig: tlsConfig, - }) - - resp, err := client.Do(httpRequest) + // Call the extension. + resp, err := opts.httpClient.Do(httpRequest) // Create http request metric. defer func() { diff --git a/vendor/sigs.k8s.io/cluster-api/test/e2e/cluster_upgrade_runtimesdk.go b/vendor/sigs.k8s.io/cluster-api/test/e2e/cluster_upgrade_runtimesdk.go index 4c575079f..3c22d484b 100644 --- a/vendor/sigs.k8s.io/cluster-api/test/e2e/cluster_upgrade_runtimesdk.go +++ b/vendor/sigs.k8s.io/cluster-api/test/e2e/cluster_upgrade_runtimesdk.go @@ -687,7 +687,7 @@ func beforeClusterDeleteHandler(ctx context.Context, c client.Client, cluster ty var blocked = true // If the Cluster is not found it has been deleted and the hook is unblocked. - if apierrors.IsNotFound(c.Get(ctx, client.ObjectKey{Name: cluster.Name, Namespace: cluster.Namespace}, &clusterv1.Cluster{})) { + if apierrors.IsNotFound(c.Get(ctx, cluster, &clusterv1.Cluster{})) { blocked = false } return blocked diff --git a/vendor/sigs.k8s.io/cluster-api/util/cache/cache.go b/vendor/sigs.k8s.io/cluster-api/util/cache/cache.go index 31ec3e2c1..93faf3518 100644 --- a/vendor/sigs.k8s.io/cluster-api/util/cache/cache.go +++ b/vendor/sigs.k8s.io/cluster-api/util/cache/cache.go @@ -49,6 +49,9 @@ type Cache[E Entry] interface { // Has checks if the given key (still) exists in the Cache. // Note: entries expire after the ttl. Has(key string) (E, bool) + + // Len returns the number of entries in the cache. + Len() int } // New creates a new cache. @@ -96,6 +99,10 @@ func (r *cache[E]) Has(key string) (E, bool) { return *new(E), false } +func (r *cache[E]) Len() int { + return len(r.ListKeys()) +} + // ReconcileEntry is an Entry for the Cache that stores the // earliest time after which the next Reconcile should be executed. type ReconcileEntry struct {