From: Kobi Ginon Date: Mon, 25 May 2026 12:38:34 +0000 (+0300) Subject: cephadm: set Grafana http_addr to 0.0.0.0 when unset X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=c8ffac91f0f7dd6c0124c3a3ea0daa4913f54d35;p=ceph.git cephadm: set Grafana http_addr to 0.0.0.0 when unset Grafana 11.1+ rejects non-literal http_addr values (e.g. localhost) in grafana-apiserver. Use 0.0.0.0 by default; stop bracket-wrapping IPv6 addresses in http_addr. Fixes: https://tracker.ceph.com/issues/75365 Signed-off-by: Kobi Ginon --- diff --git a/src/pybind/mgr/cephadm/services/monitoring.py b/src/pybind/mgr/cephadm/services/monitoring.py index 86f0aa0a8e8..e3fd676e22c 100644 --- a/src/pybind/mgr/cephadm/services/monitoring.py +++ b/src/pybind/mgr/cephadm/services/monitoring.py @@ -2,7 +2,6 @@ import errno import logging import os from typing import List, Any, Tuple, Dict, Optional, cast, TYPE_CHECKING -import ipaddress import time import requests @@ -74,8 +73,15 @@ class GrafanaService(CephadmService): if ip_to_bind_to: daemon_spec.port_ips = {str(grafana_port): ip_to_bind_to} grafana_ip = ip_to_bind_to - if ipaddress.ip_network(grafana_ip).version == 6: - grafana_ip = f"[{grafana_ip}]" + + if not grafana_ip: + # Grafana 11.1+ validates http_addr with net.ParseIP; hostnames such as + # localhost fail in grafana-apiserver. Use a literal address (bind all IPv4). + # Check if the primary manager or orchestrator is configured for IPv6 + if self.mgr.get_mgr_ip().startswith('::') or ':' in self.mgr.get_mgr_ip(): + grafana_ip = '::' + else: + grafana_ip = '0.0.0.0' domain = self.mgr.get_fqdn(daemon_spec.host) mgmt_gw_ips = [] diff --git a/src/pybind/mgr/cephadm/tests/services/test_monitoring.py b/src/pybind/mgr/cephadm/tests/services/test_monitoring.py index 57a9d8a3da1..d582b07863c 100644 --- a/src/pybind/mgr/cephadm/tests/services/test_monitoring.py +++ b/src/pybind/mgr/cephadm/tests/services/test_monitoring.py @@ -1329,7 +1329,7 @@ class TestMonitoring: cert_file = /etc/grafana/certs/cert_file cert_key = /etc/grafana/certs/cert_key http_port = 3000 - http_addr = + http_addr = :: root_url = %(protocol)s://%(domain)s:%(http_port)s/grafana/ serve_from_sub_path = true [snapshots] @@ -1490,7 +1490,7 @@ class TestMonitoring: cert_file = /etc/grafana/certs/cert_file cert_key = /etc/grafana/certs/cert_key http_port = 3000 - http_addr = + http_addr = :: root_url = %(protocol)s://%(domain)s:%(http_port)s/grafana/ serve_from_sub_path = true [snapshots] @@ -1590,7 +1590,7 @@ class TestMonitoring: cert_file = /etc/grafana/certs/cert_file cert_key = /etc/grafana/certs/cert_key http_port = 3000 - http_addr = + http_addr = :: [snapshots] external_enabled = false [security] @@ -1681,6 +1681,7 @@ class TestMonitoring: ) @patch("cephadm.serve.CephadmServe._run_cephadm", _run_cephadm('{}')) + @patch("cephadm.module.CephadmOrchestrator.get_mgr_ip", lambda _: '192.0.2.1') def test_grafana_initial_admin_pw(self, cephadm_module: CephadmOrchestrator): with with_host(cephadm_module, 'test'): with with_service(cephadm_module, ServiceSpec('mgr')) as _, \ @@ -1705,7 +1706,7 @@ class TestMonitoring: ' cert_file = /etc/grafana/certs/cert_file\n' ' cert_key = /etc/grafana/certs/cert_key\n' ' http_port = 3000\n' - ' http_addr = \n' + ' http_addr = 0.0.0.0\n' '[snapshots]\n' ' external_enabled = false\n' '[security]\n' @@ -1750,6 +1751,33 @@ class TestMonitoring: }}, ['certificate_source: cephadm-signed', 'secure_monitoring_stack:False']) @patch("cephadm.serve.CephadmServe._run_cephadm", _run_cephadm('{}')) + @patch("cephadm.module.CephadmOrchestrator.get_mgr_ip", lambda _: '192.0.2.1') + def test_grafana_http_addr_binds_all_by_default_ipv4(self, cephadm_module: CephadmOrchestrator): + grafana_svc = service_registry.get_service('grafana') + with with_host(cephadm_module, 'test'): + with with_service(cephadm_module, GrafanaSpec()): + ini = grafana_svc.generate_grafana_ini( + CephadmDaemonDeploySpec('test', 'daemon', 'grafana'), + mgmt_gw_enabled=False, + oauth2_enabled=False, + ) + assert 'http_addr = 0.0.0.0' in ini + + @patch("cephadm.serve.CephadmServe._run_cephadm", _run_cephadm('{}')) + @patch("cephadm.module.CephadmOrchestrator.get_mgr_ip", lambda _: '1::4') + def test_grafana_http_addr_binds_all_by_default_ipv6(self, cephadm_module: CephadmOrchestrator): + grafana_svc = service_registry.get_service('grafana') + with with_host(cephadm_module, 'test'): + with with_service(cephadm_module, GrafanaSpec()): + ini = grafana_svc.generate_grafana_ini( + CephadmDaemonDeploySpec('test', 'daemon', 'grafana'), + mgmt_gw_enabled=False, + oauth2_enabled=False, + ) + assert 'http_addr = ::' in ini + + @patch("cephadm.serve.CephadmServe._run_cephadm", _run_cephadm('{}')) + @patch("cephadm.module.CephadmOrchestrator.get_mgr_ip", lambda _: '192.0.2.1') def test_grafana_no_anon_access(self, cephadm_module: CephadmOrchestrator): # with anonymous_access set to False, expecting the [auth.anonymous] section # to not be present in the grafana config. Note that we require an initial_admin_password @@ -1774,7 +1802,7 @@ class TestMonitoring: ' cert_file = /etc/grafana/certs/cert_file\n' ' cert_key = /etc/grafana/certs/cert_key\n' ' http_port = 3000\n' - ' http_addr = \n' + ' http_addr = 0.0.0.0\n' '[snapshots]\n' ' external_enabled = false\n' '[security]\n'