[hypervisor] Add management actions to charm

Add management actions to hypervisor charm to allow enabling / disabling
the compute service, and get a list of running guests on that
hypervisor.

Change-Id: Ibea004be22462aff5a4d64704c67970af1b038d1
Signed-off-by: Guillaume Boutry <guillaume.boutry@canonical.com>
This commit is contained in:
Guillaume Boutry 2024-11-20 12:37:40 +01:00
parent 87364abd0e
commit 66a4ae378f
No known key found for this signature in database
GPG Key ID: E95E3326872E55DE
3 changed files with 94 additions and 9 deletions

View File

@ -62,6 +62,25 @@ actions:
description: |
List host NICS, and which one are candidates for use as external NIC.
additionalProperties: false
disable:
description: |
Prevent new instances from being created.
params:
reason:
type: string
description: Reason for disabling the hypervisor
default: Stopped via operator action
additionalProperties: false
enable:
description: |
Allow new instances to be created.
additionalProperties: false
running-guests:
description: |
List the running guests on the hypervisor.
Only lists guests created by the OpenStack cloud.
additionalProperties: false
requires:
amqp:

View File

@ -71,6 +71,10 @@ DATA_BINDING = "data"
MTLS_USAGES = {x509.OID_SERVER_AUTH, x509.OID_CLIENT_AUTH}
class HypervisorError(Exception):
"""Custom exception for Hypervisor errors."""
@sunbeam_tracing.trace_type
class MTlsCertificatesHandler(sunbeam_rhandlers.TlsCertificatesHandler):
"""Handler for certificates interface."""
@ -178,6 +182,18 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
self.on.list_nics_action,
self._list_nics_action,
)
self.framework.observe(
self.on.enable_action,
self._enable_action,
)
self.framework.observe(
self.on.disable_action,
self._disable_action,
)
self.framework.observe(
self.on.running_guests_action,
self._running_guests_action,
)
self.framework.observe(
self.on.install,
self._on_install,
@ -231,6 +247,14 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
return None
return str(address)
def _proxy_configs(self) -> dict[str, str]:
"""Return proxy configs."""
return {
"HTTPS_PROXY": os.environ.get("JUJU_CHARM_HTTPS_PROXY", ""),
"HTTP_PROXY": os.environ.get("JUJU_CHARM_HTTP_PROXY", ""),
"NO_PROXY": os.environ.get("JUJU_CHARM_NO_PROXY", ""),
}
def check_relation_exists(self, relation_name: str) -> bool:
"""Check if a relation exists or not."""
if self.model.get_relation(relation_name):
@ -325,14 +349,13 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
if new_snap_settings:
self.set_snap_data(new_snap_settings)
def _list_nics_action(self, event: ActionEvent):
"""Run list_nics action."""
def _hypervisor_cli_cmd(self, cmd: str):
"""Helper to run cli commands on the snap."""
cache = self.get_snap_cache()
hypervisor = cache["openstack-hypervisor"]
if not hypervisor.present:
event.fail("Hypervisor is not installed")
return
raise HypervisorError("Hypervisor is not installed")
process = subprocess.run(
[
@ -340,10 +363,8 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
"run",
"openstack-hypervisor",
"--verbose",
"list-nics",
"--format",
"json",
],
]
+ cmd.split(),
capture_output=True,
)
@ -352,12 +373,54 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
stdout = process.stdout.decode("utf-8")
logger.debug("stdout: %s", stdout)
if process.returncode != 0:
event.fail(stderr)
raise HypervisorError(stderr)
return stdout
def _list_nics_action(self, event: ActionEvent):
"""Run list_nics action."""
try:
stdout = self._hypervisor_cli_cmd("list-nics --format json")
except HypervisorError as e:
event.fail(str(e))
return
# cli returns a json dict with keys "nics" and "candidate"
event.set_results({"result": stdout})
def _enable_action(self, event: ActionEvent):
"""Run enable action."""
try:
stdout = self._hypervisor_cli_cmd("hypervisor enable")
except HypervisorError as e:
event.fail(str(e))
return
event.set_results({"result": stdout})
def _disable_action(self, event: ActionEvent):
"""Run disable action."""
try:
stdout = self._hypervisor_cli_cmd("hypervisor disable")
except HypervisorError as e:
event.fail(str(e))
return
event.set_results({"result": stdout})
def _running_guests_action(self, event: ActionEvent):
"""List running openstack guests."""
try:
stdout = self._hypervisor_cli_cmd(
"hypervisor running-guests --format json"
)
except HypervisorError as e:
event.fail(str(e))
return
# cli returns a json list
event.set_results({"result": stdout})
def ensure_services_running(self):
"""Ensure systemd services running."""
# This should taken care of by the snap
@ -476,6 +539,7 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
"identity.password": contexts.identity_credentials.password,
"identity.project-domain-id": contexts.identity_credentials.project_domain_id,
"identity.project-domain-name": contexts.identity_credentials.project_domain_name,
"identity.project-id": contexts.identity_credentials.project_id,
"identity.project-name": contexts.identity_credentials.project_name,
"identity.region-name": contexts.identity_credentials.region,
"identity.user-domain-id": contexts.identity_credentials.user_domain_id,

View File

@ -150,6 +150,7 @@ class TestCharm(test_utils.CharmTestCase):
"identity.password": "user-password",
"identity.project-domain-id": "pdomain-id",
"identity.project-domain-name": "pdomain_-ame",
"identity.project-id": "uproj-id",
"identity.project-name": "user-project",
"identity.region-name": "region12",
"identity.user-domain-id": "udomain-id",
@ -261,6 +262,7 @@ class TestCharm(test_utils.CharmTestCase):
"identity.password": "user-password",
"identity.project-domain-id": "pdomain-id",
"identity.project-domain-name": "pdomain_-ame",
"identity.project-id": "uproj-id",
"identity.project-name": "user-project",
"identity.region-name": "region12",
"identity.user-domain-id": "udomain-id",