[nova-k8s/placement-k8s] Add placement interface

nova-scheduler errors out if placement service is
not available even if the container healthchecks
shows active. Add placement integration in nova-k8s
to ensure placement is defined in the bundle/tf plan

Add ServiceReadinessProviderHandler in placement-k8s
and corresponding RequiresHandler in nova-k8s.

Fixes: #2097327
Change-Id: Ica072b98c4668c6248702ca680b2885c4d542e23
This commit is contained in:
Hemanth Nakkina 2025-02-04 11:10:25 +05:30
parent e07819a9d9
commit f218d87642
No known key found for this signature in database
GPG Key ID: 2E4970F7B143168E
9 changed files with 64 additions and 0 deletions

View File

@ -10,6 +10,7 @@ external-libraries:
- charms.tempo_k8s.v1.charm_tracing - charms.tempo_k8s.v1.charm_tracing
internal-libraries: internal-libraries:
- charms.keystone_k8s.v1.identity_service - charms.keystone_k8s.v1.identity_service
- charms.sunbeam_libs.v0.service_readiness
templates: templates:
- parts/section-database - parts/section-database
- parts/database-connection - parts/database-connection

View File

@ -93,6 +93,8 @@ requires:
interface: rabbitmq interface: rabbitmq
identity-service: identity-service:
interface: keystone interface: keystone
placement:
interface: placement
cloud-compute: cloud-compute:
interface: nova-compute interface: nova-compute
optional: true optional: true

View File

@ -543,6 +543,13 @@ class NovaOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
[NOVA_API_INGRESS_NAME, NOVA_SPICEPROXY_INGRESS_NAME], [NOVA_API_INGRESS_NAME, NOVA_SPICEPROXY_INGRESS_NAME],
) )
handlers.append(self.traefik_route_internal) 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 return handlers

View File

@ -94,6 +94,10 @@ class TestNovaOperatorCharm(test_utils.CharmTestCase):
app_data={"external_host": "dummy-ip", "scheme": "http"}, 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: def add_db_relation(self, harness: Harness, name: str) -> str:
"""Add db relation.""" """Add db relation."""
rel_id = harness.add_relation(name, "mysql") rel_id = harness.add_relation(name, "mysql")
@ -117,6 +121,7 @@ class TestNovaOperatorCharm(test_utils.CharmTestCase):
# this adds all the default/common relations # this adds all the default/common relations
test_utils.add_all_relations(self.harness) test_utils.add_all_relations(self.harness)
self.add_complete_ingress_relation(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 # but nova has some extra db relations, so add them manually here
rel_id = self.add_db_relation(self.harness, "api-database") rel_id = self.add_db_relation(self.harness, "api-database")

View File

@ -8,6 +8,7 @@ external-libraries:
- charms.tempo_k8s.v1.charm_tracing - charms.tempo_k8s.v1.charm_tracing
internal-libraries: internal-libraries:
- charms.keystone_k8s.v1.identity_service - charms.keystone_k8s.v1.identity_service
- charms.sunbeam_libs.v0.service_readiness
templates: templates:
- parts/database-connection - parts/database-connection
- parts/database-connection-settings - parts/database-connection-settings

View File

@ -30,7 +30,11 @@ import ops.pebble
import ops_sunbeam.charm as sunbeam_charm import ops_sunbeam.charm as sunbeam_charm
import ops_sunbeam.container_handlers as sunbeam_chandlers import ops_sunbeam.container_handlers as sunbeam_chandlers
import ops_sunbeam.core as sunbeam_core import ops_sunbeam.core as sunbeam_core
import ops_sunbeam.relation_handlers as sunbeam_rhandlers
import ops_sunbeam.tracing as sunbeam_tracing import ops_sunbeam.tracing as sunbeam_tracing
from ops.charm import (
RelationEvent,
)
from ops.framework import ( from ops.framework import (
StoredState, 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 @property
def container_configs(self) -> List[sunbeam_core.ContainerConfigFile]: def container_configs(self) -> List[sunbeam_core.ContainerConfigFile]:
"""Container configurations for the operator.""" """Container configurations for the operator."""

View File

@ -418,6 +418,8 @@ relations:
- nova:traefik-route-internal - nova:traefik-route-internal
- - keystone:send-ca-cert - - keystone:send-ca-cert
- nova:receive-ca-cert - nova:receive-ca-cert
- - placement:placement
- nova:placement
- - mysql:database - - mysql:database
- placement:database - placement:database

View File

@ -188,6 +188,8 @@ relations:
- nova:traefik-route-internal - nova:traefik-route-internal
- - keystone:send-ca-cert - - keystone:send-ca-cert
- nova:receive-ca-cert - nova:receive-ca-cert
- - placement:placement
- nova:placement
- - mysql:database - - mysql:database
- placement:database - placement:database

View File

@ -183,6 +183,8 @@ relations:
- nova:traefik-route-internal - nova:traefik-route-internal
- - keystone:send-ca-cert - - keystone:send-ca-cert
- nova:receive-ca-cert - nova:receive-ca-cert
- - placement:placement
- nova:placement
- - mysql:database - - mysql:database
- placement:database - placement:database