From 0214e8f17333e3aa4ee767f2dbe71a12242326fe Mon Sep 17 00:00:00 2001 From: Guillaume Boutry Date: Sun, 7 Jul 2024 14:18:31 +0200 Subject: [PATCH] [*-k8s] implement log forwarder Implement LogForwardHandler for every k8s charm to forward service stdout to logging provider. Tempest-k8s is excluded because it implements its own logging handler. Change-Id: Iccc9f1f911acfaaecf733fe78cc4bc3191a231d5 Signed-off-by: Guillaume Boutry --- charms/aodh-k8s/metadata.yaml | 3 + charms/barbican-k8s/metadata.yaml | 3 + charms/ceilometer-k8s/metadata.yaml | 3 + charms/cinder-ceph-k8s/metadata.yaml | 3 + charms/cinder-k8s/metadata.yaml | 3 + charms/designate-bind-k8s/metadata.yaml | 5 + charms/designate-k8s/metadata.yaml | 3 + charms/glance-k8s/metadata.yaml | 3 + charms/gnocchi-k8s/metadata.yaml | 3 + charms/heat-k8s/metadata.yaml | 3 + charms/horizon-k8s/metadata.yaml | 5 +- charms/keystone-k8s/metadata.yaml | 3 + .../tests/unit/test_keystone_charm.py | 2 + charms/keystone-ldap-k8s/metadata.yaml | 4 + charms/magnum-k8s/metadata.yaml | 3 + charms/neutron-k8s/metadata.yaml | 3 + charms/nova-k8s/metadata.yaml | 3 + charms/octavia-k8s/metadata.yaml | 3 + charms/openstack-exporter-k8s/metadata.yaml | 3 + .../openstack-images-sync-k8s/charmcraft.yaml | 3 + charms/ovn-central-k8s/metadata.yaml | 3 + charms/ovn-relay-k8s/metadata.yaml | 3 + charms/placement-k8s/metadata.yaml | 3 + charms/tempest-k8s/charmcraft.yaml | 1 + charms/tempest-k8s/src/charm.py | 42 +- .../tests/unit/test_tempest_charm.py | 19 +- common.sh | 653 +++++++++--------- .../lib/charms/loki_k8s/v1/loki_push_api.py | 47 +- ops-sunbeam/ops_sunbeam/charm.py | 14 + ops-sunbeam/ops_sunbeam/relation_handlers.py | 42 ++ ops-sunbeam/ops_sunbeam/test_utils.py | 22 + 31 files changed, 547 insertions(+), 366 deletions(-) diff --git a/charms/aodh-k8s/metadata.yaml b/charms/aodh-k8s/metadata.yaml index 930cd4d0..344f0708 100644 --- a/charms/aodh-k8s/metadata.yaml +++ b/charms/aodh-k8s/metadata.yaml @@ -75,6 +75,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true provides: aodh: diff --git a/charms/barbican-k8s/metadata.yaml b/charms/barbican-k8s/metadata.yaml index bd166320..e7dc9be5 100644 --- a/charms/barbican-k8s/metadata.yaml +++ b/charms/barbican-k8s/metadata.yaml @@ -45,6 +45,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true peers: peers: diff --git a/charms/ceilometer-k8s/metadata.yaml b/charms/ceilometer-k8s/metadata.yaml index 66ce8658..15ab0084 100644 --- a/charms/ceilometer-k8s/metadata.yaml +++ b/charms/ceilometer-k8s/metadata.yaml @@ -52,6 +52,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true peers: peers: diff --git a/charms/cinder-ceph-k8s/metadata.yaml b/charms/cinder-ceph-k8s/metadata.yaml index f9225aa2..8e4c3464 100644 --- a/charms/cinder-ceph-k8s/metadata.yaml +++ b/charms/cinder-ceph-k8s/metadata.yaml @@ -42,6 +42,9 @@ requires: identity-credentials: interface: keystone-credentials optional: true + logging: + interface: loki_push_api + optional: true provides: ceph-access: diff --git a/charms/cinder-k8s/metadata.yaml b/charms/cinder-k8s/metadata.yaml index e8cd1a3c..a8ce6e06 100644 --- a/charms/cinder-k8s/metadata.yaml +++ b/charms/cinder-k8s/metadata.yaml @@ -60,6 +60,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true peers: peers: diff --git a/charms/designate-bind-k8s/metadata.yaml b/charms/designate-bind-k8s/metadata.yaml index f8615165..d562253c 100644 --- a/charms/designate-bind-k8s/metadata.yaml +++ b/charms/designate-bind-k8s/metadata.yaml @@ -31,6 +31,11 @@ provides: dns-backend: interface: bind-rndc +requires: + logging: + interface: loki_push_api + optional: true + peers: peers: interface: bind-peer diff --git a/charms/designate-k8s/metadata.yaml b/charms/designate-k8s/metadata.yaml index 4c7a0a5c..53a40486 100644 --- a/charms/designate-k8s/metadata.yaml +++ b/charms/designate-k8s/metadata.yaml @@ -52,6 +52,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true peers: peers: diff --git a/charms/glance-k8s/metadata.yaml b/charms/glance-k8s/metadata.yaml index 782052a8..3608e67c 100644 --- a/charms/glance-k8s/metadata.yaml +++ b/charms/glance-k8s/metadata.yaml @@ -71,6 +71,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true provides: image-service: diff --git a/charms/gnocchi-k8s/metadata.yaml b/charms/gnocchi-k8s/metadata.yaml index a17d491e..cffbcbf3 100644 --- a/charms/gnocchi-k8s/metadata.yaml +++ b/charms/gnocchi-k8s/metadata.yaml @@ -54,6 +54,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true provides: gnocchi-service: diff --git a/charms/heat-k8s/metadata.yaml b/charms/heat-k8s/metadata.yaml index f14630bf..e5d7e8a8 100644 --- a/charms/heat-k8s/metadata.yaml +++ b/charms/heat-k8s/metadata.yaml @@ -57,6 +57,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true peers: peers: diff --git a/charms/horizon-k8s/metadata.yaml b/charms/horizon-k8s/metadata.yaml index 0c49f3ec..25ab1bca 100644 --- a/charms/horizon-k8s/metadata.yaml +++ b/charms/horizon-k8s/metadata.yaml @@ -25,7 +25,7 @@ containers: resources: horizon-image: type: oci-image - description: OCI image for Horizon + description: OCI image for Horizon # ghcr.io/canonical/horizon:2024.1 upstream-source: ghcr.io/canonical/horizon:2024.1 @@ -46,6 +46,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true provides: horizon: diff --git a/charms/keystone-k8s/metadata.yaml b/charms/keystone-k8s/metadata.yaml index 83459997..61e45cb4 100644 --- a/charms/keystone-k8s/metadata.yaml +++ b/charms/keystone-k8s/metadata.yaml @@ -48,6 +48,9 @@ requires: optional: true domain-config: interface: keystone-domain-config + logging: + interface: loki_push_api + optional: true peers: peers: diff --git a/charms/keystone-k8s/tests/unit/test_keystone_charm.py b/charms/keystone-k8s/tests/unit/test_keystone_charm.py index f77bff95..b3f9a95d 100644 --- a/charms/keystone-k8s/tests/unit/test_keystone_charm.py +++ b/charms/keystone-k8s/tests/unit/test_keystone_charm.py @@ -254,6 +254,7 @@ class TestKeystoneOperatorCharm(test_utils.CharmTestCase): test_utils.add_db_relation_credentials( self.harness, test_utils.add_base_db_relation(self.harness) ) + test_utils.add_complete_logging_relation(self.harness) self.km_mock.setup_keystone.assert_called_once_with() self.km_mock.setup_initial_projects_and_users.assert_called_once_with() @@ -270,6 +271,7 @@ class TestKeystoneOperatorCharm(test_utils.CharmTestCase): "credential-keys-secret-id": credential_secret_id, }, ) + assert self.harness.charm.logging.ready def test_on_peer_data_changed_no_bootstrap(self): """Test peer_relation_changed on no bootstrap.""" diff --git a/charms/keystone-ldap-k8s/metadata.yaml b/charms/keystone-ldap-k8s/metadata.yaml index 0c6d8b9f..e52645bc 100644 --- a/charms/keystone-ldap-k8s/metadata.yaml +++ b/charms/keystone-ldap-k8s/metadata.yaml @@ -12,3 +12,7 @@ peers: provides: domain-config: interface: keystone-domain-config +requires: + logging: + interface: loki_push_api + optional: true diff --git a/charms/magnum-k8s/metadata.yaml b/charms/magnum-k8s/metadata.yaml index 0dfcb3c6..67597a06 100644 --- a/charms/magnum-k8s/metadata.yaml +++ b/charms/magnum-k8s/metadata.yaml @@ -54,6 +54,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true peers: peers: diff --git a/charms/neutron-k8s/metadata.yaml b/charms/neutron-k8s/metadata.yaml index 461a3794..35b335f4 100644 --- a/charms/neutron-k8s/metadata.yaml +++ b/charms/neutron-k8s/metadata.yaml @@ -63,6 +63,9 @@ requires: external-dns: interface: designate optional: true + logging: + interface: loki_push_api + optional: true peers: peers: diff --git a/charms/nova-k8s/metadata.yaml b/charms/nova-k8s/metadata.yaml index b50e4b9e..7895d6aa 100644 --- a/charms/nova-k8s/metadata.yaml +++ b/charms/nova-k8s/metadata.yaml @@ -96,6 +96,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true provides: nova-service: diff --git a/charms/octavia-k8s/metadata.yaml b/charms/octavia-k8s/metadata.yaml index 8a336d9b..5b5b6f74 100644 --- a/charms/octavia-k8s/metadata.yaml +++ b/charms/octavia-k8s/metadata.yaml @@ -79,6 +79,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true peers: peers: diff --git a/charms/openstack-exporter-k8s/metadata.yaml b/charms/openstack-exporter-k8s/metadata.yaml index 3fc5d616..f0332ae6 100644 --- a/charms/openstack-exporter-k8s/metadata.yaml +++ b/charms/openstack-exporter-k8s/metadata.yaml @@ -31,6 +31,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true provides: metrics-endpoint: diff --git a/charms/openstack-images-sync-k8s/charmcraft.yaml b/charms/openstack-images-sync-k8s/charmcraft.yaml index 84fc8b24..69704b25 100644 --- a/charms/openstack-images-sync-k8s/charmcraft.yaml +++ b/charms/openstack-images-sync-k8s/charmcraft.yaml @@ -73,3 +73,6 @@ requires: limit: 1 identity-service: interface: keystone + logging: + interface: loki_push_api + optional: true diff --git a/charms/ovn-central-k8s/metadata.yaml b/charms/ovn-central-k8s/metadata.yaml index 899005ab..85220c75 100644 --- a/charms/ovn-central-k8s/metadata.yaml +++ b/charms/ovn-central-k8s/metadata.yaml @@ -69,6 +69,9 @@ resources: requires: certificates: interface: tls-certificates + logging: + interface: loki_push_api + optional: true provides: ovsdb: diff --git a/charms/ovn-relay-k8s/metadata.yaml b/charms/ovn-relay-k8s/metadata.yaml index a809eb14..96e3f32f 100644 --- a/charms/ovn-relay-k8s/metadata.yaml +++ b/charms/ovn-relay-k8s/metadata.yaml @@ -34,6 +34,9 @@ requires: interface: ovsdb-cms certificates: interface: tls-certificates + logging: + interface: loki_push_api + optional: true provides: ovsdb-cms-relay: diff --git a/charms/placement-k8s/metadata.yaml b/charms/placement-k8s/metadata.yaml index bc18f76f..8000069d 100644 --- a/charms/placement-k8s/metadata.yaml +++ b/charms/placement-k8s/metadata.yaml @@ -43,6 +43,9 @@ requires: receive-ca-cert: interface: certificate_transfer optional: true + logging: + interface: loki_push_api + optional: true provides: placement: diff --git a/charms/tempest-k8s/charmcraft.yaml b/charms/tempest-k8s/charmcraft.yaml index f5fb437b..705d5f69 100644 --- a/charms/tempest-k8s/charmcraft.yaml +++ b/charms/tempest-k8s/charmcraft.yaml @@ -62,6 +62,7 @@ requires: interface: keystone-resources logging: interface: loki_push_api + optional: true provides: grafana-dashboard: diff --git a/charms/tempest-k8s/src/charm.py b/charms/tempest-k8s/src/charm.py index 70d79263..1405c9d3 100755 --- a/charms/tempest-k8s/src/charm.py +++ b/charms/tempest-k8s/src/charm.py @@ -157,7 +157,7 @@ class TempestOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S): schedule.valid and schedule.value and self.is_tempest_ready() - and self.loki.ready + and self.logging.ready and self.user_id_ops.ready ) @@ -179,9 +179,27 @@ class TempestOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S): ) ] - def get_relation_handlers(self) -> List[sunbeam_rhandlers.RelationHandler]: + def get_relation_handlers( + self, handlers: list[sunbeam_rhandlers.RelationHandler] | None = None + ) -> list[sunbeam_rhandlers.RelationHandler]: """Relation handlers for the service.""" - handlers = super().get_relation_handlers() + handlers = handlers or [] + # Ensure the logging relation is before the one setup by the base class + self.logging = LoggingRelationHandler( + self, + LOKI_RELATION_NAME, + self.configure_charm, + mandatory=LOKI_RELATION_NAME in self.mandatory_relations, + ) + handlers.append(self.logging) + handlers = super().get_relation_handlers(handlers) + self.grafana = GrafanaDashboardRelationHandler( + self, + "grafana-dashboard", + self.configure_charm, + mandatory="grafana-dashboard" in self.mandatory_relations, + ) + handlers.append(self.grafana) self.user_id_ops = TempestUserIdentityRelationHandler( self, "identity-ops", @@ -190,20 +208,6 @@ class TempestOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S): region=self.config["region"], ) handlers.append(self.user_id_ops) - self.loki = LoggingRelationHandler( - self, - LOKI_RELATION_NAME, - self.configure_charm, - mandatory="logging" in self.mandatory_relations, - ) - handlers.append(self.loki) - self.grafana = GrafanaDashboardRelationHandler( - self, - "grafana-dashboard", - self.configure_charm, - mandatory="grafana-dashboard" in self.mandatory_relations, - ) - handlers.append(self.grafana) return handlers def _get_proxy_environment(self) -> Dict[str, str]: @@ -350,9 +354,9 @@ class TempestOperatorCharm(sunbeam_charm.OSBaseOperatorCharmK8S): else: ensure_alert_rules_disabled() - if self.loki.ready: + if self.logging.ready: for relation in self.model.relations[LOKI_RELATION_NAME]: - self.loki.interface._handle_alert_rules(relation) + self.logging.interface._handle_alert_rules(relation) self.status.set(ActiveStatus("")) logger.info("Finished configuring the tempest environment") diff --git a/charms/tempest-k8s/tests/unit/test_tempest_charm.py b/charms/tempest-k8s/tests/unit/test_tempest_charm.py index ffa389cd..0842bbdc 100644 --- a/charms/tempest-k8s/tests/unit/test_tempest_charm.py +++ b/charms/tempest-k8s/tests/unit/test_tempest_charm.py @@ -167,10 +167,9 @@ class TestTempestOperatorCharm(test_utils.CharmTestCase): def add_logging_relation(self, harness): """Add logging relation.""" - rel_id = harness.add_relation("logging", "loki") - harness.add_relation_unit(rel_id, "loki/0") - harness.charm.loki.interface = Mock() - harness.charm.loki.interface._promtail_config = Mock() + rel_id = test_utils.add_complete_logging_relation(harness) + harness.charm.logging.interface = Mock() + harness.charm.logging.interface._promtail_config = Mock() return rel_id def add_grafana_dashboard_relation(self, harness): @@ -625,7 +624,7 @@ class TestTempestOperatorCharm(test_utils.CharmTestCase): rel_id = self.add_logging_relation(self.harness) # client endpoints found - self.harness.charm.loki.interface._promtail_config.return_value = { + self.harness.charm.logging.interface._promtail_config.return_value = { "clients": [ { "url": "http://grafana-agent-k8s-endpoints:3500/loki/api/v1/push" @@ -633,16 +632,16 @@ class TestTempestOperatorCharm(test_utils.CharmTestCase): ], "other_key": "other_values", } - self.assertEqual(self.harness.charm.loki.ready, True) + self.assertEqual(self.harness.charm.logging.ready, True) # empty client endpoints - self.harness.charm.loki.interface._promtail_config.return_value = { + self.harness.charm.logging.interface._promtail_config.return_value = { "clients": [], "other_key": "other_values", } - self.assertEqual(self.harness.charm.loki.ready, False) + self.assertEqual(self.harness.charm.logging.ready, False) # empty promtail config self.harness.remove_relation(rel_id) - self.harness.charm.loki.interface._promtail_config.return_value = {} - self.assertEqual(self.harness.charm.loki.ready, False) + self.harness.charm.logging.interface._promtail_config.return_value = {} + self.assertEqual(self.harness.charm.logging.ready, False) diff --git a/common.sh b/common.sh index 75578b73..cc928d30 100644 --- a/common.sh +++ b/common.sh @@ -17,520 +17,533 @@ NULL_ARRAY=() # Internal libs for component. If libs are repeated, reuse the existing component INTERNAL_CEILOMETER_LIBS=( - "keystone_k8s" - "ceilometer_k8s" - "gnocchi_k8s" + "keystone_k8s" + "ceilometer_k8s" + "gnocchi_k8s" ) INTERNAL_CINDER_LIBS=( - "keystone_k8s" - "cinder_k8s" + "keystone_k8s" + "cinder_k8s" ) INTERNAL_CINDER_CEPH_LIBS=( - "keystone_k8s" - "cinder_k8s" - "cinder_ceph_k8s" + "keystone_k8s" + "cinder_k8s" + "cinder_ceph_k8s" ) INTERNAL_DESIGNATE_LIBS=( - "keystone_k8s" - "designate_bind_k8s" - "designate_k8s" + "keystone_k8s" + "designate_bind_k8s" + "designate_k8s" ) INTERNAL_DESIGNATE_BIND_LIBS=( - "designate_bind_k8s" + "designate_bind_k8s" ) INTERNAL_GNOCCHI_LIBS=( - "keystone_k8s" - "gnocchi_k8s" + "keystone_k8s" + "gnocchi_k8s" ) INTERNAL_KEYSTONE_LIBS=( - "keystone_k8s" + "keystone_k8s" ) INTERNAL_NEUTRON_LIBS=( - "keystone_k8s" - "ovn_central_k8s" - "designate_k8s" + "keystone_k8s" + "ovn_central_k8s" + "designate_k8s" ) INTERNAL_NOVA_LIBS=( - "keystone_k8s" - "nova_k8s" - "sunbeam_nova_compute_operator" + "keystone_k8s" + "nova_k8s" + "sunbeam_nova_compute_operator" ) INTERNAL_OPENSTACK_HYPERVISOR_LIBS=( - "keystone_k8s" - "ovn_central_k8s" - "cinder_ceph_k8s" - "ceilometer_k8s" - "nova_k8s" + "keystone_k8s" + "ovn_central_k8s" + "cinder_ceph_k8s" + "ceilometer_k8s" + "nova_k8s" ) INTERNAL_OPENSTACK_IMAGES_SYNC_LIBS=( - "keystone_k8s" + "keystone_k8s" ) INTERNAL_OVN_CENTRAL_LIBS=( - "ovn_central_k8s" + "ovn_central_k8s" ) # External libs for component. If libs are repeated, reuse the existing component EXTERNAL_AODH_LIBS=( - "data_platform_libs" - "rabbitmq_k8s" - "traefik_k8s" - "certificate_transfer_interface" + "data_platform_libs" + "rabbitmq_k8s" + "traefik_k8s" + "certificate_transfer_interface" + "loki_k8s" ) EXTERNAL_BARBICAN_LIBS=( - "data_platform_libs" - "rabbitmq_k8s" - "traefik_k8s" - "vault_k8s" - "certificate_transfer_interface" + "data_platform_libs" + "rabbitmq_k8s" + "traefik_k8s" + "vault_k8s" + "certificate_transfer_interface" + "loki_k8s" ) EXTERNAL_CEILOMETER_LIBS=( - "rabbitmq_k8s" - "certificate_transfer_interface" + "rabbitmq_k8s" + "certificate_transfer_interface" + "loki_k8s" ) EXTERNAL_CINDER_CEPH_LIBS=( - "data_platform_libs" - "rabbitmq_k8s" - "traefik_k8s" + "data_platform_libs" + "rabbitmq_k8s" + "traefik_k8s" + "loki_k8s" ) EXTERNAL_DESIGNATE_BIND_LIBS=( - "observability_libs" + "observability_libs" + "loki_k8s" ) EXTERNAL_HEAT_LIBS=( - "data_platform_libs" - "rabbitmq_k8s" - "traefik_route_k8s" - "certificate_transfer_interface" + "data_platform_libs" + "rabbitmq_k8s" + "traefik_route_k8s" + "certificate_transfer_interface" + "loki_k8s" ) EXTERNAL_NEUTRON_LIBS=( - "data_platform_libs" - "rabbitmq_k8s" - "traefik_k8s" - "tls_certificates_interface" - "certificate_transfer_interface" + "data_platform_libs" + "rabbitmq_k8s" + "traefik_k8s" + "tls_certificates_interface" + "certificate_transfer_interface" + "loki_k8s" ) EXTERNAL_NOVA_LIBS=( - "data_platform_libs" - "rabbitmq_k8s" - "traefik_k8s" - "traefik_route_k8s" - "certificate_transfer_interface" + "data_platform_libs" + "rabbitmq_k8s" + "traefik_k8s" + "traefik_route_k8s" + "certificate_transfer_interface" + "loki_k8s" ) EXTERNAL_OCTAVIA_LIBS=( - "data_platform_libs" - "traefik_k8s" - "tls_certificates_interface" - "certificate_transfer_interface" + "data_platform_libs" + "traefik_k8s" + "tls_certificates_interface" + "certificate_transfer_interface" + "loki_k8s" ) EXTERNAL_OPENSTACK_EXPORTER_LIBS=( - "grafana_k8s" - "prometheus_k8s" - "tls_certificates_interface" - "certificate_transfer_interface" + "grafana_k8s" + "prometheus_k8s" + "tls_certificates_interface" + "certificate_transfer_interface" + "loki_k8s" ) EXTERNAL_OPENSTACK_HYPERVISOR_LIBS=( - "data_platform_libs" - "grafana_agent" - "observability_libs" - "operator_libs_linux" - "rabbitmq_k8s" - "traefik_k8s" - "tls_certificates_interface" - "certificate_transfer_interface" + "data_platform_libs" + "grafana_agent" + "observability_libs" + "operator_libs_linux" + "rabbitmq_k8s" + "traefik_k8s" + "tls_certificates_interface" + "certificate_transfer_interface" ) EXTERNAL_OPENSTACK_IMAGES_SYNC_LIBS=( "traefik_k8s" + "loki_k8s" ) EXTERNAL_SUNBEAM_CLUSTERD_LIBS=( - "operator_libs_linux" - "tls_certificates_interface" + "operator_libs_linux" + "tls_certificates_interface" ) EXTERNAL_SUNBEAM_MACHINE_LIBS=( - "operator_libs_linux" + "operator_libs_linux" ) EXTERNAL_OVN_CENTRAL_LIBS=( - "tls_certificates_interface" + "tls_certificates_interface" + "loki_k8s" ) EXTERNAL_OVN_RELAY_LIBS=( - "tls_certificates_interface" - "observability_libs" + "tls_certificates_interface" + "observability_libs" + "loki_k8s" ) EXTERNAL_TEMPEST_LIBS=( - "observability_libs" - "grafana_k8s" - "loki_k8s" + "observability_libs" + "grafana_k8s" + "loki_k8s" ) # Config template parts for each component. CONFIG_TEMPLATES_AODH=( - "parts/section-database" - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-identity" - "parts/identity-data" - "parts/section-oslo-messaging-rabbit" - "parts/section-service-credentials" - "ca-bundle.pem.j2" + "parts/section-database" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-identity" + "parts/identity-data" + "parts/section-oslo-messaging-rabbit" + "parts/section-service-credentials" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_BARBICAN=( - "parts/section-database" - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-identity" - "parts/identity-data" - "parts/section-oslo-messaging-rabbit" - "parts/section-service-user" - "ca-bundle.pem.j2" + "parts/section-database" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-identity" + "parts/identity-data" + "parts/section-oslo-messaging-rabbit" + "parts/section-service-user" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_CEILOMETER=( - "parts/identity-data-id-creds" - "parts/section-oslo-messaging-rabbit" - "parts/section-service-credentials-from-identity-service" - "ca-bundle.pem.j2" + "parts/identity-data-id-creds" + "parts/section-oslo-messaging-rabbit" + "parts/section-service-credentials-from-identity-service" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_CINDER=( - "parts/section-database" - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-identity" - "parts/identity-data" - "parts/section-oslo-messaging-rabbit" - "parts/section-service-user" - "ca-bundle.pem.j2" + "parts/section-database" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-identity" + "parts/identity-data" + "parts/section-oslo-messaging-rabbit" + "parts/section-service-user" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_CINDER_CEPH=( - "parts/section-database" - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-oslo-messaging-rabbit" - "parts/section-oslo-notifications" + "parts/section-database" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-oslo-messaging-rabbit" + "parts/section-oslo-notifications" ) CONFIG_TEMPLATES_DESIGNATE=( - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-identity" - "parts/identity-data" - "parts/section-oslo-messaging-rabbit" - "parts/section-service-user" - "ca-bundle.pem.j2" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-identity" + "parts/identity-data" + "parts/section-oslo-messaging-rabbit" + "parts/section-service-user" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_GLANCE=( - "parts/section-database" - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-identity" - "parts/identity-data" - "parts/section-oslo-messaging-rabbit" - "parts/section-oslo-notifications" - "parts/section-service-user" - "ca-bundle.pem.j2" + "parts/section-database" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-identity" + "parts/identity-data" + "parts/section-oslo-messaging-rabbit" + "parts/section-oslo-notifications" + "parts/section-service-user" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_GNOCCHI=( - "parts/database-connection" - "parts/section-identity" - "parts/identity-data" - "ca-bundle.pem.j2" + "parts/database-connection" + "parts/section-identity" + "parts/identity-data" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_HEAT=( - "parts/section-database" - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-identity" - "parts/identity-data" - "parts/section-trustee" - "parts/section-oslo-messaging-rabbit" - "ca-bundle.pem.j2" + "parts/section-database" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-identity" + "parts/identity-data" + "parts/section-trustee" + "parts/section-oslo-messaging-rabbit" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_HORIZON=( - "ca-bundle.pem.j2" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_KEYSTONE=( - "parts/section-database" - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-federation" - "parts/section-middleware" - "parts/section-oslo-cache" - "parts/section-oslo-messaging-rabbit" - "parts/section-oslo-middleware" - "parts/section-oslo-notifications" - "parts/section-signing" + "parts/section-database" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-federation" + "parts/section-middleware" + "parts/section-oslo-cache" + "parts/section-oslo-messaging-rabbit" + "parts/section-oslo-middleware" + "parts/section-oslo-notifications" + "parts/section-signing" ) CONFIG_TEMPLATES_MAGNUM=( - "parts/section-database" - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-identity" - "parts/identity-data" - "parts/section-oslo-messaging-rabbit" - "parts/section-service-user" - "parts/section-trust" - "ca-bundle.pem.j2" + "parts/section-database" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-identity" + "parts/identity-data" + "parts/section-oslo-messaging-rabbit" + "parts/section-service-user" + "parts/section-trust" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_NEUTRON=( - "parts/section-database" - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-identity" - "parts/identity-data" - "parts/section-oslo-messaging-rabbit" - "parts/section-service-user" - "ca-bundle.pem.j2" + "parts/section-database" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-identity" + "parts/identity-data" + "parts/section-oslo-messaging-rabbit" + "parts/section-service-user" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_NOVA=${CONFIG_TEMPLATES_NEUTRON[@]} CONFIG_TEMPLATES_OCTAVIA=( - "parts/section-database" - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-identity" - "parts/identity-data" - "ca-bundle.pem.j2" + "parts/section-database" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-identity" + "parts/identity-data" + "ca-bundle.pem.j2" ) CONFIG_TEMPLATES_PLACEMENT=( - "parts/database-connection" - "parts/database-connection-settings" - "parts/section-identity" - "parts/identity-data" - "parts/section-service-user" - "ca-bundle.pem.j2" + "parts/database-connection" + "parts/database-connection-settings" + "parts/section-identity" + "parts/identity-data" + "parts/section-service-user" + "ca-bundle.pem.j2" ) declare -A INTERNAL_LIBS=( - [aodh-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} - [barbican-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} - [ceilometer-k8s]=${INTERNAL_CEILOMETER_LIBS[@]} - [cinder-k8s]=${INTERNAL_CINDER_LIBS[@]} - [cinder-ceph-k8s]=${INTERNAL_CINDER_CEPH_LIBS[@]} - [designate-k8s]=${INTERNAL_DESIGNATE_LIBS[@]} - [designate-bind-k8s]=${INTERNAL_DESIGNATE_BIND_LIBS[@]} - [glance-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} - [gnocchi-k8s]=${INTERNAL_GNOCCHI_LIBS[@]} - [heat-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} - [horizon-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} - [keystone-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} - [keystone-ldap-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} - [magnum-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} - [neutron-k8s]=${INTERNAL_NEUTRON_LIBS[@]} - [nova-k8s]=${INTERNAL_NOVA_LIBS[@]} - [octavia-k8s]=${INTERNAL_NEUTRON_LIBS[@]} - [openstack-exporter-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} - [openstack-hypervisor]=${INTERNAL_OPENSTACK_HYPERVISOR_LIBS[@]} - [openstack-images-sync-k8s]=${INTERNAL_OPENSTACK_IMAGES_SYNC_LIBS[@]} - [sunbeam-clusterd]=${NULL_ARRAY[@]} - [sunbeam-machine]=${NULL_ARRAY[@]} - [ovn-central-k8s]=${INTERNAL_OVN_CENTRAL_LIBS[@]} - [ovn-relay-k8s]=${INTERNAL_OVN_CENTRAL_LIBS[@]} - [placement-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} - [tempest-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} + [aodh-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} + [barbican-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} + [ceilometer-k8s]=${INTERNAL_CEILOMETER_LIBS[@]} + [cinder-k8s]=${INTERNAL_CINDER_LIBS[@]} + [cinder-ceph-k8s]=${INTERNAL_CINDER_CEPH_LIBS[@]} + [designate-k8s]=${INTERNAL_DESIGNATE_LIBS[@]} + [designate-bind-k8s]=${INTERNAL_DESIGNATE_BIND_LIBS[@]} + [glance-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} + [gnocchi-k8s]=${INTERNAL_GNOCCHI_LIBS[@]} + [heat-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} + [horizon-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} + [keystone-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} + [keystone-ldap-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} + [magnum-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} + [neutron-k8s]=${INTERNAL_NEUTRON_LIBS[@]} + [nova-k8s]=${INTERNAL_NOVA_LIBS[@]} + [octavia-k8s]=${INTERNAL_NEUTRON_LIBS[@]} + [openstack-exporter-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} + [openstack-hypervisor]=${INTERNAL_OPENSTACK_HYPERVISOR_LIBS[@]} + [openstack-images-sync-k8s]=${INTERNAL_OPENSTACK_IMAGES_SYNC_LIBS[@]} + [sunbeam-clusterd]=${NULL_ARRAY[@]} + [sunbeam-machine]=${NULL_ARRAY[@]} + [ovn-central-k8s]=${INTERNAL_OVN_CENTRAL_LIBS[@]} + [ovn-relay-k8s]=${INTERNAL_OVN_CENTRAL_LIBS[@]} + [placement-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} + [tempest-k8s]=${INTERNAL_KEYSTONE_LIBS[@]} ) declare -A EXTERNAL_LIBS=( - [aodh-k8s]=${EXTERNAL_AODH_LIBS[@]} - [barbican-k8s]=${EXTERNAL_BARBICAN_LIBS[@]} - [ceilometer-k8s]=${EXTERNAL_CEILOMETER_LIBS[@]} - [cinder-k8s]=${EXTERNAL_AODH_LIBS[@]} - [cinder-ceph-k8s]=${EXTERNAL_CINDER_CEPH_LIBS[@]} - [designate-k8s]=${EXTERNAL_AODH_LIBS[@]} - [designate-bind-k8s]=${EXTERNAL_DESIGNATE_BIND_LIBS[@]} - [glance-k8s]=${EXTERNAL_AODH_LIBS[@]} - [gnocchi-k8s]=${EXTERNAL_AODH_LIBS[@]} - [heat-k8s]=${EXTERNAL_HEAT_LIBS[@]} - [horizon-k8s]=${EXTERNAL_AODH_LIBS[@]} - [keystone-k8s]=${EXTERNAL_AODH_LIBS[@]} - [keystone-ldap-k8s]=${NULL_ARRAY[@]} - [magnum-k8s]=${EXTERNAL_AODH_LIBS[@]} - [neutron-k8s]=${EXTERNAL_NEUTRON_LIBS[@]} - [nova-k8s]=${EXTERNAL_NOVA_LIBS[@]} - [octavia-k8s]=${EXTERNAL_OCTAVIA_LIBS[@]} - [openstack-exporter-k8s]=${EXTERNAL_OPENSTACK_EXPORTER_LIBS[@]} - [openstack-hypervisor]=${EXTERNAL_OPENSTACK_HYPERVISOR_LIBS[@]} - [openstack-images-sync-k8s]=${EXTERNAL_OPENSTACK_IMAGES_SYNC_LIBS[@]} - [sunbeam-clusterd]=${EXTERNAL_SUNBEAM_CLUSTERD_LIBS[@]} - [sunbeam-machine]=${EXTERNAL_SUNBEAM_MACHINE_LIBS[@]} - [ovn-central-k8s]=${EXTERNAL_OVN_CENTRAL_LIBS[@]} - [ovn-relay-k8s]=${EXTERNAL_OVN_RELAY_LIBS[@]} - [placement-k8s]=${EXTERNAL_AODH_LIBS[@]} - [tempest-k8s]=${EXTERNAL_TEMPEST_LIBS[@]} + [aodh-k8s]=${EXTERNAL_AODH_LIBS[@]} + [barbican-k8s]=${EXTERNAL_BARBICAN_LIBS[@]} + [ceilometer-k8s]=${EXTERNAL_CEILOMETER_LIBS[@]} + [cinder-k8s]=${EXTERNAL_AODH_LIBS[@]} + [cinder-ceph-k8s]=${EXTERNAL_CINDER_CEPH_LIBS[@]} + [designate-k8s]=${EXTERNAL_AODH_LIBS[@]} + [designate-bind-k8s]=${EXTERNAL_DESIGNATE_BIND_LIBS[@]} + [glance-k8s]=${EXTERNAL_AODH_LIBS[@]} + [gnocchi-k8s]=${EXTERNAL_AODH_LIBS[@]} + [heat-k8s]=${EXTERNAL_HEAT_LIBS[@]} + [horizon-k8s]=${EXTERNAL_AODH_LIBS[@]} + [keystone-k8s]=${EXTERNAL_AODH_LIBS[@]} + [keystone-ldap-k8s]=${NULL_ARRAY[@]} + [magnum-k8s]=${EXTERNAL_AODH_LIBS[@]} + [neutron-k8s]=${EXTERNAL_NEUTRON_LIBS[@]} + [nova-k8s]=${EXTERNAL_NOVA_LIBS[@]} + [octavia-k8s]=${EXTERNAL_OCTAVIA_LIBS[@]} + [openstack-exporter-k8s]=${EXTERNAL_OPENSTACK_EXPORTER_LIBS[@]} + [openstack-hypervisor]=${EXTERNAL_OPENSTACK_HYPERVISOR_LIBS[@]} + [openstack-images-sync-k8s]=${EXTERNAL_OPENSTACK_IMAGES_SYNC_LIBS[@]} + [sunbeam-clusterd]=${EXTERNAL_SUNBEAM_CLUSTERD_LIBS[@]} + [sunbeam-machine]=${EXTERNAL_SUNBEAM_MACHINE_LIBS[@]} + [ovn-central-k8s]=${EXTERNAL_OVN_CENTRAL_LIBS[@]} + [ovn-relay-k8s]=${EXTERNAL_OVN_RELAY_LIBS[@]} + [placement-k8s]=${EXTERNAL_AODH_LIBS[@]} + [tempest-k8s]=${EXTERNAL_TEMPEST_LIBS[@]} ) declare -A CONFIG_TEMPLATES=( - [aodh-k8s]=${CONFIG_TEMPLATES_AODH[@]} - [barbican-k8s]=${CONFIG_TEMPLATES_BARBICAN[@]} - [ceilometer-k8s]=${CONFIG_TEMPLATES_CEILOMETER[@]} - [cinder-k8s]=${CONFIG_TEMPLATES_CINDER[@]} - [cinder-ceph-k8s]=${CONFIG_TEMPLATES_CINDER_CEPH[@]} - [designate-k8s]=${CONFIG_TEMPLATES_DESIGNATE[@]} - [designate-bind-k8s]=${NULL_ARRAY[@]} - [glance-k8s]=${CONFIG_TEMPLATES_GLANCE[@]} - [gnocchi-k8s]=${CONFIG_TEMPLATES_GNOCCHI[@]} - [heat-k8s]=${CONFIG_TEMPLATES_HEAT[@]} - [horizon-k8s]=${CONFIG_TEMPLATES_HORIZON[@]} - [keystone-k8s]=${CONFIG_TEMPLATES_KEYSTONE[@]} - [keystone-ldap-k8s]=${NULL_ARRAY[@]} - [magnum-k8s]=${CONFIG_TEMPLATES_MAGNUM[@]} - [neutron-k8s]=${CONFIG_TEMPLATES_NEUTRON[@]} - [nova-k8s]=${CONFIG_TEMPLATES_NOVA[@]} - [octavia-k8s]=${CONFIG_TEMPLATES_OCTAVIA[@]} - [openstack-exporter-k8s]=${CONFIG_TEMPLATES_HORIZON[@]} - [openstack-hypervisor]=${NULL_ARRAY[@]} - [openstack-images-sync-k8s]=${NULL_ARRAY[@]} - [sunbeam-clusterd]=${NULL_ARRAY[@]} - [sunbeam-machine]=${NULL_ARRAY[@]} - [ovn-central-k8s]=${NULL_ARRAY[@]} - [ovn-relay-k8s]=${NULL_ARRAY[@]} - [placement-k8s]=${CONFIG_TEMPLATES_PLACEMENT[@]} - [tempest-k8s]=${NULL_ARRAY[@]} + [aodh-k8s]=${CONFIG_TEMPLATES_AODH[@]} + [barbican-k8s]=${CONFIG_TEMPLATES_BARBICAN[@]} + [ceilometer-k8s]=${CONFIG_TEMPLATES_CEILOMETER[@]} + [cinder-k8s]=${CONFIG_TEMPLATES_CINDER[@]} + [cinder-ceph-k8s]=${CONFIG_TEMPLATES_CINDER_CEPH[@]} + [designate-k8s]=${CONFIG_TEMPLATES_DESIGNATE[@]} + [designate-bind-k8s]=${NULL_ARRAY[@]} + [glance-k8s]=${CONFIG_TEMPLATES_GLANCE[@]} + [gnocchi-k8s]=${CONFIG_TEMPLATES_GNOCCHI[@]} + [heat-k8s]=${CONFIG_TEMPLATES_HEAT[@]} + [horizon-k8s]=${CONFIG_TEMPLATES_HORIZON[@]} + [keystone-k8s]=${CONFIG_TEMPLATES_KEYSTONE[@]} + [keystone-ldap-k8s]=${NULL_ARRAY[@]} + [magnum-k8s]=${CONFIG_TEMPLATES_MAGNUM[@]} + [neutron-k8s]=${CONFIG_TEMPLATES_NEUTRON[@]} + [nova-k8s]=${CONFIG_TEMPLATES_NOVA[@]} + [octavia-k8s]=${CONFIG_TEMPLATES_OCTAVIA[@]} + [openstack-exporter-k8s]=${CONFIG_TEMPLATES_HORIZON[@]} + [openstack-hypervisor]=${NULL_ARRAY[@]} + [openstack-images-sync-k8s]=${NULL_ARRAY[@]} + [sunbeam-clusterd]=${NULL_ARRAY[@]} + [sunbeam-machine]=${NULL_ARRAY[@]} + [ovn-central-k8s]=${NULL_ARRAY[@]} + [ovn-relay-k8s]=${NULL_ARRAY[@]} + [placement-k8s]=${CONFIG_TEMPLATES_PLACEMENT[@]} + [tempest-k8s]=${NULL_ARRAY[@]} ) function copy_ops_sunbeam { - cp -rf ../../ops-sunbeam/ops_sunbeam lib/ + cp -rf ../../ops-sunbeam/ops_sunbeam lib/ } function copy_internal_libs { - internal_libs_=${INTERNAL_LIBS[$1]} - echo "copy_internal_libs for $1:" - for lib in ${internal_libs_[@]}; do - echo "Copying $lib" - cp -rf ../../libs/internal/lib/charms/$lib lib/charms/ - done + internal_libs_=${INTERNAL_LIBS[$1]} + echo "copy_internal_libs for $1:" + for lib in ${internal_libs_[@]}; do + echo "Copying $lib" + cp -rf ../../libs/internal/lib/charms/$lib lib/charms/ + done } function copy_external_libs { - echo "copy_external_libs for $1:" - external_libs_=${EXTERNAL_LIBS[$1]} - for lib in ${external_libs_[@]}; do - echo "Copying $lib" - cp -rf ../../libs/external/lib/charms/$lib lib/charms/ - done + echo "copy_external_libs for $1:" + external_libs_=${EXTERNAL_LIBS[$1]} + for lib in ${external_libs_[@]}; do + echo "Copying $lib" + cp -rf ../../libs/external/lib/charms/$lib lib/charms/ + done } function copy_config_templates { - echo "copy_config_templates for $1:" - config_templates_=${CONFIG_TEMPLATES[$1]} - for part in ${config_templates_[@]}; do - echo "Copying $part" - cp -rf ../../templates/$part src/templates/$part - done + echo "copy_config_templates for $1:" + config_templates_=${CONFIG_TEMPLATES[$1]} + for part in ${config_templates_[@]}; do + echo "Copying $part" + cp -rf ../../templates/$part src/templates/$part + done } function copy_juju_ignore { - cp ../../.jujuignore . + cp ../../.jujuignore . } function copy_stestr_conf { - cp ../../.stestr.conf . + cp ../../.stestr.conf . } function remove_libs { - rm -rf lib + rm -rf lib } function remove_config_templates { - echo "remove_config_templates for $1:" - config_templates_=${CONFIG_TEMPLATES[$1]} - for part in ${config_templates_[@]}; do - echo "Removing $part" - rm src/templates/$part - done + echo "remove_config_templates for $1:" + config_templates_=${CONFIG_TEMPLATES[$1]} + for part in ${config_templates_[@]}; do + echo "Removing $part" + rm src/templates/$part + done - if (test -d src/templates/parts) && (test -n "$(find src/templates/parts -maxdepth 0 -empty)") - then - remove_templates_parts_dir - fi +if (test -d src/templates/parts) && (test -n "$(find src/templates/parts -maxdepth 0 -empty)") +then + remove_templates_parts_dir +fi } function remove_templates_parts_dir { - rm -rf src/templates/parts +rm -rf src/templates/parts } function remove_juju_ignore { - rm .jujuignore +rm .jujuignore } function remove_stestr_conf { - rm .stestr.conf +rm .stestr.conf } function push_common_files { - if [[ $# != 1 ]]; - then - echo "push_common_files: Expected one argument" - exit 1 - fi +if [[ $# != 1 ]]; +then + echo "push_common_files: Expected one argument" + exit 1 + fi - pushd charms/$1 + pushd charms/$1 - mkdir -p lib/charms - mkdir -p src/templates/parts + mkdir -p lib/charms + mkdir -p src/templates/parts - copy_ops_sunbeam - copy_internal_libs $1 - copy_external_libs $1 - copy_config_templates $1 - copy_stestr_conf - copy_juju_ignore + copy_ops_sunbeam + copy_internal_libs $1 + copy_external_libs $1 + copy_config_templates $1 + copy_stestr_conf + copy_juju_ignore - popd + popd } function pop_common_files { - pushd charms/$1 + pushd charms/$1 - remove_libs - remove_config_templates $1 - remove_stestr_conf - remove_juju_ignore + remove_libs + remove_config_templates $1 + remove_stestr_conf + remove_juju_ignore - popd + popd } function copy_libs_for_ops_sunbeam { - mkdir -p tests/lib - cp -rf ../libs/external/lib ../libs/internal/lib tests/ + mkdir -p tests/lib + cp -rf ../libs/external/lib ../libs/internal/lib tests/ } function remove_libs_for_ops_sunbeam { - rm -rf tests/lib + rm -rf tests/lib } diff --git a/libs/external/lib/charms/loki_k8s/v1/loki_push_api.py b/libs/external/lib/charms/loki_k8s/v1/loki_push_api.py index 1aa092ed..c3c1d086 100644 --- a/libs/external/lib/charms/loki_k8s/v1/loki_push_api.py +++ b/libs/external/lib/charms/loki_k8s/v1/loki_push_api.py @@ -16,20 +16,24 @@ The provider side of the relation represents the server side, to which logs are send log to Loki by implementing the consumer side of the `loki_push_api` relation interface. For instance, a Promtail or Grafana agent charm which needs to send logs to Loki. -- `LogProxyConsumer`: This object can be used by any Charmed Operator which needs to -send telemetry, such as logs, to Loki through a Log Proxy by implementing the consumer side of the -`loki_push_api` relation interface. +- `LogProxyConsumer`: DEPRECATED. +This object can be used by any Charmed Operator which needs to send telemetry, such as logs, to +Loki through a Log Proxy by implementing the consumer side of the `loki_push_api` relation +interface. +In order to be able to control the labels on the logs pushed this object adds a Pebble layer +that runs Promtail in the workload container, injecting Juju topology labels into the +logs on the fly. +This object is deprecated. Consider migrating to LogForwarder with the release of Juju 3.6 LTS. - `LogForwarder`: This object can be used by any Charmed Operator which needs to send the workload standard output (stdout) through Pebble's log forwarding mechanism, to Loki endpoints through the `loki_push_api` relation interface. +In order to be able to control the labels on the logs pushed this object updates the pebble layer's +"log-targets" section with Juju topology. Filtering logs in Loki is largely performed on the basis of labels. In the Juju ecosystem, Juju topology labels are used to uniquely identify the workload which generates telemetry like logs. -In order to be able to control the labels on the logs pushed this object adds a Pebble layer -that runs Promtail in the workload container, injecting Juju topology labels into the -logs on the fly. ## LokiPushApiProvider Library Usage @@ -42,13 +46,14 @@ and three optional arguments. - `charm`: A reference to the parent (Loki) charm. - `relation_name`: The name of the relation that the charm uses to interact - with its clients, which implement `LokiPushApiConsumer` or `LogProxyConsumer`. + with its clients, which implement `LokiPushApiConsumer` `LogForwarder`, or `LogProxyConsumer` + (note that LogProxyConsumer is deprecated). If provided, this relation name must match a provided relation in metadata.yaml with the `loki_push_api` interface. - The default relation name is "logging" for `LokiPushApiConsumer` and "log-proxy" for - `LogProxyConsumer`. + The default relation name is "logging" for `LokiPushApiConsumer` and `LogForwarder`, and + "log-proxy" for `LogProxyConsumer` (note that LogProxyConsumer is deprecated). For example, a provider's `metadata.yaml` file may look as follows: @@ -223,6 +228,9 @@ to do this with promtail. ## LogProxyConsumer Library Usage +> Note: This object is deprecated. Consider migrating to LogForwarder with the release of Juju 3.6 +> LTS. + Let's say that we have a workload charm that produces logs, and we need to send those logs to a workload implementing the `loki_push_api` interface, such as `Loki` or `Grafana Agent`. @@ -519,7 +527,7 @@ LIBAPI = 1 # Increment this PATCH version before using `charmcraft publish-lib` or reset # to 0 if you are raising the major API version -LIBPATCH = 9 +LIBPATCH = 11 PYDEPS = ["cosl"] @@ -535,17 +543,20 @@ PROMTAIL_BASE_URL = "https://github.com/canonical/loki-k8s-operator/releases/dow # update all sha256 sums in PROMTAIL_BINARIES. To support a new architecture # you only need to add a new key value pair for the architecture in PROMTAIL_BINARIES. PROMTAIL_VERSION = "v2.9.7" +PROMTAIL_ARM_BINARY = { + "filename": "promtail-static-arm64", + "zipsha": "c083fdb45e5c794103f974eeb426489b4142438d9e10d0ae272b2aff886e249b", + "binsha": "4cd055c477a301c0bdfdbcea514e6e93f6df5d57425ce10ffc77f3e16fec1ddf", +} + PROMTAIL_BINARIES = { "amd64": { "filename": "promtail-static-amd64", "zipsha": "6873cbdabf23062aeefed6de5f00ff382710332af3ab90a48c253ea17e08f465", "binsha": "28da9b99f81296fe297831f3bc9d92aea43b4a92826b8ff04ba433b8cb92fb50", }, - "arm64": { - "filename": "promtail-static-arm64", - "zipsha": "c083fdb45e5c794103f974eeb426489b4142438d9e10d0ae272b2aff886e249b", - "binsha": "4cd055c477a301c0bdfdbcea514e6e93f6df5d57425ce10ffc77f3e16fec1ddf", - }, + "arm64": PROMTAIL_ARM_BINARY, + "aarch64": PROMTAIL_ARM_BINARY, } # Paths in `charm` container @@ -1590,7 +1601,8 @@ class LokiPushApiConsumer(ConsumerBase): the Loki API endpoint to push logs. It is intended for workloads that can speak loki_push_api (https://grafana.com/docs/loki/latest/api/#push-log-entries-to-loki), such as grafana-agent. - (If you only need to forward a few workload log files, then use LogProxyConsumer.) + (If you need to forward workload stdout logs, then use LogForwarder; if you need to forward + log files, then use LogProxyConsumer.) `LokiPushApiConsumer` can be instantiated as follows: @@ -1765,6 +1777,9 @@ class LogProxyEvents(ObjectEvents): class LogProxyConsumer(ConsumerBase): """LogProxyConsumer class. + > Note: This object is deprecated. Consider migrating to LogForwarder with the release of Juju + > 3.6 LTS. + The `LogProxyConsumer` object provides a method for attaching `promtail` to a workload in order to generate structured logging data from applications which traditionally log to syslog or do not have native Loki integration. diff --git a/ops-sunbeam/ops_sunbeam/charm.py b/ops-sunbeam/ops_sunbeam/charm.py index ff3ba0c8..362b1657 100644 --- a/ops-sunbeam/ops_sunbeam/charm.py +++ b/ops-sunbeam/ops_sunbeam/charm.py @@ -653,6 +653,20 @@ class OSBaseOperatorCharmK8S(OSBaseOperatorCharm): self.run_db_sync() self._state.unit_bootstrapped = True + def get_relation_handlers( + self, handlers: list[sunbeam_rhandlers.RelationHandler] | None = None + ) -> list[sunbeam_rhandlers.RelationHandler]: + """Relation handlers for the service.""" + handlers = handlers or [] + if self.can_add_handler("logging", handlers): + self.logging = sunbeam_rhandlers.LogForwardHandler( + self, + "logging", + "logging" in self.mandatory_relations, + ) + handlers.append(self.logging) + return super().get_relation_handlers(handlers) + def add_pebble_health_checks(self): """Add health checks for services in payload containers.""" for ph in self.pebble_handlers: diff --git a/ops-sunbeam/ops_sunbeam/relation_handlers.py b/ops-sunbeam/ops_sunbeam/relation_handlers.py index d367c8c6..866bd9e4 100644 --- a/ops-sunbeam/ops_sunbeam/relation_handlers.py +++ b/ops-sunbeam/ops_sunbeam/relation_handlers.py @@ -2178,3 +2178,45 @@ class NovaServiceRequiresHandler(RelationHandler): return bool(self.interface.nova_spiceproxy_url) except (AttributeError, KeyError): return False + + +class LogForwardHandler(RelationHandler): + """Handle log forward relation on the requires side.""" + + def __init__( + self, + charm: ops.charm.CharmBase, + relation_name: str, + mandatory: bool = False, + ): + """Create a new log-forward handler. + + Create a new LogForwardHandler that handles initial + events from the relation and invokes the provided callbacks based on + the event raised. + + :param charm: the Charm class the handler is for + :type charm: ops.charm.CharmBase + :param relation_name: the relation the handler is bound to + :type relation_name: str + :param mandatory: If the relation is mandatory to proceed with + configuring charm + :type mandatory: bool + """ + super().__init__(charm, relation_name, lambda *args: None, mandatory) + + def setup_event_handler(self) -> ops.Object: + """Configure event handlers for log forward relation.""" + import charms.loki_k8s.v1.loki_push_api as loki_push_api + + logger.debug("Setting up log forward event handler") + log_forwarder = loki_push_api.LogForwarder( + self.charm, + relation_name=self.relation_name, + ) + return log_forwarder + + @property + def ready(self) -> bool: + """Whether handler is ready for use.""" + return self.interface.is_ready() diff --git a/ops-sunbeam/ops_sunbeam/test_utils.py b/ops-sunbeam/ops_sunbeam/test_utils.py index 7d310f70..cb4331d7 100644 --- a/ops-sunbeam/ops_sunbeam/test_utils.py +++ b/ops-sunbeam/ops_sunbeam/test_utils.py @@ -611,6 +611,26 @@ def add_complete_peer_relation(harness: Harness) -> None: return rel_id +def add_base_logging_relation(harness: Harness) -> int: + """Add logging relation.""" + rel_id = harness.add_relation("logging", "loki") + harness.add_relation_unit(rel_id, "loki/0") + harness.update_relation_data( + rel_id, + "loki/0", + { + "endpoint": '{"url": "http://10.20.23.1/cos-loki-0/loki/api/v1/push"}' + }, + ) + return rel_id + + +def add_complete_logging_relation(harness: Harness) -> int: + """Add complete ceph relation.""" + rel_id = add_base_logging_relation(harness) + return rel_id + + test_relations = { "database": add_complete_db_relation, "amqp": add_complete_amqp_relation, @@ -619,6 +639,7 @@ test_relations = { "peers": add_complete_peer_relation, "certificates": add_complete_certificates_relation, "ceph": add_complete_ceph_relation, + "logging": add_complete_logging_relation, } @@ -761,6 +782,7 @@ def get_harness( with open(metadata_file) as f: charm_metadata = f.read() + os.environ["JUJU_VERSION"] = "3.4.4" harness = Harness( charm_class, meta=charm_metadata,