Skip to content
This repository has been archived by the owner on Dec 5, 2024. It is now read-only.

Commit

Permalink
Add support for Flatcar OS (#22)
Browse files Browse the repository at this point in the history
Fetch os_distro metadata and pass to helm chart.

Depends on Helm chart flatcar support:
https://github.com/stackhpc/capi-helm-charts/pull/53
  • Loading branch information
dalees authored Nov 22, 2023
1 parent 2f50dbe commit b0765ea
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 15 deletions.
23 changes: 21 additions & 2 deletions magnum_capi_helm/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ def provides(self):
"os": "ubuntu",
"coe": "kubernetes",
},
{
"server_type": "vm",
"os": "flatcar",
"coe": "kubernetes",
},
]

def _update_control_plane_nodegroup_status(self, cluster, nodegroup):
Expand Down Expand Up @@ -502,12 +507,25 @@ def _get_kube_version(self, image):
# TODO(johngarbutt) more validation required?
return re.sub(r"[^0-9\.]+", "", raw)

def _get_os_distro(self, image):
os_distro = image.get("os_distro")
if not os_distro:
raise exception.MagnumException(
message=f"Image {image.id} does not "
"have an os_distro property."
)
return re.sub(r"[^a-zA-Z0-9\.\-\/ ]+", "", os_distro)

def _get_image_details(self, context, image_identifier):
osc = clients.OpenStackClients(context)
image = api_utils.get_openstack_resource(
osc.glance().images, image_identifier, "images"
)
return image.id, self._get_kube_version(image)
return (
image.id,
self._get_kube_version(image),
self._get_os_distro(image),
)

def _get_app_cred_name(self, cluster):
return self._sanitized_name(
Expand Down Expand Up @@ -547,7 +565,7 @@ def _update_helm_release(self, context, cluster, nodegroups=None):
if nodegroups is None:
nodegroups = cluster.nodegroups

image_id, kube_version = self._get_image_details(
image_id, kube_version, os_distro = self._get_image_details(
context, cluster.cluster_template.image_id
)

Expand Down Expand Up @@ -581,6 +599,7 @@ def _update_helm_release(self, context, cluster, nodegroups=None):
),
},
},
"osDistro": os_distro,
"controlPlane": {
"machineFlavor": cluster.master_flavor_id,
"machineCount": cluster.master_count,
Expand Down
126 changes: 113 additions & 13 deletions magnum_capi_helm/tests/test_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ def test_provides(self):
"server_type": "vm",
"os": "ubuntu",
"coe": "kubernetes",
}
},
{
"server_type": "vm",
"os": "flatcar",
"coe": "kubernetes",
},
],
self.driver.provides,
)
Expand Down Expand Up @@ -1017,24 +1022,61 @@ def test_get_kube_version_works(self):
self.assertEqual("1.27.9", result)
mock_image.get.assert_called_once_with("kube_version")

@mock.patch("magnum.common.clients.OpenStackClients")
@mock.patch("magnum.api.utils.get_openstack_resource")
def test_get_image_details(self, mock_get, mock_osc):
@mock.patch("magnum.common.clients.OpenStackClients", autospec=True)
@mock.patch("magnum.api.utils.get_openstack_resource", autospec=True)
def test_get_image_details_ubuntu(self, mock_get, mock_osc):
mock_image = mock.Mock()
mock_image.get.return_value = "v1.27.9"
image_metadata = {
"os_distro": "ubuntu",
"kube_version": "1.27.9",
}

def image_side_effect(arg):
return image_metadata[arg]

mock_image.get.side_effect = image_side_effect
mock_image.id = "myid"
mock_get.return_value = mock_image

id, version = self.driver._get_image_details(
id, version, distro = self.driver._get_image_details(
self.context, "myimagename"
)

self.assertEqual("1.27.9", version)
self.assertEqual("myid", id)
mock_image.get.assert_called_once_with("kube_version")
self.assertEqual("ubuntu", distro)
mock_image.get.assert_any_call("kube_version")
mock_image.get.assert_any_call("os_distro")
mock_get.assert_called_once_with(mock.ANY, "myimagename", "images")

@mock.patch("magnum.common.clients.OpenStackClients", autospec=True)
@mock.patch("magnum.api.utils.get_openstack_resource", autospec=True)
def test_get_image_details_flatcar(self, mock_get, mock_osc):
mock_image = mock.Mock()
image_metadata = {
"os_distro": "flatcar",
"kube_version": "1.28.2",
}

def image_side_effect(arg):
return image_metadata[arg]

mock_image.get.side_effect = image_side_effect
mock_image.id = "myid-flatcar"
mock_get.return_value = mock_image

id, version, distro = self.driver._get_image_details(
self.context, "myimagename"
)

self.assertEqual("1.28.2", version)
self.assertEqual("myid-flatcar", id)
self.assertEqual("flatcar", distro)
mock_image.get.assert_any_call("kube_version")
mock_image.get.assert_any_call("os_distro")
mock_get.assert_called_once_with(mock.ANY, "myimagename", "images")

def test_get_chart_release_name_lenght(self):
def test_get_chart_release_name_length(self):
self.cluster_obj.stack_id = "foo"

result = self.driver._get_chart_release_name(self.cluster_obj)
Expand Down Expand Up @@ -1137,6 +1179,7 @@ def get_cluster_helm_standard_values(self):
"machineCount": 3,
},
],
"osDistro": "ubuntu",
"machineSSHKeyName": None,
}

