# Copyright (c) 2023 VEXXHOST, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import glob
import json
import os
import textwrap
import types

import certifi
import pkg_resources
import pykube
import yaml
from magnum import objects as magnum_objects
from magnum.common import cert_manager, cinder, context, neutron
from magnum.common import utils as magnum_utils
from magnum.common.x509 import operations as x509
from oslo_config import cfg
from oslo_serialization import base64
from oslo_utils import encodeutils

from magnum_cluster_api import clients, helm, image_utils, images, objects, utils

CONF = cfg.CONF
CLOUD_PROVIDER_TAG = "v1.25.3"
CALICO_TAG = "v3.24.2"
CINDER_CSI_TAG = "v1.25.3"
MANILA_CSI_TAG = "v1.25.3"

CLUSTER_CLASS_VERSION = pkg_resources.require("magnum_cluster_api")[0].version
CLUSTER_CLASS_NAME = f"magnum-v{CLUSTER_CLASS_VERSION}"

CLUSTER_UPGRADE_LABELS = {"kube_tag"}

PLACEHOLDER = "PLACEHOLDER"

AUTOSCALE_ANNOTATION_MIN = "cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size"
AUTOSCALE_ANNOTATION_MAX = "cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size"


class ClusterAutoscalerHelmRelease:
    def __init__(self, api, cluster) -> None:
        image = images.get_cluster_autoscaler_image(
            utils.get_kube_tag(cluster),
        )
        image_repo, image_tag = image.split(":", 1)

        self.apply = helm.UpgradeReleaseCommand(
            namespace="magnum-system",
            release_name=cluster.stack_id,
            chart_ref=os.path.join(
                pkg_resources.resource_filename("magnum_cluster_api", "charts"),
                "cluster-autoscaler/",
            ),
            values={
                "fullnameOverride": f"{cluster.stack_id}-autoscaler",
                "cloudProvider": "clusterapi",
                "clusterAPIMode": "kubeconfig-incluster",
                "clusterAPIKubeconfigSecret": f"{cluster.stack_id}-kubeconfig",
                "autoDiscovery": {
                    "clusterName": cluster.stack_id,
                },
                "image": {
                    "repository": image_repo,
                    "tag": image_tag,
                },
                "nodeSelector": {
                    "openstack-control-plane": "enabled",
                },
            },
        )

        self.delete = helm.DeleteReleaseCommand(
            namespace="magnum-system",
            release_name=cluster.stack_id,
            skip_missing=True,
        )


class Base:
    def __init__(self, api: pykube.HTTPClient):
        self.api = api

    def apply(self) -> None:
        resource = self.get_object()
        resp = resource.api.patch(
            **resource.api_kwargs(
                headers={
                    "Content-Type": "application/apply-patch+yaml",
                },
                params={
                    "fieldManager": "atmosphere-operator",
                    "force": True,
                },
                data=json.dumps(resource.obj),
            )
        )

        resource.api.raise_for_status(resp)
        resource.set_obj(resp.json())

    def delete(self) -> None:
        resource = self.get_object()
        resource.delete()


class Namespace(Base):
    def get_object(self) -> pykube.Namespace:
        return pykube.Namespace(
            self.api,
            {
                "apiVersion": pykube.Namespace.version,
                "kind": pykube.Namespace.kind,
                "metadata": {
                    "name": "magnum-system",
                },
            },
        )


class ClusterBase(Base):
    def __init__(self, api: pykube.HTTPClient, cluster: any):
        super().__init__(api)
        self.cluster = cluster

    @property
    def labels(self) -> dict:
        return {
            "cluster-uuid": self.cluster.uuid,
        }


