Skip to content

Commit 18114b4

Browse files
Refactors ceph_cos_agent lib as a charm-lib
Signed-off-by: utkarsh bhatt <utkarsh.bhatt@canonical.com>
1 parent f29d53e commit 18114b4

File tree

4 files changed

+138
-88
lines changed

4 files changed

+138
-88
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Copyright 2022 Canonical Ltd.
2+
# See LICENSE file for licensing details.
3+
4+
"""
5+
Library for handling ceph observability integrations
6+
"""
7+
8+
import logging
9+
import socket
10+
import tenacity
11+
from typing import TYPE_CHECKING
12+
13+
if TYPE_CHECKING:
14+
import charm
15+
16+
from charms.grafana_agent.v0 import cos_agent
17+
from charms_ceph import utils as ceph_utils
18+
19+
# The unique Charmhub library identifier, never change it
20+
LIBID = "ac526775f8ed42ebb46b231dc00519d3"
21+
22+
# Increment this major API version when introducing breaking changes
23+
LIBAPI = 0
24+
25+
# Increment this PATCH version before using `charmcraft publish-lib` or reset
26+
# to 0 if you are raising the major API version
27+
LIBPATCH = 1
28+
29+
logger = logging.getLogger(__name__)
30+
31+
32+
class CephCOSAgentProvider(cos_agent.COSAgentProvider):
33+
34+
def __init__(self, charm):
35+
super().__init__(
36+
charm,
37+
metrics_rules_dir="./files/prometheus_alert_rules",
38+
dashboard_dirs=["./files/grafana_dashboards"],
39+
scrape_configs=self._custom_scrape_configs,
40+
)
41+
events = self._charm.on[cos_agent.DEFAULT_RELATION_NAME]
42+
self.framework.observe(
43+
events.relation_departed, self._on_relation_departed
44+
)
45+
46+
def _on_refresh(self, event):
47+
"""Enable prometheus on relation change"""
48+
if not ceph_utils.is_bootstrapped():
49+
logger.debug("not bootstrapped, defer _on_refresh: %s", event)
50+
event.defer()
51+
return
52+
logger.debug("refreshing cos_agent relation")
53+
if self._charm.unit.is_leader():
54+
self.mgr_config_set_rbd_stats_pools()
55+
ceph_utils.mgr_enable_module("prometheus")
56+
super()._on_refresh(event)
57+
58+
def _on_relation_departed(self, event):
59+
"""Disable prometheus on depart of relation"""
60+
if self._charm.unit.is_leader() and ceph_utils.is_bootstrapped():
61+
logger.debug(
62+
"is_leader and is_bootstrapped, running rel departed: %s",
63+
event,
64+
)
65+
ceph_utils.mgr_disable_module("prometheus")
66+
logger.debug("module_disabled")
67+
68+
def _custom_scrape_configs(self):
69+
fqdn = socket.getfqdn()
70+
fqdn_parts = fqdn.split('.')
71+
domain = '.'.join(fqdn_parts[1:]) if len(fqdn_parts) > 1 else fqdn
72+
return [
73+
{
74+
"metrics_path": "/metrics",
75+
"static_configs": [{"targets": ["localhost:9283"]}],
76+
"honor_labels": True,
77+
"metric_relabel_configs": [
78+
{
79+
# localhost:9283 is the generic default instance label
80+
# added by grafana-agent which is kinda useless.
81+
# Replace it with a somewhat more meaningful label
82+
"source_labels": ["instance"],
83+
"regex": "^localhost:9283$",
84+
"target_label": "instance",
85+
"action": "replace",
86+
"replacement": "ceph_cluster",
87+
},
88+
{ # if we have a non-empty hostname label, use it as the
89+
# instance label
90+
"source_labels": ["hostname"],
91+
"regex": "(.+)",
92+
"target_label": "instance",
93+
"action": "replace",
94+
"replacement": "${1}",
95+
},
96+
{ # tack on the domain to the instance label to make it
97+
# conform to grafana-agent's node-exporter expectations
98+
"source_labels": ["instance"],
99+
"regex": "(.*)",
100+
"target_label": "instance",
101+
"action": "replace",
102+
"replacement": "${1}." + domain,
103+
},
104+
]
105+
},
106+
107+
]
108+
109+
# TODO: switch to charms_ceph sourced util function
110+
@tenacity.retry(
111+
wait=tenacity.wait_exponential(multiplier=1, max=10),
112+
reraise=True,
113+
stop=tenacity.stop_after_attempt(30))
114+
def mgr_config_set_rbd_stats_pools(self):
115+
"""Update ceph mgr config with the value from rbd-status-pools config
116+
"""
117+
if self._charm.unit.is_leader() and ceph_utils.is_bootstrapped():
118+
rbd_stats_pools = self._charm.model.config.get('rbd-stats-pools')
119+
if rbd_stats_pools:
120+
ceph_utils.mgr_config_set(
121+
'mgr/prometheus/rbd_stats_pools',
122+
rbd_stats_pools
123+
)
124+

