Foundation. See file COPYING.
"""
-from __future__ import print_function
from time import sleep
-import codecs
import grp
import os
import pwd
+import re
+import shutil
+import stat
import sys
import time
import platform
+from typing import Dict, List, Sequence, Tuple
+
try:
input = raw_input
except NameError:
DEVMODEMSG = '*** DEVELOPER MODE: setting PATH, PYTHONPATH and LD_LIBRARY_PATH ***'
-def respawn_in_path(lib_path, pybind_path, pythonlib_path, asan_lib_path):
- execv_cmd = []
- if 'CEPH_DBG' in os.environ:
- execv_cmd += ['@Python3_EXECUTABLE@', '-mpdb']
+def add_to_ld_path(path_name, path):
+ paths = re.split('[ :]', os.environ.get(path_name, ''))
+ if path in paths:
+ return 0
+ else:
+ paths.insert(0, path)
+ os.environ[path_name] = ':'.join(paths)
+ return 1
+
+def respawn_in_path(lib_path, pybind_path, pythonlib_path, asan_lib_path):
if platform.system() == "Darwin":
lib_path_var = "DYLD_LIBRARY_PATH"
else:
lib_path_var = "LD_LIBRARY_PATH"
- execv_cmd += sys.argv
+ ld_paths_changed = 0
+ preload_libcxx = os.environ.get('CEPH_PRELOAD_LIBCXX')
+ if preload_libcxx:
+ ld_paths_changed += add_to_ld_path('LD_PRELOAD', preload_libcxx)
if asan_lib_path:
- os.environ['LD_PRELOAD'] = asan_lib_path
- if lib_path_var in os.environ:
- if lib_path not in os.environ[lib_path_var]:
- os.environ[lib_path_var] += ':' + lib_path
- if "CEPH_DEV" not in os.environ:
- print(DEVMODEMSG, file=sys.stderr)
- os.execvp(execv_cmd[0], execv_cmd)
- else:
- os.environ[lib_path_var] = lib_path
+ ld_paths_changed += add_to_ld_path('LD_PRELOAD', asan_lib_path)
+ ld_paths_changed += add_to_ld_path(lib_path_var, lib_path)
+ if ld_paths_changed > 0:
if "CEPH_DEV" not in os.environ:
print(DEVMODEMSG, file=sys.stderr)
+ execv_cmd = []
+ if 'CEPH_DBG' in os.environ:
+ execv_cmd += ['@Python3_EXECUTABLE@', '-mpdb']
+ execv_cmd += sys.argv
os.execvp(execv_cmd[0], execv_cmd)
- sys.path.insert(0, os.path.join(MYDIR, pybind_path))
- sys.path.insert(0, os.path.join(MYDIR, pythonlib_path))
+ else:
+ sys.path.insert(0, pybind_path)
+ sys.path.insert(0, pythonlib_path)
def get_pythonlib_dir():
verbose = False
cluster_handle = None
-# Always use Unicode (UTF-8) for stdout
-if sys.version_info[0] >= 3:
- raw_stdout = sys.stdout.buffer
- raw_stderr = sys.stderr.buffer
-else:
- raw_stdout = sys.__stdout__
- raw_stderr = sys.__stderr__
- sys.stdout = codecs.getwriter('utf-8')(raw_stdout)
- sys.stderr = codecs.getwriter('utf-8')(raw_stderr)
-
def raw_write(buf):
sys.stdout.flush()
- raw_stdout.write(rados.cstr(buf, ''))
+ sys.stdout.buffer.write(buf)
def osdids():
}
-def parse_cmdargs(args=None, target=''):
+def parse_cmdargs(args=None, target='') -> Tuple[argparse.ArgumentParser,
+ argparse.Namespace,
+ List[str]]:
"""
Consume generic arguments from the start of the ``args``
list. Call this first to handle arguments that are not
parser.add_argument('--cluster', help='cluster name')
parser.add_argument('--admin-daemon', dest='admin_socket',
- help='submit admin-socket commands (\"help\" for help')
+ help='submit admin-socket commands (\"help\" for help)')
parser.add_argument('-s', '--status', action='store_true',
help='show cluster status')
""", file=sys.stdout)
-def do_extended_help(parser, args, target, partial):
+def do_extended_help(parser, args, target, partial) -> int:
def help_for_sigs(sigs, partial=None):
- sys.stdout.write(format_help(parse_json_funcsigs(sigs, 'cli'),
- partial=partial))
+ try:
+ while True:
+ out = format_help(parse_json_funcsigs(sigs, 'cli'),
+ partial=partial)
+ if not out and partial:
+ # shorten partial until we get at least one matching command prefix
+ partial = ' '.join(partial.split()[:-1])
+ continue
+ sys.stdout.write(out)
+ break
+ except BrokenPipeError:
+ pass
def help_for_target(target, partial=None):
# wait for osdmap because we know this is sent after the mgrmap
yield result
-def format_help(cmddict, partial=None):
+def format_help(cmddict, partial=None) -> str:
"""
Formats all the cmdsigs and helptexts from cmddict into a sorted-by-
cmdsig 2-column display, with each column wrapped and indented to
return fullusage
-def ceph_conf(parsed_args, field, name):
- args = ['ceph-conf']
+def ceph_conf(parsed_args, field, name, pid=None):
+ cmd = 'ceph-conf'
+ bindir = os.path.dirname(__file__)
+ if shutil.which(cmd):
+ args = [cmd]
+ elif shutil.which(cmd, path=bindir):
+ args = [os.path.join(bindir, cmd)]
+ else:
+ raise RuntimeError('"ceph-conf" not found')
if name:
args.extend(['--name', name])
+ if pid:
+ args.extend(['--pid', pid])
# add any args in GLOBAL_ARGS
for key, val in GLOBAL_ARGS.items():
raise RuntimeError('unable to get conf option %s for %s: %s' % (field, name, errdata))
return outdata.rstrip()
+
PROMPT = 'ceph> '
if sys.stdin.isatty():
return ret, outbuf, outs
-def new_style_command(parsed_args, cmdargs, target, sigdict, inbuf, verbose):
+def new_style_command(parsed_args,
+ cmdargs,
+ target,
+ sigdict,
+ inbuf, verbose) -> Tuple[int, bytes, str]:
"""
Do new-style command dance.
target: daemon to receive command: mon (any) or osd.N
sig = cmd['sig']
print('{0}: {1}'.format(cmdtag, concise_sig(sig)))
- if True:
- if cmdargs:
- # Non interactive mode
- ret, outbuf, outs = do_command(parsed_args, target, cmdargs, sigdict, inbuf, verbose)
- else:
- # Interactive mode (ceph cli)
- if sys.stdin.isatty():
- # do the command-interpreter looping
- # for input to do readline cmd editing
- import readline # noqa
+ if cmdargs:
+ # Non interactive mode
+ ret, outbuf, outs = do_command(parsed_args, target, cmdargs, sigdict, inbuf, verbose)
+ else:
+ # Interactive mode (ceph cli)
+ if sys.stdin.isatty():
+ # do the command-interpreter looping
+ # for input to do readline cmd editing
+ import readline # noqa
- while True:
- try:
- interactive_input = read_input()
- except EOFError:
- # leave user an uncluttered prompt
- return 0, '\n', ''
- if interactive_input is None:
- return 0, '', ''
- cmdargs = parse_cmdargs(shlex.split(interactive_input))[2]
- try:
- target = find_cmd_target(cmdargs)
- except Exception as e:
- print('error handling command target: {0}'.format(e),
- file=sys.stderr)
- continue
- if len(cmdargs) and cmdargs[0] == 'tell':
- print('Can not use \'tell\' in interactive mode.',
- file=sys.stderr)
- continue
- ret, outbuf, outs = do_command(parsed_args, target, cmdargs,
- sigdict, inbuf, verbose)
- if ret < 0:
- ret = -ret
- errstr = errno.errorcode.get(ret, 'Unknown')
- print(u'Error {0}: {1}'.format(errstr, outs), file=sys.stderr)
- else:
- if outs:
- print(outs, file=sys.stderr)
- if outbuf:
- print(outbuf.decode('utf-8'))
+ while True:
+ try:
+ interactive_input = read_input()
+ except EOFError:
+ # leave user an uncluttered prompt
+ return 0, b'\n', ''
+ if interactive_input is None:
+ return 0, b'', ''
+ cmdargs = parse_cmdargs(shlex.split(interactive_input))[2]
+ try:
+ target = find_cmd_target(cmdargs)
+ except Exception as e:
+ print('error handling command target: {0}'.format(e),
+ file=sys.stderr)
+ continue
+ if len(cmdargs) and cmdargs[0] == 'tell':
+ print('Can not use \'tell\' in interactive mode.',
+ file=sys.stderr)
+ continue
+ ret, outbuf, outs = do_command(parsed_args, target, cmdargs,
+ sigdict, inbuf, verbose)
+ if ret < 0:
+ ret = -ret
+ errstr = errno.errorcode.get(ret, 'Unknown')
+ print('Error {0}: {1}'.format(errstr, outs), file=sys.stderr)
+ else:
+ if outs:
+ print(outs, file=sys.stderr)
+ if outbuf:
+ print(outbuf.decode('utf-8'))
return ret, outbuf, outs
return 0
+def get_admin_socket(parsed_args, name):
+ path = ceph_conf(parsed_args, 'admin_socket', name)
+ try:
+ if stat.S_ISSOCK(os.stat(path).st_mode):
+ return path
+ except OSError:
+ pass
+ # try harder, probably the "name" option is in the form of
+ # "${name}.${pid}"?
+ parts = name.rsplit('.', 1)
+ if len(parts) > 1 and parts[-1].isnumeric():
+ name, pid = parts
+ return ceph_conf(parsed_args, 'admin_socket', name, pid)
+ else:
+ return path
+
+
def maybe_daemon_command(parsed_args, childargs):
"""
Check if --admin-socket, daemon, or daemonperf command
else:
# try resolve daemon name
try:
- sockpath = ceph_conf(parsed_args, 'admin_socket',
- childargs[1])
+ sockpath = get_admin_socket(parsed_args, childargs[1])
except Exception as e:
print('Can\'t get admin socket path: ' + str(e), file=sys.stderr)
return True, errno.EINVAL
return False
-def daemonperf(childargs, sockpath):
+def daemonperf(childargs: Sequence[str], sockpath: str):
"""
Handle daemonperf command; returns errno or 0
return 0
-def get_scrub_timestamps(childargs):
+
+def get_scrub_timestamps(childargs: Sequence[str]) -> Dict[str,
+ Tuple[str, str]]:
last_scrub_stamp = "last_" + childargs[1].replace('-', '_') + "_stamp"
results = dict()
scruball = False
results[stat['pgid']] = scrub_tuple
return results
+
def check_scrub_stamps(waitdata, currdata):
for pg in waitdata.keys():
# Try to handle the case where a pg may not exist in current results
return False
return True
+
def waitscrub(childargs, waitdata):
- print(u'Waiting for {0} to complete...'.format(childargs[1]), file=sys.stdout)
+ print('Waiting for {0} to complete...'.format(childargs[1]), file=sys.stdout)
currdata = get_scrub_timestamps(childargs)
while not check_scrub_stamps(waitdata, currdata):
time.sleep(3)
currdata = get_scrub_timestamps(childargs)
- print(u'{0} completed'.format(childargs[1]), file=sys.stdout)
+ print('{0} completed'.format(childargs[1]), file=sys.stdout)
-def wait(childargs, waitdata):
+
+def wait(childargs: Sequence[str], waitdata):
if childargs[1] in ['scrub', 'deep-scrub']:
waitscrub(childargs, waitdata)
if parsed_args.client_name:
name = parsed_args.client_name
- # default '' means default conf search
- conffile = ''
+ conffile = rados.Rados.DEFAULT_CONF_FILES
if parsed_args.cephconf:
conffile = parsed_args.cephconf
# For now, --admin-daemon is handled as usual. Try it
# an awfully simple callback
def watch_cb(arg, line, channel, name, who, stamp_sec, stamp_nsec, seq, level, msg):
# Filter on channel
- if sys.version_info[0] >= 3:
- channel = channel.decode('utf-8')
- if (channel == parsed_args.watch_channel or \
- parsed_args.watch_channel == "*"):
+ channel = channel.decode('utf-8')
+ if parsed_args.watch_channel in (channel, '*'):
print(line.decode('utf-8'))
sys.stdout.flush()
if parsed_args.input_file:
try:
if parsed_args.input_file == '-':
- inbuf = sys.stdin.read()
+ inbuf = sys.stdin.buffer.read()
else:
with open(parsed_args.input_file, 'rb') as f:
inbuf = f.read()
if parsed_args.output_file:
try:
if parsed_args.output_file == '-':
- outf = raw_stdout
+ outf = sys.stdout.buffer
else:
outf = open(parsed_args.output_file, 'wb')
except Exception as e:
errno.errorcode.get(ret, 'Unknown'), outs),
file=sys.stderr)
- if ret < 0:
- ret = -ret
- errstr = errno.errorcode.get(ret, 'Unknown')
- print(u'Error {0}: {1}'.format(errstr, outs), file=sys.stderr)
- if len(targets) > 1:
- final_ret = ret
- else:
- return ret
-
- if outs:
- print(prefix + outs, file=sys.stderr)
-
sys.stdout.flush()
if parsed_args.output_file:
except IOError as e:
if e.errno != errno.EPIPE:
raise e
+ final_e = None
try:
sys.stdout.flush()
except IOError as e:
if e.errno != errno.EPIPE:
- raise e
+ final_e = e
+
+ if ret < 0:
+ ret = -ret
+ errstr = errno.errorcode.get(ret, 'Unknown')
+ print('Error {0}: {1}'.format(errstr, outs), file=sys.stderr)
+ final_ret = ret
+ elif outs:
+ print(prefix + outs, file=sys.stderr)
+ if final_e:
+ raise final_e
# Block until command completion (currently scrub and deep_scrub only)
if block: