---
title: Charmhub | Deploy Grafana using Charmhub - The Open Operator Collection
description: Deploy the latest version of Grafana as a Kubernetes Operator on any
  cloud.
url: https://charmhub.io/grafana-k8s/libraries/grafana_source
---

# Grafana

[Canonical Observability](https://charmhub.io/publisher/observability "View all packages from Canonical Observability")

* [Canonical Observability](https://charmhub.io/publisher/observability "View all packages from Canonical Observability")

Platform:

12.4/stable tf-12.4.3-2-g8187475

```
juju deploy grafana-k8s --channel 12.4/stable --trust
```

[Learn to deploy on juju >](https://juju.is/docs/juju/manage-applications)

[Toggle side navigation](https://charmhub.io/grafana-k8s/libraries/grafana_source#drawer)

## charms.grafana\_k8s.v1.grafana\_source

* [*Docstrings*Docstrings](https://charmhub.io/grafana-k8s/libraries/grafana_source)
  [*Code*Source code](https://charmhub.io/grafana-k8s/libraries/grafana_source/source-code)
* + Download

    Fetch library

    ```
    charmcraft fetch-lib charms.grafana_k8s.v1.grafana_source
    ```

    [Download grafana\_source.py](https://charmhub.io/grafana-k8s/libraries/grafana_source/download)
  + *Last updated* 15 Sep 2026
  + *Revision* Library version 1.1

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

##### What changed in LIBAPI v1 (HA datasources)

`v1` adds support for a single, load-balanced, *application-level* datasource, in
addition to the historical *per-unit* datasources. This fixes the long-standing problem
where, in an HA deployment behind an ingress, the datasource UID changed on every leader
re-election (because the UID embedded the unit number of whichever unit happened to be
advertising), silently breaking every dashboard and alert that referenced it.

A provider now chooses its datasource *topology* explicitly via two flags:

* `app_datasource` (default `True`): the leader publishes one load-balanced address in
  the **application** databag (`grafana_source_app_host`). Grafana mints exactly one
  datasource for the whole application, with a UID of the form
  `juju_{model}_{model_uuid}_{application}` — note there is **no unit number**, so the
  UID is stable across leader re-elections. This is the correct shape for a clustered,
  HA backend behind a single load-balanced address (Mimir/Loki/Tempo coordinators,
  Alertmanager).
* `unit_datasources` (default `False`): each unit publishes its own address in its
  **unit** databag (`grafana_source_host`). Grafana mints one datasource per unit, each
  with a UID of the form `juju_{model}_{model_uuid}_{application}_{unit_number}`. This is
  the correct shape for a non-clustered backend where each unit is an independent
  datasource (e.g. a standalone Prometheus).

Both may be enabled at once (yielding one app-level datasource plus one per unit). If
both are disabled, no address is published and a warning is logged.

Ingress pairing (provider-charm responsibility — this library never talks to the ingress
library, it only receives the URL you give it):

* `app_datasource=True` <-> use **ingress-per-app**; pass the app URL as
  `app_datasource_url`.
* `unit_datasources=True` <-> use **ingress-per-unit**; pass each unit's own URL as
  `unit_datasource_url` (the value is per-unit, since the provider runs in every unit).

###### Breaking changes from v0

* The `source_url` and `is_ingress_per_app` constructor arguments were removed. Use
  `app_datasource`/`unit_datasources` and `app_datasource_url`/`unit_datasource_url`
  instead.
* The `update_source()` method was replaced by `update_app_source()` and
  `update_unit_source()`.

###### Upgrade implications

**This is a coordinated rollout** — Grafana and provider charms should be upgraded
together.

* **Both upgraded**: the datasource UID changes **once** (from `juju_..._{n}` to
  `juju_..._{app}`), which breaks dashboards/alerts referencing the old UID a single
  time; users must re-point them once. This is a one-off, deliberate break rather than
  the recurring one it replaces.
* **Old Grafana + new provider (app mode)**: the old v0 consumer ignores
  `grafana_source_app_host` and sees an empty `grafana_source_host`, resulting in **no
  datasource**. Upgrade Grafana to restore the datasource.
* **New Grafana + old provider**: the old fragile per-unit behaviour continues (no
  change until the provider is also upgraded).

##### 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 constructor arguments are:

```
`charm`: `self` from the charm instantiating this library
`source_type`: **required** — the Grafana datasource type (e.g. "prometheus",
    "loki", "tempo", "mimir", "alertmanager")
`source_port`: the port the datasource listens on (default: "")
`relation_name`: the relation name (default: "grafana-source")
`refresh_event`: a `PebbleReady` event from `charm`, used to refresh
    the address sent to Grafana on a charm lifecycle event or pod restart
    (default: auto-detected from the charm's single container, if any)
`extra_fields`: additional fields for Grafana's `jsonData` (default: None)
`secure_extra_fields`: additional fields for Grafana's `secureJsonData` (default: None)
`app_datasource`: publish a single app-level datasource (default: True)
`unit_datasources`: publish per-unit datasources (default: False)
`app_datasource_url`: explicit URL for the app-level datasource (default: None)
`unit_datasource_url`: explicit URL for this unit's datasource (default: None)
```

The values of `app_datasource_url` / `unit_datasource_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.v1.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, once a relation is
established, this application is added as a datasource in the Grafana configuration
using the [Grafana datasource provisioning](https://grafana.com/docs/grafana/latest/administration/provisioning/#data-sources)
specification via YAML files. Depending on the `app_datasource`/`unit_datasources`
flags, this is either a single application-level datasource, one datasource per unit,
or both.

This information is added to the relation data for the charms with the following
structure:

**Application databag** (written by leader):

```
{
    "grafana_source_data": {  # JSON-encoded
        "model": charm.model.name,
        "model_uuid": charm.model.uuid,
        "application": charm.model.app.name,
        "type": source_type,
        "extra_fields": {...},
        "secure_extra_fields": {...},
    },
    # app-level address (when app_datasource=True):
    "grafana_source_app_host": "{scheme}://{app}.{model}.svc.cluster.local:{port}{path}",
}
```

**Unit databag** (written by each unit when unit\_datasources=True):

```
{
    "grafana_source_host": "{scheme}://{fqdn}:{port}{path}",
}
```

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.v1.grafana_source import GrafanaSourceConsumer

def __init__(self, *args):
    super().__init__(*args)
    ...
    self.grafana_source_consumer = GrafanaSourceConsumer(
        self,
        grafana_uid=self.unique_name,
        grafana_base_url=self.external_url,
    )
    ...
```

2. 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](https://grafana.com/docs/grafana/latest/administration/provisioning/#data-sources).

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.

---

Index

* [class GrafanaSourceData](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourcedata)
* + [def get\_unit\_uid(
    self,
    unit)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourcedata-get_unit_uid)
* + [def get\_app\_uid(
    self)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourcedata-get_app_uid)
* [class RelationNotFoundError](https://charmhub.io/grafana-k8s/libraries/grafana_source#relationnotfounderror)
* + [def \_\_init\_\_(
    self,
    relation\_name)](https://charmhub.io/grafana-k8s/libraries/grafana_source#relationnotfounderror-__init__)
* [class RelationInterfaceMismatchError](https://charmhub.io/grafana-k8s/libraries/grafana_source#relationinterfacemismatcherror)
* + [def \_\_init\_\_(
    self,
    relation\_name,
    expected\_relation\_interface,
    actual\_relation\_interface)](https://charmhub.io/grafana-k8s/libraries/grafana_source#relationinterfacemismatcherror-__init__)
* [class RelationRoleMismatchError](https://charmhub.io/grafana-k8s/libraries/grafana_source#relationrolemismatcherror)
* + [def \_\_init\_\_(
    self,
    relation\_name,
    expected\_relation\_role,
    actual\_relation\_role)](https://charmhub.io/grafana-k8s/libraries/grafana_source#relationrolemismatcherror-__init__)
* [class SourceFieldsMissingError](https://charmhub.io/grafana-k8s/libraries/grafana_source#sourcefieldsmissingerror)
* [class GrafanaSourcesChanged](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceschanged)
* + [def \_\_init\_\_(
    self,
    handle,
    data)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceschanged-__init__)
* + [def snapshot(
    self)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceschanged-snapshot)
* + [def restore(
    self,
    snapshot)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceschanged-restore)
* [class GrafanaSourceEvents](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceevents)
* [class GrafanaSourceProvider](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceprovider)
* + [def \_\_init\_\_(
    self,
    charm,
    source\_type,
    source\_port,
    refresh\_event,
    relation\_name,
    extra\_fields,
    secure\_extra\_fields,
    app\_datasource,
    unit\_datasources,
    app\_datasource\_url,
    unit\_datasource\_url)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceprovider-__init__)
* + [def update\_app\_source(
    self,
    app\_datasource\_url)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceprovider-update_app_source)
* + [def update\_unit\_source(
    self,
    unit\_datasource\_url)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceprovider-update_unit_source)
* + [def get\_source\_data(
    self)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceprovider-get_source_data)
* + [def get\_source\_uids(
    self)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceprovider-get_source_uids)
* [class GrafanaSourceConsumer](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceconsumer)
* + [def \_\_init\_\_(
    self,
    charm,
    grafana\_uid,
    grafana\_base\_url,
    relation\_name)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceconsumer-__init__)
* + [def upgrade\_keys(
    self)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceconsumer-upgrade_keys)
* + [def update\_sources(
    self,
    relation)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceconsumer-update_sources)
* + [def sources(
    self)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceconsumer-sources)
* + [def sources\_to\_delete(
    self)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceconsumer-sources_to_delete)
* + [def set\_peer\_data(
    self,
    key,
    data)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceconsumer-set_peer_data)
* + [def get\_peer\_data(
    self,
    key)](https://charmhub.io/grafana-k8s/libraries/grafana_source#grafanasourceconsumer-get_peer_data)

#### class GrafanaSourceData

Description

This class represents the data Grafana provides others about itself. None

Methods

GrafanaSourceData.
get\_unit\_uid(

*self*

,
unit: str
)

Description

Return the UID for a given unit. None

GrafanaSourceData.
get\_app\_uid(

*self*
)

Return the UID for the application-level (load-balanced) datasource.

Description

Returns None if the remote Grafana did not assign an app-level datasource UID
(e.g. the provider only published per-unit datasources, or the remote Grafana
predates app-level datasource support).

#### 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

,
refresh\_event

,
relation\_name: str

,
extra\_fields

,
secure\_extra\_fields

,
app\_datasource: bool

,
unit\_datasources: bool

,
app\_datasource\_url

,
unit\_datasource\_url
)

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. Used to build the datasource
address when an explicit URL is not provided.

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`

app\_datasource

whether to publish a single, load-balanced datasource for the
whole application in the application databag. Defaults to True. The
resulting datasource UID is stable across leader re-elections.

unit\_datasources

whether to publish one datasource per unit, each keyed by
unit number. Defaults to False.

app\_datasource\_url

an optional fully-resolvable URL for the application-level
datasource (e.g. an ingress-per-app URL). If unset, a Kubernetes
load-balanced service address is constructed from the application name.
Pass the base URL only: for `source_type == "mimir"` the library
appends the `/prometheus` query path itself.

unit\_datasource\_url

an optional fully-resolvable URL for this unit's
datasource (e.g. an ingress-per-unit URL). If unset, the unit's own FQDN
is used. This value is per-unit. Pass the base URL only: for
`source_type == "mimir"` the library appends the `/prometheus` query
path itself.

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

The provider can publish two distinct kinds of datasource, controlled by the
`app_datasource` and `unit_datasources` flags:

* An **application-level** datasource (`app_datasource=True`, the default):
  the leader publishes a single, load-balanced address in the application
  databag. The consumer mints exactly one datasource for the whole application
  with a UID that does NOT include a unit number, so it is stable across leader
  re-elections. This is the correct representation for an HA, clustered backend
  (e.g. a Mimir/Loki/Tempo coordinator, or Alertmanager) sitting behind a single
  load-balanced address. When behind an ingress, pair this with
  ingress-per-app and pass the app ingress URL as `app_datasource_url`.
* **Per-unit** datasources (`unit_datasources=True`): each unit publishes its
  own address in its unit databag, and the consumer mints one datasource per
  unit, each keyed by unit number. This is the correct representation for a
  non-clustered backend where each unit is an independent datasource (e.g. a
  standalone Prometheus). When behind an ingress, pair this with
  ingress-per-unit and pass each unit's own ingress URL as
  `unit_datasource_url` (the value is per-unit, since this object runs as a
  separate instance in every unit).

Both flags may be set at once (yielding one app-level datasource plus one
per-unit datasource for each unit). If both are False, no datasource address is
published at all and a warning is logged.

GrafanaSourceProvider.
update\_app\_source(

*self*

,
app\_datasource\_url
)

Update the application-level datasource URL and re-publish relation data.

Description

Useful when the load-balanced address (e.g. an ingress-per-app URL) becomes
available or changes after this object is constructed.

GrafanaSourceProvider.
update\_unit\_source(

*self*

,
unit\_datasource\_url
)

Update this unit's datasource URL and re-publish relation data.

Description

Useful when this unit's address (e.g. an ingress-per-unit URL) becomes
available or changes after this object is constructed. The value is per-unit.

GrafanaSourceProvider.
get\_source\_data(

*self*
)

Get the Grafana data assigned by the remote end(s) to this datasource.

Description

Returns a mapping from remote application UIDs to GrafanaSourceData.

GrafanaSourceProvider.
get\_source\_uids(

*self*
)

Get the datasource UID(s) assigned by the remote end(s) to this datasource.

Description

DEPRECATED: This method is deprecated. Use the `get_source_data` instead.
Returns a mapping from remote application UIDs to unit names to datasource uids.

#### class GrafanaSourceConsumer

Description

A consumer object for working with Grafana datasources. None

Methods

GrafanaSourceConsumer.
\_\_init\_\_(

*self*

,
charm: CharmBase

,
grafana\_uid: str

,
grafana\_base\_url: str

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

grafana\_uid

an unique identifier for this grafana-k8s application.

grafana\_base\_url

the base URL (potentially ingressed) for this grafana-k8s application.

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
)

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
