# listing.py - listings and status of current daemons
+#
+# listing.py is the result of a refactor of the previous mega-function list_daemons.
+# It attempts to break the operation of listing daemons and getting information about
+# those daemons into the following parts:
+#
+# Functions daemons and daemons_matching iterate the configuration tree
+# used by ceph and yields entry objects that represent either a standard
+# daemon or a legacy daemon.
+#
+# Function daemons_summary is a convenient function that return a list
+# containing the status field of entries from daemons_matching. It is designed
+# to be a drop in replacement for `list_daemons` called with the `detail=False`
+# argument.
+#
+# To provide an equivalent to the detail gathering portion of list_daemons the
+# DaemonStatusUpdater base class and subclasses are designed to be a
+# well-defined but flexible mechanism to gather additional data for each entry
+# type and update the contents of the associated status dict. The
+# DaemonStatusUpdater class is designed to support caching. The caching can be
+# set up when an updater is initialized or on the fly, being used or refreshed
+# when an update method is called. The update and legacy_update functions are
+# to be provided by sub-classes that to mutate an existing status dictionary.
+#
+# The DaemonStatusUpdater expand method is designed to be used in an iterator
+# or list comprehension in order to process the entries yielded by the listing
+# methods mentioned above. This is intended to allow callers to list daemons
+# with the level of detail needed rather than being forced to rely on a too-simple
+# iterator and gather extra details in an ad-hoc way or get too much info than
+# needed and incur extra costs getting that unwanted data.
+#
+# The CombinedStatusUpdater class exists so that multiple updaters can be
+# easily combined. The init method of the class takes a list of other
+# DaemonStatusUpdater classes and calls them (in order) to update the status
+# dict.
+#
+# Use the CombinedStatusUpdater and a list of desired updaters to list/iterate
+# with the level of detail your function needs. For example:
+# >>> updater = CombinedStatusUpdater([
+# ... CoreStatusUpdater(),
+# ... PowerLevelUpdater(),
+# ... MyCoolCustomUpdater(),
+# ... ])
+# >>> result = [updater.expand(ctx, entry) for entry in daemons(ctx)]
+#
+# These six lines let you flexibly perform the equivalent of list_daemons
+# with a more precice level of detail needed by the caller.
+
import os
import logging
-from typing import TypedDict, Union, Optional, Iterator, List
+from typing import TypedDict, Union, Optional, Iterator, List, Any, Dict, cast
from .context import CephadmContext
from .daemon_identity import DaemonIdentity
daemon_type=daemon_type,
)
]
+
+
+class DaemonStatusUpdater:
+ """Base class for types that can update and/or expand the daemon information
+ provided by the core listing functions in this module.
+ """
+
+ def update(
+ self,
+ val: Dict[str, Any],
+ ctx: CephadmContext,
+ identity: DaemonIdentity,
+ data_dir: str,
+ ) -> None:
+ """Update the val dict with new status information for the daemon with
+ the given identity and configuration dir.
+ """
+ pass
+
+ def legacy_update(
+ self,
+ val: Dict[str, Any],
+ ctx: CephadmContext,
+ fsid: str,
+ daemon_type: str,
+ name: str,
+ data_dir: str,
+ ) -> None:
+ """Update the val dict with new status information for a legacy daemon
+ described by the given parameters and configuration dir.
+ """
+ pass
+
+ def expand(
+ self,
+ ctx: CephadmContext,
+ entry: Union[LegacyDaemonEntry, DaemonEntry],
+ ) -> Dict[str, Any]:
+ """Return a status dictionary based on the entry object and its status
+ attribute expanded with additional information.
+ """
+ if isinstance(entry, LegacyDaemonEntry):
+ status = cast(Dict[str, Any], entry.status)
+ self.legacy_update(
+ status,
+ ctx,
+ entry.fsid,
+ entry.daemon_type,
+ entry.name,
+ entry.data_dir,
+ )
+ return status
+ status = cast(Dict[str, Any], entry.status)
+ self.update(status, ctx, entry.identity, entry.data_dir)
+ return status
+
+
+class NoOpDaemonStatusUpdater(DaemonStatusUpdater):
+ """A daemon status updater that adds no new information to the status
+ dictionary.
+ """
+
+ pass
+
+
+class CombinedStatusUpdater(DaemonStatusUpdater):
+ """A status updater that combines multiple status updaters together."""
+
+ def __init__(self, updaters: List[DaemonStatusUpdater]):
+ self.updaters = updaters
+
+ def update(
+ self,
+ val: Dict[str, Any],
+ ctx: CephadmContext,
+ identity: DaemonIdentity,
+ data_dir: str,
+ ) -> None:
+ for updater in self.updaters:
+ updater.update(val, ctx, identity, data_dir)
+
+ def legacy_update(
+ self,
+ val: Dict[str, Any],
+ ctx: CephadmContext,
+ fsid: str,
+ daemon_type: str,
+ name: str,
+ data_dir: str,
+ ) -> None:
+ for updater in self.updaters:
+ updater.legacy_update(val, ctx, fsid, daemon_type, name, data_dir)