Derive mandatory relations from charmcraft.yaml

Currently each charm defines in the code all the
mandatory relations. Instead populate the mandatory
relations from chamrcraft.yaml requires relations
with optional as False.
Charm can define mandatory relations that are not
derived from requires relations and they will be
appended to the list of mandatory_relations.
Barbican and ovn-central charms follows this pattern.

Change-Id: Iff45fca33dc954593ded52b97e905431b6a7bb53
This commit is contained in:
Hemanth Nakkina 2024-12-10 06:32:41 +05:30
parent 56c35f5988
commit e07819a9d9
No known key found for this signature in database
GPG Key ID: 2E4970F7B143168E
34 changed files with 34 additions and 169 deletions

View File

@ -252,13 +252,6 @@ class AodhOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
db_sync_cmds = [["aodh-dbsync"]]
mandatory_relations = {
"database",
"identity-service",
"ingress-internal",
"amqp",
}
@property
def service_conf(self) -> str:
"""Service default configuration file."""

View File

@ -66,6 +66,7 @@ requires:
interface: rabbitmq
vault-kv:
interface: vault-kv
optional: true
limit: 1
receive-ca-cert:
interface: certificate_transfer

View File

@ -250,12 +250,6 @@ class BarbicanOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
service_name = "barbican-api"
wsgi_admin_script = "/usr/bin/barbican-wsgi-api"
wsgi_public_script = "/usr/bin/barbican-wsgi-api"
mandatory_relations = {
"database",
"amqp",
"identity-service",
"ingress-internal",
}
db_sync_cmds = [
["sudo", "-u", "barbican", "barbican-manage", "db", "upgrade"]
@ -435,9 +429,7 @@ class BarbicanOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
class BarbicanVaultOperatorCharm(BarbicanOperatorCharm):
"""Vault specialized Barbican Operator Charm."""
mandatory_relations = BarbicanOperatorCharm.mandatory_relations.union(
{VAULT_KV_RELATION}
)
mandatory_relations = {VAULT_KV_RELATION}
def __init__(self, *args):
super().__init__(*args)

View File

@ -181,7 +181,6 @@ class CeilometerOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S):
shared_metering_secret_key = "shared-metering-secret"
db_sync_cmds = [["ceilometer-upgrade"]]
mandatory_relations = {"amqp", "identity-credentials", "gnocchi-db"}
def __init__(self, framework: ops.framework):
super().__init__(framework)

View File

@ -224,13 +224,6 @@ class CinderCephOperatorCharm(charm.OSBaseOperatorCharmK8S):
ceph_access_relation_name = "ceph-access"
mandatory_relations = {
"database",
"amqp",
"ceph",
"storage-backend",
}
def __init__(self, framework):
super().__init__(framework)
self._state.set_default(api_ready=False)

View File

@ -201,14 +201,6 @@ class CinderOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
wsgi_admin_script = "/usr/bin/cinder-wsgi"
wsgi_public_script = "/usr/bin/cinder-wsgi"
mandatory_relations = {
"database",
"amqp",
"storage-backend",
"identity-service",
"ingress-internal",
}
db_sync_cmds = [
[
"sudo",

View File

@ -198,8 +198,6 @@ class BindOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S):
_state = StoredState()
service_name = "designate-bind"
# mandatory_relations = {}
def __init__(self, *args):
super().__init__(*args)
self.framework.observe(self.on.secret_rotate, self._on_secret_rotate)

View File

@ -361,14 +361,6 @@ class DesignateOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
["sudo", "-u", "designate", "designate-manage", "pool", "update"],
]
mandatory_relations = {
"database",
"identity-service",
"ingress-internal",
"amqp",
BIND_RNDC_RELATION,
}
def __init__(self, *args):
super().__init__(*args)
self.framework.observe(self.on.install, self._on_install)

View File

@ -327,9 +327,10 @@ requires:
amqp:
interface: rabbitmq
optional: true
# ceph is not marked as optional as the GlanceStorage relation handler
# falls back to juju storage if ceph relation is not connected.
ceph:
interface: ceph-client
optional: true
receive-ca-cert:
interface: certificate_transfer
optional: true

