diff --git a/providers/openstack/scs2/README.md b/providers/openstack/scs2/README.md new file mode 100644 index 00000000..1eae3231 --- /dev/null +++ b/providers/openstack/scs2/README.md @@ -0,0 +1,124 @@ +# Cluster Stacks + +## Getting started + +```sh +# Create bootstrap cluster +kind create cluster + +# Init Cluster API +export CLUSTER_TOPOLOGY=true +export EXP_CLUSTER_RESOURCE_SET=true +export EXP_RUNTIME_SDK=true +kubectl apply -f https://github.com/k-orc/openstack-resource-controller/releases/latest/download/install.yaml +clusterctl init --infrastructure openstack + +kubectl -n capi-system rollout status deployment +kubectl -n capo-system rollout status deployment +``` + +``` +# Install CSO and CSPO +helm upgrade -i cso \ +-n cso-system \ +--create-namespace \ +oci://registry.scs.community/cluster-stacks/cso +``` + +```sh +export CLUSTER_NAMESPACE=cluster +export CLUSTER_NAME=my-cluster +export CLUSTERSTACK_NAMESPACE=cluster +export CLUSTERSTACK_VERSION=v1 +export OS_CLIENT_CONFIG_FILE=${PWD}/clouds.yaml +kubectl create namespace $CLUSTER_NAMESPACE --dry-run=client -o yaml | kubectl apply -f - +``` + +```sh +# Create secret for CAPO +kubectl create secret -n $CLUSTER_NAMESPACE generic openstack --from-file=clouds.yaml=$OS_CLIENT_CONFIG_FILE --dry-run=client -oyaml | kubectl apply -f - + +# Prepare the Secret as it will be deployed in the Workload Cluster +kubectl create secret -n kube-system generic clouds-yaml --from-file=clouds.yaml=$OS_CLIENT_CONFIG_FILE --dry-run=client -oyaml > clouds-yaml-secret + +# Add the Secret to the ClusterResourceSet Secret in the Management Cluster +kubectl create -n $CLUSTER_NAMESPACE secret generic clouds-yaml --from-file=clouds-yaml-secret --type=addons.cluster.x-k8s.io/resource-set --dry-run=client -oyaml | kubectl apply -f - +``` + +```yaml +cat < /tmp/kubeconfig +kubectl get nodes --kubeconfig /tmp/kubeconfig +``` diff --git a/providers/openstack/scs2/cluster-addon/ccm/Chart.yaml b/providers/openstack/scs2/cluster-addon/ccm/Chart.yaml new file mode 100644 index 00000000..541cecd0 --- /dev/null +++ b/providers/openstack/scs2/cluster-addon/ccm/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +type: application +description: CCM +name: CCM +version: v1 +dependencies: + - alias: openstack-cloud-controller-manager + name: openstack-cloud-controller-manager + repository: https://kubernetes.github.io/cloud-provider-openstack + version: 2.33.1 diff --git a/providers/openstack/scs2/cluster-addon/ccm/overwrite.yaml b/providers/openstack/scs2/cluster-addon/ccm/overwrite.yaml new file mode 100644 index 00000000..39076ecd --- /dev/null +++ b/providers/openstack/scs2/cluster-addon/ccm/overwrite.yaml @@ -0,0 +1,4 @@ +values: | + openstack-cloud-controller-manager: + cluster: + name: {{ .Cluster.metadata.name }} diff --git a/providers/openstack/scs2/cluster-addon/ccm/values.yaml b/providers/openstack/scs2/cluster-addon/ccm/values.yaml new file mode 100644 index 00000000..3f290366 --- /dev/null +++ b/providers/openstack/scs2/cluster-addon/ccm/values.yaml @@ -0,0 +1,21 @@ +openstack-cloud-controller-manager: + secret: + enabled: true + name: ccm-cloud-config + create: true + nodeSelector: + tolerations: + - key: node.cloudprovider.kubernetes.io/uninitialized + value: "true" + effect: NoSchedule + extraVolumes: + - name: clouds-yaml + secret: + secretName: clouds-yaml + extraVolumeMounts: + - name: clouds-yaml + readOnly: true + mountPath: /etc/openstack + cloudConfig: + global: + use-clouds: true diff --git a/providers/openstack/scs2/cluster-addon/cni/Chart.yaml b/providers/openstack/scs2/cluster-addon/cni/Chart.yaml new file mode 100644 index 00000000..c8a962f4 --- /dev/null +++ b/providers/openstack/scs2/cluster-addon/cni/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +type: application +description: CNI +name: CNI +version: v1 +dependencies: + - alias: cilium + name: cilium + repository: https://helm.cilium.io/ + version: 1.18.1 diff --git a/providers/openstack/scs2/cluster-addon/cni/values.yaml b/providers/openstack/scs2/cluster-addon/cni/values.yaml new file mode 100644 index 00000000..8a312f0c --- /dev/null +++ b/providers/openstack/scs2/cluster-addon/cni/values.yaml @@ -0,0 +1,14 @@ +cilium: + namespaceOverride: kube-system + tls: + secretsNamespace: + name: "kube-system" + sessionAffinity: true + sctp: + enabled: true + ipam: + mode: "kubernetes" + gatewayAPI: + enabled: true + secretsNamespace: + name: "kube-system" diff --git a/providers/openstack/scs2/cluster-addon/csi/Chart.yaml b/providers/openstack/scs2/cluster-addon/csi/Chart.yaml new file mode 100644 index 00000000..e275b2ff --- /dev/null +++ b/providers/openstack/scs2/cluster-addon/csi/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +type: application +description: CSI +name: CSI +version: v1 +dependencies: + - alias: openstack-cinder-csi + name: openstack-cinder-csi + repository: https://kubernetes.github.io/cloud-provider-openstack + version: 2.33.1 diff --git a/providers/openstack/scs2/cluster-addon/csi/overwrite.yaml b/providers/openstack/scs2/cluster-addon/csi/overwrite.yaml new file mode 100644 index 00000000..d191a115 --- /dev/null +++ b/providers/openstack/scs2/cluster-addon/csi/overwrite.yaml @@ -0,0 +1,3 @@ +values: | + openstack-cinder-csi: + clusterID: "{{ .Cluster.metadata.name }}" diff --git a/providers/openstack/scs2/cluster-addon/csi/values.yaml b/providers/openstack/scs2/cluster-addon/csi/values.yaml new file mode 100644 index 00000000..4e648a4f --- /dev/null +++ b/providers/openstack/scs2/cluster-addon/csi/values.yaml @@ -0,0 +1,41 @@ +openstack-cinder-csi: + secret: + enabled: true + name: csi-cloud-config + create: true + filename: cloud.conf + data: + cloud.conf: |- + [Global] + use-clouds = "true" + clouds-file = /etc/openstack/clouds.yaml + storageClass: + delete: + isDefault: true + csi: + plugin: + volumes: + - name: clouds-yaml + secret: + secretName: clouds-yaml + - name: cloud-conf + secret: + secretName: csi-cloud-config + volumeMounts: + - name: clouds-yaml + readOnly: true + mountPath: /etc/openstack + - name: cloud-conf + readOnly: true + mountPath: /etc/kubernetes + - name: cloud-conf + readOnly: true + mountPath: /etc/config + nodeSelector: + node-role.kubernetes.io/control-plane: "" + tolerations: + - key: node.cloudprovider.kubernetes.io/uninitialized + value: "true" + effect: NoSchedule + - key: node-role.kubernetes.io/control-plane + effect: NoSchedule diff --git a/providers/openstack/scs2/cluster-addon/metrics-server/Chart.yaml b/providers/openstack/scs2/cluster-addon/metrics-server/Chart.yaml new file mode 100644 index 00000000..2ac06b1a --- /dev/null +++ b/providers/openstack/scs2/cluster-addon/metrics-server/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +type: application +description: Metrics Server +name: metrics-server +version: v1 +dependencies: + - name: "metrics-server" + version: "3.13.0" + repository: "https://kubernetes-sigs.github.io/metrics-server/" + alias: "metrics-server" diff --git a/providers/openstack/scs2/cluster-addon/metrics-server/overwrite.yaml b/providers/openstack/scs2/cluster-addon/metrics-server/overwrite.yaml new file mode 100644 index 00000000..7b1dcd5b --- /dev/null +++ b/providers/openstack/scs2/cluster-addon/metrics-server/overwrite.yaml @@ -0,0 +1,4 @@ +values: | + metrics-server: + commonLabels: + domain: "{{ .Cluster.spec.controlPlaneEndpoint.host }}" diff --git a/providers/openstack/scs2/cluster-addon/metrics-server/values.yaml b/providers/openstack/scs2/cluster-addon/metrics-server/values.yaml new file mode 100644 index 00000000..a89bf027 --- /dev/null +++ b/providers/openstack/scs2/cluster-addon/metrics-server/values.yaml @@ -0,0 +1,4 @@ +metrics-server: + fullnameOverride: metrics-server + args: + - --kubelet-insecure-tls diff --git a/providers/openstack/scs2/cluster-class/.helmignore b/providers/openstack/scs2/cluster-class/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/providers/openstack/scs2/cluster-class/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/providers/openstack/scs2/cluster-class/Chart.yaml b/providers/openstack/scs2/cluster-class/Chart.yaml new file mode 100644 index 00000000..5737fcea --- /dev/null +++ b/providers/openstack/scs2/cluster-class/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +description: "This chart installs and configures: + + * Openstack scs2 Cluster Class + + " +name: openstack-scs2-1-33-cluster-class +type: application +version: v1 diff --git a/providers/openstack/scs2/cluster-class/templates/_helpers.tpl b/providers/openstack/scs2/cluster-class/templates/_helpers.tpl new file mode 100644 index 00000000..2339c125 --- /dev/null +++ b/providers/openstack/scs2/cluster-class/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "cluster-class.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "cluster-class.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "cluster-class.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "cluster-class.labels" -}} +helm.sh/chart: {{ include "cluster-class.chart" . }} +{{ include "cluster-class.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "cluster-class.selectorLabels" -}} +app.kubernetes.io/name: {{ include "cluster-class.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "cluster-class.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "cluster-class.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/providers/openstack/scs2/cluster-class/templates/cluster-class.yaml b/providers/openstack/scs2/cluster-class/templates/cluster-class.yaml new file mode 100644 index 00000000..34f30d6f --- /dev/null +++ b/providers/openstack/scs2/cluster-class/templates/cluster-class.yaml @@ -0,0 +1,844 @@ +apiVersion: cluster.x-k8s.io/v1beta1 +kind: ClusterClass +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }} +spec: + controlPlane: + ref: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: KubeadmControlPlaneTemplate + name: {{ .Release.Name }}-{{ .Chart.Version }}-control-plane + machineInfrastructure: + ref: + kind: OpenStackMachineTemplate + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + name: {{ .Release.Name }}-{{ .Chart.Version }}-control-plane + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + name: {{ .Release.Name }}-{{ .Chart.Version }}-cluster + workers: + machineDeployments: + - class: default-worker + template: + bootstrap: + ref: + apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 + kind: KubeadmConfigTemplate + name: {{ .Release.Name }}-{{ .Chart.Version }}-default-worker + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + name: {{ .Release.Name }}-{{ .Chart.Version }}-default-worker + variables: + # Image variables + - name: imageName + required: false + schema: + openAPIV3Schema: + type: string + description: | + The base name of the OpenStack image used for provisioning servers. + If `imageIsOrc` is enabled, this name refers to an ORC image resource. + If `imageIsOrc` is disabled, the name is used to filter images available in the OpenStack project. In this case, the specified image must already exist within the project. + If `imageAddVersion` is enabled, the Kubernetes version will be appended to form the complete image name (e.g., imageName-v1.32.5) + default: "ubuntu-capi-image" + - name: imageIsOrc + required: false + schema: + openAPIV3Schema: + type: boolean + description: | + Indicates whether the image name refers to an ORC image resource. + If set to true (default), the `imageName` is interpreted as a reference to an ORC image. + If set to false, the `imageName` is used to filter images in the OpenStack project instead. + default: false + - name: imageAddVersion + required: false + schema: + openAPIV3Schema: + type: boolean + description: | + Add a suffix with the Kubernetes version to the imageName. E.g. imageName-v1.32.5. + default: true + - name: disableAPIServerFloatingIP + required: false + schema: + openAPIV3Schema: + type: boolean + default: false + example: false + description: "DisableAPIServerFloatingIP controls whether a floating IP should be attached to the API server." + # Network variables + - name: networkExternalID + required: false + schema: + openAPIV3Schema: + type: string + example: "ebfe5546-f09f-4f42-ab54-094e457d42ec" + format: "uuid4" + description: "networkExternalID is the ID of an external OpenStack Network. This is necessary to get public internet to the VMs in case there are several external networks." + - name: networkMTU + required: false + schema: + openAPIV3Schema: + type: integer + example: 1500 + description: "networkMTU sets the maximum transmission unit (MTU) value to address fragmentation for the private network ID." + - name: dnsNameservers + required: false + schema: + openAPIV3Schema: + type: array + description: "dnsNameservers is the list of nameservers for the OpenStack Subnet being created. Set this value when you need to create a new network/subnet which requires access to DNS." + default: ["9.9.9.9", "149.112.112.112"] + example: ["9.9.9.9", "149.112.112.112"] + items: + type: string + - name: nodeCIDR + required: false + schema: + openAPIV3Schema: + type: string + format: "cidr" + default: "10.8.0.0/20" + example: "10.8.0.0/20" + description: |- + nodeCIDR is the OpenStack Subnet to be created. + Cluster actuator will create a network, a subnet with nodeCIDR, + and a router connected to this subnet. + If you leave this empty, no network will be created. + # Control plane + - name: controlPlaneFlavor + required: false + schema: + openAPIV3Schema: + type: string + default: "SCS-2V-4" + example: "SCS-2V-4" + description: |- + OpenStack instance flavor for control plane nodes. + (Default: SCS-2V-4, replace by SCS-2V-4-20s or specify a controlPlaneRootDisk.) + - name: controlPlaneRootDisk + required: false + schema: + openAPIV3Schema: + type: integer + minimum: 1 + example: 25 + default: 50 + description: |- + Root disk size in GiB for control-plane nodes. + OpenStack volume will be created and used instead of an ephemeral disk defined in flavor. + Should only be used for the diskless flavors. + - name: controlPlaneServerGroupID + required: false + schema: + openAPIV3Schema: + type: string + default: "" + example: "3adf4e92-bb33-4e44-8ad3-afda9dfe8ec3" + description: "The server group to assign the control plane nodes to (can be used for anti-affinity)." + - name: controlPlaneAvailabilityZones + required: false + schema: + openAPIV3Schema: + type: array + example: ["nova"] + description: "controlPlaneAvailabilityZones is the set of availability zones which control plane machines may be deployed to." + items: + type: string + - name: controlPlaneOmitAvailabilityZone + required: false + schema: + openAPIV3Schema: + type: boolean + example: true + description: |- + controlPlaneOmitAvailabilityZone causes availability zone to be omitted when creating control plane nodes, + allowing the Nova scheduler to make a decision on which availability zone to use based on other scheduling constraints. + # Workers + - name: workerFlavor + required: false + schema: + openAPIV3Schema: + type: string + default: "SCS-4V-8" + example: "SCS-4V-8" + description: "OpenStack instance flavor for worker nodes (default: SCS-4V-8, which requires workerRootDisk)." + - name: workerRootDisk + required: false + schema: + openAPIV3Schema: + type: integer + minimum: 1 + example: 25 + default: 50 + description: |- + Root disk size in GiB for worker nodes. + OpenStack volume will be created and used instead of an ephemeral disk defined in flavor. + Should be used for the diskless flavors. + - name: workerServerGroupID + required: false + schema: + openAPIV3Schema: + type: string + default: "" + example: "869fe071-1e56-46a9-9166-47c9f228e297" + description: "The server group to assign the worker nodes to." + - name: workerAdditionalBlockDevices + required: false + schema: + openAPIV3Schema: + type: array + default: [] + items: + type: object + properties: + name: + type: string + sizeGiB: + type: integer + default: 20 + type: + type: string + default: "__DEFAULT__" + required: ["name"] + # Access management + - name: sshKeyName + required: false + schema: + openAPIV3Schema: + type: string + default: "" + example: "capi-keypair" + description: "The ssh key name to inject in the nodes (for debugging)." + - name: securityGroups + required: false + schema: + openAPIV3Schema: + type: array + default: [] + example: ["security-group-1"] + description: |- + The names of extra security groups to assign to worker and control plane nodes. + Will be ignored if `securityGroupIDs` is used. + items: + type: string + - name: securityGroupIDs + required: false + schema: + openAPIV3Schema: + format: "uuid4" + type: array + default: [] + example: ["9ae2f488-30a3-4629-bd51-07acb8eb4278"] + description: "The UUIDs of extra security groups to assign to worker and control plane nodes" + items: + type: string + - name: workerSecurityGroups + required: false + schema: + openAPIV3Schema: + type: array + default: [] + example: ["security-group-1"] + description: |- + The names of extra security groups to assign to the worker nodes. + Will be ignored if `workerSecurityGroupIDs` is used. + items: + type: string + - name: workerSecurityGroupIDs + required: false + schema: + openAPIV3Schema: + format: "uuid4" + type: array + default: [] + example: ["9ae2f488-30a3-4629-bd51-07acb8eb4278"] + description: "The UUIDs of extra security groups to assign to the worker nodes" + items: + type: string + - name: identityRef + required: false + schema: + openAPIV3Schema: + type: object + default: {} + properties: + name: + type: string + example: "openstack" + default: "openstack" + description: "The name of the secret that carries the OpenStack clouds.yaml" + cloudName: + type: string + example: "openstack" + default: "openstack" + description: "The name of the cloud to use from the clouds.yaml" + # Kubernetes API server + - name: certSANs + required: false + schema: + openAPIV3Schema: + type: array + default: [] + example: ["mydomain.example"] + description: "certSANs sets extra Subject Alternative Names for the API Server signing cert." + items: + type: string + - name: apiServerLoadBalancer + required: false + schema: + openAPIV3Schema: + type: string + default: "octavia-ovn" + example: "none, octavia-amphora, octavia-ovn" + description: | + Cluster-API by default places a LoadBalancer in front of the kubernetes API server. + (There are also LBs that the CCM creates for a service type LoadBalancer which are configured independently.) + This setting here is to configure the LoadBalancer that is placed in front of the apiServer. + You can choose from 3 options: + + none: + No LoadBalancer solution will be deployed + + octavia-amphora: + Uses OpenStack's LoadBalancer service Octavia (provider:amphora) + + octavia-ovn: + (default) Uses OpenStack's LoadBalancer service Octavia (provider:ovn) + - name: apiServerLoadBalancerOctaviaAmphoraAllowedCIDRs + required: false + schema: + openAPIV3Schema: + type: array + example: ["192.168.10.0/24"] + description: |- + apiServerLoadBalancerOctaviaAmphoraAllowedCIDRs restrict access to the Kubernetes API server on a network level. + Ensure that at least the outgoing IP of your Management Cluster is added to the list of allowed CIDRs. + Otherwise CAPO can’t reconcile the target Cluster correctly. + This requires amphora as load balancer provider in version >= v2.12. + items: + type: string + - name: oidcConfig + required: false + schema: + openAPIV3Schema: + type: object + properties: + clientID: + type: string + example: "kubectl" + description: "A client id that all tokens must be issued for." + issuerURL: + type: string + example: "https://dex.k8s.scs.community" + description: >- + URL of the provider that allows the API server to + discover public signing keys. Only URLs that use the https:// scheme are + accepted. This is typically the provider's discovery URL, changed to have an + empty path. + usernameClaim: + type: string + example: "preferred_username" + default: "preferred_username" + description: >- + JWT claim to use as the user name. By default sub, + which is expected to be a unique identifier of the end user. Admins can choose + other claims, such as email or name, depending on their provider. However, + claims other than email will be prefixed with the issuer URL to prevent naming + clashes with other plugins. + groupsClaim: + type: string + example: "groups" + default: "groups" + description: "JWT claim to use as the user's group. If the claim is present it must be an array of strings." + usernamePrefix: + type: string + example: "oidc:" + default: "oidc:" + description: >- + Prefix prepended to username claims to prevent + clashes with existing names (such as system: users). For example, the value + oidc: will create usernames like oidc:jane.doe. If this flag isn't provided and + --oidc-username-claim is a value other than email the prefix defaults to ( + Issuer URL )# where ( Issuer URL ) is the value of --oidc-issuer-url. The value + - can be used to disable all prefixing. + groupsPrefix: + type: string + example: "oidc:" + default: "oidc:" + description: >- + Prefix prepended to group claims to prevent clashes + with existing names (such as system: groups). For example, the value oidc: will + create group names like oidc:engineering and oidc:infra. + # + # Patches + # + patches: + # + # Patches for OpenStackClusterTemplate resource. + # + - name: apiServerLoadBalancerOctaviaAmphora + description: "Takes care of the patches that should be applied when variable apiServerLoadBalancer is set to octavia-amphora." + enabledIf: {{ `'{{ eq .apiServerLoadBalancer "octavia-amphora" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: replace + path: "/spec/template/spec/apiServerLoadBalancer/enabled" + value: true + - op: add + path: "/spec/template/spec/apiServerLoadBalancer/provider" + value: "amphora" + - name: apiServerLoadBalancerOctaviaOVN + description: "Takes care of the patches that should be applied when variable apiServerLoadBalancer is set to octavia-ovn." + enabledIf: {{ `'{{ eq .apiServerLoadBalancer "octavia-ovn" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: replace + path: "/spec/template/spec/apiServerLoadBalancer/enabled" + value: true + - op: add + path: "/spec/template/spec/apiServerLoadBalancer/provider" + value: "ovn" + - name: apiServerLoadBalancerOctaviaAmphoraAllowedCIDRs + description: "Takes care of the patches that should be applied when variable allowedCIDRs is set." + enabledIf: {{ `'{{ and .apiServerLoadBalancerOctaviaAmphoraAllowedCIDRs (eq .apiServerLoadBalancer "octavia-amphora") }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/apiServerLoadBalancer/allowedCIDRs" + valueFrom: + variable: apiServerLoadBalancerOctaviaAmphoraAllowedCIDRs + - name: networkExternalID + description: "Sets the ID of an external OpenStack Network. This is necessary to get public internet to the VMs." + enabledIf: {{ `'{{ if .networkExternalID }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/externalNetwork" + value: {} + - op: add + path: "/spec/template/spec/externalNetwork/id" + valueFrom: + variable: networkExternalID + - name: networkMTU + description: "Sets the network MTU when variable networkMTU exist in cluster resource." + enabledIf: {{ `'{{ if .networkMTU }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/networkMTU" + valueFrom: + variable: networkMTU + - name: controlPlaneAvailabilityZones + description: "Sets the availability zones which control plane machines may be deployed to." + enabledIf: {{ `'{{ if .controlPlaneAvailabilityZones }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/controlPlaneAvailabilityZones" + valueFrom: + variable: controlPlaneAvailabilityZones + - name: controlPlaneOmitAvailabilityZone + description: "Causes availability zone to be omitted when creating control plane nodes." + enabledIf: {{ `'{{ if .controlPlaneOmitAvailabilityZone }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/controlPlaneOmitAvailabilityZone" + valueFrom: + variable: controlPlaneOmitAvailabilityZone + - name: identityRef + description: "Sets the OpenStack identity reference." + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: /spec/template/spec/identityRef + valueFrom: + variable: identityRef + - name: nodeCIDRSubnet + description: |- + Sets the NodeCIDR for the OpenStack Subnet to be created. + Cluster actuator will create a network, a subnet with NodeCIDR, + and a router connected to this subnet. + enabledIf: {{ `'{{ if .nodeCIDR }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/managedSubnets" + valueFrom: + template: | + - cidr: '{{ `{{ .nodeCIDR }}` }}' + dnsNameservers: + {{ `{{- range .dnsNameservers }}` }} + - {{ `{{ . }}` }} + {{ `{{- end }}` }} + - name: disableAPIServerFloatingIP + description: "DisableAPIServerFloatingIP controls whether a floating IP should be attached to the API server." + enabledIf: {{ `"{{ if .disableAPIServerFloatingIP }}true{{end}}"` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/disableAPIServerFloatingIP" + valueFrom: + variable: disableAPIServerFloatingIP + # + # Patches for control plane's OpenStackMachineTemplate resources. + # Note: Control plane patches are only applied when the control plane is managed by Kubeadm. + - name: controlPlaneImage + description: "Sets the OpenStack image name that is used for creating the control plane servers." + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: add + path: /spec/template/spec/image + valueFrom: + template: | + {{ `{{ if .imageIsOrc }}imageRef{{ else }}filter{{ end }}` }}: + name: {{ `{{ .imageName }}{{ if .imageAddVersion }}-{{ .builtin.controlPlane.version }}{{ end }}` }} + - name: controlPlaneFlavor + description: "Sets the openstack instance flavor for the KubeadmControlPlane." + enabledIf: {{ `'{{ ne .controlPlaneFlavor "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: replace + path: "/spec/template/spec/flavor" + valueFrom: + variable: controlPlaneFlavor + - name: controlPlaneRootDisk + description: "Sets the root disk size in GiB for control-plane nodes." + enabledIf: {{ `'{{ if .controlPlaneRootDisk }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: add + path: "/spec/template/spec/rootVolume" + valueFrom: + template: | + sizeGiB: {{ `{{ .controlPlaneRootDisk }}` }} + - name: controlPlaneServerGroupID + description: "Sets the server group to assign the control plane nodes to." + enabledIf: {{ `'{{ ne .controlPlaneServerGroupID "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: add + path: "/spec/template/spec/serverGroup" + valueFrom: + template: | + id: {{ `{{ .controlPlaneServerGroupID }}` }} + # + # Patches for control plane's as well as worker's OpenStackMachineTemplate resources. + # Note: Control plane patches are only applied when the control plane is managed by Kubeadm. + # + # Note: The securityGroups patch must be placed before securityGroupIDs, workerSecurityGroups, and workerSecurityGroupIDs. + # The patch order ensures the last applied patch overwrites previous ones. + - name: securityGroups + description: "Sets the list of the openstack security groups for the worker and the control plane instances." + enabledIf: {{ `'{{ if .securityGroups }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/securityGroups" + valueFrom: + template: {{ `'[ {{ range .securityGroups }} { filter: { name: {{ . }}}}, {{ end }} ]'` }} + # Note: The securityGroupIDs patch must be placed before workerSecurityGroups, workerSecurityGroupIDs and after securityGroupIDs. + # The patch order ensures the last applied patch overwrites previous ones. + - name: securityGroupIDs + description: "Sets the list of the openstack security groups for the worker and the control plane instances by UUID." + enabledIf: {{ `'{{ if .securityGroupIDs }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/securityGroups" + valueFrom: + template: {{ `'[ {{ range .securityGroupIDs }} { id: {{ . }} }, {{ end }} ]'` }} + - name: sshKeyName + description: "Sets the ssh key to inject in the nodes." + enabledIf: {{ `'{{ ne .sshKeyName "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/sshKeyName" + valueFrom: + variable: sshKeyName + # + # Patches for worker's OpenStackMachineTemplate resources. + # + - name: workerImage + description: "Sets the OpenStack image name that is used for creating the worker servers." + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: /spec/template/spec/image + valueFrom: + template: | + {{ `{{ if .imageIsOrc }}imageRef{{ else }}filter{{ end }}` }}: + name: {{ `{{ .imageName }}{{ if .imageAddVersion }}-{{ .builtin.machineDeployment.version }}{{ end }}` }} + - name: workerFlavor + description: "Sets the openstack instance flavor for the worker nodes." + enabledIf: {{ `'{{ ne .workerFlavor "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: replace + path: "/spec/template/spec/flavor" + valueFrom: + variable: workerFlavor + - name: workerRootDisk + description: "Sets the root disk size in GiB for worker nodes." + enabledIf: {{ `'{{ if .workerRootDisk }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/rootVolume" + valueFrom: + template: | + sizeGiB: {{ `{{ .workerRootDisk }}` }} + - name: workerServerGroupID + description: "Sets the server group to assign the worker nodes to." + enabledIf: {{ `'{{ ne .workerServerGroupID "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/serverGroup" + valueFrom: + template: | + id: {{ `{{ .workerServerGroupID }}` }} + - name: workerAdditionalBlockDevices + enabledIf: {{ `'{{ if .workerAdditionalBlockDevices }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: /spec/template/spec/additionalBlockDevices + valueFrom: + template: | + {{ `{{- range .workerAdditionalBlockDevices }}` }} + - name: {{ `{{ .name }}` }} + sizeGiB: {{ `{{ .sizeGiB }}` }} + storage: + type: Volume + volume: + type: {{ `{{ .type }}` }} + {{ `{{- end }}` }} + # Note: The workerSecurityGroups patch must be placed before workerSecurityGroupIDs and after securityGroups and securityGroupIDs. + # The patch order ensures the last applied patch overwrites previous ones. + - name: workerSecurityGroups + description: "Sets the list of the openstack security groups for the worker instances." + enabledIf: {{ `'{{ if .workerSecurityGroups }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/securityGroups" + valueFrom: + template: {{ `'[ {{ range .workerSecurityGroups }} { filter: { name: {{ . }}}}, {{ end }} ]'` }} + # Note: The workerSecurityGroupIDs patch must be placed after securityGroups, securityGroupIDs and workerSecurityGroupIDs. + # The patch order ensures the last applied patch overwrites previous ones. + - name: workerSecurityGroupIDs + description: "Sets the list of the openstack security groups for the worker instances by UUID." + enabledIf: {{ `'{{ if .workerSecurityGroupIDs }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/securityGroups" + valueFrom: + template: {{ `'[ {{ range .workerSecurityGroupIDs }} { id: {{ . }} }, {{ end }} ]'` }} + # + - name: certSANs + description: "certSANs sets extra Subject Alternative Names for the API Server signing cert." + enabledIf: {{ `'{{ if .certSANs }}true{{end}}'` }} + definitions: + - selector: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: KubeadmControlPlaneTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: add + path: "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/certSANs" + valueFrom: + variable: certSANs + - name: oidcConfig + description: "Configure API Server to use external authentication service." + enabledIf: {{ `'{{ if and .oidcConfig .oidcConfig.clientID .oidcConfig.issuerURL }}true{{end}}'` }} + definitions: + - selector: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: KubeadmControlPlaneTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: add + path: "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-client-id" + valueFrom: + variable: oidcConfig.clientID + - op: add + path: "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-issuer-url" + valueFrom: + variable: oidcConfig.issuerURL + - op: add + path: "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-username-claim" + valueFrom: + variable: oidcConfig.usernameClaim + - op: add + path: "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-groups-claim" + valueFrom: + variable: oidcConfig.groupsClaim + - op: add + path: "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-username-prefix" + valueFrom: + variable: oidcConfig.usernamePrefix + - op: add + path: "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-groups-prefix" + valueFrom: + variable: oidcConfig.groupsPrefix diff --git a/providers/openstack/scs2/cluster-class/templates/kubeadm-config-template-worker-openstack.yaml b/providers/openstack/scs2/cluster-class/templates/kubeadm-config-template-worker-openstack.yaml new file mode 100644 index 00000000..4c1494ed --- /dev/null +++ b/providers/openstack/scs2/cluster-class/templates/kubeadm-config-template-worker-openstack.yaml @@ -0,0 +1,13 @@ +apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 +kind: KubeadmConfigTemplate +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }}-default-worker +spec: + template: + spec: + joinConfiguration: + nodeRegistration: + kubeletExtraArgs: + cloud-provider: external + provider-id: 'openstack:///{{ `{{ instance_id }}` }}' + name: '{{ `{{ local_hostname }}` }}' diff --git a/providers/openstack/scs2/cluster-class/templates/kubeadm-control-plane-template.yaml b/providers/openstack/scs2/cluster-class/templates/kubeadm-control-plane-template.yaml new file mode 100644 index 00000000..767eac68 --- /dev/null +++ b/providers/openstack/scs2/cluster-class/templates/kubeadm-control-plane-template.yaml @@ -0,0 +1,89 @@ +apiVersion: controlplane.cluster.x-k8s.io/v1beta1 +kind: KubeadmControlPlaneTemplate +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }}-control-plane +spec: + template: + spec: + kubeadmConfigSpec: + clusterConfiguration: + apiServer: {} + controllerManager: + extraArgs: + cloud-provider: external + bind-address: 0.0.0.0 + secure-port: "10257" + scheduler: + extraArgs: + bind-address: 0.0.0.0 + secure-port: "10259" + etcd: + local: + dataDir: /var/lib/etcd + extraArgs: + listen-metrics-urls: http://0.0.0.0:2381 + auto-compaction-mode: periodic + auto-compaction-retention: 8h + election-timeout: "2500" + heartbeat-interval: "250" + snapshot-count: "6400" + files: + - content: | + --- + apiVersion: kubeproxy.config.k8s.io/v1alpha1 + kind: KubeProxyConfiguration + metricsBindAddress: "0.0.0.0:10249" + path: /etc/kube-proxy-config.yaml + - content: | + #!/usr/bin/env bash + + # + # (PK) I couldn't find a better/simpler way to conifgure it. See: + # https://github.com/kubernetes-sigs/cluster-api/issues/4512 + # + + set -o errexit + set -o nounset + set -o pipefail + + dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + readonly dir + + # Exit fast if already appended. + if [[ ! -f ${dir}/kube-proxy-config.yaml ]]; then + exit 0 + fi + + # kubeadm config is in different directory in Flatcar (/etc) and Ubuntu (/run/kubeadm). + kubeadm_file="/etc/kubeadm.yml" + if [[ ! -f ${kubeadm_file} ]]; then + kubeadm_file="/run/kubeadm/kubeadm.yaml" + fi + + # Run this script only if this is the init node. + if [[ ! -f ${kubeadm_file} ]]; then + exit 0 + fi + + # Append kube-proxy-config.yaml to kubeadm config and delete it + cat "${dir}/kube-proxy-config.yaml" >> "${kubeadm_file}" + rm "${dir}/kube-proxy-config.yaml" + + echo success > /tmp/kube-proxy-patch + owner: root:root + path: /etc/kube-proxy-patch.sh + permissions: "0755" + preKubeadmCommands: + - bash /etc/kube-proxy-patch.sh + initConfiguration: + nodeRegistration: + kubeletExtraArgs: + cloud-provider: external + provider-id: 'openstack:///{{ `{{ instance_id }}` }}' + name: '{{ `{{ local_hostname }}` }}' + joinConfiguration: + nodeRegistration: + kubeletExtraArgs: + cloud-provider: external + provider-id: 'openstack:///{{ `{{ instance_id }}` }}' + name: '{{ `{{ local_hostname }}` }}' diff --git a/providers/openstack/scs2/cluster-class/templates/openstack-cluster-template.yaml b/providers/openstack/scs2/cluster-class/templates/openstack-cluster-template.yaml new file mode 100644 index 00000000..9d03326f --- /dev/null +++ b/providers/openstack/scs2/cluster-class/templates/openstack-cluster-template.yaml @@ -0,0 +1,45 @@ +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: OpenStackClusterTemplate +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }}-cluster +spec: + template: + spec: + identityRef: + cloudName: overridden-by-patch + name: overridden-by-patch + apiServerLoadBalancer: + enabled: false + managedSecurityGroups: + allNodesSecurityGroupRules: + - remoteManagedGroups: + - controlplane + - worker + direction: ingress + etherType: IPv4 + name: VXLAN (Cilium) + portRangeMin: 8472 + portRangeMax: 8472 + protocol: udp + description: "Allow VXLAN traffic for Cilium" + - remoteManagedGroups: + - controlplane + - worker + direction: ingress + etherType: IPv4 + name: HealthCheck (Cilium) + portRangeMin: 4240 + portRangeMax: 4240 + protocol: tcp + description: "Allow HealthCheck traffic for Cilium" + - remoteManagedGroups: + - controlplane + - worker + direction: ingress + etherType: IPv4 + name: Hubble (Cilium) + portRangeMin: 4244 + portRangeMax: 4244 + protocol: tcp + description: "Allow Hubble traffic for Cilium" diff --git a/providers/openstack/scs2/cluster-class/templates/openstack-machine-template-control-plane.yaml b/providers/openstack/scs2/cluster-class/templates/openstack-machine-template-control-plane.yaml new file mode 100644 index 00000000..703c1b1c --- /dev/null +++ b/providers/openstack/scs2/cluster-class/templates/openstack-machine-template-control-plane.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: OpenStackMachineTemplate +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }}-control-plane +spec: + template: + spec: + flavor: overridden-by-patch + image: + imageRef: + name: overridden-by-patch diff --git a/providers/openstack/scs2/cluster-class/templates/openstack-machine-template-worker.yaml b/providers/openstack/scs2/cluster-class/templates/openstack-machine-template-worker.yaml new file mode 100644 index 00000000..920dbb0a --- /dev/null +++ b/providers/openstack/scs2/cluster-class/templates/openstack-machine-template-worker.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: OpenStackMachineTemplate +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }}-default-worker +spec: + template: + spec: + flavor: overridden-by-patch + image: + imageRef: + name: overridden-by-patch diff --git a/providers/openstack/scs2/cluster-class/values.yaml b/providers/openstack/scs2/cluster-class/values.yaml new file mode 100644 index 00000000..e69de29b diff --git a/providers/openstack/scs2/clusteraddon.yaml b/providers/openstack/scs2/clusteraddon.yaml new file mode 100644 index 00000000..d346ba22 --- /dev/null +++ b/providers/openstack/scs2/clusteraddon.yaml @@ -0,0 +1,21 @@ +apiVersion: clusteraddonconfig.x-k8s.io/v1alpha1 +clusterAddonVersion: clusteraddons.clusterstack.x-k8s.io/v1alpha1 +addonStages: + AfterControlPlaneInitialized: + - name: cni + action: apply + - name: metrics-server + action: apply + - name: csi + action: apply + - name: ccm + action: apply + BeforeClusterUpgrade: + - name: cni + action: apply + - name: metrics-server + action: apply + - name: csi + action: apply + - name: ccm + action: apply diff --git a/providers/openstack/scs2/csctl.yaml b/providers/openstack/scs2/csctl.yaml new file mode 100644 index 00000000..d6f827bd --- /dev/null +++ b/providers/openstack/scs2/csctl.yaml @@ -0,0 +1,7 @@ +apiVersion: csctl.clusterstack.x-k8s.io/v1alpha1 +config: + clusterStackName: scs2 + kubernetesVersion: v1.33.4 + provider: + apiVersion: openstack.csctl.clusterstack.x-k8s.io/v1alpha1 + type: openstack diff --git a/providers/openstack/scs2/versions.yaml b/providers/openstack/scs2/versions.yaml new file mode 100644 index 00000000..f21958d4 --- /dev/null +++ b/providers/openstack/scs2/versions.yaml @@ -0,0 +1,9 @@ +- kubernetes: 1.31.12 + cinder_csi: 2.31.7 + occm: 2.31.3 +- kubernetes: 1.32.8 + cinder_csi: 2.32.2 + occm: 2.32.0 +- kubernetes: 1.33.4 + cinder_csi: 2.33.1 + occm: 2.33.1