From 1a70e6a72e74e46dce189e4297278166edf3ab87 Mon Sep 17 00:00:00 2001 From: John Mulligan Date: Wed, 20 Sep 2023 10:17:29 -0400 Subject: [PATCH] cephadm: introduce daemon forms to cephadm.py Introduce the DeamonForm base class to cephadm.py and make various daemon-type classes into fully fleged deamon form classes. Some classes already had a semi-standard `init` classmethod for instantiation. In these cases the new `create` classmethod is a thin wrapper over the existing method. In cases where the class was not already being instantiated a minimal set of methods are added. Signed-off-by: John Mulligan --- src/cephadm/cephadm.py | 187 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 175 insertions(+), 12 deletions(-) diff --git a/src/cephadm/cephadm.py b/src/cephadm/cephadm.py index 38e2b59af0e..665d065c59d 100755 --- a/src/cephadm/cephadm.py +++ b/src/cephadm/cephadm.py @@ -163,6 +163,10 @@ from cephadmlib.decorators import ( ) from cephadmlib.host_facts import HostFacts, list_networks from cephadmlib.ssh import authorize_ssh_key, check_ssh_connectivity +from cephadmlib.daemon_form import ( + DaemonForm, + register as register_daemon_form, +) FuncT = TypeVar('FuncT', bound=Callable) @@ -208,15 +212,38 @@ class DeploymentType(Enum): ################################## -class Ceph(object): +@register_daemon_form +class Ceph(DaemonForm): daemons = ('mon', 'mgr', 'osd', 'mds', 'rgw', 'rbd-mirror', 'crash', 'cephfs-mirror', 'ceph-exporter') gateways = ('iscsi', 'nfs', 'nvmeof') + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + # TODO: figure out a way to un-special-case osd + return daemon_type in cls.daemons and daemon_type != 'osd' + + def __init__(self, ident: DaemonIdentity) -> None: + self._identity = ident + + @classmethod + def create(cls, ctx: CephadmContext, ident: DaemonIdentity) -> 'Ceph': + return cls(ident) + + @property + def identity(self) -> DaemonIdentity: + return self._identity + ################################## -class OSD(object): +@register_daemon_form +class OSD(Ceph): + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + # TODO: figure out a way to un-special-case osd + return daemon_type == 'osd' + @staticmethod def get_sysctl_settings() -> List[str]: return [ @@ -229,7 +256,8 @@ class OSD(object): ################################## -class SNMPGateway: +@register_daemon_form +class SNMPGateway(DaemonForm): """Defines an SNMP gateway between Prometheus and SNMP monitoring Frameworks""" daemon_type = 'snmp-gateway' SUPPORTED_VERSIONS = ['V2c', 'V3'] @@ -237,6 +265,10 @@ class SNMPGateway: DEFAULT_PORT = 9464 env_filename = 'snmp-gateway.conf' + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + return cls.daemon_type == daemon_type + def __init__(self, ctx: CephadmContext, fsid: str, @@ -271,6 +303,14 @@ class SNMPGateway: assert cfgs # assert some config data was found return cls(ctx, fsid, daemon_id, cfgs, ctx.image) + @classmethod + def create(cls, ctx: CephadmContext, ident: DaemonIdentity) -> 'SNMPGateway': + return cls.init(ctx, ident.fsid, ident.daemon_id) + + @property + def identity(self) -> DaemonIdentity: + return DaemonIdentity(self.fsid, self.daemon_type, self.daemon_id) + @staticmethod def get_version(ctx: CephadmContext, fsid: str, daemon_id: str) -> Optional[str]: """Return the version of the notifier from it's http endpoint""" @@ -371,7 +411,8 @@ class SNMPGateway: ################################## -class Monitoring(object): +@register_daemon_form +class Monitoring(DaemonForm): """Define the configs for the monitoring containers""" port_map = { @@ -454,6 +495,10 @@ class Monitoring(object): }, } # type: ignore + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + return daemon_type in cls.components + @staticmethod def get_version(ctx, container_id, daemon_type): # type: (CephadmContext, str, str) -> str @@ -486,10 +531,22 @@ class Monitoring(object): version = out.split(' ')[2] return version + def __init__(self, ident: DaemonIdentity) -> None: + self._identity = ident + + @classmethod + def create(cls, ctx: CephadmContext, ident: DaemonIdentity) -> 'Monitoring': + return cls(ident) + + @property + def identity(self) -> DaemonIdentity: + return self._identity + ################################## -class NFSGanesha(object): +@register_daemon_form +class NFSGanesha(DaemonForm): """Defines a NFS-Ganesha container""" daemon_type = 'nfs' @@ -502,6 +559,10 @@ class NFSGanesha(object): 'nfs': 2049, } + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + return cls.daemon_type == daemon_type + def __init__(self, ctx, fsid, @@ -530,6 +591,14 @@ class NFSGanesha(object): # type: (CephadmContext, str, Union[int, str]) -> NFSGanesha return cls(ctx, fsid, daemon_id, fetch_configs(ctx), ctx.image) + @classmethod + def create(cls, ctx: CephadmContext, ident: DaemonIdentity) -> 'NFSGanesha': + return cls.init(ctx, ident.fsid, ident.daemon_id) + + @property + def identity(self) -> DaemonIdentity: + return DaemonIdentity(self.fsid, self.daemon_type, self.daemon_id) + def get_container_mounts(self, data_dir): # type: (str) -> Dict[str, str] mounts = dict() @@ -626,7 +695,8 @@ class NFSGanesha(object): ################################## -class CephIscsi(object): +@register_daemon_form +class CephIscsi(DaemonForm): """Defines a Ceph-Iscsi container""" daemon_type = 'iscsi' @@ -634,6 +704,10 @@ class CephIscsi(object): required_files = ['iscsi-gateway.cfg'] + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + return cls.daemon_type == daemon_type + def __init__(self, ctx, fsid, @@ -658,6 +732,14 @@ class CephIscsi(object): return cls(ctx, fsid, daemon_id, fetch_configs(ctx), ctx.image) + @classmethod + def create(cls, ctx: CephadmContext, ident: DaemonIdentity) -> 'CephIscsi': + return cls.init(ctx, ident.fsid, ident.daemon_id) + + @property + def identity(self) -> DaemonIdentity: + return DaemonIdentity(self.fsid, self.daemon_type, self.daemon_id) + @staticmethod def get_container_mounts(data_dir, log_dir): # type: (str, str) -> Dict[str, str] @@ -813,13 +895,18 @@ done ################################## -class CephNvmeof(object): +@register_daemon_form +class CephNvmeof(DaemonForm): """Defines a Ceph-Nvmeof container""" daemon_type = 'nvmeof' required_files = ['ceph-nvmeof.conf'] default_image = DEFAULT_NVMEOF_IMAGE + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + return cls.daemon_type == daemon_type + def __init__(self, ctx, fsid, @@ -844,6 +931,14 @@ class CephNvmeof(object): return cls(ctx, fsid, daemon_id, fetch_configs(ctx), ctx.image) + @classmethod + def create(cls, ctx: CephadmContext, ident: DaemonIdentity) -> 'CephNvmeof': + return cls.init(ctx, ident.fsid, ident.daemon_id) + + @property + def identity(self) -> DaemonIdentity: + return DaemonIdentity(self.fsid, self.daemon_type, self.daemon_id) + @staticmethod def get_container_mounts(data_dir: str) -> Dict[str, str]: mounts = dict() @@ -938,7 +1033,8 @@ class CephNvmeof(object): ################################## -class CephExporter(object): +@register_daemon_form +class CephExporter(DaemonForm): """Defines a Ceph exporter container""" daemon_type = 'ceph-exporter' @@ -948,6 +1044,10 @@ class CephExporter(object): 'ceph-exporter': DEFAULT_PORT, } + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + return cls.daemon_type == daemon_type + def __init__(self, ctx: CephadmContext, fsid: str, daemon_id: Union[int, str], @@ -974,6 +1074,14 @@ class CephExporter(object): return cls(ctx, fsid, daemon_id, fetch_configs(ctx), ctx.image) + @classmethod + def create(cls, ctx: CephadmContext, ident: DaemonIdentity) -> 'CephExporter': + return cls.init(ctx, ident.fsid, ident.daemon_id) + + @property + def identity(self) -> DaemonIdentity: + return DaemonIdentity(self.fsid, self.daemon_type, self.daemon_id) + @staticmethod def get_container_mounts() -> Dict[str, str]: mounts = dict() @@ -998,12 +1106,17 @@ class CephExporter(object): ################################## -class HAproxy(object): +@register_daemon_form +class HAproxy(DaemonForm): """Defines an HAproxy container""" daemon_type = 'haproxy' required_files = ['haproxy.cfg'] default_image = DEFAULT_HAPROXY_IMAGE + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + return cls.daemon_type == daemon_type + def __init__(self, ctx: CephadmContext, fsid: str, daemon_id: Union[int, str], @@ -1024,6 +1137,14 @@ class HAproxy(object): return cls(ctx, fsid, daemon_id, fetch_configs(ctx), ctx.image) + @classmethod + def create(cls, ctx: CephadmContext, ident: DaemonIdentity) -> 'HAproxy': + return cls.init(ctx, ident.fsid, ident.daemon_id) + + @property + def identity(self) -> DaemonIdentity: + return DaemonIdentity(self.fsid, self.daemon_type, self.daemon_id) + 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): @@ -1086,12 +1207,17 @@ class HAproxy(object): ################################## -class Keepalived(object): +@register_daemon_form +class Keepalived(DaemonForm): """Defines an Keepalived container""" daemon_type = 'keepalived' required_files = ['keepalived.conf'] default_image = DEFAULT_KEEPALIVED_IMAGE + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + return cls.daemon_type == daemon_type + def __init__(self, ctx: CephadmContext, fsid: str, daemon_id: Union[int, str], @@ -1112,6 +1238,14 @@ class Keepalived(object): return cls(ctx, fsid, daemon_id, fetch_configs(ctx), ctx.image) + @classmethod + def create(cls, ctx: CephadmContext, ident: DaemonIdentity) -> 'Keepalived': + return cls.init(ctx, ident.fsid, ident.daemon_id) + + @property + def identity(self) -> DaemonIdentity: + return DaemonIdentity(self.fsid, self.daemon_type, self.daemon_id) + 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): @@ -1182,7 +1316,8 @@ class Keepalived(object): ################################## -class Tracing(object): +@register_daemon_form +class Tracing(DaemonForm): """Define the configs for the jaeger tracing containers""" components: Dict[str, Dict[str, Any]] = { @@ -1201,6 +1336,10 @@ class Tracing(object): }, } # type: ignore + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + return daemon_type in cls.components + @staticmethod def set_configuration(config: Dict[str, str], daemon_type: str) -> None: if daemon_type in ['jaeger-collector', 'jaeger-query']: @@ -1215,13 +1354,29 @@ class Tracing(object): '--processor.jaeger-compact.server-host-port=6799' ] + def __init__(self, ident: DaemonIdentity) -> None: + self._identity = ident + + @classmethod + def create(cls, ctx: CephadmContext, ident: DaemonIdentity) -> 'Tracing': + return cls(ident) + + @property + def identity(self) -> DaemonIdentity: + return self._identity + ################################## -class CustomContainer(object): +@register_daemon_form +class CustomContainer(DaemonForm): """Defines a custom container""" daemon_type = 'container' + @classmethod + def for_daemon_type(cls, daemon_type: str) -> bool: + return cls.daemon_type == daemon_type + def __init__(self, fsid: str, daemon_id: Union[int, str], config_json: Dict, image: str) -> None: @@ -1248,6 +1403,14 @@ class CustomContainer(object): return cls(fsid, daemon_id, fetch_configs(ctx), ctx.image) + @classmethod + def create(cls, ctx: CephadmContext, ident: DaemonIdentity) -> 'CustomContainer': + return cls.init(ctx, ident.fsid, ident.daemon_id) + + @property + def identity(self) -> DaemonIdentity: + return DaemonIdentity(self.fsid, self.daemon_type, self.daemon_id) + def create_daemon_dirs(self, data_dir: str, uid: int, gid: int) -> None: """ Create dirs/files below the container data directory. -- 2.39.5