]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/cephadm: Enhance AlertManagerSpec to allow adding additional webhook receiver...
authorVolker Theile <vtheile@suse.com>
Thu, 30 Jul 2020 12:24:34 +0000 (14:24 +0200)
committerSebastian Wagner <sebastian.wagner@suse.com>
Fri, 21 Aug 2020 11:04:01 +0000 (13:04 +0200)
Fixes: https://tracker.ceph.com/issues/46775
Signed-off-by: Volker Theile <vtheile@suse.com>
(cherry picked from commit 4b87eeb97861929130c4aa7e2c99e29d2a1652ac)

src/pybind/mgr/cephadm/services/monitoring.py
src/pybind/mgr/cephadm/templates/services/alertmanager/alertmanager.yml.j2
src/pybind/mgr/cephadm/tests/test_spec.py
src/python-common/ceph/deployment/service_spec.py

index f910a64446933d2bdee30304b35f822dd0ee3ae7..cc4d1416b65ad1752ebbc0e49487509589c8de17 100644 (file)
@@ -3,11 +3,13 @@ import os
 from typing import List, Any, Tuple, Dict
 
 from orchestrator import DaemonDescription
+from ceph.deployment.service_spec import AlertManagerSpec
 from cephadm.services.cephadmservice import CephadmService, CephadmDaemonSpec
 from mgr_util import verify_tls, ServerConfigException, create_self_signed_cert
 
 logger = logging.getLogger(__name__)
 
+
 class GrafanaService(CephadmService):
     TYPE = 'grafana'
     DEFAULT_SERVICE_PORT = 3000
@@ -73,20 +75,29 @@ class GrafanaService(CephadmService):
             service_url
         )
 
+
 class AlertmanagerService(CephadmService):
     TYPE = 'alertmanager'
     DEFAULT_SERVICE_PORT = 9093
 
-    def create(self, daemon_spec: CephadmDaemonSpec) -> str:
+    def create(self, daemon_spec: CephadmDaemonSpec[AlertManagerSpec]) -> str:
         assert self.TYPE == daemon_spec.daemon_type
+        assert daemon_spec.spec
         return self.mgr._create_daemon(daemon_spec)
 
-    def generate_config(self, daemon_spec: CephadmDaemonSpec) -> Tuple[Dict[str, Any], List[str]]:
+    def generate_config(self, daemon_spec: CephadmDaemonSpec[AlertManagerSpec]) -> Tuple[Dict[str, Any], List[str]]:
         assert self.TYPE == daemon_spec.daemon_type
-        deps = [] # type: List[str]
+        deps: List[str] = []
+        default_webhook_urls: List[str] = []
+
+        if daemon_spec.spec:
+            user_data = daemon_spec.spec.user_data
+            if 'default_webhook_urls' in user_data and isinstance(
+                    user_data['default_webhook_urls'], list):
+                default_webhook_urls.extend(user_data['default_webhook_urls'])
 
         # dashboard(s)
-        dashboard_urls = []
+        dashboard_urls: List[str] = []
         mgr_map = self.mgr.get('mgr_map')
         port = None
         proto = None  # http: or https:
@@ -110,7 +121,8 @@ class AlertmanagerService(CephadmService):
                                                   port))
 
         context = {
-            'dashboard_urls': dashboard_urls
+            'dashboard_urls': dashboard_urls,
+            'default_webhook_urls': default_webhook_urls
         }
         yml = self.mgr.template.render('services/alertmanager/alertmanager.yml.j2', context)
 
@@ -232,6 +244,7 @@ class PrometheusService(CephadmService):
             service_url
         )
 
+
 class NodeExporterService(CephadmService):
     TYPE = 'node-exporter'
 
index 69d5e73bbecc598651a36c07fb40d20656e42dc4..03c1479721b82b64327c8b409ed6ed7827638a24 100644 (file)
@@ -5,12 +5,20 @@ global:
   resolve_timeout: 5m
 
 route:
-  group_by: ['alertname']
-  group_wait: 10s
-  group_interval: 10s
-  repeat_interval: 1h
-  receiver: 'ceph-dashboard'
+  receiver: 'default'
+  routes:
+    - group_by: ['alertname']
+      group_wait: 10s
+      group_interval: 10s
+      repeat_interval: 1h
+      receiver: 'ceph-dashboard'
+
 receivers:
+- name: 'default'
+  webhook_configs:
+{% for url in default_webhook_urls %}
+  - url: '{{ url }}'
+{% endfor %}
 - name: 'ceph-dashboard'
   webhook_configs:
 {% for url in dashboard_urls %}
index 338759cf11ce7b0102869b190b84aeab91ecebad..41b33ac9f185c46089474df89f7caa41c7029ede 100644 (file)
@@ -3,7 +3,7 @@ import json
 import pytest
 
 from ceph.deployment.service_spec import ServiceSpec, NFSServiceSpec, RGWSpec, \
-    ServiceSpecValidationError, IscsiServiceSpec, PlacementSpec
+    IscsiServiceSpec, AlertManagerSpec
 
 from orchestrator import DaemonDescription, OrchestratorError
 
@@ -517,3 +517,15 @@ def test_daemon_description_service_name(spec: ServiceSpec,
         with pytest.raises(OrchestratorError):
             dd.service_name()
 
+
+def test_alertmanager_spec_1():
+    spec = AlertManagerSpec()
+    assert spec.service_type == 'alertmanager'
+    assert isinstance(spec.user_data, dict)
+    assert len(spec.user_data.keys()) == 0
+
+
+def test_alertmanager_spec_2():
+    spec = AlertManagerSpec(user_data={'default_webhook_urls': ['foo']})
+    assert isinstance(spec.user_data, dict)
+    assert 'default_webhook_urls' in spec.user_data.keys()
index 6763572e0433bddd88fe809cbc9d6e73dbea5f59..a2518867a0721e3b9b7e04ed479470cb961eea63 100644 (file)
@@ -387,6 +387,7 @@ class ServiceSpec(object):
             'nfs': NFSServiceSpec,
             'osd': DriveGroupSpec,
             'iscsi': IscsiServiceSpec,
+            'alertmanager': AlertManagerSpec
         }.get(service_type, cls)
         if ret == ServiceSpec and not service_type:
             raise ServiceSpecValidationError('Spec needs a "service_type" key.')
@@ -739,3 +740,38 @@ class IscsiServiceSpec(ServiceSpec):
 
 
 yaml.add_representer(IscsiServiceSpec, ServiceSpec.yaml_representer)
+
+
+class AlertManagerSpec(ServiceSpec):
+    def __init__(self,
+                 service_type: str = 'alertmanager',
+                 service_id: Optional[str] = None,
+                 placement: Optional[PlacementSpec] = None,
+                 unmanaged: bool = False,
+                 preview_only: bool = False,
+                 user_data: Optional[Dict[str, Any]] = None,
+                 ):
+        assert service_type == 'alertmanager'
+        super(AlertManagerSpec, self).__init__(
+            'alertmanager', service_id=service_id,
+            placement=placement, unmanaged=unmanaged,
+            preview_only=preview_only)
+
+        # Custom configuration.
+        #
+        # Example:
+        # service_type: alertmanager
+        # service_id: xyz
+        # user_data:
+        #   default_webhook_urls:
+        #   - "https://foo"
+        #   - "https://bar"
+        #
+        # Documentation:
+        # default_webhook_urls - A list of additional URL's that are
+        #                        added to the default receivers'
+        #                        <webhook_configs> configuration.
+        self.user_data = user_data or {}
+
+
+yaml.add_representer(AlertManagerSpec, ServiceSpec.yaml_representer)