]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph.in: use cmake-style substitution
authorJohn Spray <john.spray@redhat.com>
Mon, 3 Aug 2015 23:09:53 +0000 (00:09 +0100)
committerJohn Spray <john.spray@redhat.com>
Mon, 10 Aug 2015 13:05:53 +0000 (14:05 +0100)
Avoid need for separate ceph.in and ceph.in.cmake files.

Signed-off-by: John Spray <john.spray@redhat.com>
src/CMakeLists.txt
src/ceph.in
src/ceph.in.cmake [deleted file]

index e3a9b0e87bb5488ef67404d64dd3aa92e60e4989..14881e1e998f8acc611aed88730b887c504e2534 100644 (file)
@@ -729,7 +729,7 @@ configure_file(${CMAKE_SOURCE_DIR}/src/ceph-coverage.in
 configure_file(${CMAKE_SOURCE_DIR}/src/ceph-debugpack.in
   ${CMAKE_BINARY_DIR}/ceph-debugpack @ONLY)
 
-configure_file(${CMAKE_SOURCE_DIR}/src/ceph.in.cmake
+configure_file(${CMAKE_SOURCE_DIR}/src/ceph.in
   ${CMAKE_BINARY_DIR}/ceph @ONLY)
 
 configure_file(${CMAKE_SOURCE_DIR}/src/ceph-crush-location.in
index f55f8c7df17b5588eeebdb230baa648a1e8687da..3178ba155c672098e5dd9eb97cca14dabb583334 100755 (executable)
@@ -1,3 +1,4 @@
+#!@PYTHON_EXECUTABLE@
 # -*- mode:python -*-
 # vim: ts=4 sw=4 smarttab expandtab
 #
@@ -22,6 +23,9 @@ import os
 import sys
 import platform
 
+CEPH_GIT_VER="@CEPH_GIT_VER@"
+CEPH_GIT_NICE_VER="@CEPH_GIT_NICE_VER@"
+
 # Make life easier on developers:
 # If in src/, and .libs and pybind exist here, assume we're running
 # from a Ceph source dir and tweak PYTHONPATH and LD_LIBRARY_PATH
diff --git a/src/ceph.in.cmake b/src/ceph.in.cmake
deleted file mode 100755 (executable)
index 805393e..0000000
+++ /dev/null
@@ -1,827 +0,0 @@
-#!@PYTHON_EXECUTABLE@
-# -*- mode:python -*-
-# vim: ts=4 sw=4 smarttab expandtab
-#
-# Processed in Makefile to add python #! line and version variable
-#
-#
-
-
-"""
-ceph.in becomes ceph, the command-line management tool for Ceph clusters.
-This is a replacement for tools/ceph.cc and tools/common.cc.
-
-Copyright (C) 2013 Inktank Storage, Inc.
-
-This is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public
-License version 2, as published by the Free Software
-Foundation.  See file COPYING.
-"""
-
-import os
-import sys
-
-# Make life easier on developers:
-# If in src/, and .libs and pybind exist here, assume we're running
-# from a Ceph source dir and tweak PYTHONPATH and LD_LIBRARY_PATH
-# to use local files
-
-MYPATH = os.path.abspath(__file__)
-MYDIR = os.path.dirname(MYPATH)
-DEVMODEMSG = '*** DEVELOPER MODE: setting PATH, PYTHONPATH and LD_LIBRARY_PATH ***'
-
-if MYDIR.endswith('src') and \
-   os.path.exists(os.path.join(MYDIR, '.libs')) and \
-   os.path.exists(os.path.join(MYDIR, 'pybind')):
-    MYLIBPATH = os.path.join(MYDIR, '.libs')
-    if 'LD_LIBRARY_PATH' in os.environ:
-        if MYLIBPATH not in os.environ['LD_LIBRARY_PATH']:
-            os.environ['LD_LIBRARY_PATH'] += ':' + MYLIBPATH
-            print >> sys.stderr, DEVMODEMSG
-            os.execvp('python', ['python'] + sys.argv)
-    else:
-        os.environ['LD_LIBRARY_PATH'] = MYLIBPATH
-        print >> sys.stderr, DEVMODEMSG
-        os.execvp('python', ['python'] + sys.argv)
-    sys.path.insert(0, os.path.join(MYDIR, 'pybind'))
-    if MYDIR not in os.environ['PATH']:
-        os.environ['PATH'] += ':' + MYDIR
-
-import argparse
-import errno
-import json
-import rados
-import signal
-import socket
-import string
-import struct
-import subprocess
-
-from ceph_argparse import \
-    concise_sig, descsort, parse_json_funcsigs, \
-    matchnum, validate_command, find_cmd_target, \
-    send_command, json_command
-
-# just a couple of globals
-
-verbose = False
-cluster_handle = None
-
-############################################################################
-
-def osdids():
-    ret, outbuf, outs = json_command(cluster_handle, prefix='osd ls')
-    if ret == -errno.EINVAL:
-        # try old mon
-        ret, outbuf, outs = send_command(cluster_handle, cmd=['osd', 'ls'])
-    if ret:
-        raise RuntimeError('Can\'t contact mon for osd list')
-    return [i for i in outbuf.split('\n') if i != '']
-
-def monids():
-    ret, outbuf, outs = json_command(cluster_handle, prefix='mon dump',
-                                     argdict={'format':'json'})
-    if ret == -errno.EINVAL:
-        # try old mon
-        ret, outbuf, outs = send_command(cluster_handle,
-                                         cmd=['mon', 'dump', '--format=json'])
-    if ret:
-        raise RuntimeError('Can\'t contact mon for mon list')
-    d = json.loads(outbuf)
-    return [m['name'] for m in d['mons']]
-
-def mdsids():
-    ret, outbuf, outs = json_command(cluster_handle, prefix='mds dump',
-                                     argdict={'format':'json'})
-    if ret == -errno.EINVAL:
-        # try old mon
-        ret, outbuf, outs = send_command(cluster_handle,
-                                         cmd=['mds', 'dump', '--format=json'])
-    if ret:
-        raise RuntimeError('Can\'t contact mon for mds list')
-    d = json.loads(outbuf)
-    l = []
-    infodict = d['info']
-    for mdsdict in infodict.values():
-        l.append(mdsdict['name'])
-    return l
-
-def parse_cmdargs(args=None, target=''):
-    # alias: let the line-wrapping be sane
-    AP = argparse.ArgumentParser
-
-    # format our own help
-    parser = AP(description='Ceph administration tool', add_help=False)
-
-    parser.add_argument('--completion', action='store_true',
-                        help=argparse.SUPPRESS)
-
-    parser.add_argument('-h', '--help', help='request mon help',
-                        action='store_true')
-
-    parser.add_argument('-c', '--conf', dest='cephconf',
-                        help='ceph configuration file')
-    parser.add_argument('-i', '--in-file', dest='input_file',
-                        help='input file')
-    parser.add_argument('-o', '--out-file', dest='output_file',
-                        help='output file')
-
-    parser.add_argument('--id', '--user', dest='client_id',
-                        help='client id for authentication')
-    parser.add_argument('--name', '-n', dest='client_name',
-                        help='client name for authentication')
-    parser.add_argument('--cluster', help='cluster name')
-
-    parser.add_argument('--admin-daemon', dest='admin_socket',
-                        help='submit admin-socket commands (\"help\" for help')
-    parser.add_argument('--admin-socket', dest='admin_socket_nope',
-                        help='you probably mean --admin-daemon')
-
-    parser.add_argument('-s', '--status', action='store_true',
-                        help='show cluster status')
-
-    parser.add_argument('-w', '--watch', action='store_true',
-                        help='watch live cluster changes')
-    parser.add_argument('--watch-debug', action='store_true',
-                        help='watch debug events')
-    parser.add_argument('--watch-info', action='store_true',
-                        help='watch info events')
-    parser.add_argument('--watch-sec', action='store_true',
-                        help='watch security events')
-    parser.add_argument('--watch-warn', action='store_true',
-                        help='watch warn events')
-    parser.add_argument('--watch-error', action='store_true',
-                        help='watch error events')
-
-    parser.add_argument('--version', '-v', action="store_true", help="display version")
-    parser.add_argument('--verbose', action="store_true", help="make verbose")
-    parser.add_argument('--concise', dest='verbose', action="store_false",
-                        help="make less verbose")
-
-    parser.add_argument('-f', '--format', choices=['json', 'json-pretty',
-                        'xml', 'xml-pretty', 'plain'], dest='output_format')
-
-    parser.add_argument('--connect-timeout', dest='cluster_timeout',
-                        type=int,
-                        help='set a timeout for connecting to the cluster')
-
-    # returns a Namespace with the parsed args, and a list of all extras
-    parsed_args, extras = parser.parse_known_args(args)
-
-    return parser, parsed_args, extras
-
-
-def hdr(s):
-    print '\n', s, '\n', '=' * len(s)
-
-def do_basic_help(parser, args):
-    """
-    Print basic parser help
-    If the cluster is available, get and print monitor help
-    """
-    hdr('General usage:')
-    parser.print_help()
-
-def do_extended_help(parser, args):
-    def help_for_sigs(sigs, partial=None):
-        sys.stdout.write(format_help(parse_json_funcsigs(sigs, 'cli'),
-                         partial=partial))
-
-    def help_for_target(target, partial=None):
-        ret, outbuf, outs = json_command(cluster_handle, target=target,
-                                         prefix='get_command_descriptions', 
-                                         timeout=10)
-        if ret:
-            print >> sys.stderr, \
-                "couldn't get command descriptions for {0}: {1}".\
-                format(target, outs)
-        else:
-            help_for_sigs(outbuf, partial)
-
-    partial = ' '.join(args)
-    if (cluster_handle.state == "connected"):
-        help_for_target(target=('mon', ''), partial=partial)
-    return 0
-
-DONTSPLIT = string.letters + '{[<>]}'
-
-def wrap(s, width, indent):
-    """
-    generator to transform s into a sequence of strings width or shorter,
-    for wrapping text to a specific column width.
-    Attempt to break on anything but DONTSPLIT characters.
-    indent is amount to indent 2nd-through-nth lines.
-
-    so "long string long string long string" width=11 indent=1 becomes
-    'long string', ' long string', ' long string' so that it can be printed
-    as
-    long string
-     long string
-     long string
-
-    Consumes s.
-    """
-    result = ''
-    leader = ''
-    while len(s):
-
-        if (len(s) <= width):
-            # no splitting; just possibly indent
-            result = leader + s
-            s = ''
-            yield result
-
-        else:
-            splitpos = width
-            while (splitpos > 0) and (s[splitpos-1] in DONTSPLIT):
-                splitpos -= 1
-
-            if splitpos == 0:
-                splitpos = width
-
-            if result:
-                # prior result means we're mid-iteration, indent
-                result = leader
-            else:
-                # first time, set leader and width for next
-                leader = ' ' * indent
-                width -= 1      # for subsequent space additions
-
-            # remove any leading spaces in this chunk of s
-            result += s[:splitpos].lstrip()
-            s = s[splitpos:]
-
-            yield result
-
-    raise StopIteration
-
-def format_help(cmddict, partial=None):
-    """
-    Formats all the cmdsigs and helptexts from cmddict into a sorted-by-
-    cmdsig 2-column display, with each column wrapped and indented to
-    fit into 40 characters.
-    """
-
-    fullusage = ''
-    for cmd in sorted(cmddict.itervalues(), cmp=descsort):
-
-        if not cmd['help']:
-            continue
-        concise = concise_sig(cmd['sig'])
-        if partial and not concise.startswith(partial):
-            continue
-        siglines = [l for l in wrap(concise, 40, 1)]
-        helplines = [l for l in wrap(cmd['help'], 39, 1)]
-
-        # make lists the same length
-        maxlen = max(len(siglines), len(helplines))
-        siglines.extend([''] * (maxlen - len(siglines)))
-        helplines.extend([''] * (maxlen - len(helplines)))
-
-        # so we can zip them for output
-        for (s, h) in zip(siglines, helplines):
-            fullusage += '{0:40s} {1}\n'.format(s, h)
-
-    return fullusage
-
-def admin_socket(asok_path, cmd, format=''):
-    """
-    Send a daemon (--admin-daemon) command 'cmd'.  asok_path is the
-    path to the admin socket; cmd is a list of strings; format may be
-    set to one of the formatted forms to get output in that form
-    (daemon commands don't support 'plain' output).
-    """
-
-    def do_sockio(path, cmd):
-        """ helper: do all the actual low-level stream I/O """
-        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-        sock.connect(path)
-        try:
-            sock.sendall(cmd + '\0')
-            len_str = sock.recv(4)
-            if len(len_str) < 4:
-                raise RuntimeError("no data returned from admin socket")
-            l, = struct.unpack(">I", len_str)
-            ret = ''
-
-            got = 0
-            while got < l:
-                bit = sock.recv(l - got)
-                ret += bit
-                got += len(bit)
-
-        except Exception as e:
-            raise RuntimeError('exception: ' + str(e))
-        return ret
-
-    try:
-        cmd_json = do_sockio(asok_path,
-            json.dumps({"prefix":"get_command_descriptions"}))
-    except Exception as e:
-        raise RuntimeError('exception getting command descriptions: ' + str(e))
-
-    if cmd == 'get_command_descriptions':
-        return cmd_json
-
-    sigdict = parse_json_funcsigs(cmd_json, 'cli')
-    valid_dict = validate_command(sigdict, cmd)
-    if not valid_dict:
-        raise RuntimeError('invalid command')
-
-    if format:
-        valid_dict['format'] = format
-
-    try:
-        ret = do_sockio(asok_path, json.dumps(valid_dict))
-    except Exception as e:
-        raise RuntimeError('exception: ' + str(e))
-
-    return ret
-
-
-def ceph_conf(field, name):
-    p = subprocess.Popen(
-        args=[
-            'ceph-conf',
-           '--show-config-value',
-            field,
-            '-n',
-            name,
-            ],
-        stdout=subprocess.PIPE,
-        stderr=subprocess.PIPE)
-    outdata, errdata = p.communicate()
-    if (len(errdata)):
-        raise RuntimeError('unable to get conf option %s for %s: %s' % (field, name, errdata))
-    return outdata.rstrip()
-
-def new_style_command(parsed_args, cmdargs, target, sigdict, inbuf, verbose):
-    """
-    Do new-style command dance.
-    target: daemon to receive command: mon (any) or osd.N
-    sigdict - the parsed output from the new monitor describing commands
-    inbuf - any -i input file data
-    verbose - bool
-    """
-    if verbose:
-        for cmdtag in sorted(sigdict.keys()):
-            cmd = sigdict[cmdtag]
-            sig = cmd['sig']
-            print '{0}: {1}'.format(cmdtag, concise_sig(sig))
-
-    got_command = False
-
-    if not got_command:
-        if cmdargs:
-            # Validate input args against list of sigs
-            valid_dict = validate_command(sigdict, cmdargs, verbose)
-            if valid_dict:
-                got_command = True
-                if parsed_args.output_format:
-                    valid_dict['format'] = parsed_args.output_format
-            else:
-                return -errno.EINVAL, '', 'invalid command'
-        else:
-            # do the command-interpreter looping
-            # for raw_input to do readline cmd editing
-            import readline
-            while True:
-                interactive_input = raw_input('ceph> ')
-                if interactive_input in ['q', 'quit', 'Q']:
-                    return 0, '', ''
-                cmdargs = parse_cmdargs(interactive_input.split())[2]
-                target = find_cmd_target(cmdargs)
-                valid_dict = validate_command(sigdict, cmdargs, verbose)
-                if valid_dict:
-                    if parsed_args.output_format:
-                        valid_dict['format'] = parsed_args.output_format
-                    if verbose:
-                        print >> sys.stderr, "Submitting command ", valid_dict
-                    ret, outbuf, outs = json_command(cluster_handle,
-                                                     target=target,
-                                                     argdict=valid_dict)
-                    if ret:
-                        ret = abs(ret)
-                        print >> sys.stderr, \
-                            'Error: {0} {1}'.format(ret, errno.errorcode[ret])
-                    if outbuf:
-                        print outbuf
-                    if outs:
-                        print >> sys.stderr, 'Status:\n', outs
-                else:
-                    print >> sys.stderr, "Invalid command"
-
-    if verbose:
-        print >> sys.stderr, "Submitting command ", valid_dict
-    return json_command(cluster_handle, target=target, argdict=valid_dict,
-                        inbuf=inbuf)
-
-def complete(sigdict, args, target):
-    """
-    Command completion.  Match as much of [args] as possible,
-    and print every possible match separated by newlines. 
-    Return exitcode.
-    """
-    # XXX this looks a lot like the front of validate_command().  Refactor?
-
-    complete_verbose = 'COMPVERBOSE' in os.environ
-
-    # Repulsive hack to handle tell: lop off 'tell' and target
-    # and validate the rest of the command.  'target' is already
-    # determined in our callers, so it's ok to remove it here.
-    if len(args) and args[0] == 'tell':
-        args = args[2:]
-    # look for best match, accumulate possibles in bestcmds
-    # (so we can maybe give a more-useful error message)
-    best_match_cnt = 0
-    bestcmds = []
-    for cmdtag, cmd in sigdict.iteritems():
-        sig = cmd['sig']
-        matched = matchnum(args, sig, partial=True)
-        if (matched > best_match_cnt):
-            if complete_verbose:
-                print >> sys.stderr, \
-                    "better match: {0} > {1}: {2}:{3} ".format(matched,
-                                  best_match_cnt, cmdtag, concise_sig(sig))
-            best_match_cnt = matched
-            bestcmds = [{cmdtag:cmd}]
-        elif matched == best_match_cnt:
-            if complete_verbose:
-                print >> sys.stderr, \
-                    "equal match: {0} > {1}: {2}:{3} ".format(matched,
-                                  best_match_cnt, cmdtag, concise_sig(sig))
-            bestcmds.append({cmdtag:cmd})
-
-    # look through all matching sigs
-    comps = []
-    for cmddict in bestcmds:
-        for cmd in cmddict.itervalues():
-            sig = cmd['sig']
-            # either:
-            #   we match everything fully, so we want the next desc, or
-            #   we match more partially, so we want the partial match
-            fullindex = matchnum(args, sig, partial=False) - 1
-            partindex = matchnum(args, sig, partial=True) - 1
-            if complete_verbose:
-                print >> sys.stderr, '{}: f {} p {} len {}'.format(sig, fullindex, partindex, len(sig))
-            if fullindex == partindex and fullindex + 1 < len(sig):
-                d = sig[fullindex + 1]
-            else:
-                d = sig[partindex]
-            comps.append(str(d))
-    if complete_verbose:
-        print >> sys.stderr, '\n'.join(comps)
-    print '\n'.join(comps)
-
-    return 0
-
-###
-# ping a monitor
-###
-def ping_monitor(cluster_handle, name, timeout):
-    if 'mon.' not in name:
-        print >> sys.stderr, '"ping" expects a monitor to ping; try "ping mon.<id>"'
-        return 1
-
-    mon_id = name[len('mon.'):]
-    if (mon_id == '*') :
-        cluster_handle.connect(timeout=timeout)
-        for m in monids() :
-            s = cluster_handle.ping_monitor(m)
-            print "mon.{0}".format(m) + '\n' + s
-    else :
-            s = cluster_handle.ping_monitor(mon_id)
-            print s
-    return 0
-
-###
-# main
-###
-
-def main():
-    ceph_args = os.environ.get('CEPH_ARGS')
-    if ceph_args:
-        sys.argv.extend(ceph_args.split())
-
-    parser, parsed_args, childargs = parse_cmdargs()
-
-    if parsed_args.version:
-        print 'ceph version {0} ({1})'.format(CEPH_GIT_NICE_VER, CEPH_GIT_VER)
-        return 0
-
-    global verbose
-    verbose = parsed_args.verbose
-
-    if parsed_args.admin_socket_nope:
-        print >> sys.stderr, '--admin-socket is used by daemons; '\
-        'you probably mean --admin-daemon/daemon'
-        return 1
-
-    # pass on --id, --name, --conf
-    name = 'client.admin'
-    if parsed_args.client_id:
-        name = 'client.' + parsed_args.client_id
-    if parsed_args.client_name:
-        name = parsed_args.client_name
-
-    # default '' means default conf search
-    conffile = ''
-    if parsed_args.cephconf:
-        conffile = parsed_args.cephconf
-    # For now, --admin-daemon is handled as usual.  Try it
-    # first in case we can't connect() to the cluster
-
-    format = parsed_args.output_format
-
-    sockpath = None
-    if parsed_args.admin_socket:
-        sockpath = parsed_args.admin_socket
-    elif len(childargs) > 0 and childargs[0] == "daemon":
-        # Treat "daemon <path>" or "daemon <name>" like --admin_daemon <path>
-        if len(childargs) > 2:
-            if childargs[1].find('/') >= 0:
-                sockpath = childargs[1]
-            else:
-                # try resolve daemon name
-                try:
-                    sockpath = ceph_conf('admin_socket', childargs[1])
-                except Exception as e:
-                    print >> sys.stderr, \
-                        'Can\'t get admin socket path: ' + str(e)
-                    return errno.EINVAL
-            # for both:
-            childargs = childargs[2:]
-        else:
-            print >> sys.stderr, 'daemon requires at least 3 arguments'
-            return errno.EINVAL
-
-    if sockpath:
-        try:
-            print admin_socket(sockpath, childargs, format)
-        except Exception as e:
-            print >> sys.stderr, 'admin_socket: {0}'.format(e)
-            return errno.EINVAL
-        return 0
-
-    timeout = None
-    if parsed_args.cluster_timeout:
-        timeout = parsed_args.cluster_timeout
-
-    # basic help
-    if parsed_args.help:
-        do_basic_help(parser, childargs)
-
-    # handle any 'generic' ceph arguments that we didn't parse here
-    global cluster_handle
-
-    # rados.Rados() will call rados_create2, and then read the conf file,
-    # and then set the keys from the dict.  So we must do these
-    # "pre-file defaults" first (see common_preinit in librados)
-    conf_defaults = {
-        'log_to_stderr':'true',
-        'err_to_stderr':'true',
-        'log_flush_on_exit':'true',
-    }
-
-    clustername = 'ceph'
-    if parsed_args.cluster:
-        clustername = parsed_args.cluster
-
-    try:
-        cluster_handle = rados.Rados(name=name, clustername=clustername,
-                                     conf_defaults=conf_defaults,
-                                     conffile=conffile)
-        retargs = cluster_handle.conf_parse_argv(childargs)
-    except rados.Error as e:
-        print >> sys.stderr, 'Error initializing cluster client: {0}'.\
-            format(e.__class__.__name__)
-        return 1
-
-    #tmp = childargs
-    childargs = retargs
-    if not childargs:
-        childargs = []
-
-    # -- means "stop parsing args", but we don't want to see it either
-    if '--' in childargs:
-        childargs.remove('--')
-
-    # special deprecation warning for 'ceph <type> tell'
-    # someday 'mds' will be here too
-    if len(childargs) >= 2 and \
-        childargs[0] in ['mon', 'osd'] and \
-        childargs[1] == 'tell':
-        print >> sys.stderr, '"{0} tell" is deprecated; try "tell {0}.<id>" instead (id can be "*") '.format(childargs[0])
-        return 1
-
-    if parsed_args.help:
-        # short default timeout for -h
-        if not timeout:
-            timeout = 5
-
-        hdr('Monitor commands:')
-        print '[Contacting monitor, timeout after %d seconds]' % timeout
-
-    if childargs and childargs[0] == 'ping':
-        if len(childargs) < 2:
-            print >> sys.stderr, '"ping" requires a monitor name as argument: "ping mon.<id>"'
-            return 1
-
-    try:
-        if childargs and childargs[0] == 'ping':
-            return ping_monitor(cluster_handle, childargs[1], timeout)
-        cluster_handle.connect(timeout=timeout)
-    except KeyboardInterrupt:
-        print >> sys.stderr, 'Cluster connection aborted'
-        return 1
-    except Exception as e:
-        print >> sys.stderr, 'Error connecting to cluster: {0}'.\
-            format(e.__class__.__name__)
-        return 1
-
-    if parsed_args.help:
-        return do_extended_help(parser, childargs)
-
-    # implement -w/--watch_*
-    # This is ugly, but Namespace() isn't quite rich enough.
-    level = ''
-    for k, v in parsed_args._get_kwargs():
-        if k.startswith('watch') and v:
-            if k == 'watch':
-                level = 'info'
-            else:
-                level = k.replace('watch_', '')
-    if level:
-
-        # an awfully simple callback
-        def watch_cb(arg, line, who, stamp_sec, stamp_nsec, seq, level, msg):
-            print line
-            sys.stdout.flush()
-
-        # first do a ceph status
-        ret, outbuf, outs = json_command(cluster_handle, prefix='status')
-        if ret == -errno.EINVAL:
-            # try old mon
-            ret, outbuf, outs = send_command(cluster_handle, cmd=['status'])
-            # old mon returns status to outs...ick
-            if ret == 0:
-                outbuf += outs
-        if ret:
-            print >> sys.stderr, "status query failed: ", outs
-            return ret
-        print outbuf
-
-        # this instance keeps the watch connection alive, but is
-        # otherwise unused
-        logwatch = rados.MonitorLog(cluster_handle, level, watch_cb, 0)
-
-        # loop forever letting watch_cb print lines
-        try:
-            signal.pause()
-        except KeyboardInterrupt:
-            # or until ^C, at least
-            return 0
-
-    # read input file, if any
-    inbuf = ''
-    if parsed_args.input_file:
-        try:
-            with open(parsed_args.input_file, 'r') as f:
-                inbuf = f.read()
-        except Exception as e:
-            print >> sys.stderr, 'Can\'t open input file {0}: {1}'.format(parsed_args.input_file, e)
-            return 1
-
-    # prepare output file, if any
-    if parsed_args.output_file:
-        try:
-            outf = open(parsed_args.output_file, 'w')
-        except Exception as e:
-            print >> sys.stderr, \
-                'Can\'t open output file {0}: {1}'.\
-                format(parsed_args.output_file, e)
-            return 1
-
-    # -s behaves like a command (ceph status).
-    if parsed_args.status:
-        childargs.insert(0, 'status')
-
-    target = find_cmd_target(childargs)
-
-    # Repulsive hack to handle tell: lop off 'tell' and target
-    # and validate the rest of the command.  'target' is already
-    # determined in our callers, so it's ok to remove it here.
-    if len(childargs) and childargs[0] == 'tell':
-        childargs = childargs[2:]
-
-    # fetch JSON sigs from command
-    # each line contains one command signature (a placeholder name
-    # of the form 'cmdNNN' followed by an array of argument descriptors)
-    # as part of the validated argument JSON object
-
-    targets = [target]
-
-    if target[1] == '*':
-        if target[0] == 'osd':
-            targets = [(target[0], o) for o in osdids()]
-        elif target[0] == 'mon':
-            targets = [(target[0], m) for m in monids()]
-
-    final_ret = 0
-    for target in targets:
-        # prettify?  prefix output with target, if there was a wildcard used
-        prefix = ''
-        suffix = ''
-        if not parsed_args.output_file and len(targets) > 1:
-            prefix = '{0}.{1}: '.format(*target)
-            suffix = '\n'
-
-        ret, outbuf, outs = json_command(cluster_handle, target=target,
-                                         prefix='get_command_descriptions')
-        compat = False
-        if ret == -errno.EINVAL:
-            # send command to old monitor or OSD
-            if verbose:
-                print prefix + '{0} to old {1}'.format(' '.join(childargs), target[0])
-            compat = True
-            if parsed_args.output_format:
-                childargs.extend(['--format', parsed_args.output_format])
-            ret, outbuf, outs = send_command(cluster_handle, target, childargs,
-                                             inbuf)
-
-            if ret == -errno.EINVAL:
-                # did we race with a mon upgrade?  try again!
-                ret, outbuf, outs = json_command(cluster_handle, target=target,
-                                                 prefix='get_command_descriptions')
-                if ret == 0:
-                    compat = False  # yep, carry on
-        if not compat:
-            if ret:
-                if ret < 0:
-                    outs = 'problem getting command descriptions from {0}.{1}'.format(*target)
-            else:
-                sigdict = parse_json_funcsigs(outbuf, 'cli')
-
-                if parsed_args.completion:
-                    return complete(sigdict, childargs, target)
-
-                ret, outbuf, outs = new_style_command(parsed_args, childargs, target,
-                                                      sigdict, inbuf, verbose)
-
-                # debug tool: send any successful command *again* to
-                # verify that it is idempotent.
-                if not ret and 'CEPH_CLI_TEST_DUP_COMMAND' in os.environ:
-                    ret, outbuf, outs = new_style_command(parsed_args, childargs, target,
-                                                          sigdict, inbuf, verbose)
-                    if ret < 0:
-                        ret = -ret
-                        print >> sys.stderr, prefix + 'Second attempt of previously successful command failed with {0}: {1}'.format(errno.errorcode[ret], outs)
-
-        if ret < 0:
-            ret = -ret
-            print >> sys.stderr, prefix + 'Error {0}: {1}'.format(errno.errorcode[ret], outs)
-            if len(targets) > 1:
-                final_ret = ret
-            else:
-                return ret
-
-        # this assumes outs never has useful command output, only status
-        if compat:
-            if ret == 0:
-                # old cli/mon would send status string to stdout on non-error
-                print outs
-        else:
-            if outs:
-                print >> sys.stderr, prefix + outs
-
-        if (parsed_args.output_file):
-            outf.write(outbuf)
-        else:
-            # hack: old code printed status line before many json outputs
-            # (osd dump, etc.) that consumers know to ignore.  Add blank line
-            # to satisfy consumers that skip the first line, but not annoy
-            # consumers that don't.
-            if parsed_args.output_format and \
-               parsed_args.output_format.startswith('json') and \
-               not compat:
-                sys.stdout.write('\n')
-
-            # if we are prettifying things, normalize newlines.  sigh.
-            if suffix != '':
-                outbuf = outbuf.rstrip()
-            if outbuf != '':
-                sys.stdout.write(prefix + outbuf + suffix)
-
-        sys.stdout.flush()
-
-    if (parsed_args.output_file):
-        outf.close()
-
-    if final_ret:
-        return final_ret
-
-    return 0
-
-if __name__ == '__main__':
-    sys.exit(main())