Skip to content

Commit

Permalink
Add revision to the dashboard title of the Grafana (#510)
Browse files Browse the repository at this point in the history
With this change, two different OpenSearch applications in different
revisions, will have separate dashboards when related to COS.

- data-platform-helpers was added to use the get_charm_revision
- titles of dashboards are changed during the charm upgrade hook
- config_changed was added on refresh_events of COSAgentProvider to
re-render the dashboards after a charm upgrade

## How to test it

1. Deploy more than one opensearch application
2. Relate both apps with grafana-agent
3. In one of the applications use juju refresh and apply a local build
of this patch
4. Go to the Grafana dashboards an you will see that two dashboards are
created:
  - one with no revision (from charmhub)
  - one with Rev 0 (meaning that is a local build)
  
  
 

![image](https://github.com/user-attachments/assets/d9d82ab6-10b3-4d00-bfa2-f864bbad4d9a)
  • Loading branch information
gabrielcocenza authored Jan 29, 2025
1 parent 9f5e770 commit 4776c62
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 83 deletions.
39 changes: 39 additions & 0 deletions lib/charms/opensearch/v0/helper_cos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright 2025 Canonical Ltd.
# See LICENSE file for licensing details.
"""Utility functions for charms COS operations."""


import json
import logging
from typing import TYPE_CHECKING

from data_platform_helpers.version_check import get_charm_revision

logger = logging.getLogger(__name__)

if TYPE_CHECKING:
from charms.opensearch.v0.opensearch_base_charm import OpenSearchBaseCharm


def update_grafana_dashboards_title(charm: "OpenSearchBaseCharm") -> None:
"""Update the title of the Grafana dashboard file to include the charm revision."""
revision = get_charm_revision(charm.model.unit)
dashboard_path = charm.charm_dir / "src/grafana_dashboards/opensearch.json"

with open(dashboard_path, "r") as file:
dashboard = json.load(file)

old_title = dashboard.get("title", "Charmed OpenSearch")
title_prefix = old_title.split(" - Rev")[0]
new_title = f"{old_title} - Rev {revision}"
dashboard["title"] = f"{title_prefix} - Rev {revision}"

logger.info(
"Changing the title of dashboard %s from %s to %s",
dashboard_path.name,
old_title,
new_title,
)

with open(dashboard_path, "w") as file:
json.dump(dashboard, file, indent=4)
1 change: 1 addition & 0 deletions lib/charms/opensearch/v0/opensearch_base_charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ def __init__(self, *args, distro: Type[OpenSearchDistribution] = None):
metrics_endpoints=[],
scrape_configs=self._scrape_config,
refresh_events=[
self.on.config_changed,
self.on.set_password_action,
self.on.secret_changed,
self.on[PeerRelationName].relation_changed,
Expand Down
175 changes: 97 additions & 78 deletions poetry.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pydantic = "^1.10.17, <2"
cryptography = "^43.0.0"
jsonschema = "^4.23.0"
poetry-core = "^1.9.0"
data-platform-helpers = "^0.1.4"


[tool.poetry.group.charm-libs.dependencies]
Expand Down
2 changes: 2 additions & 0 deletions src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import ops
from charms.opensearch.v0.constants_charm import InstallError, InstallProgress
from charms.opensearch.v0.helper_cos import update_grafana_dashboards_title
from charms.opensearch.v0.models import PerformanceType
from charms.opensearch.v0.opensearch_base_charm import OpenSearchBaseCharm
from charms.opensearch.v0.opensearch_exceptions import OpenSearchInstallError
Expand Down Expand Up @@ -137,6 +138,7 @@ def _set_upgrade_status(self):
logger.debug(f"Set app status to {self.app.status}")

def _on_upgrade_charm(self, _):
update_grafana_dashboards_title(self)
if not self.performance_profile.current:
# We are running (1) install or (2) an upgrade on instance that pre-dates profile
# First, we set this unit's effective profile -> 1G heap and no index templates.
Expand Down
85 changes: 85 additions & 0 deletions tests/unit/lib/test_helper_cos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copyright 2024 Canonical Ltd.
# See LICENSE file for licensing details.

"""Unit test for the helper_cos library."""

import json
import unittest
from pathlib import Path
from unittest.mock import MagicMock, PropertyMock, mock_open, patch

from charms.opensearch.v0.helper_cos import update_grafana_dashboards_title


class TestCOSGrafanaDashboard(unittest.TestCase):

@patch("charms.opensearch.v0.helper_cos.get_charm_revision", return_value=167)
@patch(
"builtins.open",
new_callable=mock_open,
read_data=json.dumps({"title": "Charmed OpenSearch"}),
)
@patch("json.dump")
def test_update_grafana_dashboards_title_no_prior_revision(
self, mock_json_dump, mock_open_func, _
):
mock_charm = MagicMock()
mock_charm.model.unit = MagicMock()
type(mock_charm).charm_dir = PropertyMock(return_value=Path("/fake/charm/dir"))

update_grafana_dashboards_title(mock_charm)

expected_updated_dashboard = {"title": "Charmed OpenSearch - Rev 167"}
mock_json_dump.assert_called_once_with(
expected_updated_dashboard, mock_open_func(), indent=4
)

@patch("charms.opensearch.v0.helper_cos.get_charm_revision", return_value=167)
@patch(
"builtins.open",
new_callable=mock_open,
read_data=json.dumps({"title": "Charmed OpenSearch - Rev 166"}),
)
@patch("json.dump")
def test_update_grafana_dashboards_title_prior_revision(
self,
mock_json_dump,
mock_open_func,
_,
):
mock_charm = MagicMock()
mock_charm.model.unit = MagicMock()
type(mock_charm).charm_dir = PropertyMock(return_value=Path("/fake/charm/dir"))

update_grafana_dashboards_title(mock_charm)

expected_updated_dashboard = {"title": "Charmed OpenSearch - Rev 167"}
mock_json_dump.assert_called_once_with(
expected_updated_dashboard, mock_open_func(), indent=4
)

@patch("charms.opensearch.v0.helper_cos.get_charm_revision", return_value=167)
@patch(
"builtins.open",
new_callable=mock_open,
read_data=json.dumps({"my-content": "content"}),
)
@patch("json.dump")
def test_update_grafana_dashboards_title_json_no_title(
self,
mock_json_dump,
mock_open_func,
_,
):
mock_charm = MagicMock()
mock_charm.model.unit = MagicMock()
type(mock_charm).charm_dir = PropertyMock(return_value=Path("/fake/charm/dir"))
update_grafana_dashboards_title(mock_charm)

expected_updated_dashboard = {
"title": "Charmed OpenSearch - Rev 167",
"my-content": "content",
}
mock_json_dump.assert_called_once_with(
expected_updated_dashboard, mock_open_func(), indent=4
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ _meta:

## Demo users

kibanaserver:
hash: $2b$12$VNfTvrDDZ5JjT9.BZDqRTOh6sZoUxdMmgLueB4X0H93E0/e9FinRC
reserved: false
description: Kibanaserver user
admin:
hash: $2b$12$Cts2k6vk.emW.E1mQN.B5u/5DfwKybaXFRREHfIwUs7RUHNp8h.c.
hash: $2b$12$3wL/WsFm7y0S2jyfiyHV4elgGEg2jeXrPFUmYdZGkj5aDF9hpCPFi
reserved: false
backend_roles:
- admin
opendistro_security_roles:
- security_rest_api_access
- all_access
description: Admin user
kibanaserver:
hash: $2b$12$0ZYW/CiICy1.7YXpRYDjeOLD75qnPAu4I3w5KXZmJvFp1rRiCm8qa
reserved: false
description: Kibanaserver user

0 comments on commit 4776c62

Please sign in to comment.