diff --git a/magnum_capi_helm/common/capi_monitor.py b/magnum_capi_helm/common/capi_monitor.py index aaec45d..d543b6f 100644 --- a/magnum_capi_helm/common/capi_monitor.py +++ b/magnum_capi_helm/common/capi_monitor.py @@ -156,7 +156,7 @@ class CAPIMonitor(monitors.MonitorBase): resource_name = driver_utils.get_k8s_resource_name( self.cluster, "control-plane" ) - resource_kcp = self._k8s_client.get_kubeadm_control_plane( + resource_kcp = self._k8s_client.get_k8s_control_plane( resource_name, namespace ) if not resource_kcp: diff --git a/magnum_capi_helm/conf.py b/magnum_capi_helm/conf.py index efcd770..9fe56f0 100644 --- a/magnum_capi_helm/conf.py +++ b/magnum_capi_helm/conf.py @@ -130,6 +130,40 @@ capi_helm_opts = [ "generated application credentials." ), ), + cfg.StrOpt( + "api_resources", + default={}, + help=( + """ + Dictionary of cluster api resources to modify + api_version and plural names in string format. + + "Example:" + '{ + "K8sControlPlane": { + "api_version": "controlplane.cluster.x-k8s.io/v1beta1", + "plural_name": "kubeadmcontrolplanes" + }, + "OpenstackCluster": { + "api_version": "infrastructure.cluster.x-k8s.io/v1beta1", + }, + }' + """ + ), + ), + cfg.ListOpt( + "k8s_control_plane_resource_conditions", + default=[ + "MachinesReady", + "Ready", + "EtcdClusterHealthy", + "ControlPlaneComponentsHealthy", + ], + help=( + "List of conditions to check for kubernetes control plane " + "resource to consider as ready." + ), + ), ] CONF = cfg.CONF diff --git a/magnum_capi_helm/driver.py b/magnum_capi_helm/driver.py index 29e6da6..d169842 100644 --- a/magnum_capi_helm/driver.py +++ b/magnum_capi_helm/driver.py @@ -82,7 +82,7 @@ class Driver(driver.Driver): def _update_control_plane_nodegroup_status(self, cluster, nodegroup): # The status of the master nodegroup is determined by the Cluster API # control plane object - kcp = self._k8s_client.get_kubeadm_control_plane( + kcp = self._k8s_client.get_k8s_control_plane( driver_utils.get_k8s_resource_name(cluster, "control-plane"), driver_utils.cluster_namespace(cluster), ) @@ -108,12 +108,7 @@ class Driver(driver.Driver): } kcp_ready = all( cond in kcp_true_conditions - for cond in ( - "MachinesReady", - "Ready", - "EtcdClusterHealthy", - "ControlPlaneComponentsHealthy", - ) + for cond in CONF.capi_helm.k8s_control_plane_resource_conditions ) target_replicas = kcp_spec.get("replicas") current_replicas = kcp_status.get("replicas") diff --git a/magnum_capi_helm/kubernetes.py b/magnum_capi_helm/kubernetes.py index 212890b..87576a3 100644 --- a/magnum_capi_helm/kubernetes.py +++ b/magnum_capi_helm/kubernetes.py @@ -12,6 +12,7 @@ import base64 import copy +import json import os import pathlib import re @@ -171,8 +172,8 @@ class Client(requests.Session): def get_capi_openstackcluster(self, name, namespace): return OpenstackCluster(self).fetch(name, namespace) - def get_kubeadm_control_plane(self, name, namespace): - return KubeadmControlPlane(self).fetch(name, namespace) + def get_k8s_control_plane(self, name, namespace): + return K8sControlPlane(self).fetch(name, namespace) def get_machine_deployment(self, name, namespace): return MachineDeployment(self).fetch(name, namespace) @@ -201,6 +202,7 @@ class Resource: self, "plural_name", self.kind.lower() + "s" ) self.namespaced = getattr(self, "namespaced", True) + self.api_resources = json.loads(CONF.capi_helm.api_resources) def prepare_path(self, name=None, namespace=None): # Begin with either /api or /apis depending whether the api version @@ -287,29 +289,62 @@ class Secret(Resource): class Cluster(Resource): - api_version = "cluster.x-k8s.io/v1beta1" + api_version = ( + json.loads(CONF.capi_helm.api_resources) + .get("Cluster", {}) + .get("api_version", "cluster.x-k8s.io/v1beta1") + ) class OpenstackCluster(Resource): - api_version = "infrastructure.cluster.x-k8s.io/v1beta1" + api_version = ( + json.loads(CONF.capi_helm.api_resources) + .get("OpenstackCluster", {}) + .get("api_version", "infrastructure.cluster.x-k8s.io/v1beta1") + ) class MachineDeployment(Resource): - api_version = "cluster.x-k8s.io/v1beta1" + api_version = ( + json.loads(CONF.capi_helm.api_resources) + .get("MachineDeployment", {}) + .get("api_version", "cluster.x-k8s.io/v1beta1") + ) -class KubeadmControlPlane(Resource): - api_version = "controlplane.cluster.x-k8s.io/v1beta1" +class K8sControlPlane(Resource): + api_version = ( + json.loads(CONF.capi_helm.api_resources) + .get("K8sControlPlane", {}) + .get("api_version", "controlplane.cluster.x-k8s.io/v1beta1") + ) + plural_name = ( + json.loads(CONF.capi_helm.api_resources) + .get("K8sControlPlane", {}) + .get("plural_name", "kubeadmcontrolplanes") + ) class Machine(Resource): - api_version = "cluster.x-k8s.io/v1beta1" + api_version = ( + json.loads(CONF.capi_helm.api_resources) + .get("Machine", {}) + .get("api_version", "cluster.x-k8s.io/v1beta1") + ) class Manifests(Resource): - api_version = "addons.stackhpc.com/v1alpha1" + api_version = ( + json.loads(CONF.capi_helm.api_resources) + .get("Manifests", {}) + .get("api_version", "addons.stackhpc.com/v1alpha1") + ) plural_name = "manifests" class HelmRelease(Resource): - api_version = "addons.stackhpc.com/v1alpha1" + api_version = ( + json.loads(CONF.capi_helm.api_resources) + .get("HelmRelease", {}) + .get("api_version", "addons.stackhpc.com/v1alpha1") + ) diff --git a/magnum_capi_helm/tests/common/test_capi_monitor.py b/magnum_capi_helm/tests/common/test_capi_monitor.py index 899831f..2670c6c 100644 --- a/magnum_capi_helm/tests/common/test_capi_monitor.py +++ b/magnum_capi_helm/tests/common/test_capi_monitor.py @@ -55,7 +55,7 @@ class TestCAPIMonitor(base.DbTestCase): "ready": True, } } - self.mock_k8s.get_kubeadm_control_plane.return_value = copy.deepcopy( + self.mock_k8s.get_k8s_control_plane.return_value = copy.deepcopy( ready_state ) self.mock_k8s.get_machine_deployment.return_value = copy.deepcopy( @@ -193,7 +193,7 @@ class TestCAPIMonitor(base.DbTestCase): ] } } - self.mock_k8s.get_kubeadm_control_plane.return_value = cp_state + self.mock_k8s.get_k8s_control_plane.return_value = cp_state self.monitor.poll_health_status() self.assertEqual( @@ -264,7 +264,7 @@ class TestCAPIMonitor(base.DbTestCase): def test_all_missing(self): self.mock_k8s.get_capi_cluster.return_value = None self.mock_k8s.get_capi_openstackcluster.return_value = None - self.mock_k8s.get_kubeadm_control_plane.return_value = None + self.mock_k8s.get_k8s_control_plane.return_value = None self.mock_k8s.get_machine_deployment.return_value = None self.monitor.poll_health_status() diff --git a/magnum_capi_helm/tests/test_driver.py b/magnum_capi_helm/tests/test_driver.py index 63a574a..7a8ba9b 100644 --- a/magnum_capi_helm/tests/test_driver.py +++ b/magnum_capi_helm/tests/test_driver.py @@ -413,13 +413,13 @@ class ClusterAPIDriverTest(base.DbTestCase): mock_load.return_value = mock_client nodegroup = mock.MagicMock() nodegroup.name = "masters" - mock_client.get_kubeadm_control_plane.return_value = None + mock_client.get_k8s_control_plane.return_value = None self.driver._update_control_plane_nodegroup_status( self.cluster_obj, nodegroup ) - mock_client.get_kubeadm_control_plane.assert_called_once_with( + mock_client.get_k8s_control_plane.assert_called_once_with( "cluster-example-a-111111111111-control-plane", "magnum-fakeproject", ) @@ -455,13 +455,13 @@ class ClusterAPIDriverTest(base.DbTestCase): "readyReplicas": 3, }, } - mock_client.get_kubeadm_control_plane.return_value = kcp + mock_client.get_k8s_control_plane.return_value = kcp self.driver._update_control_plane_nodegroup_status( self.cluster_obj, nodegroup ) - mock_client.get_kubeadm_control_plane.assert_called_once_with( + mock_client.get_k8s_control_plane.assert_called_once_with( "cluster-example-a-111111111111-control-plane", "magnum-fakeproject", ) @@ -497,13 +497,13 @@ class ClusterAPIDriverTest(base.DbTestCase): "readyReplicas": 2, }, } - mock_client.get_kubeadm_control_plane.return_value = kcp + mock_client.get_k8s_control_plane.return_value = kcp self.driver._update_control_plane_nodegroup_status( self.cluster_obj, nodegroup ) - mock_client.get_kubeadm_control_plane.assert_called_once_with( + mock_client.get_k8s_control_plane.assert_called_once_with( "cluster-example-a-111111111111-control-plane", "magnum-fakeproject", ) @@ -539,13 +539,13 @@ class ClusterAPIDriverTest(base.DbTestCase): "readyReplicas": 3, }, } - mock_client.get_kubeadm_control_plane.return_value = kcp + mock_client.get_k8s_control_plane.return_value = kcp self.driver._update_control_plane_nodegroup_status( self.cluster_obj, nodegroup ) - mock_client.get_kubeadm_control_plane.assert_called_once_with( + mock_client.get_k8s_control_plane.assert_called_once_with( "cluster-example-a-111111111111-control-plane", "magnum-fakeproject", ) diff --git a/magnum_capi_helm/tests/test_kubernetes.py b/magnum_capi_helm/tests/test_kubernetes.py index 2591164..7f4d47c 100644 --- a/magnum_capi_helm/tests/test_kubernetes.py +++ b/magnum_capi_helm/tests/test_kubernetes.py @@ -301,14 +301,14 @@ class TestKubernetesClient(base.TestCase): ) @mock.patch.object(requests.Session, "request") - def test_get_kubeadm_control_plane_found(self, mock_request): + def test_get_k8s_control_plane_found(self, mock_request): client = kubernetes.Client(TEST_KUBECONFIG) mock_response = mock.MagicMock() mock_response.status_code = 200 mock_response.json.return_value = "mock_json" mock_request.return_value = mock_response - cluster = client.get_kubeadm_control_plane("name", "ns1") + cluster = client.get_k8s_control_plane("name", "ns1") mock_request.assert_called_once_with( "GET", diff --git a/releasenotes/notes/generalize-api-resources-e3b9f1606a51fb6f.yaml b/releasenotes/notes/generalize-api-resources-e3b9f1606a51fb6f.yaml new file mode 100644 index 0000000..c5f3671 --- /dev/null +++ b/releasenotes/notes/generalize-api-resources-e3b9f1606a51fb6f.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + Adds new configuration parameters to update api_version and plural names + of k8s resources related to Cluster API. To be specific, the resources + are Cluster, OpenstackCluster, MachineDeployment, K8sControlPlane, + Machine, Manifests, HelmRelease. + + Adds new configuration parameter to specify list of conditions to check + in kubernetes control plane resource to consider resource as ready.