Grafana

  • By Canonical Observability
Channel Revision Published Runs on
latest/stable 107 24 Apr 2024
Ubuntu 20.04
latest/candidate 110 24 Apr 2024
Ubuntu 20.04
latest/beta 111 24 Apr 2024
Ubuntu 20.04
latest/edge 112 Yesterday
Ubuntu 20.04
1.0/stable 93 12 Dec 2023
Ubuntu 20.04
1.0/candidate 93 22 Nov 2023
Ubuntu 20.04
1.0/beta 93 22 Nov 2023
Ubuntu 20.04
1.0/edge 93 22 Nov 2023
Ubuntu 20.04
juju deploy grafana-k8s
Show information

Platform:

charms.grafana_k8s.v0.grafana_source

Overview.

This document explains how to integrate with the Grafana charm for the purpose of providing a datasource which can be used by Grafana dashboards. It also explains the structure of the data expected by the grafana-source interface, and may provide a mechanism or reference point for providing a compatible interface or library by providing a definitive reference guide to the structure of relation data which is shared between the Grafana charm and any charm providing datasource information.

Provider Library Usage

The Grafana charm interacts with its datasources using its charm library. The goal of this library is to be as simple to use as possible, and instantiation of the class with or without changing the default arguments provides a complete use case. For the simplest use case of a Prometheus (or Prometheus-compatible) datasource provider in a charm which provides: grafana-source, creation of a GrafanaSourceProvider object with the default arguments is sufficient.

The default arguments are:

`charm`: `self` from the charm instantiating this library
`source_type`: None
`source_port`: None
`source_url`: None
`relation_name`: grafana-source
`refresh_event`: A `PebbleReady` event from `charm`, used to refresh
    the IP address sent to Grafana on a charm lifecycle event or
    pod restart
`extra_fields`: None
`secure_extra_fields`: None

The value of source_url should be a fully-resolvable URL for a valid Grafana source, e.g., http://example.com/api or similar.

If your configuration requires any changes from these defaults, they may be set from the class constructor. It may be instantiated as follows:

from charms.grafana_k8s.v0.grafana_source import GrafanaSourceProvider

class FooCharm:
    def __init__(self, *args):
        super().__init__(*args, **kwargs)
        ...
        self.grafana_source_provider = GrafanaSourceProvider(
            self, source_type="prometheus", source_port="9090"
        )
        ...

The first argument (self) should be a reference to the parent (datasource) charm, as this charm's model will be used for relation data, IP addresses, and lifecycle events.

An instantiated GrafanaSourceProvider will ensure that each unit of its parent charm is added as a datasource in the Grafana configuration once a relation is established, using the Grafana datasource provisioning specification via YAML files.

This information is added to the relation data for the charms as serialized JSON from a dict, with a structure of:

