from cephadmlib.daemons.ceph import get_ceph_mounts_for_type, ceph_daemons
from cephadmlib.daemons import (
Ceph,
+ CephExporter,
CephIscsi,
CephNvmeof,
CustomContainer,
node_proxy = NodeProxy.init(ctx, fsid, ident.daemon_id)
node_proxy.create_daemon_dirs(data_dir, uid, gid)
+ elif daemon_type == CephExporter.daemon_type:
+ ceph_exporter = CephExporter.init(ctx, fsid, ident.daemon_id)
+ ceph_exporter.create_daemon_dirs(data_dir, uid, gid)
+
else:
daemon = daemon_form_create(ctx, ident)
if isinstance(daemon, ContainerDaemonForm):
from ..context import CephadmContext
from ..deployment_utils import to_deployment_container
from ..exceptions import Error
-from ..file_utils import make_run_dir, pathify
+from ..file_utils import (
+ make_run_dir,
+ pathify,
+ populate_files,
+ makedirs,
+ recursive_chown,
+)
+from ..data_utils import dict_get
from ..host_facts import HostFacts
from ..logging import Highlight
from ..net_utils import get_hostname, get_ip_addresses
self.port = config_json.get('port', self.DEFAULT_PORT)
self.prio_limit = config_json.get('prio-limit', 5)
self.stats_period = config_json.get('stats-period', 5)
+ self.https_enabled: bool = config_json.get('https_enabled', False)
+ self.files = dict_get(config_json, 'files', {})
@classmethod
def init(
f'--prio-limit={self.prio_limit}',
f'--stats-period={self.stats_period}',
]
+ if self.https_enabled:
+ args.extend(
+ [
+ '--cert-file',
+ '/etc/certs/ceph-exporter.crt',
+ '--key-file',
+ '/etc/certs/ceph-exporter.key',
+ ]
+ )
return args
def validate(self) -> None:
) -> None:
cm = Ceph.get_ceph_mounts(ctx, self.identity)
mounts.update(cm)
+ if self.https_enabled:
+ data_dir = self.identity.data_dir(ctx.data_dir)
+ mounts.update({os.path.join(data_dir, 'etc/certs'): '/etc/certs'})
def customize_process_args(
self, ctx: CephadmContext, args: List[str]
# it until now
self.validate()
+ def create_daemon_dirs(self, data_dir: str, uid: int, gid: int) -> None:
+ """Create files under the container data dir"""
+ if not os.path.isdir(data_dir):
+ raise OSError('data_dir is not a directory: %s' % (data_dir))
+ logger.info('Writing ceph-exporter config...')
+ config_dir = os.path.join(data_dir, 'etc/')
+ ssl_dir = os.path.join(data_dir, 'etc/certs')
+ for ddir in [config_dir, ssl_dir]:
+ makedirs(ddir, uid, gid, 0o755)
+ recursive_chown(ddir, uid, gid)
+ cert_files = {
+ fname: content
+ for fname, content in self.files.items()
+ if fname.endswith('.crt') or fname.endswith('.key')
+ }
+ populate_files(ssl_dir, cert_files, uid, gid)
+
def get_ceph_mounts_for_type(
ctx: CephadmContext, fsid: str, daemon_type: str
# this daemon type doesn't need deps mgmt
pass
- if daemon_type in ['prometheus', 'node-exporter', 'alertmanager', 'grafana']:
+ if daemon_type in ['prometheus', 'node-exporter', 'alertmanager', 'grafana',
+ 'ceph-exporter']:
deps.append(f'secure_monitoring_stack:{self.secure_monitoring_stack}')
return sorted(deps)
action = 'reconfig'
# we need only redeploy if secure_monitoring_stack or mgmt-gateway value has changed:
# TODO(redo): check if we should just go always with redeploy (it's fast enough)
- if dd.daemon_type in ['prometheus', 'node-exporter', 'alertmanager']:
+ if dd.daemon_type in ['prometheus', 'node-exporter', 'alertmanager', 'ceph-exporter']:
diff = list(set(last_deps).symmetric_difference(set(deps)))
REDEPLOY_TRIGGERS = ['secure_monitoring_stack', 'mgmt-gateway']
if any(svc in e for e in diff for svc in REDEPLOY_TRIGGERS):
'mon', 'allow r',
'mgr', 'allow r',
'osd', 'allow r'])
- exporter_config = {}
+ exporter_config: Dict[str, Any] = {}
if spec.sock_dir:
exporter_config.update({'sock-dir': spec.sock_dir})
if spec.port:
host_fqdn = self.mgr.get_fqdn(daemon_spec.host)
return self.mgr.cert_mgr.generate_cert(host_fqdn, node_ip)
+
class CephfsMirrorService(CephService):
TYPE = 'cephfs-mirror'
import pytest
-from unittest.mock import MagicMock, call, patch, ANY
+from unittest.mock import Mock, MagicMock, call, patch, ANY
from cephadm.serve import CephadmServe
from cephadm.services.cephadmservice import MonService, MgrService, MdsService, RgwService, \
use_current_daemon_image=False,
)
+ @patch("cephadm.serve.CephadmServe._run_cephadm")
+ @patch("socket.getfqdn")
+ @patch("cephadm.module.CephadmOrchestrator.get_mgr_ip", lambda _: '::1')
+ @patch('cephadm.cert_mgr.CertMgr.get_root_ca', lambda instance: 'cephadm_root_cert')
+ @patch('cephadm.cert_mgr.CertMgr.generate_cert', lambda instance, fqdn, ip: ('mycert', 'mykey'))
+ @patch('cephadm.services.cephadmservice.CephExporterService.get_keyring_with_caps', Mock(return_value='[client.ceph-exporter.test]\nkey = fake-secret\n'))
+ def test_ceph_exporter_config_security_enabled(self, _get_fqdn, _run_cephadm, cephadm_module: CephadmOrchestrator):
+ _run_cephadm.side_effect = async_side_effect(('{}', '', 0))
+
+ fqdn = 'host1.test'
+ _get_fqdn.return_value = fqdn
+
+ with with_host(cephadm_module, 'test'):
+ cephadm_module.secure_monitoring_stack = True
+ with with_service(cephadm_module, CephExporterSpec()):
+ _run_cephadm.assert_called_with('test', 'ceph-exporter.test',
+ ['_orch', 'deploy'], [],
+ stdin=json.dumps({
+ "fsid": "fsid",
+ "name": "ceph-exporter.test",
+ "image": "",
+ "deploy_arguments": [],
+ "params": {},
+ "meta": {
+ "service_name": "ceph-exporter",
+ "ports": [],
+ "ip": None,
+ "deployed_by": [],
+ "rank": None,
+ "rank_generation": None,
+ "extra_container_args": None,
+ "extra_entrypoint_args": None
+ },
+ "config_blobs": {
+ "config": "",
+ "keyring": "[client.ceph-exporter.test]\nkey = fake-secret\n",
+ "prio-limit": "5",
+ "stats-period": "5",
+ "https_enabled": True,
+ "files": {
+ "ceph-exporter.crt": "mycert",
+ "ceph-exporter.key": "mykey"}}}),
+ use_current_daemon_image=False)
+
@patch("cephadm.serve.CephadmServe._run_cephadm")
@patch("cephadm.module.CephadmOrchestrator.get_mgr_ip", lambda _: '::1')
def test_prometheus_config_security_disabled(self, _run_cephadm, cephadm_module: CephadmOrchestrator):