]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
cephadm: support --infer-name option for lazy devs
authorJohn Mulligan <jmulligan@redhat.com>
Tue, 8 Apr 2025 23:06:45 +0000 (19:06 -0400)
committerAdam King <adking@redhat.com>
Sat, 21 Jun 2025 18:08:13 +0000 (14:08 -0400)
Add an --infer-name/-i option to the cephadm enter command. This new
option is a spin on --name/-n but allows the value to be partial.
The first part of the value must be a service type (like `mgr`, `mds`,
`nfs`, etc). That can then be followed optionally by a dot (.) and
a part (or whole) of an id. For example:

Enter the one and only mgr container running on this host:
```
cephadm enter -i mgr
```

Enter a (primary) smb container running on this host belonging to
the virtual cluster "cluster1", without specifying random chars or
rank values:
```
cephadm enter -i smb.cluster1
```

If the partial name does not match any services on the host or it
matches more than 1 service on the host it will return an error.
In the case of >1 service you can then supply more characters in
the partial id to narrow down the match. For example:
```
cephadm enter -i osd
Inferring fsid bf7116b2-2b9d-11f0-bb35-525400220000
ERROR: too many daemons match 'osd' (osd.2, osd.5)

/tmp/cephadm enter -i osd.2
Inferring fsid bf7116b2-2b9d-11f0-bb35-525400220000
Inferring daemon osd.2
[ceph: root@ceph0 /]#
```

Signed-off-by: John Mulligan <jmulligan@redhat.com>
(cherry picked from commit 211e677f1d42ea3de76981128b18f1c914841d27)

src/cephadm/cephadm.py
src/cephadm/cephadmlib/container_lookup.py

index ac5ab21e3a4af8626871963138f65398092a0ed5..7a332c2ac812cb081e124d9816ae84dc19779028 100755 (executable)
@@ -188,9 +188,9 @@ from cephadmlib.daemons import (
 )
 from cephadmlib.agent import http_query
 from cephadmlib.listing import (
+    CombinedStatusUpdater,
     DaemonStatusUpdater,
     NoOpDaemonStatusUpdater,
-    CombinedStatusUpdater,
     daemons_matching,
     daemons_summary,
 )
@@ -201,7 +201,7 @@ from cephadmlib.listing_updaters import (
     MemUsageStatusUpdater,
     VersionStatusUpdater,
 )
-from cephadmlib.container_lookup import infer_local_ceph_image
+from cephadmlib.container_lookup import infer_local_ceph_image, identify
 
 
 FuncT = TypeVar('FuncT', bound=Callable)
@@ -3151,12 +3151,9 @@ def command_shell(ctx):
 
 
 @infer_fsid
-def command_enter(ctx):
-    # type: (CephadmContext) -> int
-    if not ctx.fsid:
-        raise Error('must pass --fsid to specify cluster')
-    (daemon_type, daemon_id) = ctx.name.split('.', 1)
-    container_args = ['-i']  # type: List[str]
+def command_enter(ctx: CephadmContext) -> int:
+    ident = identify(ctx)
+    container_args = ['-i']
     if ctx.command:
         command = ctx.command
     else:
@@ -3168,10 +3165,10 @@ def command_enter(ctx):
         ]
     c = CephContainer(
         ctx,
+        identity=ident,
         image=ctx.image,
         entrypoint='doesnotmatter',
         container_args=container_args,
-        cname='ceph-%s-%s.%s' % (ctx.fsid, daemon_type, daemon_id),
     )
     command = c.exec_cmd(command)
     return call_timeout(ctx, command, ctx.timeout)
@@ -4767,10 +4764,13 @@ def _get_parser():
     parser_enter.add_argument(
         '--fsid',
         help='cluster FSID')
-    parser_enter.add_argument(
+    parser_enter_ng = parser_enter.add_mutually_exclusive_group(required=True)
+    parser_enter_ng.add_argument(
         '--name', '-n',
-        required=True,
         help='daemon name (type.id)')
+    parser_enter_ng.add_argument(
+        '--infer-name', '-i',
+        help='daemon name search (type[.partial_id])')
     parser_enter.add_argument(
         'command', nargs=argparse.REMAINDER,
         help='command')
index 3d44b57d8d4af9e01201808c4da99ce0f6920bb4..1d1d96d6ac8f87b31b43a1bb382ebc81e0f6fc66 100644 (file)
@@ -3,6 +3,7 @@
 from operator import itemgetter
 from typing import Optional, Tuple
 
+import fnmatch
 import logging
 
 from .container_engines import (
@@ -15,7 +16,8 @@ from .container_types import get_container_stats
 from .context import CephadmContext
 from .daemon_identity import DaemonIdentity
 from .daemons.ceph import ceph_daemons
-from .listing import daemons_matching
+from .exceptions import Error
+from .listing import LegacyDaemonEntry, daemons_matching
 from .listing_updaters import CoreStatusUpdater
 
 
@@ -174,3 +176,56 @@ def infer_local_ceph_image(
             reason,
         )
     return best_image.name
+
+
+def infer_daemon_identity(
+    ctx: CephadmContext, partial_name: str
+) -> DaemonIdentity:
+    """Given a partial daemon/service name, infer the identity of the
+    daemon.
+    """
+
+    if not partial_name:
+        raise Error('a daemon type is required to infer a service name')
+    if '.' in partial_name:
+        _type, _name = partial_name.split('.', 1)
+    else:
+        _type, _name = partial_name, ''
+    # allow searching for a name with just the beginning without having
+    # to expliclity supply a trailing asterisk
+    _name += '*'
+    matches = []
+    for d in daemons_matching(ctx, fsid=ctx.fsid, daemon_type=_type):
+        if isinstance(d, LegacyDaemonEntry):
+            logger.info('Ignoring legacy daemon %s', d.name)
+            continue  # ignore legacy daemons
+        if fnmatch.fnmatch(d.identity.daemon_id, _name):
+            matches.append(d)
+
+    if not matches:
+        raise Error(f'no daemons match {partial_name!r}')
+    if len(matches) > 1:
+        excess = ', '.join(d.identity.daemon_name for d in matches)
+        raise Error(f'too many daemons match {partial_name!r} ({excess})')
+    ident = matches[0].identity
+    logger.info('Inferring daemon %s', ident.daemon_name)
+    return ident
+
+
+def identify(ctx: CephadmContext) -> DaemonIdentity:
+    """Given a context try and determine a specific daemon identity to use
+    based on the --name CLI option (exact) or --infer-name (partial match)
+    option.
+    """
+    if not ctx.fsid:
+        raise Error('must pass --fsid to specify cluster')
+    name = getattr(ctx, 'name', '')
+    if name:
+        return DaemonIdentity.from_name(ctx.fsid, name)
+    iname = getattr(ctx, 'infer_name', '')
+    if iname:
+        return infer_daemon_identity(ctx, iname)
+    raise Error(
+        'must specify a daemon name'
+        ' (use --name/-n or --infer-name/-i for example)'
+    )