View File

@ -290,16 +290,6 @@ class GlanceOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
]
]
# ceph is included in the mandatory list as the GlanceStorage
# relation handler falls back to juju storage if ceph relation
# is not connected.
mandatory_relations = {
"database",
"identity-service",
"ingress-internal",
"ceph",
}
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.framework.observe(

View File

@ -184,13 +184,6 @@ class GnocchiOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
db_sync_cmds = [["gnocchi-upgrade"]]
mandatory_relations = {
"database",
"identity-service",
"ingress-internal",
"ceph",
}
@property
def service_conf(self) -> str:
"""Service default configuration file."""

View File

@ -203,14 +203,6 @@ class HeatOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
db_sync_cmds = [["heat-manage", "db_sync"]]
mandatory_relations = {
"database",
"amqp",
"identity-service",
"traefik-route-internal",
"identity-ops",
}
def __init__(self, framework):
self.traefik_route_public = None
self.traefik_route_internal = None

View File

@ -139,12 +139,6 @@ class HorizonOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
]
]
mandatory_relations = {
"database",
"ingress-internal",
"identity-credentials",
}
def __init__(self, framework):
super().__init__(framework)
self._state.set_default(plugins=[])

View File

@ -151,6 +151,7 @@ requires:
optional: true
domain-config:
interface: keystone-domain-config
optional: true
logging:
interface: loki_push_api
optional: true

View File

@ -334,7 +334,6 @@ class KeystoneOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
domain_config_dir = Path("/etc/keystone/domains")
domain_ca_dir = Path("/usr/local/share/ca-certificates")
service_port = 5000
mandatory_relations = {"database", "ingress-internal"}
db_sync_cmds = [
[
"sudo",

View File

@ -142,13 +142,6 @@ class MagnumOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
service_name = "magnum-api"
wsgi_admin_script = "/usr/bin/magnum-api-wsgi"
wsgi_public_script = "/usr/bin/magnum-api-wsgi"
mandatory_relations = {
"database",
"amqp",
"identity-service",
"ingress-internal",
"identity-ops",
}
db_sync_cmds = [["sudo", "-u", "magnum", "magnum-db-manage", "upgrade"]]

View File

@ -290,13 +290,6 @@ class MasakariHostMonitorPebbleHandler(sunbeam_chandlers.ServicePebbleHandler):
class MasakariOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
"""Charm the service."""
mandatory_relations = {
"database",
"amqp",
"identity-service",
"ingress-internal",
}
wsgi_admin_script = "/usr/bin/masakari-wsgi"
wsgi_public_script = "/usr/bin/masakari-wsgi"

View File

@ -427,14 +427,6 @@ class NeutronServerOVNPebbleHandler(NeutronServerPebbleHandler):
class NeutronOVNOperatorCharm(NeutronOperatorCharm):
"""Neutron charm class for OVN."""
mandatory_relations = {
"amqp",
"database",
"ovsdb-cms",
"identity-service",
"ingress-internal",
}
@property
def config_contexts(self) -> list[sunbeam_ctxts.ConfigContext]:
"""Configuration contexts for the operator."""

View File

@ -91,20 +91,11 @@ requires:
limit: 1
amqp:
interface: rabbitmq
image-service:
interface: glance
identity-service:
interface: keystone
cloud-compute:
interface: nova-compute
cinder-volume-service:
interface: cinder
neutron-network-service:
interface: neutron
neutron-api:
interface: neutron-api
placement:
interface: placement
optional: true
receive-ca-cert:
interface: certificate_transfer
optional: true

View File

@ -343,15 +343,6 @@ class NovaOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
wsgi_admin_script = "/usr/bin/nova-api-wsgi"
wsgi_public_script = "/usr/bin/nova-api-wsgi"
shared_metadata_secret_key = "shared-metadata-secret"
mandatory_relations = {
"database",
"api-database",
"cell-database",
"amqp",
"identity-service",
"ingress-internal",
"traefik-route-internal",
}
def __init__(self, framework):
self.traefik_route_public = None

View File

@ -300,13 +300,6 @@ class OctaviaOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
class OctaviaOVNOperatorCharm(OctaviaOperatorCharm):
"""Charm the Octavia service with OVN provider."""
mandatory_relations = {
"database",
"ovsdb-cms",
"identity-service",
"ingress-internal",
}
@property
def config_contexts(self) -> List[sunbeam_config_contexts.ConfigContext]:
"""Configuration contexts for the operator."""

View File

@ -158,9 +158,6 @@ class GrafanaDashboardsRelationHandler(sunbeam_rhandlers.RelationHandler):
class OSExporterOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S):
"""Charm the service."""
mandatory_relations = {
"identity-ops",
}
service_name = "openstack-exporter"
@property

View File

@ -105,6 +105,7 @@ requires:
interface: nova
masakari-service:
interface: service-ready
optional: true
tracing:
interface: tracing
optional: true

View File

@ -162,13 +162,6 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm):
METADATA_SECRET_KEY = "ovn-metadata-proxy-shared-secret"
DEFAULT_SECRET_LENGTH = 32
mandatory_relations = {
"amqp",
"identity-credentials",
"ovsdb-cms",
"nova-service",
}
def __init__(self, framework: ops.framework.Framework) -> None:
"""Run constructor."""
super().__init__(framework)

