[*-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 <guillaume.boutry@canonical.com>
This commit is contained in:
Guillaume Boutry 2024-07-07 14:18:31 +02:00
parent 366b83e3eb
commit 0214e8f173
No known key found for this signature in database
GPG Key ID: E95E3326872E55DE
31 changed files with 547 additions and 366 deletions

View File

@ -75,6 +75,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
provides:
aodh:

View File

@ -45,6 +45,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
peers:
peers:

View File

@ -52,6 +52,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
peers:
peers:

View File

@ -42,6 +42,9 @@ requires:
identity-credentials:
interface: keystone-credentials
optional: true
logging:
interface: loki_push_api
optional: true
provides:
ceph-access:

View File

@ -60,6 +60,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
peers:
peers:

View File

@ -31,6 +31,11 @@ provides:
dns-backend:
interface: bind-rndc
requires:
logging:
interface: loki_push_api
optional: true
peers:
peers:
interface: bind-peer

View File

@ -52,6 +52,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
peers:
peers:

View File

@ -71,6 +71,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
provides:
image-service:

View File

@ -54,6 +54,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
provides:
gnocchi-service:

View File

@ -57,6 +57,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
peers:
peers:

View File

@ -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:

View File

@ -48,6 +48,9 @@ requires:
optional: true
domain-config:
interface: keystone-domain-config
logging:
interface: loki_push_api
optional: true
peers:
peers:

View File

@ -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."""

View File

@ -12,3 +12,7 @@ peers:
provides:
domain-config:
interface: keystone-domain-config
requires:
logging:
interface: loki_push_api
optional: true

View File

@ -54,6 +54,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
peers:
peers:

View File

@ -63,6 +63,9 @@ requires:
external-dns:
interface: designate
optional: true
logging:
interface: loki_push_api
optional: true
peers:
peers:

View File

@ -96,6 +96,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
provides:
nova-service:

View File

@ -79,6 +79,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
peers:
peers:

View File

@ -31,6 +31,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
provides:
metrics-endpoint:

View File

@ -73,3 +73,6 @@ requires:
limit: 1
identity-service:
interface: keystone
logging:
interface: loki_push_api
optional: true

View File

@ -69,6 +69,9 @@ resources:
requires:
certificates:
interface: tls-certificates
logging:
interface: loki_push_api
optional: true
provides:
ovsdb:

View File

@ -34,6 +34,9 @@ requires:
interface: ovsdb-cms
certificates:
interface: tls-certificates
logging:
interface: loki_push_api
optional: true
provides:
ovsdb-cms-relay:

View File

@ -43,6 +43,9 @@ requires:
receive-ca-cert:
interface: certificate_transfer
optional: true
logging:
interface: loki_push_api
optional: true
provides:
placement:

View File

@ -62,6 +62,7 @@ requires:
interface: keystone-resources
logging:
interface: loki_push_api
optional: true
provides:
grafana-dashboard:

View File

@ -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")

View File

@ -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)

653
common.sh
View File

@ -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
}

View File

@ -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.

View File

@ -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:

View File

@ -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()

View File

@ -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,