From 9d339a382d7ecf4a70073f57915ec0bca9b8e664 Mon Sep 17 00:00:00 2001 From: Archana Sawant Date: Wed, 28 Jan 2026 15:55:27 +0530 Subject: [PATCH 01/19] [release/v1.64] Bump Go version to 1.25.6 (#1993) Signed-off-by: Archana Sawant --- .prow/e2e-features.yaml | 8 ++++---- .prow/postsubmits.yaml | 4 ++-- .prow/provider-alibaba.yaml | 2 +- .prow/provider-anexia.yaml | 2 +- .prow/provider-aws.yaml | 12 ++++++------ .prow/provider-azure.yaml | 6 +++--- .prow/provider-digitalocean.yaml | 2 +- .prow/provider-equinix-metal.yaml | 2 +- .prow/provider-gcp.yaml | 2 +- .prow/provider-hetzner.yaml | 2 +- .prow/provider-kubevirt.yaml | 2 +- .prow/provider-linode.yaml | 2 +- .prow/provider-nutanix.yaml | 2 +- .prow/provider-openstack.yaml | 4 ++-- .prow/provider-scaleway.yaml | 2 +- .prow/provider-vmware-cloud-director.yaml | 2 +- .prow/provider-vsphere.yaml | 10 +++++----- .prow/verify.yaml | 16 ++++++++-------- Dockerfile | 2 +- Makefile | 2 +- go.mod | 2 +- hack/update-fixtures.sh | 2 +- hack/verify-licenses.sh | 2 +- 23 files changed, 46 insertions(+), 46 deletions(-) diff --git a/.prow/e2e-features.yaml b/.prow/e2e-features.yaml index 65c4949e5..623c705ce 100644 --- a/.prow/e2e-features.yaml +++ b/.prow/e2e-features.yaml @@ -35,7 +35,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -65,7 +65,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -95,7 +95,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -123,7 +123,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/postsubmits.yaml b/.prow/postsubmits.yaml index 306aebf5c..53ddafa60 100644 --- a/.prow/postsubmits.yaml +++ b/.prow/postsubmits.yaml @@ -27,7 +27,7 @@ postsubmits: preset-goproxy: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - /bin/bash - -c @@ -56,7 +56,7 @@ postsubmits: preset-goproxy: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/upload-gocache.sh" resources: diff --git a/.prow/provider-alibaba.yaml b/.prow/provider-alibaba.yaml index ca537ca50..ff70a51a3 100644 --- a/.prow/provider-alibaba.yaml +++ b/.prow/provider-alibaba.yaml @@ -30,7 +30,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-anexia.yaml b/.prow/provider-anexia.yaml index 980319c01..826ad1703 100644 --- a/.prow/provider-anexia.yaml +++ b/.prow/provider-anexia.yaml @@ -32,7 +32,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-aws.yaml b/.prow/provider-aws.yaml index 3ebf52720..1f72c3086 100644 --- a/.prow/provider-aws.yaml +++ b/.prow/provider-aws.yaml @@ -30,7 +30,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -63,7 +63,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -96,7 +96,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -130,7 +130,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -162,7 +162,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -194,7 +194,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-azure.yaml b/.prow/provider-azure.yaml index 5221c1681..1a9972994 100644 --- a/.prow/provider-azure.yaml +++ b/.prow/provider-azure.yaml @@ -29,7 +29,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -62,7 +62,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -96,7 +96,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-digitalocean.yaml b/.prow/provider-digitalocean.yaml index e8427f12a..00c383042 100644 --- a/.prow/provider-digitalocean.yaml +++ b/.prow/provider-digitalocean.yaml @@ -28,7 +28,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-equinix-metal.yaml b/.prow/provider-equinix-metal.yaml index 5b52d8529..18f094259 100644 --- a/.prow/provider-equinix-metal.yaml +++ b/.prow/provider-equinix-metal.yaml @@ -29,7 +29,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-gcp.yaml b/.prow/provider-gcp.yaml index 239bf7ed0..cea2ecb30 100644 --- a/.prow/provider-gcp.yaml +++ b/.prow/provider-gcp.yaml @@ -29,7 +29,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-hetzner.yaml b/.prow/provider-hetzner.yaml index a22938b56..f18fe73a1 100644 --- a/.prow/provider-hetzner.yaml +++ b/.prow/provider-hetzner.yaml @@ -27,7 +27,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-kubevirt.yaml b/.prow/provider-kubevirt.yaml index a1ec2074d..412619e9b 100644 --- a/.prow/provider-kubevirt.yaml +++ b/.prow/provider-kubevirt.yaml @@ -31,7 +31,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-linode.yaml b/.prow/provider-linode.yaml index d60a09e04..e6320f2ee 100644 --- a/.prow/provider-linode.yaml +++ b/.prow/provider-linode.yaml @@ -29,7 +29,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-nutanix.yaml b/.prow/provider-nutanix.yaml index b79fafc60..3a241f55a 100644 --- a/.prow/provider-nutanix.yaml +++ b/.prow/provider-nutanix.yaml @@ -28,7 +28,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-openstack.yaml b/.prow/provider-openstack.yaml index 02dd62fe2..5948abce5 100644 --- a/.prow/provider-openstack.yaml +++ b/.prow/provider-openstack.yaml @@ -30,7 +30,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -64,7 +64,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-scaleway.yaml b/.prow/provider-scaleway.yaml index 9e9b21d1b..b3afb0698 100644 --- a/.prow/provider-scaleway.yaml +++ b/.prow/provider-scaleway.yaml @@ -28,7 +28,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-vmware-cloud-director.yaml b/.prow/provider-vmware-cloud-director.yaml index c24986a56..030ac99bc 100644 --- a/.prow/provider-vmware-cloud-director.yaml +++ b/.prow/provider-vmware-cloud-director.yaml @@ -32,7 +32,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/provider-vsphere.yaml b/.prow/provider-vsphere.yaml index 7f4287805..67107b388 100644 --- a/.prow/provider-vsphere.yaml +++ b/.prow/provider-vsphere.yaml @@ -29,7 +29,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -62,7 +62,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -95,7 +95,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -128,7 +128,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: @@ -161,7 +161,7 @@ presubmits: preset-kubeconfig-ci: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-kind-0.30-6 command: - "./hack/ci/run-e2e-tests.sh" args: diff --git a/.prow/verify.yaml b/.prow/verify.yaml index dbc05a702..0cada3d58 100644 --- a/.prow/verify.yaml +++ b/.prow/verify.yaml @@ -22,7 +22,7 @@ presubmits: preset-goproxy: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-6 command: - make args: @@ -44,7 +44,7 @@ presubmits: preset-goproxy: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-6 command: - make args: @@ -66,7 +66,7 @@ presubmits: preset-goproxy: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-6 command: - make args: @@ -87,7 +87,7 @@ presubmits: preset-goproxy: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-6 command: - make args: @@ -107,7 +107,7 @@ presubmits: path_alias: k8c.io/machine-controller spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-6 command: - "/usr/local/bin/shfmt" args: @@ -136,7 +136,7 @@ presubmits: path_alias: k8c.io/machine-controller spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-6 command: - "./hack/verify-boilerplate.sh" resources: @@ -156,7 +156,7 @@ presubmits: preset-goproxy: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-6 command: - ./hack/verify-licenses.sh resources: @@ -173,7 +173,7 @@ presubmits: preset-goproxy: "true" spec: containers: - - image: quay.io/kubermatic/build:go-1.25-node-22-4 + - image: quay.io/kubermatic/build:go-1.25-node-22-6 command: - make args: diff --git a/Dockerfile b/Dockerfile index cf38a1b4b..ead687b57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -ARG GO_VERSION=1.25.1 +ARG GO_VERSION=1.25.6 FROM docker.io/golang:${GO_VERSION} AS builder WORKDIR /go/src/k8c.io/machine-controller COPY . . diff --git a/Makefile b/Makefile index 1d6e4c89e..3fdbca0db 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ SHELL = /bin/bash -eu -o pipefail -GO_VERSION ?= 1.25.1 +GO_VERSION ?= 1.25.6 GOOS ?= $(shell go env GOOS) diff --git a/go.mod b/go.mod index 4731d101b..a065c50c4 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module k8c.io/machine-controller go 1.24.0 -toolchain go1.24.7 +toolchain go1.24.12 replace k8c.io/machine-controller/sdk => ./sdk diff --git a/hack/update-fixtures.sh b/hack/update-fixtures.sh index 290a7cf70..d68147900 100755 --- a/hack/update-fixtures.sh +++ b/hack/update-fixtures.sh @@ -19,7 +19,7 @@ set -euo pipefail cd $(dirname $0)/.. source hack/lib.sh -CONTAINERIZE_IMAGE=quay.io/kubermatic/build:go-1.25-node-22-4 containerize ./hack/update-fixtures.sh +CONTAINERIZE_IMAGE=quay.io/kubermatic/build:go-1.25-node-22-6 containerize ./hack/update-fixtures.sh go test ./... -v -update || go test ./... diff --git a/hack/verify-licenses.sh b/hack/verify-licenses.sh index 1182ef49f..d842d83bd 100755 --- a/hack/verify-licenses.sh +++ b/hack/verify-licenses.sh @@ -19,7 +19,7 @@ set -euo pipefail cd $(dirname $0)/.. source hack/lib.sh -CONTAINERIZE_IMAGE=quay.io/kubermatic/build:go-1.25-node-22-4 containerize ./hack/verify-licenses.sh +CONTAINERIZE_IMAGE=quay.io/kubermatic/build:go-1.25-node-22-6 containerize ./hack/verify-licenses.sh go mod vendor From c0c70740698041850c72b16e1130f2dd4a3d523e Mon Sep 17 00:00:00 2001 From: Kubermatic Bot <41968677+kubermatic-bot@users.noreply.github.com> Date: Mon, 2 Feb 2026 13:50:17 +0100 Subject: [PATCH 02/19] [release/v1.64] Synchronize OWNERS_ALIASES file with Github teams (#1976) --- OWNERS_ALIASES | 1 - 1 file changed, 1 deletion(-) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index e952ce181..609c50091 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -7,7 +7,6 @@ aliases: - ahmedwaleedmalik - buraksekili - cnvergence - - embik - julioc-p - kron4eg - moadqassem From 410e2bc83caa20ba307e062152d4618d40a29364 Mon Sep 17 00:00:00 2001 From: Kubermatic Bot <41968677+kubermatic-bot@users.noreply.github.com> Date: Thu, 5 Mar 2026 11:03:48 +0100 Subject: [PATCH 03/19] [release/v1.64] Synchronize OWNERS_ALIASES file with Github teams (#2001) --- OWNERS_ALIASES | 1 + 1 file changed, 1 insertion(+) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 609c50091..0f82fc715 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -9,6 +9,7 @@ aliases: - cnvergence - julioc-p - kron4eg + - mgoltzsche - moadqassem - moelsayed - mohamed-rafraf From 02e3154095887dc12e55b81a41eff482f2c7ca25 Mon Sep 17 00:00:00 2001 From: Etienne Wiebe Date: Fri, 16 Jan 2026 08:13:16 +0100 Subject: [PATCH 04/19] applying changes pre 1.61 --- examples/anexia-machinedeployment.yaml | 14 ++- go.mod | 7 +- go.sum | 16 +-- .../provider/anexia/network_provisioning.go | 9 +- pkg/cloudprovider/provider/anexia/provider.go | 82 +++++++++----- .../provider/anexia/provider_test.go | 100 +++++++++++++++++- .../provider/anexia/resolve_config.go | 23 +++- sdk/cloudprovider/anexia/types.go | 7 +- 8 files changed, 211 insertions(+), 47 deletions(-) diff --git a/examples/anexia-machinedeployment.yaml b/examples/anexia-machinedeployment.yaml index 64722b6ef..70d3b1124 100644 --- a/examples/anexia-machinedeployment.yaml +++ b/examples/anexia-machinedeployment.yaml @@ -31,12 +31,15 @@ spec: name: machine-controller-anexia key: token - # Currently only the "Flatcar Linux Stable" template is supported. + # Currently only the "Flatcar Linux Stable UEFI" template is supported. # Use templateBuild to specify a build. If empty => latest # Alternatively use templateID for a specific template. template: "<< ANEXIA_TEMPLATE_NAME >>" locationID: "<< ANEXIA_LOCATION_ID >>" + + # From 1 to 16 cores or the configured limit for your account. cpus: 2 + # From 1024 to 65536 MB or the configured limit for your account. memory: 2048 # this defaults to "performance", but you can set anything @@ -46,6 +49,10 @@ spec: disks: - size: 60 + # Enterprise ENT1-6 + # High Performance HPC1-5 + # Local LOC3 + # Standard STD1-6 performanceType: ENT6 # Each entry in this array will create a network interface in each @@ -72,6 +79,11 @@ spec: prefixes: - "<< ANEXIA_PREFIX_ID >>" + # (optional) BandwidthLimit specifices the allowed bandwidth in MBit/s. + # It can be set to 0, 100, 1000 or 10000 for the respective values of 100MBit/s 1GBit/s or 10GBit/s. + # It defaults to 0 which will take the default value of the anexia engine. This is 1GB/s. + bandwidthLimit: 0 + # You may have this old disk config attribute in your config - please migrate to the disks attribute. # For now it is still recognized though. #diskSize: 60 diff --git a/go.mod b/go.mod index a065c50c4..a1c344240 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( github.com/vmware/go-vcloud-director/v2 v2.25.0 github.com/vmware/govmomi v0.43.0 github.com/vultr/govultr/v3 v3.9.1 - go.anx.io/go-anxcloud v0.7.3 + go.anx.io/go-anxcloud v0.7.8 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.36.0 golang.org/x/oauth2 v0.28.0 @@ -126,6 +126,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-version v1.7.0 // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -141,8 +142,8 @@ require ( github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/ulid v1.3.1 // indirect - github.com/onsi/ginkgo/v2 v2.22.0 // indirect - github.com/onsi/gomega v1.36.1 // indirect + github.com/onsi/ginkgo/v2 v2.22.2 // indirect + github.com/onsi/gomega v1.36.2 // indirect github.com/openshift/custom-resource-status v1.1.2 // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect github.com/peterhellberg/link v1.2.0 // indirect diff --git a/go.sum b/go.sum index 720b5557a..8eb8b907a 100644 --- a/go.sum +++ b/go.sum @@ -253,8 +253,8 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -369,15 +369,15 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= +github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= -github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4= github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= @@ -455,8 +455,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.anx.io/go-anxcloud v0.7.3 h1:NWkm4KAg0GyJALBbSgp++J2K563lHQGDDVJAcM6CgUU= -go.anx.io/go-anxcloud v0.7.3/go.mod h1:RpJvC8ZmXNu9dSygIgZ0ossqPz0+6n9xDX9weeATmSo= +go.anx.io/go-anxcloud v0.7.8 h1:FJk1CKBqFeBPLswSpfAGogPITkciXQ9N7Jd9adGNcH8= +go.anx.io/go-anxcloud v0.7.8/go.mod h1:OlwFe0Kf3BTp3GphivKalBiElZPgsNEEN/tMsLymbX0= go.keploy.io/server v0.8.6 h1:czE9jaliyAkMMJcYnMPNuu6tun7UgwFbokxEG95vLN4= go.keploy.io/server v0.8.6/go.mod h1:t7BPuZQSiC3PNHZ9dbn3e3VB61HNWwiqVmaRujfDFUg= go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= diff --git a/pkg/cloudprovider/provider/anexia/network_provisioning.go b/pkg/cloudprovider/provider/anexia/network_provisioning.go index a133509a3..9ddb1f3af 100644 --- a/pkg/cloudprovider/provider/anexia/network_provisioning.go +++ b/pkg/cloudprovider/provider/anexia/network_provisioning.go @@ -73,11 +73,10 @@ func networkInterfacesForProvisioning(ctx context.Context, log *zap.SugaredLogge } ret[netIndex] = anxvm.Network{ - VLAN: network.VlanID, - IPs: addresses, - - // the one NIC type supported by the ADC API - NICType: anxtypes.VmxNet3NIC, + VLAN: network.VlanID, + IPs: addresses, + NICType: anxtypes.VirtioNIC, + BandwidthLimit: network.BandwidthLimit, } } diff --git a/pkg/cloudprovider/provider/anexia/provider.go b/pkg/cloudprovider/provider/anexia/provider.go index e0a5070ba..61d7a568b 100644 --- a/pkg/cloudprovider/provider/anexia/provider.go +++ b/pkg/cloudprovider/provider/anexia/provider.go @@ -225,6 +225,33 @@ func ensureConditions(status *anxtypes.ProviderStatus) { } } +// getTokenFromSpec got extracted from getConfig in order to circumvent it. +// +// That allowed us to reduce [Cleanup] to the bare minimum and allowing tear +// downs if the template no longer exists. (ANXKUBE-1361) +func (p *provider) getTokenFromSpec(spec clusterv1alpha1.ProviderSpec) (string, error) { + if spec.Value == nil { + return "", fmt.Errorf("machine.spec.providerSpec.value is nil") + } + + pconfig, err := providerconfig.GetConfig(spec) + if err != nil { + return "", err + } + + rawConfig, err := anxtypes.GetConfig(*pconfig) + if err != nil { + return "", fmt.Errorf("error parsing provider config: %w", err) + } + + token, err := p.configVarResolver.GetStringValueOrEnv(rawConfig.Token, anxtypes.AnxTokenEnv) + if err != nil { + return "", fmt.Errorf("failed to get 'token': %w", err) + } + + return token, nil +} + func (p *provider) getConfig(ctx context.Context, log *zap.SugaredLogger, provSpec clusterv1alpha1.ProviderSpec) (*resolvedConfig, *providerconfig.Config, error) { pconfig, err := providerconfig.GetConfig(provSpec) if err != nil { @@ -314,12 +341,12 @@ func (p *provider) Validate(ctx context.Context, log *zap.SugaredLogger, machine } func (p *provider) Get(ctx context.Context, log *zap.SugaredLogger, machine *clusterv1alpha1.Machine, pd *cloudprovidertypes.ProviderData) (instance.Instance, error) { - config, _, err := p.getConfig(ctx, log, machine.Spec.ProviderSpec) + token, err := p.getTokenFromSpec(machine.Spec.ProviderSpec) if err != nil { - return nil, newError(common.InvalidConfigurationMachineError, "failed to retrieve config: %v", err) + return nil, newError(common.InvalidConfigurationMachineError, "querying token: %v", err) } - _, cli, err := getClient(config.Token, &machine.Name) + _, cli, err := getClient(token, &machine.Name) if err != nil { return nil, newError(common.InvalidConfigurationMachineError, "failed to create Anexia client: %v", err) } @@ -337,21 +364,26 @@ func (p *provider) Get(ctx context.Context, log *zap.SugaredLogger, machine *clu } if status.InstanceID == "" { - progress, err := vsphereAPI.Provisioning().Progress().Get(ctx, status.ProvisioningID) + p, err := vsphereAPI.Provisioning().Progress().Get(ctx, status.ProvisioningID) if err != nil { return nil, anexiaErrorToTerminalError(err, "failed to get provisioning progress") } - if len(progress.Errors) > 0 { - return nil, fmt.Errorf("vm provisioning had errors: %s", strings.Join(progress.Errors, ",")) - } - if progress.Progress < 100 || progress.VMIdentifier == "" { - return &anexiaInstance{isCreating: true}, nil - } - status.InstanceID = progress.VMIdentifier - - if err := updateMachineStatus(machine, status, pd.Update); err != nil { - return nil, fmt.Errorf("failed updating machine status: %w", err) + switch p.Status { + // First, check whether the request is successful. We have to do this ahead of the error checking, + // because the errors field does not seem to get cleared if the same provisioning task was successful + // in the next run. + // + // See also: VSD-1473 + case progress.StatusSuccess: + status.InstanceID = p.VMIdentifier + if err := updateMachineStatus(machine, status, pd.Update); err != nil { + return nil, fmt.Errorf("failed updating machine status: %w", err) + } + case progress.StatusFailed: + return nil, fmt.Errorf("vm provisioning had errors: %s", strings.Join(p.Errors, ",")) + case progress.StatusInProgress: + return &anexiaInstance{isCreating: true}, nil } } @@ -390,12 +422,12 @@ func (p *provider) Cleanup(ctx context.Context, log *zap.SugaredLogger, machine }() ensureConditions(&status) - config, _, err := p.getConfig(ctx, log, machine.Spec.ProviderSpec) + token, err := p.getTokenFromSpec(machine.Spec.ProviderSpec) if err != nil { - return false, newError(common.InvalidConfigurationMachineError, "failed to parse MachineSpec: %v", err) + return false, fmt.Errorf("querying token from MachineSpec failed: %w", err) } - _, cli, err := getClient(config.Token, &machine.Name) + _, cli, err := getClient(token, &machine.Name) if err != nil { return false, newError(common.InvalidConfigurationMachineError, "failed to create Anexia client: %v", err) } @@ -437,16 +469,18 @@ func isTaskDone(ctx context.Context, cli anxclient.Client, progressIdentifier st return false, err } - if len(response.Errors) != 0 { + switch response.Status { + case progress.StatusSuccess: + return true, nil + case progress.StatusInProgress: + return false, nil + case progress.StatusCancelled, + progress.StatusFailed: taskErrors, _ := json.Marshal(response.Errors) return true, fmt.Errorf("task failed with: %s", taskErrors) + default: + panic(fmt.Sprintf("unexpected progress.Status: %#v", response.Status)) } - - if response.Progress == 100 { - return true, nil - } - - return false, nil } func (p *provider) MigrateUID(_ context.Context, _ *zap.SugaredLogger, _ *clusterv1alpha1.Machine, _ k8stypes.UID) error { diff --git a/pkg/cloudprovider/provider/anexia/provider_test.go b/pkg/cloudprovider/provider/anexia/provider_test.go index 24b51c416..9540ddf09 100644 --- a/pkg/cloudprovider/provider/anexia/provider_test.go +++ b/pkg/cloudprovider/provider/anexia/provider_test.go @@ -110,7 +110,7 @@ func TestAnexiaProvider(t *testing.T) { networkArray := jsonBody["network"].([]interface{}) networkObject := networkArray[0].(jsonObject) testhelper.AssertEquals(t, networkObject["vlan"], "VLAN-ID") - testhelper.AssertEquals(t, networkObject["nic_type"], "vmxnet3") + testhelper.AssertEquals(t, networkObject["nic_type"], "virtio") testhelper.AssertEquals(t, networkObject["ips"].([]interface{})[0], "8.8.8.8") }, }, @@ -145,6 +145,17 @@ func TestAnexiaProvider(t *testing.T) { testhelper.AssertJSONEquals(t, `[{"gb":10,"type":"STD1"}]`, jsonBody["additional_disks"]) }, }, + { + // Provision a generic VM with an increased bandwidth limit + ReconcileContext: hookableReconcileContext("LOCATION-ID", "INCREASED-BANDWIDTH-LIMIT", func(rc *reconcileContext) { + rc.Config.Networks[0].BandwidthLimit = 10000 + }), + AssertJSONBody: func(jsonBody jsonObject) { + networkArray := jsonBody["network"].([]any) + networkObject := networkArray[0].(jsonObject) + testhelper.AssertEquals(t, json.Number("10000"), networkObject["bandwidth_limit"]) + }, + }, } testhelper.Mux.HandleFunc("/api/ipam/v1/address/reserve/ip/count.json", func(writer http.ResponseWriter, _ *http.Request) { @@ -201,6 +212,92 @@ func TestAnexiaProvider(t *testing.T) { } }) + t.Run("Test resolve network", func(t *testing.T) { + t.Parallel() + + type testCase struct { + config anxtypes.RawConfig + expectedError string + expectedNetworkBandwidthLimit int + expectedNetwork []resolvedNetwork + } + + testCases := []testCase{ + { + // Failing to parse should mention the reason + config: hookableConfig(func(c *anxtypes.RawConfig) { + c.Networks = []anxtypes.RawNetwork{ + { + VlanID: providerconfigtypes.ConfigVarString{Value: "17825213"}, + PrefixIDs: []providerconfigtypes.ConfigVarString{{Value: "0987654"}}, + BandwidthLimit: 19, + }, + } + }), + expectedError: "failed to parse bandwidth limit", + expectedNetwork: []resolvedNetwork{}, + }, + { + // Without Bandwidth specified + config: hookableConfig(func(c *anxtypes.RawConfig) { + c.Networks = []anxtypes.RawNetwork{ + { + VlanID: providerconfigtypes.ConfigVarString{Value: "17825213"}, + PrefixIDs: []providerconfigtypes.ConfigVarString{{Value: "0987654"}}, + }, + } + }), + expectedError: "", + expectedNetwork: []resolvedNetwork{ + { + VlanID: "17825213", + Prefixes: []string{"0987654"}, + BandwidthLimit: 0, + }, + }, + }, + { + // With one valid network + config: hookableConfig(func(c *anxtypes.RawConfig) { + c.Networks = []anxtypes.RawNetwork{ + { + VlanID: providerconfigtypes.ConfigVarString{Value: "17825213"}, + PrefixIDs: []providerconfigtypes.ConfigVarString{{Value: "0987654"}}, + BandwidthLimit: 10000, + }, + } + }), + expectedError: "", + expectedNetwork: []resolvedNetwork{ + { + VlanID: "17825213", + Prefixes: []string{"0987654"}, + BandwidthLimit: 10000, + }, + }, + }, + } + + provider := New(configvar.NewResolver(context.Background(), fake.NewClientBuilder().Build())).(*provider) + for _, testCase := range testCases { + resolvedNetworks, err := provider.resolveNetworkConfig(log, testCase.config) + if testCase.expectedError != "" { + testhelper.AssertErr(t, err) + testhelper.AssertEquals(t, true, strings.Contains(err.Error(), testCase.expectedError)) + continue + } else { + testhelper.AssertNoErr(t, err) + for ni, network := range *resolvedNetworks { + testhelper.AssertEquals(t, testCase.expectedNetwork[ni].VlanID, network.VlanID) + for pi, prefix := range network.Prefixes { + testhelper.AssertEquals(t, testCase.expectedNetwork[ni].Prefixes[pi], prefix) + } + testhelper.AssertEquals(t, testCase.expectedNetwork[ni].BandwidthLimit, network.BandwidthLimit) + } + } + } + }) + t.Run("Test resolve template", func(t *testing.T) { t.Parallel() @@ -373,6 +470,7 @@ func TestValidate(t *testing.T) { provider := New(configvar.NewResolver(context.Background(), fake.NewClientBuilder().Build())) for _, testCase := range getSpecsForValidationTest(t, configCases) { err := provider.Validate(context.Background(), zap.NewNop().Sugar(), testCase.Spec) + t.Logf("testing config case with expected err: %s", testCase.ExpectedError.Error()) if testCase.ExpectedError != nil { if !errors.Is(err, testCase.ExpectedError) { testhelper.AssertEquals(t, testCase.ExpectedError.Error(), err.Error()) diff --git a/pkg/cloudprovider/provider/anexia/resolve_config.go b/pkg/cloudprovider/provider/anexia/resolve_config.go index 96a009a39..693b66fa1 100644 --- a/pkg/cloudprovider/provider/anexia/resolve_config.go +++ b/pkg/cloudprovider/provider/anexia/resolve_config.go @@ -37,14 +37,14 @@ type resolvedDisk struct { // resolvedNetwork contains the resolved values from types.RawNetwork. type resolvedNetwork struct { - anxtypes.RawNetwork - VlanID string // List of prefixes to each reserve an IP address from. // // Legacy compatibility: may contain an empty string as entry to reserve an IP address from the given VLAN instead of a specific prefix. Prefixes []string + + BandwidthLimit int } // resolvedConfig contains the resolved values from types.RawConfig. @@ -117,15 +117,30 @@ func (p *provider) resolveNetworkConfig(log *zap.SugaredLogger, config anxtypes. prefixes[prefixIndex] = prefixID } + bandwidthLimit, err := p.resolveBandwidthLimitConfig(net) + if err != nil { + return nil, fmt.Errorf("failed to parse bandwidth limit: %w", err) + } + ret[netIndex] = resolvedNetwork{ - VlanID: vlanID, - Prefixes: prefixes, + VlanID: vlanID, + Prefixes: prefixes, + BandwidthLimit: bandwidthLimit, } } return &ret, nil } +func (p *provider) resolveBandwidthLimitConfig(config anxtypes.RawNetwork) (int, error) { + switch config.BandwidthLimit { + case 0, 100, 1_000, 10_000: + return config.BandwidthLimit, nil + default: + return 0, fmt.Errorf("bandwidthLimit %d invalid, needs to be one of: 0, 100, 1000, 10000", config.BandwidthLimit) + } +} + func (p *provider) resolveDiskConfig(log *zap.SugaredLogger, config anxtypes.RawConfig) (*[]resolvedDisk, error) { if config.DiskSize != 0 { if len(config.Disks) != 0 { diff --git a/sdk/cloudprovider/anexia/types.go b/sdk/cloudprovider/anexia/types.go index 008ccb7e2..7ee66dd9a 100644 --- a/sdk/cloudprovider/anexia/types.go +++ b/sdk/cloudprovider/anexia/types.go @@ -37,7 +37,7 @@ const ( IPStateUnbound = "Unbound" IPProvisioningExpires = 1800 * time.Second - VmxNet3NIC = "vmxnet3" + VirtioNIC = "virtio" MachinePoweredOn = "poweredOn" ) @@ -64,6 +64,11 @@ type RawNetwork struct { // // Empty list means that no IPs will be reserved, but the interface will still be added. PrefixIDs []providerconfig.ConfigVarString `json:"prefixes"` + + // Bandwidth limit in MBit/s on the network interface. Allowed values are: 100, 1000, 10000. + // + // If unset, the default value from the Anexia Engine is used, which is usually 1000. + BandwidthLimit int `json:"bandwidthLimit,omitempty"` } // RawConfig contains all the configuration values for VMs to create, with some values maybe being fetched from secrets. From 4ff3396c8499aae8d3665e02822db54f59a35053 Mon Sep 17 00:00:00 2001 From: Etienne Wiebe Date: Fri, 16 Jan 2026 08:47:02 +0100 Subject: [PATCH 05/19] applying go mod tidy --- go.mod | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/go.mod b/go.mod index a1c344240..95aa48fb9 100644 --- a/go.mod +++ b/go.mod @@ -119,14 +119,13 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-version v1.7.0 // indirect - github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect From 014ed329b4c180c8d37e889ee47fa8a208b09cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kr=C3=B6ll?= Date: Wed, 25 Mar 2026 18:20:38 +0100 Subject: [PATCH 06/19] add fields and todos --- .../provider/anexia/helper_test.go | 8 ++ pkg/cloudprovider/provider/anexia/provider.go | 59 ++++++++----- .../provider/anexia/provider_test.go | 84 ++++++++++++------- .../provider/anexia/resolve_config.go | 17 +--- sdk/cloudprovider/anexia/types.go | 30 ++++--- 5 files changed, 123 insertions(+), 75 deletions(-) diff --git a/pkg/cloudprovider/provider/anexia/helper_test.go b/pkg/cloudprovider/provider/anexia/helper_test.go index 1bcfec34f..5a1bf920a 100644 --- a/pkg/cloudprovider/provider/anexia/helper_test.go +++ b/pkg/cloudprovider/provider/anexia/helper_test.go @@ -39,11 +39,13 @@ type ProvisionVMTestCase struct { } type ConfigTestCase struct { + Name string Config anxtypes.RawConfig Error error } type ValidateCallTestCase struct { + Name string Spec clusterv1alpha1.MachineSpec ExpectedError error } @@ -66,6 +68,7 @@ func getSpecsForValidationTest(t *testing.T, configCases []ConfigTestCase) []Val }, }, ExpectedError: configCase.Error, + Name: configCase.Name, }) } return testCases @@ -82,8 +85,13 @@ func hookableConfig(hook func(*anxtypes.RawConfig)) anxtypes.RawConfig { config := anxtypes.RawConfig{ CPUs: 1, + CPUPerformanceType: "performance", + Memory: 2, + DiskSize: 5, + DiskPerformanceType: "performance", + Disks: []anxtypes.RawDisk{ {Size: 5, PerformanceType: newConfigVarString("ENT6")}, }, diff --git a/pkg/cloudprovider/provider/anexia/provider.go b/pkg/cloudprovider/provider/anexia/provider.go index 61d7a568b..5aa2cd9fc 100644 --- a/pkg/cloudprovider/provider/anexia/provider.go +++ b/pkg/cloudprovider/provider/anexia/provider.go @@ -157,6 +157,11 @@ func provisionVM(ctx context.Context, log *zap.SugaredLogger, client anxclient.C } } + // TODO disk performance type + // TODO cpu performance type + // TODO additional disks + // TODO ssh key + // We generate a fresh SSH key but will never actually use it - we just want a valid public key to disable password authentication for our fresh VM. sshKey, err := ssh.NewKey() if err != nil { @@ -292,49 +297,65 @@ func (p *provider) Validate(ctx context.Context, log *zap.SugaredLogger, machine return fmt.Errorf("failed to parse config: %w", err) } + errs := make([]error, 0) if config.Token == "" { - return errors.New("token not set") + errs = append(errs, errors.New("token not set")) } if config.CPUs == 0 { - return errors.New("cpu count is missing") + errs = append(errs, errors.New("cpu count is missing")) + } + + if config.CPUPerformanceType == "" { + errs = append(errs, errors.New("cpu performance type is missing")) } - if len(config.Disks) == 0 { - return errors.New("no disks configured") + if config.DiskSize == 0 { + errs = append(errs, errors.New("disk size is missing")) } - for _, disk := range config.Disks { + if config.DiskPerformanceType == "" { + errs = append(errs, errors.New("disk performance type is missing")) + } + + for i, disk := range config.Disks { if disk.Size == 0 { - return errors.New("disk size is missing") + errs = append(errs, fmt.Errorf("disk size for disk %d is missing", i)) + } + if disk.PerformanceType == "" { + errs = append(errs, fmt.Errorf("disk performance type for disk %d is missing", i)) } } if config.Memory == 0 { - return errors.New("memory size is missing") + errs = append(errs, errors.New("memory size is missing")) } if config.LocationID == "" { - return errors.New("location id is missing") + errs = append(errs, errors.New("location id is missing")) } if config.TemplateID == "" { - return errors.New("no valid template configured") + errs = append(errs, errors.New("no valid template configured")) } if len(config.Networks) == 0 { - return errors.New("no networks configured") - } - - atLeastOneAddressSourceConfigured := false - for _, network := range config.Networks { - if len(network.Prefixes) > 0 { - atLeastOneAddressSourceConfigured = true - break + errs = append(errs, errors.New("no networks configured")) + } else { + atLeastOneAddressSourceConfigured := false + for _, network := range config.Networks { + if len(network.Prefixes) > 0 { + atLeastOneAddressSourceConfigured = true + break + } + } + if !atLeastOneAddressSourceConfigured { + errs = append(errs, errors.New("none of the configured networks define an address source, cannot create Machines without any IP")) } } - if !atLeastOneAddressSourceConfigured { - return errors.New("none of the configured networks define an address source, cannot create Machines without any IP") + + if len(errs) > 0 { + return errors.Join(errs...) } return nil diff --git a/pkg/cloudprovider/provider/anexia/provider_test.go b/pkg/cloudprovider/provider/anexia/provider_test.go index 9540ddf09..579297312 100644 --- a/pkg/cloudprovider/provider/anexia/provider_test.go +++ b/pkg/cloudprovider/provider/anexia/provider_test.go @@ -418,66 +418,90 @@ func TestAnexiaProvider(t *testing.T) { func TestValidate(t *testing.T) { t.Parallel() - var configCases []ConfigTestCase - configCases = append(configCases, - ConfigTestCase{ + configCases := []ConfigTestCase{ + { + Name: "no token", Config: hookableConfig(func(c *anxtypes.RawConfig) { c.Token.Value = "" }), Error: errors.New("token not set"), }, - ConfigTestCase{ + { + Name: "no cpu count", Config: hookableConfig(func(c *anxtypes.RawConfig) { c.CPUs = 0 }), Error: errors.New("cpu count is missing"), }, - ConfigTestCase{ - Config: hookableConfig(func(c *anxtypes.RawConfig) { c.Disks = []anxtypes.RawDisk{} }), - Error: errors.New("no disks configured"), + { + Name: "no disk size", + Config: hookableConfig(func(c *anxtypes.RawConfig) { c.DiskSize = 0 }), + Error: errors.New("disk size is missing"), + }, + { + Name: "no disk performance type", + Config: hookableConfig(func(c *anxtypes.RawConfig) { c.DiskPerformanceType = "" }), + Error: errors.New("disk performance type is missing"), }, - ConfigTestCase{ - Config: hookableConfig(func(c *anxtypes.RawConfig) { c.DiskSize = 10 }), - Error: anxtypes.ErrConfigDiskSizeAndDisks, + { + Name: "no cpu performance type", + Config: hookableConfig(func(c *anxtypes.RawConfig) { c.CPUPerformanceType = "" }), + Error: errors.New("cpu performance type is missing"), }, - ConfigTestCase{ + { + Name: "no disk size for additional disk disk", Config: hookableConfig(func(c *anxtypes.RawConfig) { c.Disks[0].Size = 0 }), - Error: errors.New("disk size is missing"), + Error: errors.New("disk size for disk 0 is missing"), }, - ConfigTestCase{ + { + Name: "no disk performance type for additional disk disk", + Config: hookableConfig(func(c *anxtypes.RawConfig) { c.Disks[0].PerformanceType.Value = "" }), + Error: errors.New("disk performance type for disk 0 is missing"), + }, + { + Name: "no memory", Config: hookableConfig(func(c *anxtypes.RawConfig) { c.Memory = 0 }), Error: errors.New("memory size is missing"), }, - ConfigTestCase{ + { + Name: "no location id", Config: hookableConfig(func(c *anxtypes.RawConfig) { c.LocationID.Value = "" }), Error: errors.New("location id is missing"), }, - - ConfigTestCase{ + { + Name: "no networks", Config: hookableConfig(func(c *anxtypes.RawConfig) { c.Networks = []anxtypes.RawNetwork{} }), Error: errors.New("no networks configured"), }, - ConfigTestCase{ + { + Name: "vlan deprecated", Config: hookableConfig(func(c *anxtypes.RawConfig) { c.VlanID.Value = "legacy VLAN-ID" }), Error: anxtypes.ErrConfigVlanIDAndNetworks, }, - ConfigTestCase{ - Config: hookableConfig(func(c *anxtypes.RawConfig) { c.DiskSize = 10; c.Disks = []anxtypes.RawDisk{} }), - Error: nil, + { + Name: "combined", + Config: hookableConfig(func(c *anxtypes.RawConfig) { + c.Token.Value = "" + c.CPUs = 0 + }), + Error: errors.Join(errors.New("token not set"), errors.New("cpu count is missing")), }, - ConfigTestCase{ + { + Name: "default is valid", Config: hookableConfig(nil), Error: nil, }, - ) + } provider := New(configvar.NewResolver(context.Background(), fake.NewClientBuilder().Build())) for _, testCase := range getSpecsForValidationTest(t, configCases) { - err := provider.Validate(context.Background(), zap.NewNop().Sugar(), testCase.Spec) - t.Logf("testing config case with expected err: %s", testCase.ExpectedError.Error()) - if testCase.ExpectedError != nil { - if !errors.Is(err, testCase.ExpectedError) { - testhelper.AssertEquals(t, testCase.ExpectedError.Error(), err.Error()) + testCase := testCase + t.Run(testCase.Name, func(t *testing.T) { + err := provider.Validate(context.Background(), zap.NewNop().Sugar(), testCase.Spec) + if testCase.ExpectedError != nil { + if !errors.Is(err, testCase.ExpectedError) { + testhelper.AssertEquals(t, testCase.ExpectedError.Error(), err.Error()) + } + } else { + testhelper.AssertEquals(t, testCase.ExpectedError, err) } - } else { - testhelper.AssertEquals(t, testCase.ExpectedError, err) - } + }) } } diff --git a/pkg/cloudprovider/provider/anexia/resolve_config.go b/pkg/cloudprovider/provider/anexia/resolve_config.go index 693b66fa1..e3fbf2b5d 100644 --- a/pkg/cloudprovider/provider/anexia/resolve_config.go +++ b/pkg/cloudprovider/provider/anexia/resolve_config.go @@ -141,22 +141,7 @@ func (p *provider) resolveBandwidthLimitConfig(config anxtypes.RawNetwork) (int, } } -func (p *provider) resolveDiskConfig(log *zap.SugaredLogger, config anxtypes.RawConfig) (*[]resolvedDisk, error) { - if config.DiskSize != 0 { - if len(config.Disks) != 0 { - return nil, anxtypes.ErrConfigDiskSizeAndDisks - } - - log.Info("Configuration uses the deprecated DiskSize attribute, please migrate to the Disks array instead.") - - config.Disks = []anxtypes.RawDisk{ - { - Size: config.DiskSize, - }, - } - config.DiskSize = 0 - } - +func (p *provider) resolveDiskConfig(_ *zap.SugaredLogger, config anxtypes.RawConfig) (*[]resolvedDisk, error) { ret := make([]resolvedDisk, len(config.Disks)) for idx, disk := range config.Disks { diff --git a/sdk/cloudprovider/anexia/types.go b/sdk/cloudprovider/anexia/types.go index 7ee66dd9a..582c4d84b 100644 --- a/sdk/cloudprovider/anexia/types.go +++ b/sdk/cloudprovider/anexia/types.go @@ -42,16 +42,15 @@ const ( ) var ( - // ErrConfigDiskSizeAndDisks is returned when the config has both DiskSize and Disks set, which is unsupported. - ErrConfigDiskSizeAndDisks = errors.New("both the deprecated DiskSize and new Disks attribute are set") - // ErrConfigVlanIDAndNetworks is returned when the config has both VlanID and Networks set, which is unsupported. ErrConfigVlanIDAndNetworks = errors.New("both the deprecated VlanID and new Networks attribute are set") ) // RawDisk specifies a single disk, with some values maybe being fetched from secrets. type RawDisk struct { - Size int `json:"size"` + // Size (in Gibibyte) specifies the size of the disk. + Size int `json:"size"` + // PerformanceType specifies the performance of the disk. PerformanceType providerconfig.ConfigVarString `json:"performanceType"` } @@ -73,20 +72,31 @@ type RawNetwork struct { // RawConfig contains all the configuration values for VMs to create, with some values maybe being fetched from secrets. type RawConfig struct { - Token providerconfig.ConfigVarString `json:"token,omitempty"` + // Token specifies the Anexia Engine API token. + Token providerconfig.ConfigVarString `json:"token,omitempty"` + // LocationID specifies the datacenter location. LocationID providerconfig.ConfigVarString `json:"locationID"` - TemplateID providerconfig.ConfigVarString `json:"templateID"` - Template providerconfig.ConfigVarString `json:"template"` + // TemplateID specifies the template exactly, however most cases should use Template and TemplateBuild instead. + TemplateID providerconfig.ConfigVarString `json:"templateID"` + // Template specifies the template name. + Template providerconfig.ConfigVarString `json:"template"` + // TemplateBuild specifies the template build. TemplateBuild providerconfig.ConfigVarString `json:"templateBuild"` - CPUs int `json:"cpus"` + // CPUs specify the number of CPUs of the machine + CPUs int `json:"cpus"` + // CPUPerformanceType specifies the performance of the used CPU. CPUPerformanceType string `json:"cpuPerformanceType"` - Memory int `json:"memory"` + // Memory (in Mebibyte) specifies the main memory size. + Memory int `json:"memory"` - // Deprecated, use Disks instead. + // DiskSize (in Gibibytes) for the main disk. DiskSize int `json:"diskSize"` + // DiskPerformanceType specifies the performance of the main disk. + DiskPerformanceType string `json:"diskPerformanceType"` + // Disks specifies the additional disks. Disks []RawDisk `json:"disks"` // Deprecated, use Networks instead. From 03439cd63b5be0b342d6ba16beb3621c31806c0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kr=C3=B6ll?= Date: Thu, 26 Mar 2026 09:14:47 +0100 Subject: [PATCH 07/19] add ssh key handling --- .../provider/anexia/helper_test.go | 6 ++-- pkg/cloudprovider/provider/anexia/provider.go | 30 ++++++++++--------- .../provider/anexia/resolve_config.go | 18 +++++++---- 3 files changed, 31 insertions(+), 23 deletions(-) diff --git a/pkg/cloudprovider/provider/anexia/helper_test.go b/pkg/cloudprovider/provider/anexia/helper_test.go index 5a1bf920a..8a07f276a 100644 --- a/pkg/cloudprovider/provider/anexia/helper_test.go +++ b/pkg/cloudprovider/provider/anexia/helper_test.go @@ -138,10 +138,8 @@ func hookableReconcileContext(locationID string, templateID string, hook func(*r }, }, }, - RawConfig: anxtypes.RawConfig{ - CPUs: 5, - Memory: 5, - }, + CPUs: 5, + Memory: 5, }, ProviderData: &cloudprovidertypes.ProviderData{ Update: func(*clusterv1alpha1.Machine, ...cloudprovidertypes.MachineModifier) error { diff --git a/pkg/cloudprovider/provider/anexia/provider.go b/pkg/cloudprovider/provider/anexia/provider.go index 5aa2cd9fc..fdc4cb0f1 100644 --- a/pkg/cloudprovider/provider/anexia/provider.go +++ b/pkg/cloudprovider/provider/anexia/provider.go @@ -122,17 +122,17 @@ func provisionVM(ctx context.Context, log *zap.SugaredLogger, client anxclient.C reconcileContext.Machine.Name, config.CPUs, config.Memory, - config.Disks[0].Size, + config.DiskSize, networkInterfaces, ) - vm.DiskType = config.Disks[0].PerformanceType + vm.DiskType = config.DiskPerformanceType if config.CPUPerformanceType != "" { vm.CPUPerformanceType = config.CPUPerformanceType } - for _, disk := range config.Disks[1:] { + for _, disk := range config.Disks { vm.AdditionalDisks = append(vm.AdditionalDisks, anxvm.AdditionalDisk{ SizeGBs: disk.Size, Type: disk.PerformanceType, @@ -157,17 +157,17 @@ func provisionVM(ctx context.Context, log *zap.SugaredLogger, client anxclient.C } } - // TODO disk performance type - // TODO cpu performance type - // TODO additional disks - // TODO ssh key - - // We generate a fresh SSH key but will never actually use it - we just want a valid public key to disable password authentication for our fresh VM. - sshKey, err := ssh.NewKey() - if err != nil { - return newError(common.CreateMachineError, "failed to generate ssh key: %v", err) + if len(config.SSHPublicKeys) > 0 { + // use provided SSH public key(s) if specified + vm.SSH = strings.Join(config.SSHPublicKeys, "\n") + } else { + // We generate a fresh SSH key but will never actually use it - we just want a valid public key to disable password authentication for our fresh VM. + sshKey, err := ssh.NewKey() + if err != nil { + return newError(common.CreateMachineError, "failed to generate ssh key: %v", err) + } + vm.SSH = sshKey.PublicKey } - vm.SSH = sshKey.PublicKey provisionResponse, err := vmAPI.Provisioning().VM().Provision(ctx, vm, false) meta.SetStatusCondition(&status.Conditions, metav1.Condition{ @@ -233,7 +233,7 @@ func ensureConditions(status *anxtypes.ProviderStatus) { // getTokenFromSpec got extracted from getConfig in order to circumvent it. // // That allowed us to reduce [Cleanup] to the bare minimum and allowing tear -// downs if the template no longer exists. (ANXKUBE-1361) +// downs if the template no longer exists (ANXKUBE-1361). func (p *provider) getTokenFromSpec(spec clusterv1alpha1.ProviderSpec) (string, error) { if spec.Value == nil { return "", fmt.Errorf("machine.spec.providerSpec.value is nil") @@ -277,6 +277,8 @@ func (p *provider) getConfig(ctx context.Context, log *zap.SugaredLogger, provSp return nil, nil, fmt.Errorf("error resolving config: %w", err) } + resolvedConfig.SSHPublicKeys = pconfig.SSHPublicKeys + return resolvedConfig, pconfig, nil } diff --git a/pkg/cloudprovider/provider/anexia/resolve_config.go b/pkg/cloudprovider/provider/anexia/resolve_config.go index e3fbf2b5d..0b83f2472 100644 --- a/pkg/cloudprovider/provider/anexia/resolve_config.go +++ b/pkg/cloudprovider/provider/anexia/resolve_config.go @@ -49,14 +49,18 @@ type resolvedNetwork struct { // resolvedConfig contains the resolved values from types.RawConfig. type resolvedConfig struct { - anxtypes.RawConfig - Token string LocationID string TemplateID string - Disks []resolvedDisk - Networks []resolvedNetwork + Disks []resolvedDisk + Networks []resolvedNetwork + SSHPublicKeys []string + CPUs int + CPUPerformanceType string + DiskSize int + DiskPerformanceType string + Memory int } func (p *provider) resolveTemplateID(ctx context.Context, a api.API, config anxtypes.RawConfig, locationID string) (string, error) { @@ -162,7 +166,11 @@ func (p *provider) resolveDiskConfig(_ *zap.SugaredLogger, config anxtypes.RawCo func (p *provider) resolveConfig(ctx context.Context, log *zap.SugaredLogger, config anxtypes.RawConfig) (*resolvedConfig, error) { var err error ret := resolvedConfig{ - RawConfig: config, + CPUs: config.CPUs, + CPUPerformanceType: config.CPUPerformanceType, + DiskSize: config.DiskSize, + DiskPerformanceType: config.DiskPerformanceType, + Memory: config.Memory, } ret.Token, err = p.configVarResolver.GetStringValueOrEnv(config.Token, anxtypes.AnxTokenEnv) From 6ddd5d94bc4fd676580d556ab9d9a915a0eb7f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kr=C3=B6ll?= Date: Thu, 26 Mar 2026 09:14:56 +0100 Subject: [PATCH 08/19] fix lint --- pkg/cloudprovider/provider/anexia/provider_test.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/cloudprovider/provider/anexia/provider_test.go b/pkg/cloudprovider/provider/anexia/provider_test.go index 579297312..a86766ef1 100644 --- a/pkg/cloudprovider/provider/anexia/provider_test.go +++ b/pkg/cloudprovider/provider/anexia/provider_test.go @@ -216,10 +216,9 @@ func TestAnexiaProvider(t *testing.T) { t.Parallel() type testCase struct { - config anxtypes.RawConfig - expectedError string - expectedNetworkBandwidthLimit int - expectedNetwork []resolvedNetwork + config anxtypes.RawConfig + expectedError string + expectedNetwork []resolvedNetwork } testCases := []testCase{ From 5068da96d6fdbde213e9d516a2138e3bf52b862b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kr=C3=B6ll?= Date: Thu, 26 Mar 2026 15:34:05 +0100 Subject: [PATCH 09/19] simplify reconcile context --- .../provider/anexia/network_provisioning.go | 9 ++-- pkg/cloudprovider/provider/anexia/provider.go | 41 +++++++------------ .../provider/anexia/provider_test.go | 35 +++++++++++----- .../provider/anexia/reconcile_context.go | 19 --------- 4 files changed, 43 insertions(+), 61 deletions(-) diff --git a/pkg/cloudprovider/provider/anexia/network_provisioning.go b/pkg/cloudprovider/provider/anexia/network_provisioning.go index 9ddb1f3af..d2458cefb 100644 --- a/pkg/cloudprovider/provider/anexia/network_provisioning.go +++ b/pkg/cloudprovider/provider/anexia/network_provisioning.go @@ -30,9 +30,7 @@ import ( anxtypes "k8c.io/machine-controller/sdk/cloudprovider/anexia" ) -func networkInterfacesForProvisioning(ctx context.Context, log *zap.SugaredLogger, client anxclient.Client) ([]anxvm.Network, error) { - reconcileContext := getReconcileContext(ctx) - +func networkInterfacesForProvisioning(ctx context.Context, reconcileContext reconcileContext, log *zap.SugaredLogger, client anxclient.Client) ([]anxvm.Network, error) { config := reconcileContext.Config status := reconcileContext.Status @@ -64,7 +62,7 @@ func networkInterfacesForProvisioning(ctx context.Context, log *zap.SugaredLogge networkStatus.Addresses = make([]anxtypes.NetworkAddressStatus, len(network.Prefixes)) } - reservedIP, err := getIPAddress(ctx, log, &network, prefix, &networkStatus.Addresses[prefixIndex], client) + reservedIP, err := getIPAddress(ctx, reconcileContext, log, &network, prefix, &networkStatus.Addresses[prefixIndex], client) if err != nil { return nil, newError(common.CreateMachineError, "failed to reserve IP: %v", err) } @@ -97,8 +95,7 @@ func networkInterfacesForProvisioning(ctx context.Context, log *zap.SugaredLogge // again.. it's not too expensive of a Mutex. var _engsup3404mutex sync.Mutex -func getIPAddress(ctx context.Context, log *zap.SugaredLogger, network *resolvedNetwork, prefix string, status *anxtypes.NetworkAddressStatus, client anxclient.Client) (string, error) { - reconcileContext := getReconcileContext(ctx) +func getIPAddress(ctx context.Context, reconcileContext reconcileContext, log *zap.SugaredLogger, network *resolvedNetwork, prefix string, status *anxtypes.NetworkAddressStatus, client anxclient.Client) (string, error) { // only use IP if it is still unbound if status.ReservedIP != "" && status.IPState == anxtypes.IPStateUnbound && (!status.IPProvisioningExpires.IsZero() && status.IPProvisioningExpires.After(time.Now())) { diff --git a/pkg/cloudprovider/provider/anexia/provider.go b/pkg/cloudprovider/provider/anexia/provider.go index fdc4cb0f1..7e12626b9 100644 --- a/pkg/cloudprovider/provider/anexia/provider.go +++ b/pkg/cloudprovider/provider/anexia/provider.go @@ -70,14 +70,14 @@ func (p *provider) Create(ctx context.Context, log *zap.SugaredLogger, machine * return nil, fmt.Errorf("failed to get provider config: %w", err) } - ctx = createReconcileContext(ctx, reconcileContext{ + reconcileCtx := reconcileContext{ Status: &status, UserData: userdata, Config: *config, ProviderData: data, ProviderConfig: providerCfg, Machine: machine, - }) + } _, client, err := getClient(config.Token, &machine.Name) if err != nil { @@ -91,15 +91,14 @@ func (p *provider) Create(ctx context.Context, log *zap.SugaredLogger, machine * }() // provision machine - err = provisionVM(ctx, log, client) + err = provisionVM(ctx, reconcileCtx, log, client) if err != nil { return nil, anexiaErrorToTerminalError(err, "failed waiting for vm provisioning") } return p.Get(ctx, log, machine, data) } -func provisionVM(ctx context.Context, log *zap.SugaredLogger, client anxclient.Client) error { - reconcileContext := getReconcileContext(ctx) +func provisionVM(ctx context.Context, reconcileContext reconcileContext, log *zap.SugaredLogger, client anxclient.Client) error { vmAPI := vsphere.NewAPI(client) ctx, cancel := context.WithTimeout(ctx, anxtypes.CreateRequestTimeout) @@ -110,7 +109,7 @@ func provisionVM(ctx context.Context, log *zap.SugaredLogger, client anxclient.C log.Info("Machine does not contain a provisioningID yet. Starting to provision") config := reconcileContext.Config - networkInterfaces, err := networkInterfacesForProvisioning(ctx, log, client) + networkInterfaces, err := networkInterfacesForProvisioning(ctx, reconcileContext, log, client) if err != nil { return fmt.Errorf("error generating network config for machine: %w", err) } @@ -170,15 +169,22 @@ func provisionVM(ctx context.Context, log *zap.SugaredLogger, client anxclient.C } provisionResponse, err := vmAPI.Provisioning().VM().Provision(ctx, vm, false) + if err != nil { + meta.SetStatusCondition(&status.Conditions, metav1.Condition{ + Type: ProvisionedType, + Status: metav1.ConditionFalse, + Reason: "ProvisioningError", + Message: fmt.Sprintf("instance provisioning failed: %v", err.Error()), + }) + return newError(common.CreateMachineError, "instance provisioning failed: %v", err) + } + meta.SetStatusCondition(&status.Conditions, metav1.Condition{ Type: ProvisionedType, Status: metav1.ConditionFalse, Reason: "Provisioning", Message: "provisioning request was sent", }) - if err != nil { - return newError(common.CreateMachineError, "instance provisioning failed: %v", err) - } // we successfully sent a VM provisioning request to the API, we consider the IP as 'Bound' now networkStatusMarkIPsBound(status) @@ -202,23 +208,6 @@ func provisionVM(ctx context.Context, log *zap.SugaredLogger, client anxclient.C return updateMachineStatus(reconcileContext.Machine, *status, reconcileContext.ProviderData.Update) } -func isAlreadyProvisioning(ctx context.Context) bool { - status := getReconcileContext(ctx).Status - condition := meta.FindStatusCondition(status.Conditions, ProvisionedType) - lastChange := condition.LastTransitionTime.Time - const reasonInProvisioning = "InProvisioning" - if condition.Reason == reasonInProvisioning && time.Since(lastChange) > 5*time.Minute { - meta.SetStatusCondition(&status.Conditions, metav1.Condition{ - Type: ProvisionedType, - Reason: "ReInitialising", - Message: "Could not find ongoing VM provisioning", - Status: metav1.ConditionFalse, - }) - } - - return condition.Status == metav1.ConditionFalse && condition.Reason == reasonInProvisioning -} - func ensureConditions(status *anxtypes.ProviderStatus) { conditions := [...]metav1.Condition{ {Type: ProvisionedType, Message: "", Status: metav1.ConditionUnknown, Reason: "Initialising"}, diff --git a/pkg/cloudprovider/provider/anexia/provider_test.go b/pkg/cloudprovider/provider/anexia/provider_test.go index a86766ef1..4fc440151 100644 --- a/pkg/cloudprovider/provider/anexia/provider_test.go +++ b/pkg/cloudprovider/provider/anexia/provider_test.go @@ -205,9 +205,7 @@ func TestAnexiaProvider(t *testing.T) { testhelper.AssertNoErr(t, err) }) - ctx := createReconcileContext(context.Background(), testCase.ReconcileContext) - - err := provisionVM(ctx, log, client) + err := provisionVM(context.Background(), testCase.ReconcileContext, log, client) testhelper.AssertNoErr(t, err) } }) @@ -364,25 +362,25 @@ func TestAnexiaProvider(t *testing.T) { }, }, } - ctx := createReconcileContext(context.Background(), reconcileContext{ + reconcileCtx := reconcileContext{ Status: &providerStatus, UserData: "", Config: resolvedConfig{}, ProviderData: nil, - }) + } condition := meta.FindStatusCondition(providerStatus.Conditions, ProvisionedType) condition.LastTransitionTime = metav1.Time{Time: time.Now().Add(-1 * time.Minute)} - testhelper.AssertEquals(t, true, isAlreadyProvisioning(ctx)) + testhelper.AssertEquals(t, true, isAlreadyProvisioning(reconcileCtx)) condition.Reason = "Provisioned" condition.Status = metav1.ConditionTrue - testhelper.AssertEquals(t, false, isAlreadyProvisioning(ctx)) + testhelper.AssertEquals(t, false, isAlreadyProvisioning(reconcileCtx)) condition.Reason = "InProvisioning" condition.Status = metav1.ConditionFalse condition.LastTransitionTime = metav1.Time{Time: time.Now().Add(-10 * time.Minute)} - testhelper.AssertEquals(t, false, isAlreadyProvisioning(ctx)) + testhelper.AssertEquals(t, false, isAlreadyProvisioning(reconcileCtx)) testhelper.AssertEquals(t, condition.Reason, "ReInitialising") }) @@ -400,20 +398,37 @@ func TestAnexiaProvider(t *testing.T) { }, }, } - ctx := createReconcileContext(context.Background(), reconcileContext{Status: providerStatus}) + reconcileCtx := reconcileContext{Status: providerStatus} t.Run("with unbound reserved IP", func(t *testing.T) { expectedIP := "8.8.8.8" providerStatus.Networks[0].Addresses[0].ReservedIP = expectedIP providerStatus.Networks[0].Addresses[0].IPState = anxtypes.IPStateUnbound providerStatus.Networks[0].Addresses[0].IPProvisioningExpires = time.Now().Add(anxtypes.IPProvisioningExpires) - reservedIP, err := getIPAddress(ctx, log, &resolvedNetwork{}, "Prefix-ID", &providerStatus.Networks[0].Addresses[0], client) + reservedIP, err := getIPAddress(context.Background(), reconcileCtx, log, &resolvedNetwork{}, "Prefix-ID", &providerStatus.Networks[0].Addresses[0], client) testhelper.AssertNoErr(t, err) testhelper.AssertEquals(t, expectedIP, reservedIP) }) }) } +func isAlreadyProvisioning(reconcileContext reconcileContext) bool { + status := reconcileContext.Status + condition := meta.FindStatusCondition(status.Conditions, ProvisionedType) + lastChange := condition.LastTransitionTime.Time + const reasonInProvisioning = "InProvisioning" + if condition.Reason == reasonInProvisioning && time.Since(lastChange) > 5*time.Minute { + meta.SetStatusCondition(&status.Conditions, metav1.Condition{ + Type: ProvisionedType, + Reason: "ReInitialising", + Message: "Could not find ongoing VM provisioning", + Status: metav1.ConditionFalse, + }) + } + + return condition.Status == metav1.ConditionFalse && condition.Reason == reasonInProvisioning +} + func TestValidate(t *testing.T) { t.Parallel() diff --git a/pkg/cloudprovider/provider/anexia/reconcile_context.go b/pkg/cloudprovider/provider/anexia/reconcile_context.go index e30e44365..2986624c6 100644 --- a/pkg/cloudprovider/provider/anexia/reconcile_context.go +++ b/pkg/cloudprovider/provider/anexia/reconcile_context.go @@ -17,18 +17,12 @@ limitations under the License. package anexia import ( - "context" - cloudprovidertypes "k8c.io/machine-controller/pkg/cloudprovider/types" clusterv1alpha1 "k8c.io/machine-controller/sdk/apis/cluster/v1alpha1" anxtypes "k8c.io/machine-controller/sdk/cloudprovider/anexia" providerconfigtypes "k8c.io/machine-controller/sdk/providerconfig" ) -type contextKey byte - -const machineReconcileContextKey contextKey = 0 - type reconcileContext struct { Machine *clusterv1alpha1.Machine Status *anxtypes.ProviderStatus @@ -37,16 +31,3 @@ type reconcileContext struct { ProviderData *cloudprovidertypes.ProviderData ProviderConfig *providerconfigtypes.Config } - -func createReconcileContext(ctx context.Context, cc reconcileContext) context.Context { - return context.WithValue(ctx, machineReconcileContextKey, cc) -} - -func getReconcileContext(ctx context.Context) reconcileContext { - rawContext := ctx.Value(machineReconcileContextKey) - if recContext, ok := rawContext.(reconcileContext); ok { - return recContext - } - - return reconcileContext{} -} From 0ee4da616bb68134154441586fe776521b889eba Mon Sep 17 00:00:00 2001 From: Marco Peroverde Date: Wed, 1 Apr 2026 08:31:34 +0200 Subject: [PATCH 10/19] Added Name to RawDisk --- sdk/cloudprovider/anexia/types.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk/cloudprovider/anexia/types.go b/sdk/cloudprovider/anexia/types.go index 582c4d84b..e170f1c67 100644 --- a/sdk/cloudprovider/anexia/types.go +++ b/sdk/cloudprovider/anexia/types.go @@ -52,6 +52,8 @@ type RawDisk struct { Size int `json:"size"` // PerformanceType specifies the performance of the disk. PerformanceType providerconfig.ConfigVarString `json:"performanceType"` + // Name as human readable identifier for the disk + Name string `json:"name"` } // RawNetwork specifies a single network interface. From 1b208246b530e831efdb5a99f9a3a4f6ce675ef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kr=C3=B6ll?= Date: Fri, 10 Apr 2026 11:20:16 +0200 Subject: [PATCH 11/19] vlanID omitempty --- sdk/cloudprovider/anexia/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/cloudprovider/anexia/types.go b/sdk/cloudprovider/anexia/types.go index e170f1c67..3ad42a7cc 100644 --- a/sdk/cloudprovider/anexia/types.go +++ b/sdk/cloudprovider/anexia/types.go @@ -102,7 +102,7 @@ type RawConfig struct { Disks []RawDisk `json:"disks"` // Deprecated, use Networks instead. - VlanID providerconfig.ConfigVarString `json:"vlanID"` + VlanID providerconfig.ConfigVarString `json:"vlanID,omitempty"` // Configuration of the network interfaces. At least one entry with at // least one Prefix is required. From ba6ca5b71735ba086174bee4f3e681951cd49321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kr=C3=B6ll?= Date: Fri, 10 Apr 2026 11:34:26 +0200 Subject: [PATCH 12/19] nilable vlanID added identifier to RawDisk fix disks/disksize difference handle 404 correctly on machine not found --- .../provider/anexia/helper_test.go | 8 +---- pkg/cloudprovider/provider/anexia/provider.go | 31 ++++++++--------- .../provider/anexia/provider_test.go | 24 ++++++++++--- .../provider/anexia/resolve_config.go | 34 ++++++++++--------- sdk/cloudprovider/anexia/types.go | 7 +++- 5 files changed, 58 insertions(+), 46 deletions(-) diff --git a/pkg/cloudprovider/provider/anexia/helper_test.go b/pkg/cloudprovider/provider/anexia/helper_test.go index 8a07f276a..7ffec5745 100644 --- a/pkg/cloudprovider/provider/anexia/helper_test.go +++ b/pkg/cloudprovider/provider/anexia/helper_test.go @@ -123,13 +123,7 @@ func hookableReconcileContext(locationID string, templateID string, hook func(*r Config: resolvedConfig{ LocationID: locationID, TemplateID: templateID, - Disks: []resolvedDisk{ - { - RawDisk: anxtypes.RawDisk{ - Size: 5, - }, - }, - }, + DiskSize: 5, Networks: []resolvedNetwork{ { VlanID: "VLAN-ID", diff --git a/pkg/cloudprovider/provider/anexia/provider.go b/pkg/cloudprovider/provider/anexia/provider.go index 7e12626b9..efaf34514 100644 --- a/pkg/cloudprovider/provider/anexia/provider.go +++ b/pkg/cloudprovider/provider/anexia/provider.go @@ -93,7 +93,7 @@ func (p *provider) Create(ctx context.Context, log *zap.SugaredLogger, machine * // provision machine err = provisionVM(ctx, reconcileCtx, log, client) if err != nil { - return nil, anexiaErrorToTerminalError(err, "failed waiting for vm provisioning") + return nil, wrapAnexiaError(err, "failed waiting for vm provisioning") } return p.Get(ctx, log, machine, data) } @@ -378,7 +378,7 @@ func (p *provider) Get(ctx context.Context, log *zap.SugaredLogger, machine *clu if status.InstanceID == "" { p, err := vsphereAPI.Provisioning().Progress().Get(ctx, status.ProvisioningID) if err != nil { - return nil, anexiaErrorToTerminalError(err, "failed to get provisioning progress") + return nil, wrapAnexiaError(err, "failed to get provisioning progress") } switch p.Status { @@ -407,7 +407,7 @@ func (p *provider) Get(ctx context.Context, log *zap.SugaredLogger, machine *clu info, err := vsphereAPI.Info().Get(timeoutCtx, status.InstanceID) if err != nil { - return nil, anexiaErrorToTerminalError(err, "failed getting machine info") + return nil, wrapAnexiaError(err, "failed getting machine info") } instance.info = &info @@ -459,15 +459,6 @@ func (p *provider) Cleanup(ctx context.Context, log *zap.SugaredLogger, machine if !errors.As(err, &respErr) || respErr.ErrorData.Code != http.StatusNotFound { return false, newError(common.DeleteMachineError, "failed to delete machine: %v", err) } - - // good thinking checking for a "not found" error, but go-anxcloud does only - // return >= 500 && < 600 errors (: - // since that's the legacy client in go-anxcloud and the new one is not yet available, - // this will not be fixed there but we have a nice workaround here: - - if response.Identifier == "" { - return true, nil - } } status.DeprovisioningID = response.Identifier } @@ -577,7 +568,7 @@ func updateMachineStatus(machine *clusterv1alpha1.Machine, status anxtypes.Provi return nil } -func anexiaErrorToTerminalError(err error, msg string) error { +func wrapAnexiaError(err error, msg string) error { var httpError api.HTTPError if errors.As(err, &httpError) && (httpError.StatusCode() == http.StatusForbidden || httpError.StatusCode() == http.StatusUnauthorized) { return cloudprovidererrors.TerminalError{ @@ -587,10 +578,16 @@ func anexiaErrorToTerminalError(err error, msg string) error { } var responseError *anxclient.ResponseError - if errors.As(err, &responseError) && (responseError.ErrorData.Code == http.StatusForbidden || responseError.ErrorData.Code == http.StatusUnauthorized) { - return cloudprovidererrors.TerminalError{ - Reason: common.InvalidConfigurationMachineError, - Message: "Request was rejected due to invalid credentials", + if errors.As(err, &responseError) { + if responseError.ErrorData.Code == http.StatusForbidden || responseError.ErrorData.Code == http.StatusUnauthorized { + return cloudprovidererrors.TerminalError{ + Reason: common.InvalidConfigurationMachineError, + Message: "Request was rejected due to invalid credentials", + } + } + + if responseError.ErrorData.Code == http.StatusNotFound { + return cloudprovidererrors.ErrInstanceNotFound } } diff --git a/pkg/cloudprovider/provider/anexia/provider_test.go b/pkg/cloudprovider/provider/anexia/provider_test.go index 4fc440151..cd79a3d9d 100644 --- a/pkg/cloudprovider/provider/anexia/provider_test.go +++ b/pkg/cloudprovider/provider/anexia/provider_test.go @@ -485,7 +485,7 @@ func TestValidate(t *testing.T) { }, { Name: "vlan deprecated", - Config: hookableConfig(func(c *anxtypes.RawConfig) { c.VlanID.Value = "legacy VLAN-ID" }), + Config: hookableConfig(func(c *anxtypes.RawConfig) { c.VlanID = &providerconfigtypes.ConfigVarString{Value: "legacy VLAN-ID"} }), Error: anxtypes.ErrConfigVlanIDAndNetworks, }, { @@ -572,7 +572,7 @@ func TestUpdateStatus(t *testing.T) { testhelper.AssertNoErr(t, err) } -func Test_anexiaErrorToTerminalError(t *testing.T) { +func Test_wrapAnexiaError(t *testing.T) { forbiddenMockHandler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusForbidden) _, err := w.Write([]byte(`{"error": {"code": 403}}`)) @@ -633,7 +633,7 @@ func Test_anexiaErrorToTerminalError(t *testing.T) { srv := httptest.NewServer(testCase.mockHandler) defer srv.Close() - err := anexiaErrorToTerminalError(testCase.run(srv.URL), "foo") + err := wrapAnexiaError(testCase.run(srv.URL), "foo") if ok, _, _ := cloudprovidererrors.IsTerminalError(err); !ok { t.Errorf("unexpected error %#v, expected TerminalError", err) } @@ -642,7 +642,7 @@ func Test_anexiaErrorToTerminalError(t *testing.T) { t.Run("api client 404 HTTPError shouldn't convert to TerminalError", func(t *testing.T) { err := api.NewHTTPError(http.StatusNotFound, "GET", &url.URL{}, errors.New("foo")) - err = anexiaErrorToTerminalError(err, "foo") + err = wrapAnexiaError(err, "foo") if ok, _, _ := cloudprovidererrors.IsTerminalError(err); ok { t.Errorf("unexpected error %#v, expected no TerminalError", err) } @@ -650,9 +650,23 @@ func Test_anexiaErrorToTerminalError(t *testing.T) { t.Run("legacy api client unspecific ResponseError shouldn't convert to TerminalError", func(t *testing.T) { var err error = &anxclient.ResponseError{} - err = anexiaErrorToTerminalError(err, "foo") + err = wrapAnexiaError(err, "foo") if ok, _, _ := cloudprovidererrors.IsTerminalError(err); ok { t.Errorf("unexpected error %#v, expected no TerminalError", err) } }) + + t.Run("legacy api client 404 ResponseError should convert to NotFoundError", func(t *testing.T) { + var err error = &anxclient.ResponseError{ + ErrorData: struct { + Code int `json:"code"` + Message string `json:"message"` + Validation map[string]string `json:"validation"` + }{Code: http.StatusNotFound, Message: "test msg", Validation: nil}, + } + err = wrapAnexiaError(err, "foo") + if ok := cloudprovidererrors.IsNotFound(err); !ok { + t.Errorf("unexpected error %#v, expected ErrInstanceNotFound", err) + } + }) } diff --git a/pkg/cloudprovider/provider/anexia/resolve_config.go b/pkg/cloudprovider/provider/anexia/resolve_config.go index 0b83f2472..ad4778482 100644 --- a/pkg/cloudprovider/provider/anexia/resolve_config.go +++ b/pkg/cloudprovider/provider/anexia/resolve_config.go @@ -83,25 +83,27 @@ func (p *provider) resolveTemplateID(ctx context.Context, a api.API, config anxt } func (p *provider) resolveNetworkConfig(log *zap.SugaredLogger, config anxtypes.RawConfig) (*[]resolvedNetwork, error) { - legacyVlanIDConfig, _ := config.VlanID.MarshalJSON() - if string(legacyVlanIDConfig) != `""` { - if len(config.Networks) != 0 { - return nil, anxtypes.ErrConfigVlanIDAndNetworks - } + if config.VlanID != nil { + legacyVlanIDConfig, _ := config.VlanID.MarshalJSON() + if string(legacyVlanIDConfig) != `""` { + if len(config.Networks) != 0 { + return nil, anxtypes.ErrConfigVlanIDAndNetworks + } - log.Info("Configuration uses the deprecated VlanID attribute, please migrate to the Networks array instead.") + log.Info("Configuration uses the deprecated VlanID attribute, please migrate to the Networks array instead.") - vlanID, err := p.configVarResolver.GetStringValue(config.VlanID) - if err != nil { - return nil, fmt.Errorf("failed to get 'vlanID': %w", err) - } + vlanID, err := p.configVarResolver.GetStringValue(*config.VlanID) + if err != nil { + return nil, fmt.Errorf("failed to get 'vlanID': %w", err) + } - return &[]resolvedNetwork{ - { - VlanID: vlanID, - Prefixes: []string{""}, - }, - }, nil + return &[]resolvedNetwork{ + { + VlanID: vlanID, + Prefixes: []string{""}, + }, + }, nil + } } ret := make([]resolvedNetwork, len(config.Networks)) diff --git a/sdk/cloudprovider/anexia/types.go b/sdk/cloudprovider/anexia/types.go index 3ad42a7cc..b343ce552 100644 --- a/sdk/cloudprovider/anexia/types.go +++ b/sdk/cloudprovider/anexia/types.go @@ -54,6 +54,8 @@ type RawDisk struct { PerformanceType providerconfig.ConfigVarString `json:"performanceType"` // Name as human readable identifier for the disk Name string `json:"name"` + // Identifier of the disk to maintain engine sync + Identifier string `json:"identifier,omitempty"` } // RawNetwork specifies a single network interface. @@ -70,6 +72,9 @@ type RawNetwork struct { // // If unset, the default value from the Anexia Engine is used, which is usually 1000. BandwidthLimit int `json:"bandwidthLimit,omitempty"` + + // Identifier of the Network to maintain engine sync + Identifier string `json:"identifier,omitempty"` } // RawConfig contains all the configuration values for VMs to create, with some values maybe being fetched from secrets. @@ -102,7 +107,7 @@ type RawConfig struct { Disks []RawDisk `json:"disks"` // Deprecated, use Networks instead. - VlanID providerconfig.ConfigVarString `json:"vlanID,omitempty"` + VlanID *providerconfig.ConfigVarString `json:"vlanID,omitempty"` // Configuration of the network interfaces. At least one entry with at // least one Prefix is required. From ba2b98b7f0d3353255a5b6e8c482b68c6698c93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kr=C3=B6ll?= Date: Tue, 2 Jun 2026 16:12:55 +0200 Subject: [PATCH 13/19] update example machine deployment --- examples/anexia-machinedeployment.yaml | 75 ++++++++++++-------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/examples/anexia-machinedeployment.yaml b/examples/anexia-machinedeployment.yaml index 70d3b1124..dd7f34321 100644 --- a/examples/anexia-machinedeployment.yaml +++ b/examples/anexia-machinedeployment.yaml @@ -1,6 +1,8 @@ -apiVersion: "cluster.k8s.io/v1alpha1" +apiVersion: cluster.k8s.io/v1alpha1 kind: MachineDeployment metadata: + annotations: + k8c.io/operating-system-profile: osp-flatcar-cloud-init name: anexia-machinedeployment namespace: kube-system spec: @@ -21,44 +23,37 @@ spec: providerSpec: value: cloudProvider: anexia - sshPublicKeys: - - "<< YOUR_PUBLIC_KEY >>" cloudProviderSpec: - # If empty, can be set via ANXCLOUD_TOKEN env var - token: - secretKeyRef: - namespace: kube-system - name: machine-controller-anexia - key: token + # from 1 to 16 cores + cpus: 4 - # Currently only the "Flatcar Linux Stable UEFI" template is supported. - # Use templateBuild to specify a build. If empty => latest - # Alternatively use templateID for a specific template. - template: "<< ANEXIA_TEMPLATE_NAME >>" - locationID: "<< ANEXIA_LOCATION_ID >>" + # anything supported by the Anexia Engine + cpuPerformanceType: performance + + # from 1024 to 65536 MB + memory: 4096 - # From 1 to 16 cores or the configured limit for your account. - cpus: 2 - # From 1024 to 65536 MB or the configured limit for your account. - memory: 2048 + # from 20 to 500 GB, this is for the main disk + diskSize: 20 - # this defaults to "performance", but you can set anything - # supported by the Anexia Engine here - or not set this attribute - # at all - cpuPerformanceType: standard + # anything supported by the Anexia Engine, this is for the main disk + diskPerformanceType: ENT6 + # specify additional disks here disks: - - size: 60 - # Enterprise ENT1-6 - # High Performance HPC1-5 - # Local LOC3 - # Standard STD1-6 + - size: 200 # from 20 to 500 GB + # anything supported by the Anexia Engine performanceType: ENT6 + # location ID from the Anexia Engine + locationID: "<< ANEXIA_LOCATION_ID >>" + # Each entry in this array will create a network interface in each # Machine, connected to the given VLAN. networks: - vlan: "<< ANEXIA_VLAN_ID >>" + # (optional) BandwidthLimit, can be 100, 1000 or 10000 MBit/s or empty. + bandwidthLimit: 1000 # If prefixes are given, we reserve an IP address for each of # them - if you give one IPv4 and one IPv6 prefix, your @@ -79,20 +74,18 @@ spec: prefixes: - "<< ANEXIA_PREFIX_ID >>" - # (optional) BandwidthLimit specifices the allowed bandwidth in MBit/s. - # It can be set to 0, 100, 1000 or 10000 for the respective values of 100MBit/s 1GBit/s or 10GBit/s. - # It defaults to 0 which will take the default value of the anexia engine. This is 1GB/s. - bandwidthLimit: 0 - - # You may have this old disk config attribute in your config - please migrate to the disks attribute. - # For now it is still recognized though. - #diskSize: 60 - # Flatcar is the only supported operating system - operatingSystem: "flatcar" + # Currently only the "Flatcar Linux Stable UEFI" template is supported. + template: Flatcar Linux Stable UEFI + # flatcar is the only supported operating system right now + operatingSystem: flatcar operatingSystemSpec: + disableAutoUpdate: false + disableLocksmithD: true + disableUpdateEngine: false # Force cloud-init instead of ignition. Anexia supports cloud-init only. - provisioningUtility: "cloud-init" - distUpgradeOnBoot: false - disableAutoUpdate: true + provisioningUtility: cloud-init + sshPublicKeys: + - "<< YOUR_PUBLIC_KEY >>" versions: - kubelet: 1.33.4 + kubelet: 1.35.0 + From dd4dfb572c9d355f04120799c39bf0568b6f85c5 Mon Sep 17 00:00:00 2001 From: Kim Date: Wed, 5 Aug 2026 15:54:52 +0200 Subject: [PATCH 14/19] add availabilityZone --- pkg/cloudprovider/provider/anexia/provider.go | 1 + sdk/cloudprovider/anexia/types.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/pkg/cloudprovider/provider/anexia/provider.go b/pkg/cloudprovider/provider/anexia/provider.go index efaf34514..378509ab9 100644 --- a/pkg/cloudprovider/provider/anexia/provider.go +++ b/pkg/cloudprovider/provider/anexia/provider.go @@ -127,6 +127,7 @@ func provisionVM(ctx context.Context, reconcileContext reconcileContext, log *za vm.DiskType = config.DiskPerformanceType + vm.AvailabilityZone = config.AvailabilityZone if config.CPUPerformanceType != "" { vm.CPUPerformanceType = config.CPUPerformanceType } diff --git a/sdk/cloudprovider/anexia/types.go b/sdk/cloudprovider/anexia/types.go index b343ce552..cb332e24a 100644 --- a/sdk/cloudprovider/anexia/types.go +++ b/sdk/cloudprovider/anexia/types.go @@ -112,6 +112,8 @@ type RawConfig struct { // Configuration of the network interfaces. At least one entry with at // least one Prefix is required. Networks []RawNetwork `json:"networks"` + + AvailabilityZone string `json:"availability_zone,omitempty"` } type NetworkAddressStatus struct { From 8e42c31f0e3e782257a3574a9c15fec38c6ffd2f Mon Sep 17 00:00:00 2001 From: Kim Date: Fri, 7 Aug 2026 08:50:28 +0200 Subject: [PATCH 15/19] fix missing AvailabilityZone field error --- go.mod | 33 ++++---- go.sum | 80 ++++++++++++------- pkg/cloudprovider/provider/anexia/provider.go | 1 + .../provider/anexia/resolve_config.go | 2 + 4 files changed, 71 insertions(+), 45 deletions(-) diff --git a/go.mod b/go.mod index 95aa48fb9..aa7715e02 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module k8c.io/machine-controller -go 1.24.0 - -toolchain go1.24.12 +go 1.25.1 replace k8c.io/machine-controller/sdk => ./sdk @@ -12,7 +10,7 @@ require ( github.com/Azure/azure-sdk-for-go v68.0.0+incompatible github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 github.com/Azure/go-autorest/autorest/to v0.4.0 - github.com/Masterminds/semver/v3 v3.3.0 + github.com/Masterminds/semver/v3 v3.4.0 github.com/OpenNebula/one/src/oca/go/src/goca v0.0.0-20240905143811-b2ab5b7c9c14 github.com/aliyun/alibaba-cloud-sdk-go v1.63.15 github.com/aws/aws-sdk-go-v2 v1.30.5 @@ -24,7 +22,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/digitalocean/godo v1.124.0 github.com/equinix/equinix-sdk-go v0.46.0 - github.com/go-logr/logr v1.4.2 + github.com/go-logr/logr v1.4.3 github.com/go-logr/zapr v1.3.0 github.com/go-test/deep v1.1.0 github.com/google/go-cmp v0.7.0 @@ -45,9 +43,9 @@ require ( github.com/vmware/go-vcloud-director/v2 v2.25.0 github.com/vmware/govmomi v0.43.0 github.com/vultr/govultr/v3 v3.9.1 - go.anx.io/go-anxcloud v0.7.8 + go.anx.io/go-anxcloud v0.14.5 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.36.0 + golang.org/x/crypto v0.47.0 golang.org/x/oauth2 v0.28.0 gomodules.xyz/jsonpatch/v2 v2.4.0 google.golang.org/api v0.197.0 @@ -119,7 +117,7 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect + github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // indirect @@ -141,8 +139,8 @@ require ( github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/ulid v1.3.1 // indirect - github.com/onsi/ginkgo/v2 v2.22.2 // indirect - github.com/onsi/gomega v1.36.2 // indirect + github.com/onsi/ginkgo/v2 v2.28.0 // indirect + github.com/onsi/gomega v1.39.1 // indirect github.com/openshift/custom-resource-status v1.1.2 // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect github.com/peterhellberg/link v1.2.0 // indirect @@ -165,18 +163,19 @@ require ( go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/mod v0.32.0 // indirect + golang.org/x/net v0.49.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/term v0.39.0 // indirect + golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.31.0 // indirect + golang.org/x/tools v0.41.0 // indirect google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/grpc v1.72.1 // indirect - google.golang.org/protobuf v1.36.5 // indirect + google.golang.org/protobuf v1.36.7 // indirect gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 8eb8b907a..8a595b8ca 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,8 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= -github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OpenNebula/one/src/oca/go/src/goca v0.0.0-20240905143811-b2ab5b7c9c14 h1:9uqKGeUuok/9Q5B5DzDM+bVgyEZVruzaflXw8WiaZ+Y= github.com/OpenNebula/one/src/oca/go/src/goca v0.0.0-20240905143811-b2ab5b7c9c14/go.mod h1:dvAwZi1Aol7eu6BENzHtl8ztGBkacB9t/fJj+fYk+Xg= @@ -152,13 +152,19 @@ github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sa github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= +github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= +github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= +github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk= +github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE= +github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= @@ -202,6 +208,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= @@ -253,8 +261,8 @@ github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc= +github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -296,6 +304,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= +github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -330,11 +340,15 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= +github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= +github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -369,15 +383,15 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= -github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/ginkgo/v2 v2.28.0 h1:Rrf+lVLmtlBIKv6KrIGJCjyY8N36vDVcutbGJkyqjJc= +github.com/onsi/ginkgo/v2 v2.28.0/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= +github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4= github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= @@ -435,6 +449,14 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/tinkerbell/tink v0.10.1 h1:mxdPQf7n4nB/AVdjbqCm5c98vsITU35g7Yw5cdOWmCw= github.com/tinkerbell/tink v0.10.1/go.mod h1:yULdVrzAfPnA8KdOkjvo8qDn6pw0JD6kBzF94gtXMjA= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= @@ -455,8 +477,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.anx.io/go-anxcloud v0.7.8 h1:FJk1CKBqFeBPLswSpfAGogPITkciXQ9N7Jd9adGNcH8= -go.anx.io/go-anxcloud v0.7.8/go.mod h1:OlwFe0Kf3BTp3GphivKalBiElZPgsNEEN/tMsLymbX0= +go.anx.io/go-anxcloud v0.14.5 h1:7oVdLWWe4hZtP4BJvcouzpKKNHqlaDGqnyggUC9Lom4= +go.anx.io/go-anxcloud v0.14.5/go.mod h1:nhwk53AePw9CH91dAGGGzrjlpovbR8dfixtFUkHD/PA= go.keploy.io/server v0.8.6 h1:czE9jaliyAkMMJcYnMPNuu6tun7UgwFbokxEG95vLN4= go.keploy.io/server v0.8.6/go.mod h1:t7BPuZQSiC3PNHZ9dbn3e3VB61HNWwiqVmaRujfDFUg= go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= @@ -505,8 +527,8 @@ golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -532,6 +554,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -560,8 +584,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= @@ -576,8 +600,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -611,8 +635,8 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -623,8 +647,8 @@ golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -637,8 +661,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= @@ -662,8 +686,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= -golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -708,8 +732,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 h1:FVCohIoYO7IJoDDVpV2pdq7SgrMH6wHnuTyrdrxJNoY= gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/cloudprovider/provider/anexia/provider.go b/pkg/cloudprovider/provider/anexia/provider.go index 378509ab9..4ce7472c2 100644 --- a/pkg/cloudprovider/provider/anexia/provider.go +++ b/pkg/cloudprovider/provider/anexia/provider.go @@ -123,6 +123,7 @@ func provisionVM(ctx context.Context, reconcileContext reconcileContext, log *za config.Memory, config.DiskSize, networkInterfaces, + ) vm.DiskType = config.DiskPerformanceType diff --git a/pkg/cloudprovider/provider/anexia/resolve_config.go b/pkg/cloudprovider/provider/anexia/resolve_config.go index ad4778482..7d2ab2ba8 100644 --- a/pkg/cloudprovider/provider/anexia/resolve_config.go +++ b/pkg/cloudprovider/provider/anexia/resolve_config.go @@ -61,6 +61,8 @@ type resolvedConfig struct { DiskSize int DiskPerformanceType string Memory int + + AvailabilityZone string } func (p *provider) resolveTemplateID(ctx context.Context, a api.API, config anxtypes.RawConfig, locationID string) (string, error) { From 5751c6e6ed6137d71371ce1e42f7b7aea6f5856e Mon Sep 17 00:00:00 2001 From: Kim Date: Fri, 7 Aug 2026 14:47:49 +0200 Subject: [PATCH 16/19] set availability zone --- pkg/cloudprovider/provider/anexia/provider_test.go | 11 +++++++++++ pkg/cloudprovider/provider/anexia/resolve_config.go | 1 + 2 files changed, 12 insertions(+) diff --git a/pkg/cloudprovider/provider/anexia/provider_test.go b/pkg/cloudprovider/provider/anexia/provider_test.go index cd79a3d9d..e3b7bf598 100644 --- a/pkg/cloudprovider/provider/anexia/provider_test.go +++ b/pkg/cloudprovider/provider/anexia/provider_test.go @@ -156,6 +156,17 @@ func TestAnexiaProvider(t *testing.T) { testhelper.AssertEquals(t, json.Number("10000"), networkObject["bandwidth_limit"]) }, }, + { + // Provision a generic VM with an availability zone + ReconcileContext: hookableReconcileContext("LOCATION-ID", "SET-AVAILABILITY-ZONE", func(rc *reconcileContext) { + rc.Config.AvailabilityZone = "zone" + }), + AssertJSONBody: func(jsonBody jsonObject) { + zone := jsonBody["availability_zone"].(string) + //networkObject := networkArray[0].(jsonObject) + testhelper.AssertEquals(t, "zone", zone) + }, + }, } testhelper.Mux.HandleFunc("/api/ipam/v1/address/reserve/ip/count.json", func(writer http.ResponseWriter, _ *http.Request) { diff --git a/pkg/cloudprovider/provider/anexia/resolve_config.go b/pkg/cloudprovider/provider/anexia/resolve_config.go index 7d2ab2ba8..00ecbe522 100644 --- a/pkg/cloudprovider/provider/anexia/resolve_config.go +++ b/pkg/cloudprovider/provider/anexia/resolve_config.go @@ -175,6 +175,7 @@ func (p *provider) resolveConfig(ctx context.Context, log *zap.SugaredLogger, co DiskSize: config.DiskSize, DiskPerformanceType: config.DiskPerformanceType, Memory: config.Memory, + AvailabilityZone: config.AvailabilityZone, } ret.Token, err = p.configVarResolver.GetStringValueOrEnv(config.Token, anxtypes.AnxTokenEnv) From ffefe5236e4c456ce7e2d12ea951395c4d9781df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kr=C3=B6ll?= Date: Tue, 25 Aug 2026 09:58:55 +0200 Subject: [PATCH 17/19] remove anexia API token field from spec This is a cleanup, token has been moved to environment variable long ago --- .../provider/anexia/helper_test.go | 1 - pkg/cloudprovider/provider/anexia/provider.go | 51 ++----------------- .../provider/anexia/provider_test.go | 9 +--- .../provider/anexia/resolve_config.go | 8 +-- sdk/cloudprovider/anexia/types.go | 2 - 5 files changed, 8 insertions(+), 63 deletions(-) diff --git a/pkg/cloudprovider/provider/anexia/helper_test.go b/pkg/cloudprovider/provider/anexia/helper_test.go index 7ffec5745..9b3cbcc6c 100644 --- a/pkg/cloudprovider/provider/anexia/helper_test.go +++ b/pkg/cloudprovider/provider/anexia/helper_test.go @@ -100,7 +100,6 @@ func hookableConfig(hook func(*anxtypes.RawConfig)) anxtypes.RawConfig { {VlanID: newConfigVarString("test-vlan"), PrefixIDs: []providerconfigtypes.ConfigVarString{newConfigVarString("test-prefix")}}, }, - Token: newConfigVarString("test-token"), LocationID: newConfigVarString("test-location"), TemplateID: newConfigVarString("test-template-id"), } diff --git a/pkg/cloudprovider/provider/anexia/provider.go b/pkg/cloudprovider/provider/anexia/provider.go index 4ce7472c2..3ef14b3a7 100644 --- a/pkg/cloudprovider/provider/anexia/provider.go +++ b/pkg/cloudprovider/provider/anexia/provider.go @@ -79,7 +79,7 @@ func (p *provider) Create(ctx context.Context, log *zap.SugaredLogger, machine * Machine: machine, } - _, client, err := getClient(config.Token, &machine.Name) + _, client, err := getClient(&machine.Name) if err != nil { return nil, err } @@ -123,7 +123,6 @@ func provisionVM(ctx context.Context, reconcileContext reconcileContext, log *za config.Memory, config.DiskSize, networkInterfaces, - ) vm.DiskType = config.DiskPerformanceType @@ -221,33 +220,6 @@ func ensureConditions(status *anxtypes.ProviderStatus) { } } -// getTokenFromSpec got extracted from getConfig in order to circumvent it. -// -// That allowed us to reduce [Cleanup] to the bare minimum and allowing tear -// downs if the template no longer exists (ANXKUBE-1361). -func (p *provider) getTokenFromSpec(spec clusterv1alpha1.ProviderSpec) (string, error) { - if spec.Value == nil { - return "", fmt.Errorf("machine.spec.providerSpec.value is nil") - } - - pconfig, err := providerconfig.GetConfig(spec) - if err != nil { - return "", err - } - - rawConfig, err := anxtypes.GetConfig(*pconfig) - if err != nil { - return "", fmt.Errorf("error parsing provider config: %w", err) - } - - token, err := p.configVarResolver.GetStringValueOrEnv(rawConfig.Token, anxtypes.AnxTokenEnv) - if err != nil { - return "", fmt.Errorf("failed to get 'token': %w", err) - } - - return token, nil -} - func (p *provider) getConfig(ctx context.Context, log *zap.SugaredLogger, provSpec clusterv1alpha1.ProviderSpec) (*resolvedConfig, *providerconfig.Config, error) { pconfig, err := providerconfig.GetConfig(provSpec) if err != nil { @@ -291,10 +263,6 @@ func (p *provider) Validate(ctx context.Context, log *zap.SugaredLogger, machine } errs := make([]error, 0) - if config.Token == "" { - errs = append(errs, errors.New("token not set")) - } - if config.CPUs == 0 { errs = append(errs, errors.New("cpu count is missing")) } @@ -355,12 +323,7 @@ func (p *provider) Validate(ctx context.Context, log *zap.SugaredLogger, machine } func (p *provider) Get(ctx context.Context, log *zap.SugaredLogger, machine *clusterv1alpha1.Machine, pd *cloudprovidertypes.ProviderData) (instance.Instance, error) { - token, err := p.getTokenFromSpec(machine.Spec.ProviderSpec) - if err != nil { - return nil, newError(common.InvalidConfigurationMachineError, "querying token: %v", err) - } - - _, cli, err := getClient(token, &machine.Name) + _, cli, err := getClient(&machine.Name) if err != nil { return nil, newError(common.InvalidConfigurationMachineError, "failed to create Anexia client: %v", err) } @@ -436,12 +399,8 @@ func (p *provider) Cleanup(ctx context.Context, log *zap.SugaredLogger, machine }() ensureConditions(&status) - token, err := p.getTokenFromSpec(machine.Spec.ProviderSpec) - if err != nil { - return false, fmt.Errorf("querying token from MachineSpec failed: %w", err) - } - _, cli, err := getClient(token, &machine.Name) + _, cli, err := getClient(&machine.Name) if err != nil { return false, newError(common.InvalidConfigurationMachineError, "failed to create Anexia client: %v", err) } @@ -500,7 +459,7 @@ func (p *provider) SetMetricsForMachines(_ clusterv1alpha1.MachineList) error { return nil } -func getClient(token string, machineName *string) (api.API, anxclient.Client, error) { +func getClient(machineName *string) (api.API, anxclient.Client, error) { logPrefix := "[Anexia API]" if machineName != nil { @@ -513,7 +472,7 @@ func getClient(token string, machineName *string) (api.API, anxclient.Client, er }.New() legacyClientOptions := []anxclient.Option{ - anxclient.TokenFromString(token), + anxclient.TokenFromEnv(false), anxclient.HTTPClient(&httpClient), } diff --git a/pkg/cloudprovider/provider/anexia/provider_test.go b/pkg/cloudprovider/provider/anexia/provider_test.go index e3b7bf598..20be4c347 100644 --- a/pkg/cloudprovider/provider/anexia/provider_test.go +++ b/pkg/cloudprovider/provider/anexia/provider_test.go @@ -444,11 +444,6 @@ func TestValidate(t *testing.T) { t.Parallel() configCases := []ConfigTestCase{ - { - Name: "no token", - Config: hookableConfig(func(c *anxtypes.RawConfig) { c.Token.Value = "" }), - Error: errors.New("token not set"), - }, { Name: "no cpu count", Config: hookableConfig(func(c *anxtypes.RawConfig) { c.CPUs = 0 }), @@ -502,10 +497,10 @@ func TestValidate(t *testing.T) { { Name: "combined", Config: hookableConfig(func(c *anxtypes.RawConfig) { - c.Token.Value = "" c.CPUs = 0 + c.CPUPerformanceType = "" }), - Error: errors.Join(errors.New("token not set"), errors.New("cpu count is missing")), + Error: errors.Join(errors.New("cpu count is missing"), errors.New("cpu performance type is missing")), }, { Name: "default is valid", diff --git a/pkg/cloudprovider/provider/anexia/resolve_config.go b/pkg/cloudprovider/provider/anexia/resolve_config.go index 00ecbe522..c57794d09 100644 --- a/pkg/cloudprovider/provider/anexia/resolve_config.go +++ b/pkg/cloudprovider/provider/anexia/resolve_config.go @@ -49,7 +49,6 @@ type resolvedNetwork struct { // resolvedConfig contains the resolved values from types.RawConfig. type resolvedConfig struct { - Token string LocationID string TemplateID string @@ -178,11 +177,6 @@ func (p *provider) resolveConfig(ctx context.Context, log *zap.SugaredLogger, co AvailabilityZone: config.AvailabilityZone, } - ret.Token, err = p.configVarResolver.GetStringValueOrEnv(config.Token, anxtypes.AnxTokenEnv) - if err != nil { - return nil, fmt.Errorf("failed to get 'token': %w", err) - } - ret.LocationID, err = p.configVarResolver.GetStringValue(config.LocationID) if err != nil { return nil, fmt.Errorf("failed to get 'locationID': %w", err) @@ -207,7 +201,7 @@ func (p *provider) resolveConfig(ctx context.Context, log *zap.SugaredLogger, co // when "templateID" is not set, we expect "template" to be if ret.TemplateID == "" { - a, _, err := getClient(ret.Token, nil) + a, _, err := getClient(nil) if err != nil { return nil, fmt.Errorf("failed initializing API clients: %w", err) } diff --git a/sdk/cloudprovider/anexia/types.go b/sdk/cloudprovider/anexia/types.go index cb332e24a..168b93dce 100644 --- a/sdk/cloudprovider/anexia/types.go +++ b/sdk/cloudprovider/anexia/types.go @@ -79,8 +79,6 @@ type RawNetwork struct { // RawConfig contains all the configuration values for VMs to create, with some values maybe being fetched from secrets. type RawConfig struct { - // Token specifies the Anexia Engine API token. - Token providerconfig.ConfigVarString `json:"token,omitempty"` // LocationID specifies the datacenter location. LocationID providerconfig.ConfigVarString `json:"locationID"` From 2ea34c77e6ab7f392541fcf641c75bd9421b4091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kr=C3=B6ll?= Date: Tue, 25 Aug 2026 12:15:50 +0200 Subject: [PATCH 18/19] do not use strict json unmarshalling (allow unknown fields) --- sdk/cloudprovider/anexia/types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/cloudprovider/anexia/types.go b/sdk/cloudprovider/anexia/types.go index 168b93dce..186366ea3 100644 --- a/sdk/cloudprovider/anexia/types.go +++ b/sdk/cloudprovider/anexia/types.go @@ -17,10 +17,10 @@ limitations under the License. package anexia import ( + "encoding/json" "errors" "time" - "k8c.io/machine-controller/sdk/jsonutil" "k8c.io/machine-controller/sdk/providerconfig" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -138,5 +138,5 @@ type ProviderStatus struct { func GetConfig(pconfig providerconfig.Config) (*RawConfig, error) { rawConfig := &RawConfig{} - return rawConfig, jsonutil.StrictUnmarshal(pconfig.CloudProviderSpec.Raw, rawConfig) + return rawConfig, json.Unmarshal(pconfig.CloudProviderSpec.Raw, rawConfig) } From 9160e023d882db15a772574e6eaf40245eb4d3df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kr=C3=B6ll?= Date: Tue, 25 Aug 2026 12:26:16 +0200 Subject: [PATCH 19/19] fix lint --- pkg/cloudprovider/provider/anexia/network_provisioning.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/cloudprovider/provider/anexia/network_provisioning.go b/pkg/cloudprovider/provider/anexia/network_provisioning.go index d2458cefb..3e3f21a37 100644 --- a/pkg/cloudprovider/provider/anexia/network_provisioning.go +++ b/pkg/cloudprovider/provider/anexia/network_provisioning.go @@ -96,7 +96,6 @@ func networkInterfacesForProvisioning(ctx context.Context, reconcileContext reco var _engsup3404mutex sync.Mutex func getIPAddress(ctx context.Context, reconcileContext reconcileContext, log *zap.SugaredLogger, network *resolvedNetwork, prefix string, status *anxtypes.NetworkAddressStatus, client anxclient.Client) (string, error) { - // only use IP if it is still unbound if status.ReservedIP != "" && status.IPState == anxtypes.IPStateUnbound && (!status.IPProvisioningExpires.IsZero() && status.IPProvisioningExpires.After(time.Now())) { log.Infow("Re-using already provisioned IP", "ip", status.ReservedIP)