Skip to content

Commit bf2fa60

Browse files
authored
Merge pull request ceph#63247 from phlogistonjohn/jjm-cephadm-guess-name
cephadm: minor ergonomic improvements for hackers Reviewed-by: Adam King <[email protected]>
2 parents 6fc8894 + eb0519b commit bf2fa60

File tree

2 files changed

+113
-46
lines changed

2 files changed

+113
-46
lines changed

src/cephadm/cephadm.py

Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,9 @@
188188
)
189189
from cephadmlib.agent import http_query
190190
from cephadmlib.listing import (
191+
CombinedStatusUpdater,
191192
DaemonStatusUpdater,
192193
NoOpDaemonStatusUpdater,
193-
CombinedStatusUpdater,
194194
daemons_matching,
195195
daemons_summary,
196196
)
@@ -201,7 +201,7 @@
201201
MemUsageStatusUpdater,
202202
VersionStatusUpdater,
203203
)
204-
from cephadmlib.container_lookup import infer_local_ceph_image
204+
from cephadmlib.container_lookup import infer_local_ceph_image, identify
205205

206206

207207
FuncT = TypeVar('FuncT', bound=Callable)
@@ -3151,12 +3151,9 @@ def command_shell(ctx):
31513151

31523152

31533153
@infer_fsid
3154-
def command_enter(ctx):
3155-
# type: (CephadmContext) -> int
3156-
if not ctx.fsid:
3157-
raise Error('must pass --fsid to specify cluster')
3158-
(daemon_type, daemon_id) = ctx.name.split('.', 1)
3159-
container_args = ['-i'] # type: List[str]
3154+
def command_enter(ctx: CephadmContext) -> int:
3155+
ident = identify(ctx)
3156+
container_args = ['-i']
31603157
if ctx.command:
31613158
command = ctx.command
31623159
else:
@@ -3168,12 +3165,15 @@ def command_enter(ctx):
31683165
]
31693166
c = CephContainer(
31703167
ctx,
3168+
identity=ident,
31713169
image=ctx.image,
31723170
entrypoint='doesnotmatter',
31733171
container_args=container_args,
3174-
cname='ceph-%s-%s.%s' % (ctx.fsid, daemon_type, daemon_id),
31753172
)
31763173
command = c.exec_cmd(command)
3174+
if ctx.dry_run:
3175+
print(' '.join(shlex.quote(arg) for arg in command))
3176+
return 0
31773177
return call_timeout(ctx, command, ctx.timeout)
31783178

31793179
##################################
@@ -3228,50 +3228,48 @@ def command_ceph_volume(ctx):
32283228

32293229

32303230
@infer_fsid
3231-
def command_unit_install(ctx):
3232-
# type: (CephadmContext) -> int
3233-
if not getattr(ctx, 'fsid', None):
3234-
raise Error('must pass --fsid to specify cluster')
3235-
if not getattr(ctx, 'name', None):
3236-
raise Error('daemon name required')
3237-
ident = DaemonIdentity.from_context(ctx)
3231+
def command_unit_install(ctx: CephadmContext) -> int:
3232+
ident = identify(ctx)
32383233
systemd_unit.update_files(ctx, ident)
32393234
call_throws(ctx, ['systemctl', 'daemon-reload'])
32403235
return 0
32413236

32423237

32433238
@infer_fsid
3244-
def command_unit(ctx):
3245-
# type: (CephadmContext) -> int
3246-
if not ctx.fsid:
3247-
raise Error('must pass --fsid to specify cluster')
3248-
3249-
unit_name = lookup_unit_name_by_daemon_name(ctx, ctx.fsid, ctx.name)
3250-
3239+
def command_unit(ctx: CephadmContext) -> int:
3240+
ident = identify(ctx)
3241+
unit_name = lookup_unit_name_by_daemon_name(
3242+
ctx, ident.fsid, ident.daemon_name
3243+
)
3244+
command = ['systemctl', ctx.command, unit_name]
3245+
if ctx.dry_run:
3246+
print(' '.join(shlex.quote(arg) for arg in command))
3247+
return 0
32513248
_, _, code = call(
32523249
ctx,
3253-
['systemctl', ctx.command, unit_name],
3250+
command,
32543251
verbosity=CallVerbosity.VERBOSE,
3255-
desc=''
3252+
desc='',
32563253
)
32573254
return code
32583255

32593256
##################################
32603257

32613258

32623259
@infer_fsid
3263-
def command_logs(ctx):
3264-
# type: (CephadmContext) -> None
3265-
if not ctx.fsid:
3266-
raise Error('must pass --fsid to specify cluster')
3267-
3268-
unit_name = lookup_unit_name_by_daemon_name(ctx, ctx.fsid, ctx.name)
3269-
3260+
def command_logs(ctx: CephadmContext) -> None:
3261+
ident = identify(ctx)
3262+
unit_name = lookup_unit_name_by_daemon_name(
3263+
ctx, ident.fsid, ident.daemon_name
3264+
)
32703265
cmd = [find_program('journalctl')]
32713266
cmd.extend(['-u', unit_name])
32723267
if ctx.command:
32733268
cmd.extend(ctx.command)
32743269

3270+
if ctx.dry_run:
3271+
print(' '.join(shlex.quote(arg) for arg in cmd))
3272+
return
32753273
# call this directly, without our wrapper, so that we get an unmolested
32763274
# stdout with logger prefixing.
32773275
logger.debug('Running command: %s' % ' '.join(cmd))
@@ -4499,6 +4497,20 @@ def _add_deploy_parser_args(
44994497
)
45004498

45014499

