From: Sebastian Wagner Date: Fri, 16 Jul 2021 14:20:32 +0000 (+0200) Subject: mgr/cephadm: Add GrafanaSpec.initial_admin_password X-Git-Tag: v17.1.0~356^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=fdae665a2fe645d3f76b212f440ffe2c96281bc0;p=ceph.git mgr/cephadm: Add GrafanaSpec.initial_admin_password By default, we're not creating any admin accout for Grafana now, but we're adding an option to set the grafana password manually using: ```yaml service_type: grafana spec: initial_admin_password: mypassword ``` Users can then easily log into Grafana with the given password. Fixes: https://tracker.ceph.com/issues/48291 Signed-off-by: Sebastian Wagner --- diff --git a/doc/cephadm/services/monitoring.rst b/doc/cephadm/services/monitoring.rst index 91b8742f3cf..5cb1537dbb4 100644 --- a/doc/cephadm/services/monitoring.rst +++ b/doc/cephadm/services/monitoring.rst @@ -161,6 +161,8 @@ For example, if you had changed the prometheus image ceph config rm mgr mgr/cephadm/container_image_prometheus +.. _cephadm-overwrite-jinja2-templates: + Using custom configuration files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -180,7 +182,7 @@ preserved and automatically applied on future deployments of these services. The configuration of the custom template is also preserved when the default configuration of cephadm changes. If the updated configuration is to be used, - the custom template needs to be migrated *manually*. + the custom template needs to be migrated *manually* after each upgrade of Ceph. Option names """""""""""" @@ -338,6 +340,30 @@ update its configuration: The ``reconfig`` command also sets the proper URL for Ceph Dashboard. +Setting the initial admin password +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, Grafana will not create an initial +admin user. In order to create the admin user, please create a file +``grafana.yaml`` with this content: + +.. code-block:: yaml + + service_type: grafana + spec: + initial_admin_password: mypassword + +Then apply this specification: + +.. code-block:: bash + + ceph orch apply -i grafana.yaml + ceph orch redeploy grafana + +Grafana will now create an admin user called ``admin`` with the +given password. + + Setting up Alertmanager ----------------------- diff --git a/src/pybind/mgr/cephadm/services/monitoring.py b/src/pybind/mgr/cephadm/services/monitoring.py index 3ec2a66789e..627673d4dd6 100644 --- a/src/pybind/mgr/cephadm/services/monitoring.py +++ b/src/pybind/mgr/cephadm/services/monitoring.py @@ -7,7 +7,7 @@ from urllib.parse import urlparse from mgr_module import HandleCommandResult from orchestrator import DaemonDescription -from ceph.deployment.service_spec import AlertManagerSpec, ServiceSpec +from ceph.deployment.service_spec import AlertManagerSpec, GrafanaSpec, ServiceSpec from cephadm.services.cephadmservice import CephadmService, CephadmDaemonDeploySpec from cephadm.services.ingress import IngressSpec from mgr_util import verify_tls, ServerConfigException, create_self_signed_cert, build_url @@ -57,8 +57,11 @@ class GrafanaService(CephadmService): 'value': 'false', }) + spec: GrafanaSpec = cast( + GrafanaSpec, self.mgr.spec_store.active_specs[daemon_spec.service_name]) grafana_ini = self.mgr.template.render( 'services/grafana/grafana.ini.j2', { + 'initial_admin_password': spec.initial_admin_password, 'http_port': daemon_spec.ports[0] if daemon_spec.ports else self.DEFAULT_SERVICE_PORT, 'http_addr': daemon_spec.ip if daemon_spec.ip else '' }) diff --git a/src/pybind/mgr/cephadm/templates/services/grafana/grafana.ini.j2 b/src/pybind/mgr/cephadm/templates/services/grafana/grafana.ini.j2 index 3d6303f4466..642d0647f3f 100644 --- a/src/pybind/mgr/cephadm/templates/services/grafana/grafana.ini.j2 +++ b/src/pybind/mgr/cephadm/templates/services/grafana/grafana.ini.j2 @@ -13,6 +13,10 @@ http_port = {{ http_port }} http_addr = {{ http_addr }} [security] +{% if not initial_admin_password %} + disable_initial_admin_creation = true +{% else %} admin_user = admin - admin_password = admin + admin_password = {{ initial_admin_password }} +{% endif %} allow_embedding = true diff --git a/src/pybind/mgr/cephadm/tests/test_services.py b/src/pybind/mgr/cephadm/tests/test_services.py index 09a5b2b411c..b8e6f784ef4 100644 --- a/src/pybind/mgr/cephadm/tests/test_services.py +++ b/src/pybind/mgr/cephadm/tests/test_services.py @@ -4,7 +4,7 @@ import yaml import pytest -from unittest.mock import MagicMock, call, patch +from unittest.mock import MagicMock, call, patch, ANY from cephadm.serve import CephadmServe from cephadm.services.cephadmservice import MonService, MgrService, MdsService, RgwService, \ @@ -16,7 +16,7 @@ from cephadm.services.monitoring import GrafanaService, AlertmanagerService, Pro NodeExporterService from cephadm.module import CephadmOrchestrator from ceph.deployment.service_spec import IscsiServiceSpec, MonitoringSpec, AlertManagerSpec, \ - ServiceSpec, RGWSpec + ServiceSpec, RGWSpec, GrafanaSpec from cephadm.tests.fixtures import with_host, with_service, _run_cephadm, async_side_effect from orchestrator import OrchestratorError @@ -332,7 +332,7 @@ class TestMonitoring: cephadm_module.set_store('grafana_crt', 'c') cephadm_module.set_store('grafana_key', 'k') with with_service(cephadm_module, MonitoringSpec('prometheus')) as _, \ - with_service(cephadm_module, MonitoringSpec('grafana')) as _: + with_service(cephadm_module, GrafanaSpec('grafana')) as _: files = { 'grafana.ini': dedent(""" # This file is generated by cephadm. @@ -350,8 +350,7 @@ class TestMonitoring: http_port = 3000 http_addr = [security] - admin_user = admin - admin_password = admin + disable_initial_admin_creation = true allow_embedding = true""").lstrip(), # noqa: W291 'provisioning/datasources/ceph-dashboard.yml': dedent(""" # This file is generated by cephadm. @@ -389,6 +388,47 @@ class TestMonitoring: stdin=json.dumps({"files": files}), image='') + @patch("cephadm.serve.CephadmServe._run_cephadm", _run_cephadm('{}')) + def test_grafana_initial_admin_pw(self, cephadm_module: CephadmOrchestrator): + with with_host(cephadm_module, 'test'): + with with_service(cephadm_module, GrafanaSpec(initial_admin_password='secure')): + out = cephadm_module.cephadm_services['grafana'].generate_config( + CephadmDaemonDeploySpec('test', 'daemon', 'grafana')) + assert out == ( + { + 'files': + { + 'certs/cert_file': ANY, + 'certs/cert_key': ANY, + 'grafana.ini': + '# This file is generated by cephadm.\n' + '[users]\n' + ' default_theme = light\n' + '[auth.anonymous]\n' + ' enabled = true\n' + " org_name = 'Main Org.'\n" + " org_role = 'Viewer'\n" + '[server]\n' + " domain = 'bootstrap.storage.lab'\n" + ' protocol = https\n' + ' cert_file = /etc/grafana/certs/cert_file\n' + ' cert_key = /etc/grafana/certs/cert_key\n' + ' http_port = 3000\n' + ' http_addr = \n' + '[security]\n' + ' admin_user = admin\n' + ' admin_password = secure\n' + ' allow_embedding = true', + 'provisioning/datasources/ceph-dashboard.yml': + '# This file is generated by cephadm.\n' + 'deleteDatasources:\n' + '\n' + 'datasources:\n' + } + }, + [], + ) + @patch("cephadm.serve.CephadmServe._run_cephadm") def test_monitoring_ports(self, _run_cephadm, cephadm_module: CephadmOrchestrator): _run_cephadm.side_effect = async_side_effect(('{}', '', 0)) diff --git a/src/python-common/ceph/deployment/service_spec.py b/src/python-common/ceph/deployment/service_spec.py index 37776bb8a96..48d511fc3dc 100644 --- a/src/python-common/ceph/deployment/service_spec.py +++ b/src/python-common/ceph/deployment/service_spec.py @@ -432,7 +432,7 @@ class ServiceSpec(object): 'alertmanager': AlertManagerSpec, 'ingress': IngressSpec, 'container': CustomContainerSpec, - 'grafana': MonitoringSpec, + 'grafana': GrafanaSpec, 'node-exporter': MonitoringSpec, 'prometheus': MonitoringSpec, }.get(service_type, cls) @@ -1093,3 +1093,27 @@ class AlertManagerSpec(MonitoringSpec): yaml.add_representer(AlertManagerSpec, ServiceSpec.yaml_representer) + + +class GrafanaSpec(MonitoringSpec): + def __init__(self, + service_type: str = 'grafana', + service_id: Optional[str] = None, + placement: Optional[PlacementSpec] = None, + unmanaged: bool = False, + preview_only: bool = False, + config: Optional[Dict[str, str]] = None, + networks: Optional[List[str]] = None, + port: Optional[int] = None, + initial_admin_password: Optional[str] = None + ): + assert service_type == 'grafana' + super(GrafanaSpec, self).__init__( + 'grafana', service_id=service_id, + placement=placement, unmanaged=unmanaged, + preview_only=preview_only, config=config, networks=networks, port=port) + + self.initial_admin_password = initial_admin_password + + +yaml.add_representer(GrafanaSpec, ServiceSpec.yaml_representer) diff --git a/src/python-common/ceph/tests/test_service_spec.py b/src/python-common/ceph/tests/test_service_spec.py index b0541d653ef..e2e30944ceb 100644 --- a/src/python-common/ceph/tests/test_service_spec.py +++ b/src/python-common/ceph/tests/test_service_spec.py @@ -249,6 +249,12 @@ service_name: grafana spec: port: 1234 --- +service_type: grafana +service_name: grafana +spec: + initial_admin_password: secure + port: 1234 +--- service_type: ingress service_id: rgw.foo service_name: ingress.rgw.foo