+++ /dev/null
-#!@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())