diff --git a/charms/nova-k8s/.sunbeam-build.yaml b/charms/nova-k8s/.sunbeam-build.yaml index ac9eaf37..ccdf5529 100644 --- a/charms/nova-k8s/.sunbeam-build.yaml +++ b/charms/nova-k8s/.sunbeam-build.yaml @@ -10,6 +10,7 @@ external-libraries: - charms.tempo_k8s.v1.charm_tracing internal-libraries: - charms.keystone_k8s.v1.identity_service + - charms.sunbeam_libs.v0.service_readiness templates: - parts/section-database - parts/database-connection diff --git a/charms/nova-k8s/charmcraft.yaml b/charms/nova-k8s/charmcraft.yaml index d1a92d9f..ab8414ed 100644 --- a/charms/nova-k8s/charmcraft.yaml +++ b/charms/nova-k8s/charmcraft.yaml @@ -93,6 +93,8 @@ requires: interface: rabbitmq identity-service: interface: keystone + placement: + interface: placement cloud-compute: interface: nova-compute optional: true diff --git a/charms/nova-k8s/src/charm.py b/charms/nova-k8s/src/charm.py index 9b9997a7..20efd171 100755 --- a/charms/nova-k8s/src/charm.py +++ b/charms/nova-k8s/src/charm.py @@ -543,6 +543,13 @@ class NovaOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm): [NOVA_API_INGRESS_NAME, NOVA_SPICEPROXY_INGRESS_NAME], ) handlers.append(self.traefik_route_internal) + self.placement_svc = sunbeam_rhandlers.ServiceReadinessRequiresHandler( + self, + "placement", + self.configure_charm, + "placement" in self.mandatory_relations, + ) + handlers.append(self.placement_svc) return handlers diff --git a/charms/nova-k8s/tests/unit/test_nova_charm.py b/charms/nova-k8s/tests/unit/test_nova_charm.py index f4c67996..943c26ca 100644 --- a/charms/nova-k8s/tests/unit/test_nova_charm.py +++ b/charms/nova-k8s/tests/unit/test_nova_charm.py @@ -94,6 +94,10 @@ class TestNovaOperatorCharm(test_utils.CharmTestCase): app_data={"external_host": "dummy-ip", "scheme": "http"}, ) + def add_placement_relation(self, harness: Harness) -> None: + """Add placement relation.""" + harness.add_relation("placement", "nova", app_data={"ready": "true"}) + def add_db_relation(self, harness: Harness, name: str) -> str: """Add db relation.""" rel_id = harness.add_relation(name, "mysql") @@ -117,6 +121,7 @@ class TestNovaOperatorCharm(test_utils.CharmTestCase): # this adds all the default/common relations test_utils.add_all_relations(self.harness) self.add_complete_ingress_relation(self.harness) + self.add_placement_relation(self.harness) # but nova has some extra db relations, so add them manually here rel_id = self.add_db_relation(self.harness, "api-database") diff --git a/charms/placement-k8s/.sunbeam-build.yaml b/charms/placement-k8s/.sunbeam-build.yaml index 24e0a900..11bcac2a 100644 --- a/charms/placement-k8s/.sunbeam-build.yaml +++ b/charms/placement-k8s/.sunbeam-build.yaml @@ -8,6 +8,7 @@ external-libraries: - charms.tempo_k8s.v1.charm_tracing internal-libraries: - charms.keystone_k8s.v1.identity_service + - charms.sunbeam_libs.v0.service_readiness templates: - parts/database-connection - parts/database-connection-settings diff --git a/charms/placement-k8s/src/charm.py b/charms/placement-k8s/src/charm.py index a725a7fa..e53d8d33 100755 --- a/charms/placement-k8s/src/charm.py +++ b/charms/placement-k8s/src/charm.py @@ -30,7 +30,11 @@ import ops.pebble import ops_sunbeam.charm as sunbeam_charm import ops_sunbeam.container_handlers as sunbeam_chandlers import ops_sunbeam.core as sunbeam_core +import ops_sunbeam.relation_handlers as sunbeam_rhandlers import ops_sunbeam.tracing as sunbeam_tracing +from ops.charm import ( + RelationEvent, +) from ops.framework import ( StoredState, ) @@ -86,6 +90,44 @@ class PlacementOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm): ) ] + def get_relation_handlers( + self, handlers: list[sunbeam_rhandlers.RelationHandler] | None = None + ) -> list[sunbeam_rhandlers.RelationHandler]: + """Relation handlers for the service.""" + handlers = handlers or [] + self.svc_ready_handler = ( + sunbeam_rhandlers.ServiceReadinessProviderHandler( + self, + "placement", + self.handle_readiness_request_from_event, + ) + ) + handlers.append(self.svc_ready_handler) + + handlers = super().get_relation_handlers(handlers) + return handlers + + def post_config_setup(self): + """Configuration steps after services have been setup.""" + super().post_config_setup() + self.set_readiness_on_related_units() + + def handle_readiness_request_from_event( + self, event: RelationEvent + ) -> None: + """Set service readiness in relation data.""" + self.svc_ready_handler.interface.set_service_status( + event.relation, self.bootstrapped() + ) + + def set_readiness_on_related_units(self) -> None: + """Set service readiness on placement related units.""" + logger.debug( + "Set service readiness on all connected placement relations" + ) + for relation in self.framework.model.relations["placement"]: + self.svc_ready_handler.interface.set_service_status(relation, True) + @property def container_configs(self) -> List[sunbeam_core.ContainerConfigFile]: """Container configurations for the operator.""" diff --git a/tests/all-k8s/smoke.yaml.j2 b/tests/all-k8s/smoke.yaml.j2 index 4951b30a..a4b0c298 100644 --- a/tests/all-k8s/smoke.yaml.j2 +++ b/tests/all-k8s/smoke.yaml.j2 @@ -418,6 +418,8 @@ relations: - nova:traefik-route-internal - - keystone:send-ca-cert - nova:receive-ca-cert +- - placement:placement + - nova:placement - - mysql:database - placement:database diff --git a/tests/core/smoke.yaml.j2 b/tests/core/smoke.yaml.j2 index de04a3dd..84ce7a62 100644 --- a/tests/core/smoke.yaml.j2 +++ b/tests/core/smoke.yaml.j2 @@ -188,6 +188,8 @@ relations: - nova:traefik-route-internal - - keystone:send-ca-cert - nova:receive-ca-cert +- - placement:placement + - nova:placement - - mysql:database - placement:database diff --git a/tests/tempest/smoke.yaml.j2 b/tests/tempest/smoke.yaml.j2 index c6627dba..8f1a09b2 100644 --- a/tests/tempest/smoke.yaml.j2 +++ b/tests/tempest/smoke.yaml.j2 @@ -183,6 +183,8 @@ relations: - nova:traefik-route-internal - - keystone:send-ca-cert - nova:receive-ca-cert +- - placement:placement + - nova:placement - - mysql:database - placement:database