From: John Mulligan Date: Wed, 13 Dec 2023 21:10:11 +0000 (-0500) Subject: mgr/cephadm: add a new smb ceph service subclass X-Git-Tag: v20.0.0~2300^2~15 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=a88cf505a051298996b6be99d6d55a91a7684467;p=ceph.git mgr/cephadm: add a new smb ceph service subclass Will be used in a later commit to implement deploying smb instances. Signed-off-by: John Mulligan --- diff --git a/src/pybind/mgr/cephadm/services/smb.py b/src/pybind/mgr/cephadm/services/smb.py new file mode 100644 index 0000000000000..920c4ef02f741 --- /dev/null +++ b/src/pybind/mgr/cephadm/services/smb.py @@ -0,0 +1,123 @@ +import logging +from typing import Any, Dict, Iterator, List, Tuple, cast + +from ceph.deployment.service_spec import ServiceSpec, SMBSpec + +from orchestrator import DaemonDescription +from .cephadmservice import ( + AuthEntity, + CephService, + CephadmDaemonDeploySpec, + simplified_keyring, +) + +logger = logging.getLogger(__name__) + + +class SMBService(CephService): + TYPE = 'smb' + + def config(self, spec: ServiceSpec) -> None: + assert self.TYPE == spec.service_type + logger.warning('config is a no-op') + + def prepare_create( + self, daemon_spec: CephadmDaemonDeploySpec + ) -> CephadmDaemonDeploySpec: + assert self.TYPE == daemon_spec.daemon_type + logger.debug('smb prepare_create') + daemon_spec.final_config, daemon_spec.deps = self.generate_config( + daemon_spec + ) + return daemon_spec + + def generate_config( + self, daemon_spec: CephadmDaemonDeploySpec + ) -> Tuple[Dict[str, Any], List[str]]: + logger.debug('smb generate_config') + assert self.TYPE == daemon_spec.daemon_type + smb_spec = cast( + SMBSpec, self.mgr.spec_store[daemon_spec.service_name].spec + ) + config_blobs: Dict[str, Any] = {} + + config_blobs['cluster_id'] = smb_spec.cluster_id + config_blobs['features'] = smb_spec.features + config_blobs['config_uri'] = smb_spec.config_uri + if smb_spec.join_sources: + config_blobs['join_sources'] = smb_spec.join_sources + if smb_spec.custom_dns: + config_blobs['custom_dns'] = smb_spec.custom_dns + ceph_users = smb_spec.include_ceph_users or [] + config_blobs.update( + self._ceph_config_and_keyring_for( + smb_spec, daemon_spec.daemon_id, ceph_users + ) + ) + logger.debug('smb generate_config: %r', config_blobs) + return config_blobs, [] + + def config_dashboard( + self, daemon_descrs: List[DaemonDescription] + ) -> None: + # TODO ??? + logger.warning('config_dashboard is a no-op') + + def get_auth_entity(self, daemon_id: str, host: str = "") -> AuthEntity: + # We want a clear, distinct auth entity for fetching the config versus + # data path access. + return AuthEntity(f'client.{self.TYPE}.config.{daemon_id}') + + def _rados_uri_to_pool(self, uri: str) -> str: + """Given a psudo-uri possibly pointing to an object in a pool, return + the name of the pool if a rados uri, otherwise return an empty string. + """ + if not uri.startswith('rados://'): + return '' + pool = uri[8:].lstrip('/').split('/')[0] + logger.debug('extracted pool %r from uri %r', pool, uri) + return pool + + def _allow_config_key_command(self, name: str) -> str: + # permit the samba container config access to the mon config key store + # with keys like smb/config//*. + return f'allow command "config-key get" with "key" prefix "smb/config/{name}/"' + + def _pools_in_spec(self, smb_spec: SMBSpec) -> Iterator[str]: + uris = [smb_spec.config_uri] + uris.extend(smb_spec.join_sources or []) + for uri in uris: + pool = self._rados_uri_to_pool(uri) + if pool: + yield pool + + def _key_for_user(self, entity: str) -> str: + ret, keyring, err = self.mgr.mon_command({ + 'prefix': 'auth get', + 'entity': entity, + }) + if ret != 0: + raise ValueError(f'no auth key for user: {entity!r}') + return '\n' + simplified_keyring(entity, keyring) + + def _ceph_config_and_keyring_for( + self, smb_spec: SMBSpec, daemon_id: str, ceph_users: List[str] + ) -> Dict[str, str]: + ackc = self._allow_config_key_command(smb_spec.cluster_id) + wanted_caps = ['mon', f'allow r, {ackc}'] + pools = list(self._pools_in_spec(smb_spec)) + if pools: + wanted_caps.append('osd') + wanted_caps.append( + ', '.join(f'allow r pool={pool}' for pool in pools) + ) + entity = self.get_auth_entity(daemon_id) + keyring = self.get_keyring_with_caps(entity, wanted_caps) + # add additional data-path users to the ceph keyring + for ceph_user in ceph_users: + keyring += self._key_for_user(ceph_user) + return { + 'config': self.mgr.get_minimal_ceph_conf(), + 'keyring': keyring, + 'config_auth_entity': entity, + }