4500+
def _name_opts(parser: argparse.ArgumentParser) -> None:
4501+
ng = parser.add_mutually_exclusive_group(required=True)
4502+
ng.add_argument(
4503+
'--name',
4504+
'-n',
4505+
help='daemon name (type.id)',
4506+
)
4507+
ng.add_argument(
4508+
'--infer-name',
4509+
'-i',
4510+
help='daemon name search (type[.partial_id])',
4511+
)
4512+
4513+
45024514
def _get_parser():
45034515
# type: () -> argparse.ArgumentParser
45044516
parser = argparse.ArgumentParser(
@@ -4767,10 +4779,11 @@ def _get_parser():
47674779
parser_enter.add_argument(
47684780
'--fsid',
47694781
help='cluster FSID')
4782+
_name_opts(parser_enter)
47704783
parser_enter.add_argument(
4771-
'--name', '-n',
4772-
required=True,
4773-
help='daemon name (type.id)')
4784+
'--dry-run',
4785+
action='store_true',
4786+
help='print, but do not execute, the command to enter the container')
47744787
parser_enter.add_argument(
47754788
'command', nargs=argparse.REMAINDER,
47764789
help='command')
@@ -4820,31 +4833,30 @@ def _get_parser():
48204833
'--fsid',
48214834
help='cluster FSID')
48224835
parser_unit.add_argument(
4823-
'--name', '-n',
4824-
required=True,
4825-
help='daemon name (type.id)')
4836+
'--dry-run',
4837+
action='store_true',
4838+
help='print, but do not execute, the unit command')
4839+
_name_opts(parser_unit)
48264840

48274841
parser_unit_install = subparsers.add_parser(
48284842
'unit-install', help="Install the daemon's systemd unit")
48294843
parser_unit_install.set_defaults(func=command_unit_install)
48304844
parser_unit_install.add_argument(
48314845
'--fsid',
48324846
help='cluster FSID')
4833-
parser_unit_install.add_argument(
4834-
'--name', '-n',
4835-
required=True,
4836-
help='daemon name (type.id)')
4847+
_name_opts(parser_unit_install)
48374848

48384849
parser_logs = subparsers.add_parser(
48394850
'logs', help='print journald logs for a daemon container')
48404851
parser_logs.set_defaults(func=command_logs)
48414852
parser_logs.add_argument(
48424853
'--fsid',
48434854
help='cluster FSID')
4855+
_name_opts(parser_logs)
48444856
parser_logs.add_argument(
4845-
'--name', '-n',
4846-
required=True,
4847-
help='daemon name (type.id)')
4857+
'--dry-run',
4858+
action='store_true',
4859+
help='print, but do not execute, the command to show the logs')
48484860
parser_logs.add_argument(
48494861
'command', nargs='*',
48504862
help='additional journalctl args')

src/cephadm/cephadmlib/container_lookup.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from operator import itemgetter
44
from typing import Optional, Tuple
55

6+
import fnmatch
67
import logging
78

89
from .container_engines import (
@@ -15,7 +16,8 @@
1516
from .context import CephadmContext
1617
from .daemon_identity import DaemonIdentity
1718
from .daemons.ceph import ceph_daemons
18-
from .listing import daemons_matching
19+
from .exceptions import Error
20+
from .listing import LegacyDaemonEntry, daemons_matching
1921
from .listing_updaters import CoreStatusUpdater
2022

2123

@@ -176,3 +178,56 @@ def _keyfunc(image: ImageInfo) -> Tuple[bool, bool, str]:
176178
reason,
177179
)
178180
return best_image.name
181+
182+
183+
def infer_daemon_identity(
184+
ctx: CephadmContext, partial_name: str
185+
) -> DaemonIdentity:
186+
"""Given a partial daemon/service name, infer the identity of the
187+
daemon.
188+
"""
189+
190+
if not partial_name:
191+
raise Error('a daemon type is required to infer a service name')
192+
if '.' in partial_name:
193+
_type, _name = partial_name.split('.', 1)
194+
else:
195+
_type, _name = partial_name, ''
196+
# allow searching for a name with just the beginning without having
197+
# to expliclity supply a trailing asterisk
198+
_name += '*'
199+
matches = []
200+
for d in daemons_matching(ctx, fsid=ctx.fsid, daemon_type=_type):
201+
if isinstance(d, LegacyDaemonEntry):
202+
logger.info('Ignoring legacy daemon %s', d.name)
203+
continue # ignore legacy daemons
204+
if fnmatch.fnmatch(d.identity.daemon_id, _name):
205+
matches.append(d)
206+
207+
if not matches:
208+
raise Error(f'no daemons match {partial_name!r}')
209+
if len(matches) > 1:
210+
excess = ', '.join(d.identity.daemon_name for d in matches)
211+
raise Error(f'too many daemons match {partial_name!r} ({excess})')
212+
ident = matches[0].identity
213+
logger.info('Inferring daemon %s', ident.daemon_name)
214+
return ident
215+
216+
217+
def identify(ctx: CephadmContext) -> DaemonIdentity:
218+
"""Given a context try and determine a specific daemon identity to use
219+
based on the --name CLI option (exact) or --infer-name (partial match)
220+
option.
221+
"""
222+
if not ctx.fsid:
223+
raise Error('must pass --fsid to specify cluster')
224+
name = getattr(ctx, 'name', '')
225+
if name:
226+
return DaemonIdentity.from_name(ctx.fsid, name)
227+
iname = getattr(ctx, 'infer_name', '')
228+
if iname:
229+
return infer_daemon_identity(ctx, iname)
230+
raise Error(
231+
'must specify a daemon name'
232+
' (use --name/-n or --infer-name/-i for example)'
233+
)

0 commit comments

Comments
 (0)