class ClusterResourcesConfigMap(ClusterBase):
    def __init__(
        self,
        context: context.RequestContext,
        api: pykube.HTTPClient,
        cluster: magnum_objects.Cluster,
    ):
        self.context = context
        self.api = api
        self.cluster = cluster

    def get_object(self) -> pykube.ConfigMap:
        # NOTE(mnaser): We have to assert that the only CNI we support is Calico.
        assert CONF.cluster_template.kubernetes_allowed_network_drivers == ["calico"]

        manifests_path = pkg_resources.resource_filename(
            "magnum_cluster_api", "manifests"
        )
        calico_version = utils.get_cluster_label(self.cluster, "calico_tag", CALICO_TAG)
        ccm_version = utils.get_cluster_label(
            self.cluster, "cloud_provider_tag", CLOUD_PROVIDER_TAG
        )

        repository = utils.get_cluster_container_infra_prefix(self.cluster)

        osc = clients.get_openstack_api(self.context)

        data = {
            **{
                os.path.basename(manifest): image_utils.update_manifest_images(
                    self.cluster.uuid,
                    manifest,
                    repository=repository,
                    replacements=[
                        (
                            "docker.io/k8scloudprovider/openstack-cloud-controller-manager:latest",
                            f"docker.io/k8scloudprovider/openstack-cloud-controller-manager:{ccm_version}",
                        ),
                    ],
                )
                for manifest in glob.glob(os.path.join(manifests_path, "ccm/*.yaml"))
            },
            **{
                "calico.yml": image_utils.update_manifest_images(
                    self.cluster.uuid,
                    os.path.join(manifests_path, f"calico/{calico_version}.yaml"),
                    repository=repository,
                )
            },
        }

        if utils.is_cinder_csi_enabled(self.cluster):
            volume_types = osc.cinder().volume_types.list()
            default_volume_type = osc.cinder().volume_types.default()
            csi_version = utils.get_cluster_label(
                self.cluster, "cinder_csi_plugin_tag", CINDER_CSI_TAG
            )
            data = {
                **data,
                **{
                    os.path.basename(manifest): image_utils.update_manifest_images(
                        self.cluster.uuid,
                        manifest,
                        repository=repository,
                        replacements=[
                            (
                                "docker.io/k8scloudprovider/cinder-csi-plugin:latest",
                                f"docker.io/k8scloudprovider/cinder-csi-plugin:{csi_version}",
                            ),
                        ],
                    )
                    for manifest in glob.glob(
                        os.path.join(manifests_path, "cinder-csi/*.yaml")
                    )
                },
                **{
                    f"storageclass-cinder-{vt.name}.yaml": yaml.dump(
                        {
                            "apiVersion": objects.StorageClass.version,
                            "allowVolumeExpansion": True,
                            "kind": objects.StorageClass.kind,
                            "metadata": {
                                "annotations": {
                                    "storageclass.kubernetes.io/is-default-class": "true"
                                }
                                if default_volume_type.name == vt.name
                                else {},
                                "name": "cinder-%s" % vt.name.lower(),
                            },
                            "provisioner": "kubernetes.io/cinder",
                            "parameters": {
                                "type": vt.name,
                            },
                            "reclaimPolicy": "Delete",
                            "volumeBindingMode": "Immediate",
                        }
                    )
                    for vt in volume_types
                    if vt.name != "__DEFAULT__"
                },
            }

        if utils.is_manila_csi_enabled(self.cluster):
            share_types = osc.manila().share_types.list()
            csi_version = utils.get_cluster_label(
                self.cluster, "manila_csi_plugin_tag", MANILA_CSI_TAG
            )
            share_network_id = utils.get_cluster_label(
                self.cluster, "manila_csi_share_network_id", None
            )
            data = {
                **data,
                **{
                    "manila-csi-secret.yaml": yaml.dump(
                        {
                            "apiVersion": pykube.Secret.version,
                            "kind": pykube.Secret.kind,
                            "metadata": {
                                "name": "csi-manila-secrets",
                                "namespace": "kube-system",
                            },
                            "stringData": utils.generate_manila_csi_cloud_config(
                                self.api,
                                self.cluster,
                            ),
                        },
                    )
                },
                **{
                    os.path.basename(manifest): image_utils.update_manifest_images(
                        self.cluster.uuid,
                        manifest,
                        repository=repository,
                    )
                    for manifest in glob.glob(
                        os.path.join(manifests_path, "nfs-csi/*.yaml")
                    )
                },
                **{
                    os.path.basename(manifest): image_utils.update_manifest_images(
                        self.cluster.uuid,
                        manifest,
                        repository=repository,
                        replacements=[
                            (
                                "registry.k8s.io/provider-os/manila-csi-plugin:latest",
                                f"registry.k8s.io/provider-os/manila-csi-plugin:{csi_version}",
                            ),
                        ],
                    )
                    for manifest in glob.glob(
                        os.path.join(manifests_path, "manila-csi/*.yaml")
                    )
                },
            }
            # NOTE: We only create StorageClasses if share_network_id specified.
            if share_network_id:
                data = {
                    **data,
                    **{
                        f"storageclass-manila-{st.name}.yaml": yaml.dump(
                            {
                                "apiVersion": objects.StorageClass.version,
                                "allowVolumeExpansion": True,
                                "kind": objects.StorageClass.kind,
                                "metadata": {
                                    "name": "manila-%s" % st.name.lower(),
                                },
                                "provisioner": "manila.csi.openstack.org",
                                "parameters": {
                                    "type": st.name,
                                    "shareNetworkID": share_network_id,
                                    "csi.storage.k8s.io/provisioner-secret-name": "csi-manila-secrets",
                                    "csi.storage.k8s.io/provisioner-secret-namespace": "kube-system",
                                    "csi.storage.k8s.io/controller-expand-secret-name": "csi-manila-secrets",
                                    "csi.storage.k8s.io/controller-expand-secret-namespace": "kube-system",
                                    "csi.storage.k8s.io/node-stage-secret-name": "csi-manila-secrets",
                                    "csi.storage.k8s.io/node-stage-secret-namespace": "kube-system",
                                    "csi.storage.k8s.io/node-publish-secret-name": "csi-manila-secrets",
                                    "csi.storage.k8s.io/node-publish-secret-namespace": "kube-system",
                                },
                                "reclaimPolicy": "Delete",
                                "volumeBindingMode": "Immediate",
                            }
                        )
                        for st in share_types
                    },
                }

        return pykube.ConfigMap(
            self.api,
            {
                "apiVersion": pykube.ConfigMap.version,
                "kind": pykube.ConfigMap.kind,
                "metadata": {
                    "name": self.cluster.uuid,
                    "namespace": "magnum-system",
                },
                "data": data,
            },
        )

    def get_or_none(self) -> objects.Cluster:
        return pykube.ConfigMap.objects(
            self.api, namespace="magnum-system"
        ).get_or_none(name=self.cluster.uuid)

    def delete(self):
        cr_cm = self.get_or_none()
        if cr_cm:
            cr_cm.delete()


class ClusterResourceSet(ClusterBase):
    def get_object(self) -> objects.ClusterResourceSet:
        return objects.ClusterResourceSet(
            self.api,
            {
                "apiVersion": objects.ClusterResourceSet.version,
                "kind": objects.ClusterResourceSet.kind,
                "metadata": {
                    "name": self.cluster.uuid,
                    "namespace": "magnum-system",
                },
                "spec": {
                    "clusterSelector": {
                        "matchLabels": {
                            "cluster-uuid": self.cluster.uuid,
                        },
                    },
                    "resources": [
                        {
                            "name": self.cluster.uuid,
                            "kind": "ConfigMap",
                        },
                    ],
                },
            },
        )


class CertificateAuthoritySecret(ClusterBase):
    def delete(self) -> None:
        resource = self.get_or_none()
        if resource:
            resource.delete()

    def get_or_none(self) -> pykube.Secret:
        return pykube.Secret.objects(self.api, namespace="magnum-system").get_or_none(
            name=f"{self.cluster.stack_id}-{self.CERT}"
        )

    def get_object(self) -> pykube.Secret:
        cert_ref = getattr(self.cluster, self.REF)
        if cert_ref is None:
            raise Exception("Certificate for %s doesn't exist." % self.REF)

        ca_cert = cert_manager.get_backend().CertManager.get_cert(
            cert_ref,
            resource_ref=self.cluster.uuid,
        )

        return pykube.Secret(
            self.api,
            {
                "apiVersion": pykube.Secret.version,
                "kind": pykube.Secret.kind,
                "type": "kubernetes.io/tls",
                "metadata": {
                    "name": f"{self.cluster.stack_id}-{self.CERT}",
                    "namespace": "magnum-system",
                },
                "stringData": {
                    "tls.crt": encodeutils.safe_decode(ca_cert.get_certificate()),
                    "tls.key": encodeutils.safe_decode(
                        x509.decrypt_key(
                            ca_cert.get_private_key(),
                            ca_cert.get_private_key_passphrase(),
                        )
                    ),
                },
            },
        )