Expand All @@ -1155,7 +1198,11 @@ def test_create_cluster(
mock_certs,
mock_get_net,
):
mock_image.return_value = ("imageid1", "1.27.4")
mock_image.return_value = (
"imageid1",
"1.27.4",
"ubuntu",
)
mock_client = mock.MagicMock(spec=kubernetes.Client)
mock_load.return_value = mock_client
mock_get_net.side_effect = (
Expand Down Expand Up @@ -1194,7 +1241,7 @@ def test_create_cluster_no_dns(
mock_appcred,
mock_certs,
):
mock_image.return_value = ("imageid1", "1.27.4")
mock_image.return_value = ("imageid1", "1.27.4", "ubuntu")
mock_client = mock.MagicMock(spec=kubernetes.Client)
mock_load.return_value = mock_client

Expand All @@ -1205,6 +1252,9 @@ def test_create_cluster_no_dns(
expected_values = self.get_cluster_helm_standard_values()
expected_values["clusterNetworking"]["dnsNameservers"] = None

helm_install_values = mock_install.call_args[0][2]
self.assertDictEqual(helm_install_values, expected_values)

mock_install.assert_called_once_with(
"cluster-example-a-111111111111",
"openstack-cluster",
Expand Down Expand Up @@ -1234,7 +1284,7 @@ def test_create_cluster_boot_volume(
mock_appcred,
mock_certs,
):
mock_image.return_value = ("imageid1", "1.27.4")
mock_image.return_value = ("imageid1", "1.27.4", "ubuntu")
mock_client = mock.MagicMock(spec=kubernetes.Client)
mock_load.return_value = mock_client

Expand Down Expand Up @@ -1266,6 +1316,7 @@ def test_create_cluster_boot_volume(
"enableLoadBalancer": True,
"loadBalancerProvider": "amphora",
},
"osDistro": "ubuntu",
"controlPlane": {
"machineFlavor": "flavor_small",
"machineCount": 3,
Expand Down Expand Up @@ -1323,7 +1374,11 @@ def test_create_cluster_boot_volume_extra_network(
mock_appcred,
mock_certs,
):
mock_image.return_value = ("imageid1", "1.27.4")
mock_image.return_value = (
"imageid1",
"1.27.4",
"ubuntu",
)
mock_client = mock.MagicMock(spec=kubernetes.Client)
mock_load.return_value = mock_client

Expand Down Expand Up @@ -1357,6 +1412,7 @@ def test_create_cluster_boot_volume_extra_network(
"enableLoadBalancer": True,
"loadBalancerProvider": "amphora",
},
"osDistro": "ubuntu",
"controlPlane": {
"machineFlavor": "flavor_small",
"machineCount": 3,
Expand Down Expand Up @@ -1423,7 +1479,11 @@ def test_create_cluster_with_keypair(
mock_appcred,
mock_certs,
):
mock_image.return_value = ("imageid1", "1.27.4")
mock_image.return_value = (
"imageid1",
"1.27.4",
"ubuntu",
)
mock_client = mock.MagicMock(spec=kubernetes.Client)
mock_load.return_value = mock_client

Expand All @@ -1448,6 +1508,46 @@ def test_create_cluster_with_keypair(
mock_appcred.assert_called_once_with(self.context, self.cluster_obj)
mock_certs.assert_called_once_with(self.context, self.cluster_obj)

@mock.patch.object(driver.Driver, "_ensure_certificate_secrets")
@mock.patch.object(driver.Driver, "_create_appcred_secret")
@mock.patch.object(kubernetes.Client, "load")
@mock.patch.object(driver.Driver, "_get_image_details")
@mock.patch.object(helm.Client, "install_or_upgrade")
def test_create_cluster_flatcar(
self,
mock_install,
mock_image,
mock_load,
mock_appcred,
mock_certs,
):
mock_image.return_value = (
"imageid1",
"1.27.4",
"flatcar",
)
mock_client = mock.MagicMock(spec=kubernetes.Client)
mock_load.return_value = mock_client

self.driver.create_cluster(self.context, self.cluster_obj, 10)

expected_values = self.get_cluster_helm_standard_values()
expected_values["osDistro"] = "flatcar"

mock_install.assert_called_once_with(
"cluster-example-a-111111111111",
"openstack-cluster",
expected_values,
repo=CONF.capi_helm.helm_chart_repo,
version=CONF.capi_helm.default_helm_chart_version,
namespace="magnum-fakeproject",
)
mock_client.ensure_namespace.assert_called_once_with(
"magnum-fakeproject"
)
mock_appcred.assert_called_once_with(self.context, self.cluster_obj)
mock_certs.assert_called_once_with(self.context, self.cluster_obj)

@mock.patch.object(app_creds, "get_app_cred_string_data")
@mock.patch.object(kubernetes.Client, "load")
def test_create_appcred_secret(self, mock_load, mock_sd):
Expand Down
6 changes: 6 additions & 0 deletions magnum_capi_helm/tests/test_magnum_capi_helm.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,9 @@ class TestMagnumDriverLoads(base.TestCase):
def test_get_driver(self):
cluster_driver = common.Driver.get_driver("vm", "ubuntu", "kubernetes")
self.assertIsInstance(cluster_driver, driver.Driver)

def test_get_flatcar_driver(self):
cluster_driver = common.Driver.get_driver(
"vm", "flatcar", "kubernetes"
)
self.assertIsInstance(cluster_driver, driver.Driver)

0 comments on commit b0765ea

Please sign in to comment.