View File

@ -59,7 +59,6 @@ requires:
ingress-internal:
interface: ingress
limit: 1
optional: true
ingress-public:
interface: ingress
optional: true

View File

@ -155,10 +155,6 @@ class OpenstackImagesSyncK8SCharm(sunbeam_charm.OSBaseOperatorAPICharm):
"""Charm the application."""
service_name = "openstack-images-sync"
mandatory_relations = {
"identity-service",
"ingress-internal",
}
@property
def service_conf(self) -> str:

View File

@ -183,7 +183,7 @@ class OVNCentralOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S):
"""Charm the service."""
_state = StoredState()
mandatory_relations = {"certificates", "peers"}
mandatory_relations = {"peers"}
def __init__(self, framework):
"""Setup OVN central charm class."""

View File

@ -93,11 +93,6 @@ class OVNRelayPebbleHandler(ovn_chandlers.OVNPebbleHandler):
class OVNRelayOperatorCharm(ovn_charm.OSBaseOVNOperatorCharm):
"""Charm the service."""
mandatory_relations = {
"ovsdb-cms",
"certificates",
}
def __init__(self, framework):
super().__init__(framework)
self.service_patcher = KubernetesServicePatch(

View File

@ -117,6 +117,7 @@ requires:
interface: keystone-resources
logging:
interface: loki_push_api
optional: true
receive-ca-cert:
interface: certificate_transfer
optional: true

View File

@ -107,8 +107,6 @@ class TempestOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S):
_state = ops.framework.StoredState()
service_name = "tempest"
mandatory_relations = {"identity-ops"}
def __init__(self, framework: ops.framework.Framework) -> None:
"""Run the constructor."""
# config for openstack, used by tempest

View File

@ -118,12 +118,6 @@ class WatcherOperatorCharm(sunbeam_charm.OSBaseOperatorAPICharm):
service_name = "watcher-api"
wsgi_admin_script = "/usr/bin/watcher-api-wsgi"
wsgi_public_script = "/usr/bin/watcher-api-wsgi"
mandatory_relations = {
"database",
"amqp",
"identity-service",
"ingress-internal",
}
db_sync_cmds = [
[

View File

@ -79,6 +79,7 @@ class OSBaseOperatorCharm(ops.charm.CharmBase):
_state = ops.framework.StoredState()
# Holds set of mandatory relations
# Auto-updates the mandatory requires relations from charmcraft.yaml
mandatory_relations: set[str] = set()
service_name: str
@ -92,6 +93,17 @@ class OSBaseOperatorCharm(ops.charm.CharmBase):
"by ops_sunbeam"
)
)
# Update mandatory relations from charmcraft.yaml definitions
requires_relations: set[str] = {
name
for name, metadata in self.meta.requires.items()
if metadata.optional is False
}
self.mandatory_relations = requires_relations.union(
self.mandatory_relations
)
# unit_bootstrapped is stored in the local unit storage which is lost
# when the pod is replaced, so this will revert to False on charm
# upgrade or upgrade of the payload container.
@ -789,7 +801,6 @@ class OSBaseOperatorCharmK8S(OSBaseOperatorCharm):
class OSBaseOperatorAPICharm(OSBaseOperatorCharmK8S):
"""Base class for OpenStack API operators."""
mandatory_relations = {"database", "identity-service", "ingress-internal"}
wsgi_admin_script: str
wsgi_public_script: str

