Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add show-unit probes #381

Merged
merged 8 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions probes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# External probes

These probes are meant to be run from the host where the juju client is installed,

```bash
juju export-bundle | ./probe_bundle.py
juju status --format=yaml | ./probe_status.py
juju show-unit --format=yaml | ./probe_show_unit.py
```

or by piping in the bundle or status yaml,

```bash
cat bundle.yaml | ./probe_bundle.py
cat status.yaml | ./probe_status.py
cat show_unit.yaml | ./probe_show_unit.py
```
64 changes: 64 additions & 0 deletions probes/show-unit/relation_dashboard_uid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python3

"""Probe for juju show-unit."""

import sys
import yaml
import json
import base64
import lzma
import re


def _uid_from_encoded_dashboard(data: bytes) -> str:
decoded_data = base64.b64decode(data)
decompressed_data = lzma.decompress(decoded_data)
return json.loads(decompressed_data).get("uid")


def _is_valid_format(uid: str) -> bool:
if not uid:
return False
# https://grafana.com/docs/grafana/latest/developers/http_api/dashboard/#identifier-id-vs-unique-identifier-uid
if len(uid) > 40:
return False
# https://community.grafana.com/t/which-characters-will-never-appear-in-a-dashboard-uid/11500
for char in uid:
if not re.match(r"[a-zA-Z0-9_-]", char):
return False

return True


def validate_dashboard_uid(show_unit: dict):
"""The top-level UID for each dashboard in relation data is not empty and has a valid format.

Args:
show_unit: A dict containing the contents of 'juju show-unit grafana/0'
"""
unit_name = next(iter(show_unit))
# 1. Extract the relation-info
relation_info = show_unit[unit_name]["relation-info"]
# 2. Extract the "grafana" endpoint relations
grafana_endpoints = [
relation for relation in relation_info if relation["endpoint"] == "grafana"
]
for grafana_endpoint in grafana_endpoints:
# 3. Extract the application data
app_data = grafana_endpoint["application-data"]
relation_id = grafana_endpoint["relation-id"]
# 4. Convert dashboard data to JSON and decode
dashboards = json.loads(app_data["dashboards"])
for id in dashboards:
for meta in dashboards[id]:
decoded_uid = _uid_from_encoded_dashboard(meta["content"])
# 5. Check if the top-level UID exist and is not empty
if not _is_valid_format(decoded_uid):
print(f"Invalid dashboard UID ({id}) for relation-id ({relation_id})", file=sys.stderr)

print("Probe finished!")


if __name__ == "__main__":
data = yaml.safe_load(sys.stdin)
validate_dashboard_uid(data)
Loading