ceph-mon/src/ceph_metrics.py

+1-80
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
66
Configure prometheus scrape jobs via the metrics-endpoint relation.
77
"""
8+
89
import json
910
import logging
1011
import os.path
1112
import pathlib
12-
import socket
1313

1414
from typing import Optional, Union, List, TYPE_CHECKING
1515

@@ -19,7 +19,6 @@
1919
import charm
2020

2121
from charms.prometheus_k8s.v0 import prometheus_scrape
22-
from charms.grafana_agent.v0 import cos_agent
2322
from charms_ceph import utils as ceph_utils
2423
from ops.framework import BoundEvent
2524
from utils import mgr_config_set_rbd_stats_pools
@@ -151,81 +150,3 @@ def update_alert_rules(self):
151150
self._charm._stored.alert_rule_errors = msg
152151
return
153152
self._set_alert_rules(alert_rules_as_dict)
154-
155-
156-
class CephCOSAgentProvider(cos_agent.COSAgentProvider):
157-
158-
def __init__(self, charm):
159-
super().__init__(
160-
charm,
161-
metrics_rules_dir="./files/prometheus_alert_rules",
162-
dashboard_dirs=["./files/grafana_dashboards"],
163-
scrape_configs=self._custom_scrape_configs,
164-
)
165-
events = self._charm.on[cos_agent.DEFAULT_RELATION_NAME]
166-
self.framework.observe(
167-
events.relation_departed, self._on_relation_departed
168-
)
169-
170-
def _on_refresh(self, event):
171-
"""Enable prometheus on relation change"""
172-
if not ceph_utils.is_bootstrapped():
173-
logger.debug("not bootstrapped, defer _on_refresh: %s", event)
174-
event.defer()
175-
return
176-
logger.debug("refreshing cos_agent relation")
177-
if self._charm.unit.is_leader():
178-
mgr_config_set_rbd_stats_pools()
179-
ceph_utils.mgr_enable_module("prometheus")
180-
super()._on_refresh(event)
181-
182-
def _on_relation_departed(self, event):
183-
"""Disable prometheus on depart of relation"""
184-
if self._charm.unit.is_leader() and ceph_utils.is_bootstrapped():
185-
logger.debug(
186-
"is_leader and is_bootstrapped, running rel departed: %s",
187-
event,
188-
)
189-
ceph_utils.mgr_disable_module("prometheus")
190-
logger.debug("module_disabled")
191-
192-
def _custom_scrape_configs(self):
193-
fqdn = socket.getfqdn()
194-
fqdn_parts = fqdn.split('.')
195-
domain = '.'.join(fqdn_parts[1:]) if len(fqdn_parts) > 1 else fqdn
196-
return [
197-
{
198-
"metrics_path": "/metrics",
199-
"static_configs": [{"targets": ["localhost:9283"]}],
200-
"honor_labels": True,
201-
"metric_relabel_configs": [
202-
{
203-
# localhost:9283 is the generic default instance label
204-
# added by grafana-agent which is kinda useless.
205-
# Replace it with a somewhat more meaningful label
206-
"source_labels": ["instance"],
207-
"regex": "^localhost:9283$",
208-
"target_label": "instance",
209-
"action": "replace",
210-
"replacement": "ceph_cluster",
211-
},
212-
{ # if we have a non-empty hostname label, use it as the
213-
# instance label
214-
"source_labels": ["hostname"],
215-
"regex": "(.+)",
216-
"target_label": "instance",
217-
"action": "replace",
218-
"replacement": "${1}",
219-
},
220-
{ # tack on the domain to the instance label to make it
221-
# conform to grafana-agent's node-exporter expectations
222-
"source_labels": ["instance"],
223-
"regex": "(.*)",
224-
"target_label": "instance",
225-
"action": "replace",
226-
"replacement": "${1}." + domain,
227-
},
228-
]
229-
},
230-
231-
]

ceph-mon/src/charm.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import charms.operator_libs_linux.v0.apt as apt
1212
import charms.operator_libs_linux.v1.systemd as systemd
13+
from charms.ceph_mon.v0 import ceph_cos_agent
1314

1415
from ops.charm import CharmEvents
1516
from ops.framework import EventBase, EventSource
@@ -41,7 +42,7 @@ class CephCharmEvents(CharmEvents):
4142

4243
class CephMonCharm(ops_openstack.core.OSBaseCharm):
4344

44-
release = 'quincy'
45+
release = 'squid'
4546

4647
PACKAGES = [
4748
'ceph', 'gdisk',
@@ -216,7 +217,7 @@ def __init__(self, *args):
216217

217218
self.clients = ceph_client.CephClientProvides(self)
218219
self.metrics_endpoint = ceph_metrics.CephMetricsEndpointProvider(self)
219-
self.cos_agent = ceph_metrics.CephCOSAgentProvider(self)
220+
self.cos_agent = ceph_cos_agent.CephCOSAgentProvider(self)
220221
self.ceph_status = ceph_status.StatusAssessor(self)
221222
self.mds = ceph_mds.CephMdsProvides(self)
222223

ceph-mon/unit_tests/test_ceph_metrics.py

+10-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
from ops.testing import Harness
1414

15-
import ceph_metrics # noqa: avoid circ. import
1615
import charm
1716

1817

@@ -155,17 +154,21 @@ def test_init(self):
155154
"cos-agent",
156155
)
157156

158-
@patch("ceph_metrics.mgr_config_set_rbd_stats_pools", lambda: None)
159-
@patch("ceph_metrics.ceph_utils.is_bootstrapped", return_value=True)
160-
@patch("ceph_metrics.ceph_utils.is_mgr_module_enabled", return_value=False)
161-
@patch("ceph_metrics.ceph_utils.mgr_enable_module")
162-
@patch("ceph_metrics.ceph_utils.mgr_disable_module")
157+
@patch("charms.ceph_mon.v0.ceph_cos_agent."
158+
"CephCOSAgentProvider.mgr_config_set_rbd_stats_pools")
159+
@patch("charms.ceph_mon.v0.ceph_cos_agent."
160+
"ceph_utils.is_bootstrapped", return_value=True)
161+
@patch("charms.ceph_mon.v0.ceph_cos_agent."
162+
"ceph_utils.is_mgr_module_enabled", return_value=False)
163+
@patch("charms.ceph_mon.v0.ceph_cos_agent.ceph_utils.mgr_enable_module")
164+
@patch("charms.ceph_mon.v0.ceph_cos_agent.ceph_utils.mgr_disable_module")
163165
def test_add_remove_rel(
164166
self,
165167
mgr_disable_module,
166168
mgr_enable_module,
167169
_is_mgr_module_enable,
168170
_is_bootstrapped,
171+
mgr_config_set_rbd_stats_pools,
169172
):
170173
rel_id = self.harness.add_relation("cos-agent", "grafana-agent")
171174
self.harness.add_relation_unit(rel_id, "grafana-agent/0")
@@ -181,6 +184,7 @@ def test_add_remove_rel(
181184
self.assertTrue("metrics_alert_rules" in data)
182185
self.assertTrue("groups" in data["metrics_alert_rules"])
183186
mgr_enable_module.assert_called_once()
187+
mgr_config_set_rbd_stats_pools.assert_called_once()
184188

185189
self.harness.remove_relation(rel_id)
186190
mgr_disable_module.assert_called_once()

0 commit comments

Comments
 (0)