{
    "application": {
        "model": charm.model.name, # from `charm` in the constructor
        "model_uuid": charm.model.uuid,
        "application": charm.model.app.name,
        "type": source_type,
    },
    "unit/0": {
        "uri": {ip_address}:{port}{path} # `ip_address` is derived at runtime, `port` from the constructor,
                                         # and `path` from the constructor, if specified
    },

This is ingested by :class:GrafanaSourceConsumer, and is sufficient for configuration.

Consumer Library Usage

The GrafanaSourceConsumer object may be used by Grafana charms to manage relations with available datasources. For this purpose, a charm consuming Grafana datasource information should do the following things:

  1. Instantiate the GrafanaSourceConsumer object by providing it a reference to the parent (Grafana) charm and, optionally, the name of the relation that the Grafana charm uses to interact with datasources. This relation must confirm to the grafana-source interface.

For example a Grafana charm may instantiate the GrafanaSourceConsumer in its constructor as follows

from charms.grafana_k8s.v0.grafana_source import GrafanaSourceConsumer

def __init__(self, *args):
    super().__init__(*args)
    ...
    self.grafana_source_consumer = GrafanaSourceConsumer(self)
    ...
  1. A Grafana charm also needs to listen to the GrafanaSourceEvents events emitted by the GrafanaSourceConsumer by adding itself as an observer for these events:

    self.framework.observe( self.grafana_source_consumer.on.sources_changed, self._on_sources_changed, ) self.framework.observe( self.grafana_source_consumer.on.sources_to_delete_changed, self._on_sources_to_delete_change, )

The reason for two separate events is that Grafana keeps track of removed datasources in its datasource provisioning.

If your charm is merely implementing a grafana-source-compatible API, and is does not follow exactly the same semantics as Grafana, observing these events may not be needed.


class RelationNotFoundError

Description

Raised if there is no relation with the given name. None

Methods

RelationNotFoundError. __init__( self , relation_name: str )

class RelationInterfaceMismatchError

Description

Raised if the relation with the given name has a different interface. None

Methods

RelationInterfaceMismatchError. __init__( self , relation_name: str , expected_relation_interface: str , actual_relation_interface: str )

class RelationRoleMismatchError

Description

Raised if the relation with the given name has a different direction. None

Methods

RelationRoleMismatchError. __init__( self , relation_name: str , expected_relation_role: RelationRole , actual_relation_role: RelationRole )

class SourceFieldsMissingError

Description

An exception to indicate there a missing fields from a Grafana datsource definition. None

class GrafanaSourcesChanged

Description

Event emitted when Grafana sources change. None

Methods

GrafanaSourcesChanged. __init__( self , handle , data )

GrafanaSourcesChanged. snapshot( self )

Description

Save grafana source information. None

GrafanaSourcesChanged. restore( self , snapshot )

Description

Restore grafana source information. None

class GrafanaSourceEvents

Description

Events raised by :class:`GrafanaSourceEvents. None

class GrafanaSourceProvider

Description

A provider object for Grafana datasources. None

Methods

GrafanaSourceProvider. __init__( self , charm: CharmBase , source_type: str , source_port , source_url , refresh_event , relation_name: str , extra_fields , secure_extra_fields )

Construct a Grafana charm client.

Arguments

charm

a :class:CharmBase object which manages this :class:GrafanaSourceProvider object. Generally this is self in the instantiating class.

source_type

an optional (default prometheus) source type required for Grafana configuration. The value must match the DataSource type from the Grafana perspective.

source_port

an optional (default 9090) source port required for Grafana configuration.

source_url

an optional source URL which can be used, for example, if ingress for a source is enabled, or a URL path to the API consumed by the datasource must be specified for another reason. If set, 'source_port' will not be used.

relation_name

string name of the relation that is provides the Grafana source service. It is strongly advised not to change the default, so that people deploying your charm will have a consistent experience with all other charms that provide Grafana datasources.

refresh_event

a :class:CharmEvents event (or a list of them) on which the IP address should be refreshed in case of pod or machine/VM restart.

extra_fields

a :dict: which is used for additional information required for some datasources in the jsonData field

secure_extra_fields

a :dict: which is used for additional information required for some datasources in the secureJsonData

Description

The :class:GrafanaSourceProvider object provides an interface to Grafana. This interface supports providing additional sources for Grafana to monitor. For example, if a charm exposes some metrics which are consumable by an ingestor (such as Prometheus), then an additional source can be added by instantiating a :class:GrafanaSourceProvider object and adding its datasources as follows:

self.grafana = GrafanaSourceProvider(self)
self.grafana.add_source(
    address=<address>,
    port=<port>
)

GrafanaSourceProvider. update_source( self , source_url )

Description

Trigger the update of relation data. None

class GrafanaSourceConsumer

Description

A consumer object for working with Grafana datasources. None

Methods

GrafanaSourceConsumer. __init__( self , charm: CharmBase , relation_name: str )

A Grafana based Monitoring service consumer, i.e., the charm that uses a datasource.

Arguments

charm

a :class:CharmBase instance that manages this instance of the Grafana source service.

relation_name

string name of the relation that is provides the Grafana source service. It is strongly advised not to change the default, so that people deploying your charm will have a consistent experience with all other charms that provide Grafana datasources.

GrafanaSourceConsumer. upgrade_keys( self )

Description

On upgrade, ensure stored data maintains compatibility. None

GrafanaSourceConsumer. update_sources( self , relation )

Re-establish sources on one or more relations.

Arguments

relation

a specific relation for which the datasources have to be updated. If not specified, all relations managed by this :class:GrafanaSourceConsumer will be updated.

Description

If something changes between this library and a datasource, try to re-establish datasources.

GrafanaSourceConsumer. sources( self )

Description

Returns an array of sources the source_consumer knows about. None

GrafanaSourceConsumer. sources_to_delete( self )

Description

Returns an array of source names which have been removed. None

GrafanaSourceConsumer. set_peer_data( self , key: str , data: Any )

Description

Put information into the peer data bucket instead of StoredState. None

GrafanaSourceConsumer. get_peer_data( self , key: str )

Description

Retrieve information from the peer data bucket instead of StoredState. None