From 309ed5890c1e547032271bb45bc3d127b1323577 Mon Sep 17 00:00:00 2001 From: Hemanth Nakkina Date: Wed, 3 Sep 2025 07:12:29 +0530 Subject: [PATCH] Add support for HelmChartProxy resource Define HelmChartProxy resource and use the resource to get addons. Change-Id: I89999f43ea5676181a84639873323deb832830bd Signed-off-by: Hemanth Nakkina --- doc/source/user_docs/index.rst | 2 +- magnum_capi_helm/kubernetes.py | 30 +++++++++++++++++-- magnum_capi_helm/tests/test_kubernetes.py | 13 ++++++-- ...mchartproxy-resource-ad5dab507b219dfa.yaml | 14 +++++++++ 4 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 releasenotes/notes/add-helmchartproxy-resource-ad5dab507b219dfa.yaml diff --git a/doc/source/user_docs/index.rst b/doc/source/user_docs/index.rst index d3363a3..280206f 100644 --- a/doc/source/user_docs/index.rst +++ b/doc/source/user_docs/index.rst @@ -91,7 +91,7 @@ highlights these various components and their relationships: - A representation of the OpenStack cloud resources required by a single workload cluster. The `cluster-api-provider-openstack `_ (``capo-controller-manager`` in the above diagram) is responsible for reconciling the state of these resources using OpenStack API calls. The ``cluster-api-janitor`` also watches these CRDs to clean up any OpenStack resources left behind upon deletion of the workload cluster. - * **{helmrelease, manifests}.addons.stackhpc.com** + * **{helmrelease, manifests}.addons.stackhpc.com** & **helmchartproxy.addons.cluster.x-k8s.io** - A representation of a `Helm `_ release or plain Kubernetes manifest to be installed on a workload cluster. Installation and subsequent reconciliation are carried out by the `cluster-api-addon-provider `_. diff --git a/magnum_capi_helm/kubernetes.py b/magnum_capi_helm/kubernetes.py index 87576a3..c69d467 100644 --- a/magnum_capi_helm/kubernetes.py +++ b/magnum_capi_helm/kubernetes.py @@ -184,9 +184,26 @@ class Client(requests.Session): def get_helm_releases_by_label(self, labels, namespace): return list(HelmRelease(self).fetch_all_by_label(labels, namespace)) + def get_helm_chart_proxies_by_label(self, labels, namespace): + return list(HelmChartProxy(self).fetch_all_by_label(labels, namespace)) + def get_addons_by_label(self, labels, namespace): - addons = list(self.get_manifests_by_label(labels, namespace)) - addons.extend(self.get_helm_releases_by_label(labels, namespace)) + addons = [] + try: + addons.extend(self.get_helm_releases_by_label(labels, namespace)) + addons.extend(self.get_manifests_by_label(labels, namespace)) + except requests.exceptions.HTTPError as e: + if e.response.status_code != 404: + raise + + try: + addons.extend( + self.get_helm_chart_proxies_by_label(labels, namespace) + ) + except requests.exceptions.HTTPError as e: + if e.response.status_code != 404: + raise + return addons def get_all_machines_by_label(self, labels, namespace): @@ -348,3 +365,12 @@ class HelmRelease(Resource): .get("HelmRelease", {}) .get("api_version", "addons.stackhpc.com/v1alpha1") ) + + +class HelmChartProxy(Resource): + api_version = ( + json.loads(CONF.capi_helm.api_resources) + .get("HelmChartProxy", {}) + .get("api_version", "addons.cluster.x-k8s.io/v1alpha1") + ) + plural_name = "helmchartproxies" diff --git a/magnum_capi_helm/tests/test_kubernetes.py b/magnum_capi_helm/tests/test_kubernetes.py index 7f4d47c..264fba6 100644 --- a/magnum_capi_helm/tests/test_kubernetes.py +++ b/magnum_capi_helm/tests/test_kubernetes.py @@ -474,10 +474,14 @@ class TestKubernetesClient(base.TestCase): ) self.assertEqual(items, helm_releases) + @mock.patch.object(kubernetes.Client, "get_helm_chart_proxies_by_label") @mock.patch.object(kubernetes.Client, "get_helm_releases_by_label") @mock.patch.object(kubernetes.Client, "get_manifests_by_label") def test_get_addons_by_label( - self, mock_get_manifests, mock_get_helm_releases + self, + mock_get_manifests, + mock_get_helm_releases, + mock_get_helm_chart_proxies, ): manifests = [ { @@ -497,6 +501,11 @@ class TestKubernetesClient(base.TestCase): mock_get_manifests.return_value = manifests mock_get_helm_releases.return_value = helm_releases + mock_response = mock.MagicMock() + mock_response.status_code = 404 + mock_response.raise_for_status.side_effect = requests.HTTPError + mock_get_helm_chart_proxies.side_effect = mock_response + client = kubernetes.Client(TEST_KUBECONFIG) addons = client.get_addons_by_label({"label": "cluster1"}, "ns1") @@ -506,7 +515,7 @@ class TestKubernetesClient(base.TestCase): mock_get_helm_releases.assert_called_once_with( {"label": "cluster1"}, "ns1" ) - self.assertEqual(manifests + helm_releases, addons) + self.assertEqual(helm_releases + manifests, addons) @mock.patch.object(requests.Session, "request") def test_get_all_machines_by_label(self, mock_request): diff --git a/releasenotes/notes/add-helmchartproxy-resource-ad5dab507b219dfa.yaml b/releasenotes/notes/add-helmchartproxy-resource-ad5dab507b219dfa.yaml new file mode 100644 index 0000000..b5f04a6 --- /dev/null +++ b/releasenotes/notes/add-helmchartproxy-resource-ad5dab507b219dfa.yaml @@ -0,0 +1,14 @@ +--- +features: + - | + Add support for new resource HelmChartProxy. + + Users can manage addons on workload clusters as + part of magnum cluster operations by defining + HelmChartProxy resources in their CAPI helm chart [1]. + + Sample examples on how to define HelmChartProxy + resources are available in link [2]. + + [1] https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm + [2] https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm/tree/9d44995329945a318abd6b2ffd7bca7b526401a9/config/samples