[openstack-hypervisor] Add action list-gpus

Add action list-gpus to retrieve any GPUs
from openstack-hypervisor snap

Change-Id: I021547c1c951375bce3c6ecfbd7e1c2132e6f3cc
Signed-off-by: Hemanth Nakkina <hemanth.nakkina@canonical.com>
This commit is contained in:
Hemanth Nakkina
2025-10-08 10:28:20 +05:30
parent 14036120de
commit 4f1796c862
3 changed files with 76 additions and 0 deletions

View File

@@ -164,6 +164,10 @@ actions:
description: |
List host NICS, and which one are candidates for use as external NIC.
additionalProperties: false
list-gpus:
description: |
List host GPUs
additionalProperties: false
disable:
description: |
Prevent new instances from being created.

View File

@@ -206,6 +206,10 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
self.on.list_nics_action,
self._list_nics_action,
)
self.framework.observe(
self.on.list_gpus_action,
self._list_gpus_action,
)
self.framework.observe(
self.on.enable_action,
self._enable_action,
@@ -451,6 +455,17 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
# cli returns a json dict with keys "nics" and "candidate"
event.set_results({"result": stdout})
def _list_gpus_action(self, event: ActionEvent):
"""Run list_gpus action."""
try:
stdout = self._hypervisor_cli_cmd("list-gpus --format json")
except HypervisorError as e:
event.fail(str(e))
return
# cli returns a json dict with keys "gpus"
event.set_results({"result": stdout})
def _enable_action(self, event: ActionEvent):
"""Run enable action."""
try:

View File

@@ -353,6 +353,8 @@ class TestCharm(test_utils.CharmTestCase):
}
with self.assertRaises(ops.testing.ActionFailed):
self.harness.run_action("list-nics")
with self.assertRaises(ops.testing.ActionFailed):
self.harness.run_action("list-gpus")
def test_list_nics(self):
"""Check action returns nics."""
@@ -399,6 +401,61 @@ class TestCharm(test_utils.CharmTestCase):
with self.assertRaises(ops.testing.ActionFailed):
self.harness.run_action("list-nics")
def test_list_gpus(self):
"""Check action returns gpus."""
self.harness.begin()
hypervisor_snap_mock = MagicMock()
hypervisor_snap_mock.present = True
epa_orchestrator_snap_mock = MagicMock()
epa_orchestrator_snap_mock.present = False
self.snap.SnapCache.return_value = {
"openstack-hypervisor": hypervisor_snap_mock,
"epa-orchestrator": epa_orchestrator_snap_mock,
}
subprocess_run_mock = MagicMock()
subprocess_run_mock.return_value = MagicMock(
stdout=bytes(
json.dumps(
{
"gpus": [
{
"pci_address": "0000:09:00.0",
"product_id": "0x0534",
"vendor_id": "0x102b",
}
]
}
),
"utf-8",
),
stderr=b"yes things went well",
returncode=0,
)
self.subprocess.run = subprocess_run_mock
action_output = self.harness.run_action("list-gpus")
assert "gpus" in action_output.results["result"]
def test_list_gpus_error(self):
"""Check action raises ActionFailed if subprocess returns non-zero."""
self.harness.begin()
hypervisor_snap_mock = MagicMock()
hypervisor_snap_mock.present = True
epa_orchestrator_snap_mock = MagicMock()
epa_orchestrator_snap_mock.present = False
self.snap.SnapCache.return_value = {
"openstack-hypervisor": hypervisor_snap_mock,
"epa-orchestrator": epa_orchestrator_snap_mock,
}
subprocess_run_mock = MagicMock()
subprocess_run_mock.return_value = MagicMock(
stdout=b"",
stderr=b"things did not go well",
returncode=1,
)
self.subprocess.run = subprocess_run_mock
with self.assertRaises(ops.testing.ActionFailed):
self.harness.run_action("list-gpus")
def test_list_flavors(self):
"""Check action return flavors."""
flavors = "flavor1,flavor2"