-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
grafana_datasource interface specification (#204)
* added basic schema and interface spec * initial draft * base model * flip requirer and provider * flip requirer and provider * newer scenario syntax * app name fix * provider tests * source host field type fix * extra fields optional * json schemas * json schemas * schema fix for interface.yaml * default * stripped branch names
- Loading branch information
1 parent
2ccb05c
commit 2556a56
Showing
9 changed files
with
448 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
{ | ||
"$defs": { | ||
"GrafanaSourceData": { | ||
"properties": { | ||
"model": { | ||
"description": "Name of the Juju model where the source is deployed.", | ||
"examples": [ | ||
"cos" | ||
], | ||
"title": "Model", | ||
"type": "string" | ||
}, | ||
"model_uuid": { | ||
"description": "UUID of the Juju model where the source is deployed.", | ||
"examples": [ | ||
"0000-0000-0000-0000" | ||
], | ||
"title": "Model Uuid", | ||
"type": "string" | ||
}, | ||
"application": { | ||
"description": "Name of the Juju model where the source is deployed.", | ||
"examples": [ | ||
"tempo", | ||
"loki", | ||
"prometheus" | ||
], | ||
"title": "Application", | ||
"type": "string" | ||
}, | ||
"type": { | ||
"description": "Type of the datasource.", | ||
"examples": [ | ||
"tempo", | ||
"loki", | ||
"prometheus" | ||
], | ||
"title": "Type", | ||
"type": "string" | ||
}, | ||
"extra_fields": { | ||
"anyOf": [ | ||
{ | ||
"contentMediaType": "application/json", | ||
"contentSchema": {}, | ||
"type": "string" | ||
}, | ||
{ | ||
"type": "null" | ||
} | ||
], | ||
"description": "Any datasource-type-specific additional configuration.", | ||
"title": "Extra Fields" | ||
}, | ||
"secure_extra_fields": { | ||
"anyOf": [ | ||
{ | ||
"contentMediaType": "application/json", | ||
"contentSchema": {}, | ||
"type": "string" | ||
}, | ||
{ | ||
"type": "null" | ||
} | ||
], | ||
"description": "Any secure datasource-type-specific additional configuration.", | ||
"title": "Secure Extra Fields" | ||
} | ||
}, | ||
"required": [ | ||
"model", | ||
"model_uuid", | ||
"application", | ||
"type", | ||
"extra_fields", | ||
"secure_extra_fields" | ||
], | ||
"title": "GrafanaSourceData", | ||
"type": "object" | ||
}, | ||
"GrafanaSourceProviderAppData": { | ||
"description": "Application databag model for the requirer side of this interface.", | ||
"properties": { | ||
"grafana_source_data": { | ||
"contentMediaType": "application/json", | ||
"contentSchema": { | ||
"$ref": "#/$defs/GrafanaSourceData" | ||
}, | ||
"title": "Grafana Source Data", | ||
"type": "string" | ||
} | ||
}, | ||
"required": [ | ||
"grafana_source_data" | ||
], | ||
"title": "GrafanaSourceProviderAppData", | ||
"type": "object" | ||
}, | ||
"GrafanaSourceProviderUnitData": { | ||
"description": "Application databag model for the requirer side of this interface.", | ||
"properties": { | ||
"grafana_source_host": { | ||
"description": "Hostname of a source server.", | ||
"examples": [ | ||
"localhost:80" | ||
], | ||
"title": "Grafana Source Host", | ||
"type": "string" | ||
} | ||
}, | ||
"required": [ | ||
"grafana_source_host" | ||
], | ||
"title": "GrafanaSourceProviderUnitData", | ||
"type": "object" | ||
} | ||
}, | ||
"description": "The schemas for the requirer side of this interface.", | ||
"properties": { | ||
"unit": { | ||
"$ref": "#/$defs/GrafanaSourceProviderUnitData" | ||
}, | ||
"app": { | ||
"$ref": "#/$defs/GrafanaSourceProviderAppData" | ||
} | ||
}, | ||
"required": [ | ||
"unit", | ||
"app" | ||
], | ||
"title": "ProviderSchema", | ||
"type": "object" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
{ | ||
"$defs": { | ||
"BaseModel": { | ||
"properties": {}, | ||
"title": "BaseModel", | ||
"type": "object" | ||
}, | ||
"GrafanaSourceRequirerAppData": { | ||
"description": "Application databag model for the requirer side of this interface.", | ||
"properties": { | ||
"datasource_uids": { | ||
"contentMediaType": "application/json", | ||
"contentSchema": { | ||
"additionalProperties": { | ||
"type": "string" | ||
}, | ||
"type": "object" | ||
}, | ||
"title": "Datasource Uids", | ||
"type": "string" | ||
} | ||
}, | ||
"required": [ | ||
"datasource_uids" | ||
], | ||
"title": "GrafanaSourceRequirerAppData", | ||
"type": "object" | ||
} | ||
}, | ||
"description": "The schema for the provider side of this interface.", | ||
"properties": { | ||
"unit": { | ||
"anyOf": [ | ||
{ | ||
"$ref": "#/$defs/BaseModel" | ||
}, | ||
{ | ||
"type": "null" | ||
} | ||
], | ||
"default": null | ||
}, | ||
"app": { | ||
"$ref": "#/$defs/GrafanaSourceRequirerAppData" | ||
} | ||
}, | ||
"required": [ | ||
"app" | ||
], | ||
"title": "RequirerSchema", | ||
"type": "object" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# `grafana_datasource` | ||
|
||
## Usage | ||
|
||
This relation interface describes the expected behavior of any charm claiming to be able to provide a grafana datasource. | ||
|
||
In most cases, this will be accomplished using the [grafana_source library](https://github.com/canonical/grafana-k8s-operator/blob/main/lib/charms/grafana_k8s/v0/grafana_source.py), although charm developers are free to provide alternative libraries as long as they fulfill the behavioral and schematic requirements described in this document. | ||
|
||
## Direction | ||
The `grafana_datasource` interface implements a provider/requirer pattern. | ||
The provider is a charm that implements a grafana datasource-compatible endpoint, and the requirer is a charm that is able to use such an endpoint to query the data. | ||
|
||
The requirer is furthermore expected to share back to the provider a unique identifier assigned to the source. This can be used by the provider to share with other charms for data correlation and cross-referencing purposes. | ||
|
||
```mermaid | ||
flowchart TD | ||
Provider -- DatasourceEndpoint --> Requirer | ||
Requirer -- DatasourceUID --> Provider | ||
``` | ||
|
||
## Behavior | ||
|
||
The requirer and the provider need to adhere to a certain set of criteria to be considered compatible with the interface. | ||
|
||
### Provider | ||
|
||
- Is expected to expose a server implementing [the grafana source HTTP API](https://grafana.com/docs/grafana/latest/developers/http_api/data_source/). | ||
- Is expected to communicate said endpoint URL over unit data, as each unit will expose its own server. | ||
|
||
### Requirer | ||
|
||
- Is expected to share back via application data a mapping from provider unit names to unique datasource IDs. | ||
|
||
## Relation Data | ||
|
||
[\[Pydantic model\]](./schema.py) | ||
|
||
|
||
### Requirer | ||
|
||
|
||
Additionally to a subset of the the (mandatory) [juju topology fields](https://discourse.charmhub.io/t/juju-topology-labels/8874), | ||
the requirer is expected to share the following fields: | ||
- `type`: the grafana datasource type. For the possible values see [the upstream docs](https://grafana.com/docs/grafana/latest/datasources/#built-in-core-data-sources). Required. | ||
- `extra_fields`: used to configure certain datasources. Maps to the `jsonData` field. Optional. | ||
- `secure_extra_fields`: used to configure certain datasources. Maps to the `secureJsonData` field. Optional. | ||
|
||
The whole configuration is expected to be json-encoded and nested under a `grafana_source_data` | ||
toplevel field. | ||
|
||
#### Example | ||
|
||
```yaml | ||
application_data: { | ||
grafana_source_data: | ||
{ | ||
model: cos, | ||
model_uuid: 0000-0000-0000-0000, | ||
application: tempo, | ||
type: tempo, | ||
extra_fields: { | ||
some: value | ||
}, | ||
secure_extra_fields: { | ||
some: password | ||
}, | ||
|
||
} | ||
} | ||
``` | ||
|
||
### Provider | ||
|
||
The provider is expected to share back a unique identifier for each unit of the requirer, as a mapping. | ||
This will be encoded as a json dict and nested under the `datasource_uids` field in the application databag. | ||
|
||
#### Example | ||
```yaml | ||
application-data: { | ||
datasource_uids: { | ||
"tempo/0": 0000-0000-0000-0001, | ||
"tempo/1": 0000-0000-0000-0002, | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
name: grafana_datasource | ||
|
||
internal: true | ||
|
||
version: 0 | ||
|
||
status: published | ||
|
||
providers: | ||
- name: tempo-coordinator-k8s | ||
url: https://github.com/canonical/tempo-coordinator-k8s-operator | ||
test_setup: | ||
location: tests/interface/conftest.py | ||
identifier: grafana_datasource_tester | ||
|
||
requirers: | ||
- name: grafana-k8s | ||
url: https://github.com/canonical/grafana-k8s-operator | ||
test_setup: | ||
location: tests/interface/conftest.py | ||
identifier: grafana_source_tester | ||
|
||
|
||
maintainer: observability |
24 changes: 24 additions & 0 deletions
24
interfaces/grafana_datasource/v0/interface_tests/test_provider.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from interface_tester import Tester | ||
from scenario import State, Relation | ||
|
||
|
||
def test_share_datasource_on_remote_joined(): | ||
# GIVEN the remote side hasn't sent anything | ||
tester = Tester(state_in=State( | ||
relations=[ | ||
Relation( | ||
endpoint='grafana-source', | ||
interface='grafana_datasource', | ||
remote_app_name='foo', | ||
remote_app_data={}, | ||
remote_units_data={ | ||
0: {} | ||
} | ||
) | ||
] | ||
)) | ||
# WHEN the provider processes a relation-joined event | ||
tester.run('grafana-source-relation-joined') | ||
# THEN the provider publishes valid datasource data | ||
tester.assert_schema_valid() | ||
|
Oops, something went wrong.