Skip to content

Commit 6c14178

Browse files
authored
Add openstack managed control-plane (#4098)
* Add openstack control-plane types and provider Signed-off-by: Artiom Diomin <artiom@kubermatic.com> * Upgrade terraform-provider-openstack provider Signed-off-by: Artiom Diomin <artiom@kubermatic.com> * Use OS_USERNAME Signed-off-by: Artiom Diomin <artiom@kubermatic.com> * log INFO task description, log debug task operation Signed-off-by: Artiom Diomin <artiom@kubermatic.com> * Dynamically lookup for load balancer in OpenStack Signed-off-by: Artiom Diomin <artiom@kubermatic.com> * Avoid uploading /etc/kubernetes/cloud-config Signed-off-by: Artiom Diomin <artiom@kubermatic.com> * Update MachineController image to the latest main Signed-off-by: Artiom Diomin <artiom@kubermatic.com> * Update openstack terraform README Signed-off-by: Artiom Diomin <artiom@kubermatic.com> * Add ordered map utilities and improve machine address handling - Improve handling of addresses with empty type by attempting to classify them - Update GetMachineInfo to use ordered iteration for consistent address processing - Add IterateInOrder and FromMap functions to maputils for preserving insertion order Signed-off-by: Artiom Diomin <artiom@kubermatic.com> * Handle empty address type when inspecting instances Signed-off-by: Artiom Diomin <artiom@kubermatic.com> * Use IsPrivate method for IP address checks Signed-off-by: Artiom Diomin <artiom@kubermatic.com> --------- Signed-off-by: Artiom Diomin <artiom@kubermatic.com>
1 parent a6b6730 commit 6c14178

34 files changed

Lines changed: 1248 additions & 444 deletions

docs/api_reference/v1beta2.en.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
+++
22
title = "v1beta2 API Reference"
3-
date = 2026-05-08T17:16:28+03:00
3+
date = 2026-05-29T13:59:16+03:00
44
weight = 11
55
+++
66
## v1beta2
@@ -62,6 +62,8 @@ weight = 11
6262
* [NutanixSpec](#nutanixspec)
6363
* [OpenIDConnect](#openidconnect)
6464
* [OpenIDConnectConfig](#openidconnectconfig)
65+
* [OpenstackControlPlane](#openstackcontrolplane)
66+
* [OpenstackLoadBalancer](#openstackloadbalancer)
6567
* [OpenstackSpec](#openstackspec)
6668
* [OperatingSystemManagerConfig](#operatingsystemmanagerconfig)
6769
* [OperatingSystemSpec](#operatingsystemspec)
@@ -817,12 +819,34 @@ OpenIDConnectConfig config
817819

818820
[Back to Group](#v1beta2)
819821

822+
### OpenstackControlPlane
823+
824+
OpenstackControlPlane defines control plane config on OpenStack
825+
826+
| Field | Description | Scheme | Required |
827+
| ----- | ----------- | ------ | -------- |
828+
| loadBalancer | LoadBalancer config of a pre-existing loadbalancer to register control plane members | [OpenstackLoadBalancer](#openstackloadbalancer) | true |
829+
830+
[Back to Group](#v1beta2)
831+
832+
### OpenstackLoadBalancer
833+
834+
OpenstackLoadBalancer references a pre-existing Octavia loadbalancer for the kubeapi-server endpoint
835+
836+
| Field | Description | Scheme | Required |
837+
| ----- | ----------- | ------ | -------- |
838+
| name | Name of the pre-existing loadbalancer. Default: \"<CLUSTER_NAME>-kube-apiserver\" | string | false |
839+
| poolID | PoolID is the optional Octavia pool ID. If empty, KubeOne discovers the pool from the loadbalancer. | string | false |
840+
841+
[Back to Group](#v1beta2)
842+
820843
### OpenstackSpec
821844

822845
OpenstackSpec defines the Openstack provider
823846

824847
| Field | Description | Scheme | Required |
825848
| ----- | ----------- | ------ | -------- |
849+
| controlPlane | ControlPlane configures control plane provisioning on OpenStack | *[OpenstackControlPlane](#openstackcontrolplane) | false |
826850

827851
[Back to Group](#v1beta2)
828852

docs/api_reference/v1beta3.en.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
+++
22
title = "v1beta3 API Reference"
3-
date = 2026-05-08T17:16:28+03:00
3+
date = 2026-05-29T13:59:16+03:00
44
weight = 11
55
+++
66
## v1beta3
@@ -62,6 +62,8 @@ weight = 11
6262
* [NutanixSpec](#nutanixspec)
6363
* [OpenIDConnect](#openidconnect)
6464
* [OpenIDConnectConfig](#openidconnectconfig)
65+
* [OpenstackControlPlane](#openstackcontrolplane)
66+
* [OpenstackLoadBalancer](#openstackloadbalancer)
6567
* [OpenstackSpec](#openstackspec)
6668
* [OperatingSystemManagerConfig](#operatingsystemmanagerconfig)
6769
* [OperatingSystemSpec](#operatingsystemspec)
@@ -819,12 +821,34 @@ OpenIDConnectConfig config
819821

820822
[Back to Group](#v1beta3)
821823

824+
### OpenstackControlPlane
825+
826+
OpenstackControlPlane defines control plane config on OpenStack
827+
828+
| Field | Description | Scheme | Required |
829+
| ----- | ----------- | ------ | -------- |
830+
| loadBalancer | LoadBalancer config of a pre-existing loadbalancer to register control plane members | [OpenstackLoadBalancer](#openstackloadbalancer) | true |
831+
832+
[Back to Group](#v1beta3)
833+
834+
### OpenstackLoadBalancer
835+
836+
OpenstackLoadBalancer references a pre-existing Octavia loadbalancer for the kubeapi-server endpoint
837+
838+
| Field | Description | Scheme | Required |
839+
| ----- | ----------- | ------ | -------- |
840+
| name | Name of the pre-existing loadbalancer. Default: \"<CLUSTER_NAME>-kube-apiserver\" | string | false |
841+
| poolID | PoolID is the optional Octavia pool ID. If empty, KubeOne discovers the pool from the loadbalancer. | string | false |
842+
843+
[Back to Group](#v1beta3)
844+
822845
### OpenstackSpec
823846

824847
OpenstackSpec defines the Openstack provider
825848

826849
| Field | Description | Scheme | Required |
827850
| ----- | ----------- | ------ | -------- |
851+
| controlPlane | ControlPlane configures control plane provisioning on OpenStack | *[OpenstackControlPlane](#openstackcontrolplane) | false |
828852

829853
[Back to Group](#v1beta3)
830854

examples/terraform/openstack/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ See the [Terraform loadbalancers in examples document][docs-tf-loadbalancer].
1717
| Name | Version |
1818
|------|---------|
1919
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0.0 |
20-
| <a name="requirement_openstack"></a> [openstack](#requirement\_openstack) | ~> 1.52.0 |
20+
| <a name="requirement_openstack"></a> [openstack](#requirement\_openstack) | ~> 3.4.0 |
2121

2222
## Providers
2323

2424
| Name | Version |
2525
|------|---------|
26-
| <a name="provider_openstack"></a> [openstack](#provider\_openstack) | ~> 1.52.0 |
26+
| <a name="provider_openstack"></a> [openstack](#provider\_openstack) | ~> 3.4.0 |
2727

2828
## Modules
2929

examples/terraform/openstack/versions.tf

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ terraform {
44
required_providers {
55
openstack = {
66
source = "terraform-provider-openstack/openstack"
7-
version = "~> 1.52.0"
7+
version = "~> 3.4.0"
88
}
99
}
1010
}
1111

1212
provider "openstack" {
13-
use_octavia = true
1413
}

go.mod

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ require (
1818
github.com/google/go-cmp v0.7.0
1919
github.com/google/go-containerregistry v0.20.3
2020
github.com/google/go-github/v65 v65.0.0
21+
github.com/gophercloud/gophercloud v1.14.1
2122
github.com/hetznercloud/hcloud-go/v2 v2.36.0
2223
github.com/iancoleman/orderedmap v0.3.0
2324
github.com/koron-go/prefixw v1.0.0
@@ -36,8 +37,8 @@ require (
3637
google.golang.org/grpc v1.79.3
3738
gopkg.in/yaml.v2 v2.4.0
3839
helm.sh/helm/v3 v3.20.2
39-
k8c.io/machine-controller v1.65.0
40-
k8c.io/machine-controller/sdk v1.65.0
40+
k8c.io/machine-controller v1.65.1-0.20260609121331-090279e10f65
41+
k8c.io/machine-controller/sdk v1.65.1-0.20260609121331-090279e10f65
4142
k8s.io/api v0.35.1
4243
k8s.io/apiextensions-apiserver v0.35.1
4344
k8s.io/apimachinery v0.35.1
@@ -152,7 +153,6 @@ require (
152153
github.com/google/uuid v1.6.0 // indirect
153154
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
154155
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
155-
github.com/gophercloud/gophercloud v1.14.0 // indirect
156156
github.com/gosuri/uitable v0.0.4 // indirect
157157
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
158158
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
@@ -228,9 +228,9 @@ require (
228228
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
229229
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
230230
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
231-
go.opentelemetry.io/otel v1.39.0 // indirect
232-
go.opentelemetry.io/otel/metric v1.39.0 // indirect
233-
go.opentelemetry.io/otel/trace v1.39.0 // indirect
231+
go.opentelemetry.io/otel v1.41.0 // indirect
232+
go.opentelemetry.io/otel/metric v1.41.0 // indirect
233+
go.opentelemetry.io/otel/trace v1.41.0 // indirect
234234
go.uber.org/zap v1.27.0 // indirect
235235
go.yaml.in/yaml/v2 v2.4.3 // indirect
236236
go.yaml.in/yaml/v3 v3.0.4 // indirect
@@ -255,7 +255,7 @@ require (
255255
k8s.io/klog v1.0.0 // indirect
256256
k8s.io/klog/v2 v2.130.1 // indirect
257257
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
258-
kubevirt.io/api v1.3.1 // indirect
258+
kubevirt.io/api v1.4.0 // indirect
259259
kubevirt.io/containerized-data-importer-api v1.60.3 // indirect
260260
kubevirt.io/controller-lifecycle-operator-sdk/api v0.2.4 // indirect
261261
oras.land/oras-go/v2 v2.6.0 // indirect

go.sum

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,8 @@ github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDP
371371
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
372372
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
373373
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
374-
github.com/gophercloud/gophercloud v1.14.0 h1:Bt9zQDhPrbd4qX7EILGmy+i7GP35cc+AAL2+wIJpUE8=
375-
github.com/gophercloud/gophercloud v1.14.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
374+
github.com/gophercloud/gophercloud v1.14.1 h1:DTCNaTVGl8/cFu58O1JwWgis9gtISAFONqpMKNg/Vpw=
375+
github.com/gophercloud/gophercloud v1.14.1/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
376376
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
377377
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
378378
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
@@ -676,8 +676,8 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6
676676
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
677677
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
678678
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
679-
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
680-
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
679+
go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
680+
go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
681681
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 h1:WzNab7hOOLzdDF/EoWCt4glhrbMPVMOO5JYTmpz36Ls=
682682
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0/go.mod h1:hKvJwTzJdp90Vh7p6q/9PAOd55dI6WA6sWj62a/JvSs=
683683
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 h1:S+LdBGiQXtJdowoJoQPEtI52syEP/JYBUpjO49EQhV8=
@@ -702,16 +702,16 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0 h1:cC2yDI3IQd0Udsu
702702
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0/go.mod h1:2PD5Ex6z8CFzDbTdOlwyNIUywRr1DN0ospafJM1wJ+s=
703703
go.opentelemetry.io/otel/log v0.8.0 h1:egZ8vV5atrUWUbnSsHn6vB8R21G2wrKqNiDt3iWertk=
704704
go.opentelemetry.io/otel/log v0.8.0/go.mod h1:M9qvDdUTRCopJcGRKg57+JSQ9LgLBrwwfC32epk5NX8=
705-
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
706-
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
705+
go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
706+
go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
707707
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
708708
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
709709
go.opentelemetry.io/otel/sdk/log v0.8.0 h1:zg7GUYXqxk1jnGF/dTdLPrK06xJdrXgqgFLnI4Crxvs=
710710
go.opentelemetry.io/otel/sdk/log v0.8.0/go.mod h1:50iXr0UVwQrYS45KbruFrEt4LvAdCaWWgIrsN3ZQggo=
711711
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
712712
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
713-
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
714-
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
713+
go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
714+
go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
715715
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
716716
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
717717
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -992,10 +992,10 @@ helm.sh/helm/v3 v3.20.2 h1:binM4rvPx5DcNsa1sIt7UZi55lRbu3pZUFmQkSoRh48=
992992
helm.sh/helm/v3 v3.20.2/go.mod h1:Fl1kBaWCpkUrM6IYXPjQ3bdZQfFrogKArqptvueZ6Ww=
993993
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
994994
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
995-
k8c.io/machine-controller v1.65.0 h1:oq8qE5/atZNSDS8nw2qlVoebN98L5p6MGxJw1NhRn2Q=
996-
k8c.io/machine-controller v1.65.0/go.mod h1:KlH8yWFZsbF5bMnt/KBXSb0QC2UG6UXvwXponapGreU=
997-
k8c.io/machine-controller/sdk v1.65.0 h1:FTTVPWinEARnbyNiZkETfMWl1H2uTVlX1YXSguMPSGk=
998-
k8c.io/machine-controller/sdk v1.65.0/go.mod h1:/5eWTMcfa7mTQUQoqziaalViiHSVzqzy3fXjejT1qLg=
995+
k8c.io/machine-controller v1.65.1-0.20260609121331-090279e10f65 h1:3QMhlGFnqhsrz9SoeYuIUOnIstgbp3aI3stqA+HLg6o=
996+
k8c.io/machine-controller v1.65.1-0.20260609121331-090279e10f65/go.mod h1:zZ4PiOlziPA44EbiTkJJQHLS8GJxxOCmeoo5n09qIso=
997+
k8c.io/machine-controller/sdk v1.65.1-0.20260609121331-090279e10f65 h1:wv1ve211b759MOCV0WuKePYcctvD8o4GjyIdblnjiS8=
998+
k8c.io/machine-controller/sdk v1.65.1-0.20260609121331-090279e10f65/go.mod h1:/5eWTMcfa7mTQUQoqziaalViiHSVzqzy3fXjejT1qLg=
999999
k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ=
10001000
k8s.io/api v0.35.1 h1:0PO/1FhlK/EQNVK5+txc4FuhQibV25VLSdLMmGpDE/Q=
10011001
k8s.io/api v0.35.1/go.mod h1:28uR9xlXWml9eT0uaGo6y71xK86JBELShLy4wR1XtxM=
@@ -1045,8 +1045,8 @@ k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
10451045
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
10461046
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
10471047
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
1048-
kubevirt.io/api v1.3.1 h1:MoTNo/zvDlZ44c2ocXLPln8XTaQOeUodiYbEKrTCqv4=
1049-
kubevirt.io/api v1.3.1/go.mod h1:tCn7VAZktEvymk490iPSMPCmKM9UjbbfH2OsFR/IOLU=
1048+
kubevirt.io/api v1.4.0 h1:dDLyQLSp9obzsDrv3cyL1olIc/66IWVaGiR3gfPfgT0=
1049+
kubevirt.io/api v1.4.0/go.mod h1:qcnumjJeOCo+qdYXf0OjpHGMhad0SAn4i0h6IAP+6Eg=
10501050
kubevirt.io/containerized-data-importer-api v1.60.3 h1:kQEXi7scpzUa0RPf3/3MKk1Kmem0ZlqqiuK3kDF5L2I=
10511051
kubevirt.io/containerized-data-importer-api v1.60.3/go.mod h1:8mwrkZIdy8j/LmCyKt2wFXbiMavLUIqDaegaIF67CZs=
10521052
kubevirt.io/controller-lifecycle-operator-sdk/api v0.2.4 h1:fZYvD3/Vnitfkx6IJxjLAk8ugnZQ7CXVYcRfkSKmuZY=

pkg/apis/kubeone/config/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,8 @@ func SetKubeOneClusterDynamicDefaults(cluster *kubeoneapi.KubeOneCluster, creden
319319
switch {
320320
case cluster.CloudProvider.Hetzner != nil:
321321
setDefaultHetznerControlPlane(cluster.Name, cluster.CloudProvider.Hetzner.ControlPlane)
322+
case cluster.CloudProvider.Openstack != nil:
323+
setDefaultOpenstackControlPlane(cluster.Name, cluster.CloudProvider.Openstack.ControlPlane)
322324
default:
323325
return fail.ConfigError{
324326
Op: "cloud provider checking",
@@ -359,6 +361,13 @@ func setDefaultHetznerControlPlane(clusterName string, hzCP *kubeoneapi.HetznerC
359361
)
360362
}
361363

364+
func setDefaultOpenstackControlPlane(clusterName string, osCP *kubeoneapi.OpenstackControlPlane) {
365+
osCP.LoadBalancer.Name = defaults(
366+
osCP.LoadBalancer.Name,
367+
clusterName+"-kube-apiserver",
368+
)
369+
}
370+
362371
// SetDefaultsCloudConfig sets default values for the CloudConfig field in the KubeOneCluster object.
363372
// this function assigns a default cloud configuration.
364373
func SetDefaultsCloudConfig(obj *kubeoneapi.KubeOneCluster) {

pkg/apis/kubeone/config/migrate.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,7 @@ func MigrateV1beta2V1beta3(clusterFilePath string, tfOutput []byte) ([]byte, err
102102
originalManifest.Walk(p, func(key yamled.Path, value any) {
103103
refval := reflect.ValueOf(value)
104104

105-
//nolint:exhaustive
106-
switch refval.Kind() {
105+
switch refval.Kind() { //nolint:exhaustive
107106
case reflect.Pointer, reflect.Map, reflect.Slice:
108107
if refval.IsNil() {
109108
originalManifest.Remove(key)

pkg/apis/kubeone/types.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,25 @@ type KubevirtSpec struct {
608608
type NutanixSpec struct{}
609609

610610
// OpenstackSpec defines the Openstack provider
611-
type OpenstackSpec struct{}
611+
type OpenstackSpec struct {
612+
// ControlPlane configures control plane provisioning on OpenStack
613+
ControlPlane *OpenstackControlPlane `json:"controlPlane,omitempty"`
614+
}
615+
616+
// OpenstackControlPlane defines control plane config on OpenStack
617+
type OpenstackControlPlane struct {
618+
// LoadBalancer config of a pre-existing loadbalancer to register control plane members
619+
LoadBalancer OpenstackLoadBalancer `json:"loadBalancer"`
620+
}
621+
622+
// OpenstackLoadBalancer references a pre-existing Octavia loadbalancer for the kubeapi-server endpoint
623+
type OpenstackLoadBalancer struct {
624+
// Name of the pre-existing loadbalancer. Default: "<CLUSTER_NAME>-kube-apiserver"
625+
Name string `json:"name,omitempty"`
626+
627+
// PoolID is the optional Octavia pool ID. If empty, KubeOne discovers the pool from the loadbalancer.
628+
PoolID string `json:"poolID,omitempty"`
629+
}
612630

613631
// EquinixMetalSpec defines the Equinix Metal cloud provider
614632
type EquinixMetalSpec struct{}

pkg/apis/kubeone/v1beta2/defaults.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ func SetDefaults_ClusterNetwork(obj *KubeOneCluster) {
226226
}
227227
case obj.CloudProvider.Openstack != nil:
228228
defaultCanal.MTU = defaults(defaultCanal.MTU, 1400) // Openstack specific 1450 bytes - 50 VXLAN bytes
229+
if obj.ControlPlane.NodeSets != nil {
230+
if obj.CloudProvider.Openstack.ControlPlane == nil {
231+
obj.CloudProvider.Openstack.ControlPlane = &OpenstackControlPlane{}
232+
}
233+
}
229234
}
230235

231236
if obj.ClusterNetwork.CNI == nil {

0 commit comments

Comments
 (0)