class ApiCertificateAuthoritySecret(CertificateAuthoritySecret):
    CERT = "ca"
    REF = "ca_cert_ref"


class EtcdCertificateAuthoritySecret(CertificateAuthoritySecret):
    CERT = "etcd"
    REF = "etcd_ca_cert_ref"


class FrontProxyCertificateAuthoritySecret(CertificateAuthoritySecret):
    CERT = "proxy"
    REF = "front_proxy_ca_cert_ref"


class ServiceAccountCertificateAuthoritySecret(CertificateAuthoritySecret):
    CERT = "sa"
    REF = "magnum_cert_ref"


class CloudConfigSecret(ClusterBase):
    def __init__(
        self,
        api: pykube.HTTPClient,
        cluster: any,
        auth_url: str = None,
        region_name: str = None,
        credential: any = types.SimpleNamespace(id=None, secret=None),
    ):
        super().__init__(api, cluster)
        self.auth_url = auth_url
        self.region_name = region_name
        self.credential = credential

    def get_object(self) -> pykube.Secret:
        ca_certificate = magnum_utils.get_openstack_ca()

        return pykube.Secret(
            self.api,
            {
                "apiVersion": pykube.Secret.version,
                "kind": pykube.Secret.kind,
                "metadata": {
                    "name": utils.get_or_generate_cluster_api_cloud_config_secret_name(
                        self.api, self.cluster
                    ),
                    "namespace": "magnum-system",
                    "labels": self.labels,
                },
                "stringData": {
                    "cacert": ca_certificate
                    if ca_certificate
                    else open(certifi.where(), "r").read(),
                    "clouds.yaml": yaml.dump(
                        {
                            "clouds": {
                                "default": {
                                    "region_name": self.region_name,
                                    "interface": CONF.nova_client.endpoint_type.replace(
                                        "URL", ""
                                    ),
                                    "identity_api_version": 3,
                                    "verify": CONF.drivers.verify_ca,
                                    "auth": {
                                        "auth_url": self.auth_url,
                                        "application_credential_id": self.credential.id,
                                        "application_credential_secret": self.credential.secret,
                                    },
                                }
                            }
                        }
                    ),
                },
            },
        )