View File

@ -108,6 +108,7 @@ requires:
limit: 1
ingress-public:
interface: ingress
optional: true
limit: 1
amqp:
interface: rabbitmq
@ -115,9 +116,11 @@ requires:
interface: keystone
identity-credentials:
interface: keystone-credentials
optional: true
limit: 1
ceph-access:
interface: cinder-ceph-key
optional: true
peers:
peers:
@ -253,12 +256,6 @@ class MyAPICharm(sunbeam_charm.OSBaseOperatorAPICharm):
service_name = "my-service"
wsgi_admin_script = "/bin/wsgi_admin"
wsgi_public_script = "/bin/wsgi_public"
mandatory_relations = {
"database",
"amqp",
"identity-service",
"ingress-public",
}
def __init__(self, framework: "ops.framework.Framework") -> None:
"""Run constructor."""

View File

@ -365,7 +365,7 @@ class TestOSBaseOperatorAPICharm(_TestOSBaseOperatorAPICharm):
self.harness.charm.get_mandatory_relations_not_ready(
self.mock_event
),
{"identity-service", "ingress-public", "amqp"},
{"identity-service", "ingress-internal", "amqp"},
)
amqp_rel_id = test_utils.add_base_amqp_relation(self.harness)
@ -374,7 +374,7 @@ class TestOSBaseOperatorAPICharm(_TestOSBaseOperatorAPICharm):
self.harness.charm.get_mandatory_relations_not_ready(
self.mock_event
),
{"ingress-public", "identity-service"},
{"ingress-internal", "identity-service"},
)
identity_rel_id = test_utils.add_base_identity_service_relation(
@ -387,14 +387,14 @@ class TestOSBaseOperatorAPICharm(_TestOSBaseOperatorAPICharm):
self.harness.charm.get_mandatory_relations_not_ready(
self.mock_event
),
{"ingress-public"},
{"ingress-internal"},
)
ingress_rel_id = test_utils.add_ingress_relation(
self.harness, "public"
self.harness, "internal"
)
test_utils.add_ingress_relation_data(
self.harness, ingress_rel_id, "public"
self.harness, ingress_rel_id, "internal"
)
ceph_access_rel_id = test_utils.add_base_ceph_access_relation(
@ -413,10 +413,10 @@ class TestOSBaseOperatorAPICharm(_TestOSBaseOperatorAPICharm):
# Add an optional relation and test if relation_handlers_ready
# returns True
optional_rel_id = test_utils.add_ingress_relation(
self.harness, "internal"
self.harness, "public"
)
test_utils.add_ingress_relation_data(
self.harness, optional_rel_id, "internal"
self.harness, optional_rel_id, "public"
)
self.assertSetEqual(
self.harness.charm.get_mandatory_relations_not_ready(
@ -432,15 +432,15 @@ class TestOSBaseOperatorAPICharm(_TestOSBaseOperatorAPICharm):
self.harness.charm.get_mandatory_relations_not_ready(
self.mock_event
),
{"ingress-public"},
{"ingress-internal"},
)
# Add the mandatory relation back and retest relation_handlers_ready
ingress_rel_id = test_utils.add_ingress_relation(
self.harness, "public"
self.harness, "internal"
)
test_utils.add_ingress_relation_data(
self.harness, ingress_rel_id, "public"
self.harness, ingress_rel_id, "internal"
)
self.assertSetEqual(
self.harness.charm.get_mandatory_relations_not_ready(