# systemd_unit.py - creating/managing systemd unit files
+import contextlib
import os
+import pathlib
+
+from typing import IO, List, Optional, Union
from . import templating
from .call_wrappers import call_throws
from .container_engines import Docker, Podman
from .context import CephadmContext
-from .daemon_identity import DaemonIdentity
+from .daemon_identity import DaemonIdentity, DaemonSubIdentity
from .file_utils import write_new
from .logging import write_cluster_logrotate_config
+_DROP_IN_FILENAME = '99-cephadm.conf'
+
+
+class PathInfo:
+ """Utility class to map basic service identities, to the paths used by
+ their corresponding systemd unit files.
+ """
+
+ def __init__(
+ self,
+ unit_dir: Union[str, pathlib.Path],
+ identity: DaemonIdentity,
+ sidecar_ids: Optional[List[DaemonSubIdentity]] = None,
+ ) -> None:
+ self.identity = identity
+ self.sidecar_ids = sidecar_ids or []
+
+ unit_dir = pathlib.Path(unit_dir)
+ self.default_unit_file = unit_dir / f'ceph-{identity.fsid}@.service'
+ self.init_ctr_unit_file = unit_dir / identity.init_service_name
+ self.sidecar_unit_files = {
+ si: unit_dir / si.sidecar_service_name for si in self.sidecar_ids
+ }
+ dname = f'{identity.service_name}.d'
+ self.drop_in_file = unit_dir / dname / _DROP_IN_FILENAME
+
+
+def _write_drop_in(
+ dest: IO,
+ ctx: CephadmContext,
+ identity: DaemonIdentity,
+ enable_init_containers: bool,
+ sidecar_ids: List[DaemonSubIdentity],
+) -> None:
+ templating.render_to_file(
+ dest,
+ ctx,
+ templating.Templates.dropin_service,
+ identity=identity,
+ enable_init_containers=enable_init_containers,
+ sidecar_ids=sidecar_ids,
+ )
+
+
+def _write_init_containers_unit_file(
+ dest: IO, ctx: CephadmContext, identity: DaemonIdentity
+) -> None:
+ has_docker_engine = isinstance(ctx.container_engine, Docker)
+ has_podman_engine = isinstance(ctx.container_engine, Podman)
+ templating.render_to_file(
+ dest,
+ ctx,
+ templating.Templates.init_ctr_service,
+ identity=identity,
+ has_docker_engine=has_docker_engine,
+ has_podman_engine=has_podman_engine,
+ has_podman_split_version=(
+ has_podman_engine and ctx.container_engine.supports_split_cgroups
+ ),
+ )
+
+
+def _write_sidecar_unit_file(
+ dest: IO, ctx: CephadmContext, primary: DaemonIdentity, sidecar: DaemonSubIdentity
+) -> None:
+ has_docker_engine = isinstance(ctx.container_engine, Docker)
+ has_podman_engine = isinstance(ctx.container_engine, Podman)
+ templating.render_to_file(
+ dest,
+ ctx,
+ templating.Templates.sidecar_service,
+ primary=primary,
+ sidecar=sidecar,
+ sidecar_script=sidecar.sidecar_script(ctx.data_dir),
+ has_docker_engine=has_docker_engine,
+ has_podman_engine=has_podman_engine,
+ has_podman_split_version=(
+ has_podman_engine and ctx.container_engine.supports_split_cgroups
+ ),
+ )
+
+
+def _install_extended_systemd_services(
+ ctx: CephadmContext,
+ pinfo: PathInfo,
+ identity: DaemonIdentity,
+ enable_init_containers: bool = False,
+) -> None:
+ """Install the systemd unit files needed for more complex services
+ that have init containers and/or sidecars.
+ """
+ with contextlib.ExitStack() as estack:
+ # install the unit file to handle running init containers
+ if enable_init_containers:
+ icfh = estack.enter_context(
+ write_new(pinfo.init_ctr_unit_file, perms=None)
+ )
+ _write_init_containers_unit_file(icfh, ctx, identity)
+
+ # install the unit files to handle running sidecars
+ sids = []
+ for si, sup in pinfo.sidecar_unit_files.items():
+ sufh = estack.enter_context(write_new(sup, perms=None))
+ _write_sidecar_unit_file(sufh, ctx, identity, si)
+ sids.append(si)
+
+ # create a drop-in to create a relationship between the primary
+ # service and the init- and sidecar-based services.
+ if enable_init_containers or sids:
+ pinfo.drop_in_file.parent.mkdir(parents=True, exist_ok=True)
+ difh = estack.enter_context(
+ write_new(pinfo.drop_in_file, perms=None)
+ )
+ _write_drop_in(
+ difh, ctx, identity, enable_init_containers, sids
+ )
+
+
def _get_unit_file(ctx: CephadmContext, fsid: str) -> str:
has_docker_engine = isinstance(ctx.container_engine, Docker)
has_podman_engine = isinstance(ctx.container_engine, Podman)
write_cluster_logrotate_config(ctx, fsid)
-def update_files(ctx: CephadmContext, ident: DaemonIdentity) -> None:
+def update_files(
+ ctx: CephadmContext,
+ ident: DaemonIdentity,
+ *,
+ init_container_ids: Optional[List[DaemonSubIdentity]] = None,
+ sidecar_ids: Optional[List[DaemonSubIdentity]] = None,
+) -> None:
_install_base_units(ctx, ident.fsid)
unit = _get_unit_file(ctx, ident.fsid)
- unit_file = 'ceph-%s@.service' % (ident.fsid)
- with write_new(ctx.unit_dir + '/' + unit_file, perms=None) as f:
+ pathinfo = PathInfo(ctx.unit_dir, ident, sidecar_ids=sidecar_ids)
+ with write_new(pathinfo.default_unit_file, perms=None) as f:
f.write(unit)
+ _install_extended_systemd_services(
+ ctx, pathinfo, ident, bool(init_container_ids)
+ )