class KubeadmControlPlaneTemplate(Base):
    def get_object(self) -> objects.KubeadmControlPlaneTemplate:
        manifests_path = pkg_resources.resource_filename(
            "magnum_cluster_api.manifests", "audit"
        )
        audit_policy = open(os.path.join(manifests_path, "policy.yaml")).read()

        return objects.KubeadmControlPlaneTemplate(
            self.api,
            {
                "apiVersion": objects.KubeadmControlPlaneTemplate.version,
                "kind": objects.KubeadmControlPlaneTemplate.kind,
                "metadata": {
                    "name": CLUSTER_CLASS_NAME,
                    "namespace": "magnum-system",
                },
                "spec": {
                    "template": {
                        "spec": {
                            "kubeadmConfigSpec": {
                                "clusterConfiguration": {
                                    "apiServer": {
                                        "extraArgs": {
                                            "cloud-provider": "external",
                                            "profiling": "false",
                                        },
                                        "extraVolumes": [],
                                    },
                                    "controllerManager": {
                                        "extraArgs": {
                                            "cloud-provider": "external",
                                            "profiling": "false",
                                        },
                                    },
                                    "scheduler": {
                                        "extraArgs": {
                                            "profiling": "false",
                                        },
                                    },
                                },
                                "files": [
                                    {
                                        "path": "/etc/kubernetes/audit-policy/apiserver-audit-policy.yaml",
                                        "permissions": "0600",
                                        "content": base64.encode_as_text(audit_policy),
                                        "encoding": "base64",
                                    },
                                ],
                                "initConfiguration": {
                                    "nodeRegistration": {
                                        "name": "{{ local_hostname }}",
                                        "kubeletExtraArgs": {
                                            "cloud-provider": "external",
                                        },
                                    },
                                },
                                "joinConfiguration": {
                                    "nodeRegistration": {
                                        "name": "{{ local_hostname }}",
                                        "kubeletExtraArgs": {
                                            "cloud-provider": "external",
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            },
        )


class KubeadmConfigTemplate(Base):
    def get_object(self) -> objects.KubeadmConfigTemplate:
        return objects.KubeadmConfigTemplate(
            self.api,
            {
                "apiVersion": objects.KubeadmConfigTemplate.version,
                "kind": objects.KubeadmConfigTemplate.kind,
                "metadata": {
                    "name": CLUSTER_CLASS_NAME,
                    "namespace": "magnum-system",
                },
                "spec": {
                    "template": {
                        "spec": {
                            "files": [],
                            "joinConfiguration": {
                                "nodeRegistration": {
                                    "name": "{{ local_hostname }}",
                                    "kubeletExtraArgs": {
                                        "cloud-provider": "external",
                                    },
                                },
                            },
                        }
                    }
                },
            },
        )


class OpenStackMachineTemplate(Base):
    def get_object(self) -> objects.OpenStackMachineTemplate:
        return objects.OpenStackMachineTemplate(
            self.api,
            {
                "apiVersion": objects.OpenStackMachineTemplate.version,
                "kind": objects.OpenStackMachineTemplate.kind,
                "metadata": {
                    "name": CLUSTER_CLASS_NAME,
                    "namespace": "magnum-system",
                },
                "spec": {
                    "template": {
                        "spec": {"cloudName": "default", "flavor": PLACEHOLDER}
                    }
                },
            },
        )


class OpenStackClusterTemplate(Base):
    def get_object(self) -> objects.OpenStackClusterTemplate:
        return objects.OpenStackClusterTemplate(
            self.api,
            {
                "apiVersion": objects.OpenStackClusterTemplate.version,
                "kind": objects.OpenStackClusterTemplate.kind,
                "metadata": {
                    "name": CLUSTER_CLASS_NAME,
                    "namespace": "magnum-system",
                },
                "spec": {
                    "template": {
                        "spec": {
                            "cloudName": "default",
                            "managedSecurityGroups": True,
                        },
                    },
                },
            },
        )


class ClusterClass(Base):
    def get_object(self) -> objects.ClusterClass:
        return objects.ClusterClass(
            self.api,
            {
                "apiVersion": objects.ClusterClass.version,
                "kind": objects.ClusterClass.kind,
                "metadata": {
                    "name": CLUSTER_CLASS_NAME,
                    "namespace": "magnum-system",
                },
                "spec": {
                    "controlPlane": {
                        "ref": {
                            "apiVersion": objects.KubeadmControlPlaneTemplate.version,
                            "kind": objects.KubeadmControlPlaneTemplate.kind,
                            "name": CLUSTER_CLASS_NAME,
                        },
                        "machineInfrastructure": {
                            "ref": {
                                "apiVersion": objects.OpenStackMachineTemplate.version,
                                "kind": objects.OpenStackMachineTemplate.kind,
                                "name": CLUSTER_CLASS_NAME,
                            },
                        },
                        "machineHealthCheck": {
                            "maxUnhealthy": "33%",
                            "unhealthyConditions": [
                                {
                                    "type": "Ready",
                                    "status": "False",
                                    "timeout": "5m",
                                },
                                {
                                    "type": "Ready",
                                    "status": "Unknown",
                                    "timeout": "5m",
                                },
                            ],
                        },
                    },
                    "infrastructure": {
                        "ref": {
                            "apiVersion": objects.OpenStackClusterTemplate.version,
                            "kind": objects.OpenStackClusterTemplate.kind,
                            "name": CLUSTER_CLASS_NAME,
                        },
                    },
                    "workers": {
                        "machineDeployments": [
                            {
                                "class": "default-worker",
                                "template": {
                                    "bootstrap": {
                                        "ref": {
                                            "apiVersion": objects.KubeadmConfigTemplate.version,
                                            "kind": objects.KubeadmConfigTemplate.kind,
                                            "name": CLUSTER_CLASS_NAME,
                                        }
                                    },
                                    "infrastructure": {
                                        "ref": {
                                            "apiVersion": objects.OpenStackMachineTemplate.version,
                                            "kind": objects.OpenStackMachineTemplate.kind,
                                            "name": CLUSTER_CLASS_NAME,
                                        }
                                    },
                                },
                                "machineHealthCheck": {
                                    "maxUnhealthy": "33%",
                                    "unhealthyConditions": [
                                        {
                                            "type": "Ready",
                                            "status": "False",
                                            "timeout": "5m",
                                        },
                                        {
                                            "type": "Ready",
                                            "status": "Unknown",
                                            "timeout": "5m",
                                        },
                                    ],
                                },
                            }
                        ],
                    },
                    "variables": [
                        {
                            "name": "apiServerLoadBalancer",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "object",
                                    "required": ["enabled"],
                                    "properties": {
                                        "enabled": {
                                            "type": "boolean",
                                        },
                                    },
                                },
                            },
                        },
                        {
                            "name": "openidConnect",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "object",
                                    "required": [
                                        "issuerUrl",
                                        "clientId",
                                        "usernameClaim",
                                        "usernamePrefix",
                                        "groupsClaim",
                                        "groupsPrefix",
                                    ],
                                    "properties": {
                                        "issuerUrl": {
                                            "type": "string",
                                        },
                                        "clientId": {
                                            "type": "string",
                                        },
                                        "usernameClaim": {
                                            "type": "string",
                                        },
                                        "usernamePrefix": {
                                            "type": "string",
                                        },
                                        "groupsClaim": {
                                            "type": "string",
                                        },
                                        "groupsPrefix": {
                                            "type": "string",
                                        },
                                    },
                                },
                            },
                        },
                        {
                            "name": "auditLog",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "object",
                                    "required": [
                                        "enabled",
                                        "maxAge",
                                        "maxBackup",
                                        "maxSize",
                                    ],
                                    "properties": {
                                        "enabled": {
                                            "type": "boolean",
                                        },
                                        "maxAge": {
                                            "type": "string",
                                        },
                                        "maxBackup": {
                                            "type": "string",
                                        },
                                        "maxSize": {
                                            "type": "string",
                                        },
                                    },
                                },
                            },
                        },
                        {
                            "name": "bootVolume",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "object",
                                    "required": ["size"],
                                    "properties": {
                                        "size": {
                                            "type": "integer",
                                        },
                                        "type": {
                                            "type": "string",
                                        },
                                    },
                                },
                            },
                        },
                        {
                            "name": "clusterIdentityRef",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "object",
                                    "required": ["kind", "name"],
                                    "properties": {
                                        "kind": {
                                            "type": "string",
                                            "enum": [pykube.Secret.kind],
                                        },
                                        "name": {"type": "string"},
                                    },
                                },
                            },
                        },
                        {
                            "name": "cloudControllerManagerConfig",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "string",
                                },
                            },
                        },
                        {
                            "name": "containerdConfig",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "string",
                                },
                            },
                        },
                        {
                            "name": "controlPlaneFlavor",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "string",
                                },
                            },
                        },
                        {
                            "name": "disableAPIServerFloatingIP",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "boolean",
                                },
                            },
                        },
                        {
                            "name": "dnsNameservers",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "array",
                                    "items": {
                                        "type": "string",
                                    },
                                },
                            },
                        },
                        {
                            "name": "externalNetworkId",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "string",
                                },
                            },
                        },
                        {
                            "name": "fixedNetworkName",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "string",
                                },
                            },
                        },
                        {
                            "name": "fixedSubnetId",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "string",
                                },
                            },
                        },
                        {
                            "name": "flavor",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "string",
                                },
                            },
                        },
                        {
                            "name": "imageRepository",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "string",
                                },
                            },
                        },
                        {
                            "name": "imageUUID",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "string",
                                },
                            },
                        },
                        {
                            "name": "nodeCidr",
                            "required": True,
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "string",
                                },
                            },
                        },
                        {
                            "name": "sshKeyName",
                            "schema": {
                                "openAPIV3Schema": {
                                    "type": "string",
                                },
                            },
                        },
                    ],
                    "patches": [
                        {
                            "name": "auditLog",
                            "enabledIf": "{{ if .auditLog.enabled }}true{{end}}",
                            "definitions": [
                                {
                                    "selector": {
                                        "apiVersion": objects.KubeadmControlPlaneTemplate.version,
                                        "kind": objects.KubeadmControlPlaneTemplate.kind,
                                        "matchResources": {
                                            "controlPlane": True,
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/audit-log-path",  # noqa: E501
                                            "value": "/var/log/audit/kube-apiserver-audit.log",
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/audit-log-maxage",  # noqa: E501
                                            "valueFrom": {
                                                "variable": "auditLog.maxAge",
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/audit-log-maxbackup",  # noqa: E501
                                            "valueFrom": {
                                                "variable": "auditLog.maxBackup",
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/audit-log-maxsize",  # noqa: E501
                                            "valueFrom": {
                                                "variable": "auditLog.maxSize",
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/audit-policy-file",  # noqa: E501
                                            "value": "/etc/kubernetes/audit-policy/apiserver-audit-policy.yaml",
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraVolumes",  # noqa: E501
                                            "valueFrom": {
                                                "template": textwrap.dedent(
                                                    """\
                                                    - name: audit-policy
                                                      hostPath: /etc/kubernetes/audit-policy
                                                      mountPath: /etc/kubernetes/audit-policy
                                                    - name: audit-logs
                                                      hostPath: /var/log/kubernetes/audit
                                                      mountPath: /var/log/audit
                                                    """
                                                ),
                                            },
                                        },
                                    ],
                                }
                            ],
                        },
                        {
                            "name": "openidConnect",
                            "enabledIf": "{{ if .openidConnect.issuerUrl }}true{{end}}",
                            "definitions": [
                                {
                                    "selector": {
                                        "apiVersion": objects.KubeadmControlPlaneTemplate.version,
                                        "kind": objects.KubeadmControlPlaneTemplate.kind,
                                        "matchResources": {
                                            "controlPlane": True,
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-issuer-url",  # noqa: E501
                                            "valueFrom": {
                                                "variable": "openidConnect.issuerUrl",
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-client-id",  # noqa: E501
                                            "valueFrom": {
                                                "variable": "openidConnect.clientId",
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-username-claim",  # noqa: E501
                                            "valueFrom": {
                                                "variable": "openidConnect.usernameClaim",
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-username-prefix",  # noqa: E501
                                            "valueFrom": {
                                                "variable": "openidConnect.usernamePrefix",
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-groups-claim",  # noqa: E501
                                            "valueFrom": {
                                                "variable": "openidConnect.groupsClaim",
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/extraArgs/oidc-groups-prefix",  # noqa: E501
                                            "valueFrom": {
                                                "variable": "openidConnect.groupsPrefix",
                                            },
                                        },
                                    ],
                                }
                            ],
                        },
                        {
                            "name": "bootVolume",
                            "enabledIf": "{{ if gt .bootVolume.size 0.0 }}true{{end}}",
                            "definitions": [
                                {
                                    "selector": {
                                        "apiVersion": objects.OpenStackMachineTemplate.version,
                                        "kind": objects.OpenStackMachineTemplate.kind,
                                        "matchResources": {
                                            "controlPlane": True,
                                            "machineDeploymentClass": {
                                                "names": ["default-worker"],
                                            },
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/rootVolume",
                                            "valueFrom": {
                                                "template": textwrap.dedent(
                                                    """\
                                                    diskSize: {{ .bootVolume.size }}
                                                    volumeType: {{ .bootVolume.type }}
                                                    """
                                                ),
                                            },
                                        },
                                    ],
                                }
                            ],
                        },
                        {
                            "name": "clusterConfig",
                            "definitions": [
                                {
                                    "selector": {
                                        "apiVersion": objects.OpenStackMachineTemplate.version,
                                        "kind": objects.OpenStackMachineTemplate.kind,
                                        "matchResources": {
                                            "controlPlane": True,
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/flavor",
                                            "valueFrom": {
                                                "variable": "controlPlaneFlavor",
                                            },
                                        },
                                    ],
                                },
                                {
                                    "selector": {
                                        "apiVersion": objects.OpenStackMachineTemplate.version,
                                        "kind": objects.OpenStackMachineTemplate.kind,
                                        "matchResources": {
                                            "machineDeploymentClass": {
                                                "names": ["default-worker"],
                                            },
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/flavor",
                                            "valueFrom": {
                                                "variable": "flavor",
                                            },
                                        },
                                    ],
                                },
                                {
                                    "selector": {
                                        "apiVersion": objects.OpenStackMachineTemplate.version,
                                        "kind": objects.OpenStackMachineTemplate.kind,
                                        "matchResources": {
                                            "controlPlane": True,
                                            "machineDeploymentClass": {
                                                "names": ["default-worker"],
                                            },
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/identityRef",
                                            "valueFrom": {
                                                "variable": "clusterIdentityRef"
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/sshKeyName",
                                            "valueFrom": {"variable": "sshKeyName"},
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/imageUUID",
                                            "valueFrom": {"variable": "imageUUID"},
                                        },
                                    ],
                                },
                                {
                                    "selector": {
                                        "apiVersion": objects.OpenStackClusterTemplate.version,
                                        "kind": objects.OpenStackClusterTemplate.kind,
                                        "matchResources": {
                                            "infrastructureCluster": True,
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/apiServerLoadBalancer",
                                            "valueFrom": {
                                                "variable": "apiServerLoadBalancer"
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/identityRef",
                                            "valueFrom": {
                                                "variable": "clusterIdentityRef"
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/disableAPIServerFloatingIP",
                                            "valueFrom": {
                                                "variable": "disableAPIServerFloatingIP"
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/dnsNameservers",
                                            "valueFrom": {"variable": "dnsNameservers"},
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/externalNetworkId",
                                            "valueFrom": {
                                                "variable": "externalNetworkId"
                                            },
                                        },
                                    ],
                                },
                            ],
                        },
                        {
                            "name": "newNetworkConfig",
                            "enabledIf": '{{ if eq .fixedNetworkName "" }}true{{end}}',
                            "definitions": [
                                {
                                    "selector": {
                                        "apiVersion": objects.OpenStackClusterTemplate.version,
                                        "kind": objects.OpenStackClusterTemplate.kind,
                                        "matchResources": {
                                            "infrastructureCluster": True,
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/nodeCidr",
                                            "valueFrom": {"variable": "nodeCidr"},
                                        },
                                    ],
                                },
                            ],
                        },
                        {
                            "name": "existingFixedNetworkNameConfig",
                            "enabledIf": '{{ if ne .fixedNetworkName "" }}true{{end}}',
                            "definitions": [
                                {
                                    "selector": {
                                        "apiVersion": objects.OpenStackClusterTemplate.version,
                                        "kind": objects.OpenStackClusterTemplate.kind,
                                        "matchResources": {
                                            "infrastructureCluster": True,
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/network/name",
                                            "valueFrom": {
                                                "variable": "fixedNetworkName"
                                            },
                                        },
                                    ],
                                },
                            ],
                        },
                        {
                            "name": "existingFixedSubnetIdConfig",
                            "enabledIf": '{{ if ne .fixedSubnetId "" }}true{{end}}',
                            "definitions": [
                                {
                                    "selector": {
                                        "apiVersion": objects.OpenStackClusterTemplate.version,
                                        "kind": objects.OpenStackClusterTemplate.kind,
                                        "matchResources": {
                                            "infrastructureCluster": True,
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/subnet/id",
                                            "valueFrom": {"variable": "fixedSubnetId"},
                                        },
                                    ],
                                },
                            ],
                        },
                        {
                            "name": "controlPlaneConfig",
                            "definitions": [
                                {
                                    "selector": {
                                        "apiVersion": objects.KubeadmControlPlaneTemplate.version,
                                        "kind": objects.KubeadmControlPlaneTemplate.kind,
                                        "matchResources": {
                                            "controlPlane": True,
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/files/-",
                                            "valueFrom": {
                                                "template": textwrap.dedent(
                                                    """\
                                                    path: "/etc/containerd/config.toml"
                                                    owner: "root:root"
                                                    permissions: "0644"
                                                    content: "{{ .containerdConfig }}"
                                                    encoding: "base64"
                                                    """
                                                )
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/imageRepository",  # noqa: E501
                                            "valueFrom": {
                                                "variable": "imageRepository",
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration/apiServer/certSANs",  # noqa: E501
                                            "valueFrom": {
                                                "template": textwrap.dedent(
                                                    """\
                                                    - {{ .builtin.cluster.name }}
                                                    - {{ .builtin.cluster.name }}.{{ .builtin.cluster.namespace }}
                                                    - {{ .builtin.cluster.name }}.{{ .builtin.cluster.namespace }}.svc
                                                    - {{ .builtin.cluster.name }}.{{ .builtin.cluster.namespace }}.svc.cluster.local # noqa: E501
                                                    """
                                                ),
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/kubeadmConfigSpec/files/-",
                                            "valueFrom": {
                                                "template": textwrap.dedent(
                                                    """\
                                                    path: "/etc/kubernetes/cloud.conf"
                                                    owner: "root:root"
                                                    permissions: "0600"
                                                    content: "{{ .cloudControllerManagerConfig }}"
                                                    encoding: "base64"
                                                    """
                                                ),
                                            },
                                        },
                                    ],
                                },
                                {
                                    "selector": {
                                        "apiVersion": objects.KubeadmConfigTemplate.version,
                                        "kind": objects.KubeadmConfigTemplate.kind,
                                        "matchResources": {
                                            "machineDeploymentClass": {
                                                "names": ["default-worker"],
                                            }
                                        },
                                    },
                                    "jsonPatches": [
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/clusterConfiguration",
                                            "valueFrom": {
                                                "template": textwrap.dedent(
                                                    """\
                                                    imageRepository: "{{ .imageRepository }}"
                                                    """
                                                ),
                                            },
                                        },
                                        {
                                            "op": "add",
                                            "path": "/spec/template/spec/files",
                                            "valueFrom": {
                                                "template": textwrap.dedent(
                                                    """\
                                                    - path: "/etc/kubernetes/cloud.conf"
                                                      owner: "root:root"
                                                      permissions: "0600"
                                                      content: "{{ .cloudControllerManagerConfig }}"
                                                      encoding: "base64"
                                                    - path: "/etc/containerd/config.toml"
                                                      owner: "root:root"
                                                      permissions: "0644"
                                                      content: "{{ .containerdConfig }}"
                                                      encoding: "base64"
                                                """
                                                ),
                                            },
                                        },
                                    ],
                                },
                            ],
                        },
                    ],
                },
            },
        )


def create_cluster_class(
    api: pykube.HTTPClient,
) -> ClusterClass:
    """
    Create a ClusterClass and all of it's supporting resources from a Magnum
    cluster template using server-side apply.
    """

    KubeadmControlPlaneTemplate(api).apply()
    KubeadmConfigTemplate(api).apply()
    OpenStackMachineTemplate(api).apply()
    OpenStackClusterTemplate(api).apply()
    ClusterClass(api).apply()


def generate_machine_deployments_for_cluster(
    context: context.RequestContext, cluster: objects.Cluster
) -> list:
    auto_scaling_enabled = utils.get_auto_scaling_enabled(cluster)
    return [
        {
            "class": "default-worker",
            "name": ng.name,
            "replicas": None if auto_scaling_enabled else ng.node_count,
            "metadata": {
                "annotations": {
                    AUTOSCALE_ANNOTATION_MIN: f"{utils.get_node_group_min_node_count(ng)}",  # noqa: E501
                    AUTOSCALE_ANNOTATION_MAX: f"{utils.get_node_group_max_node_count(context, ng)}",  # noqa: E501
                }
            }
            if auto_scaling_enabled
            else {},
            "failureDomain": utils.get_cluster_label(cluster, "availability_zone", ""),
            "machineHealthCheck": {
                "enable": utils.get_cluster_label_as_bool(
                    cluster, "auto_healing_enabled", True
                )
            },
            "variables": {
                "overrides": [
                    {
                        "name": "bootVolume",
                        "value": {
                            "size": utils.get_node_group_label_as_int(
                                context,
                                ng,
                                "boot_volume_size",
                                CONF.cinder.default_boot_volume_size,
                            ),
                            "type": utils.get_node_group_label(
                                context,
                                ng,
                                "boot_volume_type",
                                cinder.get_default_boot_volume_type(context),
                            ),
                        },
                    },
                    {
                        "name": "flavor",
                        "value": ng.flavor_id,
                    },
                    {
                        "name": "imageRepository",
                        "value": utils.get_node_group_label(
                            context,
                            ng,
                            "container_infra_prefix",
                            "quay.io/vexxhost",
                        ),
                    },
                    {
                        "name": "imageUUID",
                        "value": ng.image_id,
                    },
                ],
            },
        }
        for ng in cluster.nodegroups
        if ng.role != "master" and not ng.status.startswith("DELETE")
    ]


class Cluster(ClusterBase):
    def __init__(
        self,
        context: context.RequestContext,
        api: pykube.HTTPClient,
        cluster: magnum_objects.Cluster,
    ):
        self.context = context
        self.api = api
        self.cluster = cluster

    @property
    def labels(self) -> dict:
        ccm_version = utils.get_cluster_label(
            self.cluster, "cloud_provider_tag", CLOUD_PROVIDER_TAG
        )
        cni_version = utils.get_cluster_label(self.cluster, "calico_tag", CALICO_TAG)
        labels = {
            "cni": f"calico-{cni_version}",
            "ccm": f"openstack-cloud-controller-manager-{ccm_version}",
        }

        if utils.is_cinder_csi_enabled(self.cluster):
            csi_version = utils.get_cluster_label(
                self.cluster, "cinder_csi_plugin_tag", CINDER_CSI_TAG
            )
            labels["csi"] = "cinder"
            labels["cinder-csi-version"] = csi_version

        if utils.is_manila_csi_enabled(self.cluster):
            manila_version = utils.get_cluster_label(
                self.cluster, "manila_csi_plugin_tag", MANILA_CSI_TAG
            )
            labels["manila-csi-version"] = manila_version

        return {**super().labels, **labels}

    def get_or_none(self) -> objects.Cluster:
        return objects.Cluster.objects(self.api, namespace="magnum-system").get_or_none(
            name=self.cluster.stack_id
        )

    def get_observed_generation(self) -> int:
        capi_cluster = self.get_or_none()
        if capi_cluster:
            return capi_cluster.obj["status"]["observedGeneration"]
        raise Exception("Cluster doesn't exists.")

    def get_object(self) -> objects.Cluster:
        return objects.Cluster(
            self.api,
            {
                "apiVersion": objects.Cluster.version,
                "kind": objects.Cluster.kind,
                "metadata": {
                    "name": self.cluster.stack_id,
                    "namespace": "magnum-system",
                    "labels": self.labels,
                },
                "spec": {
                    "clusterNetwork": {
                        "serviceDomain": utils.get_cluster_label(
                            self.cluster,
                            "dns_cluster_domain",
                            "cluster.local",
                        ),
                        "pods": {
                            "cidrBlocks": [
                                utils.get_cluster_label(
                                    self.cluster,
                                    "calico_ipv4pool",
                                    "10.100.0.0/16",
                                )
                            ],
                        },
                        "services": {
                            "cidrBlocks": [
                                utils.get_cluster_label(
                                    self.cluster,
                                    "service_cluster_ip_range",
                                    "10.254.0.0/16",
                                )
                            ],
                        },
                    },
                    "topology": {
                        "class": CLUSTER_CLASS_NAME,
                        "version": utils.get_kube_tag(self.cluster),
                        "controlPlane": {
                            "replicas": self.cluster.master_count,
                            "machineHealthCheck": {
                                "enable": utils.get_cluster_label_as_bool(
                                    self.cluster, "auto_healing_enabled", True
                                )
                            },
                        },
                        "workers": {
                            "machineDeployments": generate_machine_deployments_for_cluster(
                                self.context, self.cluster
                            ),
                        },
                        "variables": [
                            {
                                "name": "apiServerLoadBalancer",
                                "value": {
                                    "enabled": self.cluster.master_lb_enabled,
                                },
                            },
                            {
                                "name": "openidConnect",
                                "value": {
                                    "clientId": utils.get_cluster_label(
                                        self.cluster, "oidc_client_id", ""
                                    ),
                                    "groupsClaim": utils.get_cluster_label(
                                        self.cluster, "oidc_groups_claim", ""
                                    ),
                                    "groupsPrefix": utils.get_cluster_label(
                                        self.cluster, "oidc_groups_prefix", ""
                                    ),
                                    "issuerUrl": utils.get_cluster_label(
                                        self.cluster, "oidc_issuer_url", ""
                                    ),
                                    "usernameClaim": utils.get_cluster_label(
                                        self.cluster, "oidc_username_claim", "sub"
                                    ),
                                    "usernamePrefix": utils.get_cluster_label(
                                        self.cluster, "oidc_username_prefix", "-"
                                    ),
                                },
                            },
                            {
                                "name": "auditLog",
                                "value": {
                                    "enabled": utils.get_cluster_label_as_bool(
                                        self.cluster, "audit_log_enabled", False
                                    ),
                                    "maxAge": utils.get_cluster_label(
                                        self.cluster, "audit_log_max_age", "30"
                                    ),
                                    "maxBackup": utils.get_cluster_label(
                                        self.cluster, "audit_log_max_backup", "10"
                                    ),
                                    "maxSize": utils.get_cluster_label(
                                        self.cluster, "audit_log_max_size", "100"
                                    ),
                                },
                            },
                            {
                                "name": "bootVolume",
                                "value": {
                                    "size": utils.get_cluster_label_as_int(
                                        self.cluster,
                                        "boot_volume_size",
                                        CONF.cinder.default_boot_volume_size,
                                    ),
                                    "type": utils.get_cluster_label(
                                        self.cluster,
                                        "boot_volume_type",
                                        cinder.get_default_boot_volume_type(
                                            self.context
                                        ),
                                    ),
                                },
                            },
                            {
                                "name": "clusterIdentityRef",
                                "value": {
                                    "kind": pykube.Secret.kind,
                                    "name": utils.get_or_generate_cluster_api_cloud_config_secret_name(
                                        self.api, self.cluster
                                    ),
                                },
                            },
                            {
                                "name": "cloudControllerManagerConfig",
                                "value": base64.encode_as_text(
                                    utils.generate_cloud_controller_manager_config(
                                        self.api, self.cluster
                                    )
                                ),
                            },
                            {
                                "name": "containerdConfig",
                                "value": base64.encode_as_text(
                                    utils.generate_containerd_config(self.cluster)
                                ),
                            },
                            {
                                "name": "controlPlaneFlavor",
                                "value": self.cluster.master_flavor_id,
                            },
                            {
                                "name": "disableAPIServerFloatingIP",
                                "value": utils.get_cluster_floating_ip_disabled(
                                    self.cluster
                                ),
                            },
                            {
                                "name": "dnsNameservers",
                                "value": self.cluster.cluster_template.dns_nameserver.split(
                                    ","
                                ),
                            },
                            {
                                "name": "externalNetworkId",
                                "value": neutron.get_external_network_id(
                                    self.context,
                                    self.cluster.cluster_template.external_network_id,
                                ),
                            },
                            {
                                "name": "fixedNetworkName",
                                "value": neutron.get_fixed_network_name(
                                    self.context, self.cluster.fixed_network
                                )
                                or "",
                            },
                            {
                                "name": "fixedSubnetId",
                                "value": neutron.get_fixed_subnet_id(
                                    self.context, self.cluster.fixed_subnet
                                )
                                or "",
                            },
                            {
                                "name": "flavor",
                                "value": self.cluster.flavor_id,
                            },
                            {
                                "name": "imageRepository",
                                "value": utils.get_cluster_container_infra_prefix(
                                    self.cluster,
                                ),
                            },
                            {
                                "name": "imageUUID",
                                "value": self.cluster.default_ng_master.image_id,
                            },
                            {
                                "name": "nodeCidr",
                                "value": utils.get_cluster_label(
                                    self.cluster,
                                    "fixed_subnet_cidr",
                                    "10.0.0.0/24",
                                ),
                            },
                            {
                                "name": "sshKeyName",
                                "value": self.cluster.keypair or "",
                            },
                        ],
                    },
                },
            },
        )

    def delete(self):
        capi_cluster = self.get_or_none()
        if capi_cluster:
            capi_cluster.delete()


def set_autoscaler_metadata_in_machinedeployment(
    context: context.RequestContext,
    api: pykube.HTTPClient,
    cluster: magnum_objects.Cluster,
    nodegroup: magnum_objects.NodeGroup,
):
    if not utils.get_auto_scaling_enabled(cluster):
        return
    mds = objects.MachineDeployment.objects(api).filter(
        namespace="magnum-system",
        selector={
            "cluster.x-k8s.io/cluster-name": cluster.stack_id,
            "topology.cluster.x-k8s.io/deployment-name": nodegroup.name,
        },
    )
    for md in mds:
        # NOTE(mnaser): The autoscaler will not scale under the minimum number
        #               of nodes, so we do that ourselves here.
        if AUTOSCALE_ANNOTATION_MIN not in md.obj["metadata"]["annotations"]:
            md.obj["spec"]["replicas"] = nodegroup.node_count
        md.obj["metadata"]["annotations"][AUTOSCALE_ANNOTATION_MIN] = str(
            utils.get_node_group_min_node_count(nodegroup)
        )
        md.obj["metadata"]["annotations"][AUTOSCALE_ANNOTATION_MAX] = str(
            utils.get_node_group_max_node_count(context, nodegroup)
        )
        md.update()


def apply_cluster_from_magnum_cluster(
    context: context.RequestContext,
    api: pykube.HTTPClient,
    cluster: magnum_objects.Cluster,
    cluster_template: magnum_objects.ClusterTemplate = None,
) -> objects.Cluster:
    """
    Create a ClusterAPI cluster given a Magnum Cluster object.
    """
    create_cluster_class(api)

    if cluster_template is None:
        cluster_template = cluster.cluster_template

    # NOTE(mnaser): When using Cluster API, there is a 1:1 mapping between image
    #               and version of Kubernetes, therefore, we need to ignore the
    #               `image_id` field, as well as copy over any tags relating to
    #               the Kubernetes version.
    #
    #               I hate this.
    for label in CLUSTER_UPGRADE_LABELS:
        cluster.labels[label] = cluster_template.labels[label]
        for ng in cluster.nodegroups:
            ng.image_id = cluster_template.image_id
            ng.labels[label] = cluster_template.labels[label]
            ng.save()
    cluster.save()

    ClusterResourcesConfigMap(context, api, cluster).apply()
    ClusterResourceSet(api, cluster).apply()
    Cluster(context, api, cluster).apply()
    if utils.get_auto_scaling_enabled(cluster):
        ClusterAutoscalerHelmRelease(api, cluster).apply()


def get_kubeadm_control_plane(
    api: pykube.HTTPClient, cluster: magnum_objects.Cluster
) -> objects.KubeadmControlPlane:
    kcps = objects.KubeadmControlPlane.objects(api, namespace="magnum-system").filter(
        selector={
            "cluster.x-k8s.io/cluster-name": cluster.stack_id,
        },
    )
    if len(kcps) == 1:
        return list(kcps)[0]
    return None


def get_machine_deployment(
    api: pykube.HTTPClient,
    cluster: magnum_objects.Cluster,
    node_group: magnum_objects.NodeGroup,
) -> objects.KubeadmControlPlane:
    mds = objects.MachineDeployment.objects(api, namespace="magnum-system").filter(
        selector={
            "cluster.x-k8s.io/cluster-name": cluster.stack_id,
            "topology.cluster.x-k8s.io/deployment-name": node_group.name,
        },
    )
    if len(mds) == 1:
        return list(mds)[0]
    return None
