Пример #1
0
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
Пример #2
0
def show_human_help(prefix):
    '''
    Dump table showing commands matching prefix
    '''
    # XXX There ought to be a better discovery mechanism than an HTML table
    s = '<html><body><table border=1><th>Possible commands:</th><th>Method</th><th>Description</th>'

    permmap = {'r': 'GET', 'rw': 'PUT', 'rx': 'GET', 'rwx': 'PUT'}
    line = ''
    for cmdsig in sorted(app.ceph_sigdict.itervalues(), cmp=descsort):
        concise = concise_sig(cmdsig['sig'])
        flavor = cmdsig.get('flavor', 'mon')
        if flavor == 'tell':
            concise = 'tell/<target>/' + concise
        if concise.startswith(prefix):
            line = ['<tr><td>']
            wrapped_sig = textwrap.wrap(
                concise_sig_for_uri(cmdsig['sig'], flavor), 40)
            for sigline in wrapped_sig:
                line.append(flask.escape(sigline) + '\n')
            line.append('</td><td>')
            line.append(permmap[cmdsig['perm']])
            line.append('</td><td>')
            line.append(flask.escape(cmdsig['help']))
            line.append('</td></tr>\n')
            s += ''.join(line)

    s += '</table></body></html>'
    if line:
        return s
    else:
        return ''
Пример #3
0
def show_human_help(prefix):
    '''
    Dump table showing commands matching prefix
    '''
    # XXX There ought to be a better discovery mechanism than an HTML table
    s = '<html><body><table border=1><th>Possible commands:</th><th>Method</th><th>Description</th>'

    permmap = {'r': 'GET', 'rw': 'PUT', 'rx': 'GET', 'rwx': 'PUT'}
    line = ''
    for cmdsig in sorted(app.ceph_sigdict.itervalues(), cmp=descsort):
        concise = concise_sig(cmdsig['sig'])
        flavor = cmdsig.get('flavor', 'mon')
        if flavor == 'tell':
            concise = 'tell/<target>/' + concise
        if concise.startswith(prefix):
            line = ['<tr><td>']
            wrapped_sig = textwrap.wrap(
                concise_sig_for_uri(cmdsig['sig'], flavor), 40
            )
            for sigline in wrapped_sig:
                line.append(flask.escape(sigline) + '\n')
            line.append('</td><td>')
            line.append(permmap[cmdsig['perm']])
            line.append('</td><td>')
            line.append(flask.escape(cmdsig['help']))
            line.append('</td></tr>\n')
            s += ''.join(line)

    s += '</table></body></html>'
    if line:
        return s
    else:
        return ''
Пример #4
0
def show_human_help(prefix):
    """
    Dump table showing commands matching prefix
    """
    # XXX There ought to be a better discovery mechanism than an HTML table
    s = "<html><body><table border=1><th>Possible commands:</th><th>Method</th><th>Description</th>"

    permmap = {"r": "GET", "rw": "PUT"}
    line = ""
    for cmdsig in sorted(app.ceph_sigdict.itervalues(), cmp=descsort):
        concise = concise_sig(cmdsig["sig"])
        flavor = cmdsig.get("flavor", "mon")
        if flavor == "tell":
            concise = "tell/<target>/" + concise
        if concise.startswith(prefix):
            line = ["<tr><td>"]
            wrapped_sig = textwrap.wrap(concise_sig_for_uri(cmdsig["sig"], flavor), 40)
            for sigline in wrapped_sig:
                line.append(flask.escape(sigline) + "\n")
            line.append("</td><td>")
            line.append(permmap[cmdsig["perm"]])
            line.append("</td><td>")
            line.append(flask.escape(cmdsig["help"]))
            line.append("</td></tr>\n")
            s += "".join(line)

    s += "</table></body></html>"
    if line:
        return s
    else:
        return ""
Пример #5
0
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
Пример #6
0
def handler(catchall_path=None, fmt=None, target=None):
    '''
    Main endpoint handler; generic for every endpoint, including catchall.
    Handles the catchall, anything with <.fmt>, anything with embedded
    <target>.  Partial match or ?help cause the HTML-table
    "show_human_help" output.
    '''

    ep = catchall_path or flask.request.endpoint
    ep = ep.replace('.<fmt>', '')

    if ep[0] != '/':
        ep = '/' + ep

    # demand that endpoint begin with app.ceph_baseurl
    if not ep.startswith(app.ceph_baseurl):
        return make_response(fmt, '', 'Page not found', 404)

    rel_ep = ep[len(app.ceph_baseurl) + 1:]

    # Extensions override Accept: headers override defaults
    if not fmt:
        if 'application/json' in flask.request.accept_mimetypes.values():
            fmt = 'json'
        elif 'application/xml' in flask.request.accept_mimetypes.values():
            fmt = 'xml'

    prefix = ''
    pgid = None
    cmdtarget = 'mon', ''

    if target:
        # got tell/<target>; validate osdid or pgid
        name = CephOsdName()
        pgidobj = CephPgid()
        try:
            name.valid(target)
        except ArgumentError:
            # try pgid
            try:
                pgidobj.valid(target)
            except ArgumentError:
                return flask.make_response("invalid osdid or pgid", 400)
            else:
                # it's a pgid
                pgid = pgidobj.val
                cmdtarget = 'pg', pgid
        else:
            # it's an osd
            cmdtarget = name.nametype, name.nameid

        # prefix does not include tell/<target>/
        prefix = ' '.join(rel_ep.split('/')[2:]).strip()
    else:
        # non-target command: prefix is entire path
        prefix = ' '.join(rel_ep.split('/')).strip()

    # show "match as much as you gave me" help for unknown endpoints
    if ep not in app.ceph_urls:
        helptext = show_human_help(prefix)
        if helptext:
            resp = flask.make_response(helptext, 400)
            resp.headers['Content-Type'] = 'text/html'
            return resp
        else:
            return make_response(fmt, '', 'Invalid endpoint ' + ep, 400)

    found = None
    exc = ''
    for urldict in app.ceph_urls[ep]:
        if flask.request.method not in urldict['methods']:
            continue
        paramsig = urldict['paramsig']

        # allow '?help' for any specifically-known endpoint
        if 'help' in flask.request.args:
            response = flask.make_response('{0}: {1}'.format(
                prefix + concise_sig(paramsig), urldict['help']))
            response.headers['Content-Type'] = 'text/plain'
            return response

        # if there are parameters for this endpoint, process them
        if paramsig:
            args = {}
            for k, l in flask.request.args.iterlists():
                if len(l) == 1:
                    args[k] = l[0]
                else:
                    args[k] = l

            # is this a valid set of params?
            try:
                argdict = validate(args, paramsig)
                found = urldict
                break
            except Exception as e:
                exc += str(e)
                continue
        else:
            if flask.request.args:
                continue
            found = urldict
            argdict = {}
            break

    if not found:
        return make_response(fmt, '', exc + '\n', 400)

    argdict['format'] = fmt or 'plain'
    argdict['module'] = found['module']
    argdict['perm'] = found['perm']
    if pgid:
        argdict['pgid'] = pgid

    if not cmdtarget:
        cmdtarget = ('mon', '')

    app.logger.debug('sending command prefix %s argdict %s', prefix, argdict)

    for _ in range(DEFAULT_TRIES):
        ret, outbuf, outs = json_command(app.ceph_cluster,
                                         prefix=prefix,
                                         target=cmdtarget,
                                         inbuf=flask.request.data,
                                         argdict=argdict,
                                         timeout=DEFAULT_TIMEOUT)
        if ret != -errno.EINTR:
            break
    else:
        return make_response(fmt, '', 'Timedout: {0} ({1})'.format(outs, ret),
                             504)
    if ret:
        return make_response(fmt, '', 'Error: {0} ({1})'.format(outs, ret),
                             400)

    response = make_response(fmt, outbuf, outs or 'OK', 200)
    if fmt:
        contenttype = 'application/' + fmt.replace('-pretty', '')
    else:
        contenttype = 'text/plain'
    response.headers['Content-Type'] = contenttype
    return response
Пример #7
0
def handler(catchall_path=None, fmt=None, target=None):
    '''
    Main endpoint handler; generic for every endpoint, including catchall.
    Handles the catchall, anything with <.fmt>, anything with embedded
    <target>.  Partial match or ?help cause the HTML-table
    "show_human_help" output.
    '''

    ep = catchall_path or flask.request.endpoint
    ep = ep.replace('.<fmt>', '')

    if ep[0] != '/':
        ep = '/' + ep

    # demand that endpoint begin with app.ceph_baseurl
    if not ep.startswith(app.ceph_baseurl):
        return make_response(fmt, '', 'Page not found', 404)

    rel_ep = ep[len(app.ceph_baseurl) + 1:]

    # Extensions override Accept: headers override defaults
    if not fmt:
        if 'application/json' in flask.request.accept_mimetypes.values():
            fmt = 'json'
        elif 'application/xml' in flask.request.accept_mimetypes.values():
            fmt = 'xml'

    prefix = ''
    pgid = None
    cmdtarget = 'mon', ''

    if target:
        # got tell/<target>; validate osdid or pgid
        name = CephOsdName()
        pgidobj = CephPgid()
        try:
            name.valid(target)
        except ArgumentError:
            # try pgid
            try:
                pgidobj.valid(target)
            except ArgumentError:
                return flask.make_response("invalid osdid or pgid", 400)
            else:
                # it's a pgid
                pgid = pgidobj.val
                cmdtarget = 'pg', pgid
        else:
            # it's an osd
            cmdtarget = name.nametype, name.nameid

        # prefix does not include tell/<target>/
        prefix = ' '.join(rel_ep.split('/')[2:]).strip()
    else:
        # non-target command: prefix is entire path
        prefix = ' '.join(rel_ep.split('/')).strip()

    # show "match as much as you gave me" help for unknown endpoints
    if ep not in app.ceph_urls:
        helptext = show_human_help(prefix)
        if helptext:
            resp = flask.make_response(helptext, 400)
            resp.headers['Content-Type'] = 'text/html'
            return resp
        else:
            return make_response(fmt, '', 'Invalid endpoint ' + ep, 400)

    found = None
    exc = ''
    for urldict in app.ceph_urls[ep]:
        if flask.request.method not in urldict['methods']:
            continue
        paramsig = urldict['paramsig']

        # allow '?help' for any specifically-known endpoint
        if 'help' in flask.request.args:
            response = flask.make_response('{0}: {1}'.
                                           format(prefix +
                                                  concise_sig(paramsig),
                                                  urldict['help']))
            response.headers['Content-Type'] = 'text/plain'
            return response

        # if there are parameters for this endpoint, process them
        if paramsig:
            args = {}
            for k, l in flask.request.args.iterlists():
                if len(l) == 1:
                    args[k] = l[0]
                else:
                    args[k] = l

            # is this a valid set of params?
            try:
                argdict = validate(args, paramsig)
                found = urldict
                break
            except Exception as e:
                exc += str(e)
                continue
        else:
            if flask.request.args:
                continue
            found = urldict
            argdict = {}
            break

    if not found:
        return make_response(fmt, '', exc + '\n', 400)

    argdict['format'] = fmt or 'plain'
    argdict['module'] = found['module']
    argdict['perm'] = found['perm']
    if pgid:
        argdict['pgid'] = pgid

    if not cmdtarget:
        cmdtarget = ('mon', '')

    app.logger.debug('sending command prefix %s argdict %s', prefix, argdict)
    ret, outbuf, outs = json_command(app.ceph_cluster, prefix=prefix,
                                     target=cmdtarget,
                                     inbuf=flask.request.data, argdict=argdict)
    if ret:
        return make_response(fmt, '', 'Error: {0} ({1})'.format(outs, ret), 400)

    response = make_response(fmt, outbuf, outs or 'OK', 200)
    if fmt:
        contenttype = 'application/' + fmt.replace('-pretty', '')
    else:
        contenttype = 'text/plain'
    response.headers['Content-Type'] = contenttype
    return response
Пример #8
0
def handler(catchall_path=None, fmt=None, target=None):
    """
    Main endpoint handler; generic for every endpoint, including catchall.
    Handles the catchall, anything with <.fmt>, anything with embedded
    <target>.  Partial match or ?help cause the HTML-table
    "show_human_help" output.
    """

    ep = catchall_path or flask.request.endpoint
    ep = ep.replace(".<fmt>", "")

    if ep[0] != "/":
        ep = "/" + ep

    # demand that endpoint begin with app.ceph_baseurl
    if not ep.startswith(app.ceph_baseurl):
        return make_response(fmt, "", "Page not found", 404)

    rel_ep = ep[len(app.ceph_baseurl) + 1 :]

    # Extensions override Accept: headers override defaults
    if not fmt:
        if "application/json" in flask.request.accept_mimetypes.values():
            fmt = "json"
        elif "application/xml" in flask.request.accept_mimetypes.values():
            fmt = "xml"

    prefix = ""
    pgid = None
    cmdtarget = "mon", ""

    if target:
        # got tell/<target>; validate osdid or pgid
        name = CephOsdName()
        pgidobj = CephPgid()
        try:
            name.valid(target)
        except ArgumentError:
            # try pgid
            try:
                pgidobj.valid(target)
            except ArgumentError:
                return flask.make_response("invalid osdid or pgid", 400)
            else:
                # it's a pgid
                pgid = pgidobj.val
                cmdtarget = "pg", pgid
        else:
            # it's an osd
            cmdtarget = name.nametype, name.nameid

        # prefix does not include tell/<target>/
        prefix = " ".join(rel_ep.split("/")[2:]).strip()
    else:
        # non-target command: prefix is entire path
        prefix = " ".join(rel_ep.split("/")).strip()

    # show "match as much as you gave me" help for unknown endpoints
    if not ep in app.ceph_urls:
        helptext = show_human_help(prefix)
        if helptext:
            resp = flask.make_response(helptext, 400)
            resp.headers["Content-Type"] = "text/html"
            return resp
        else:
            return make_response(fmt, "", "Invalid endpoint " + ep, 400)

    found = None
    exc = ""
    for urldict in app.ceph_urls[ep]:
        if flask.request.method not in urldict["methods"]:
            continue
        paramsig = urldict["paramsig"]

        # allow '?help' for any specifically-known endpoint
        if "help" in flask.request.args:
            response = flask.make_response("{0}: {1}".format(prefix + concise_sig(paramsig), urldict["help"]))
            response.headers["Content-Type"] = "text/plain"
            return response

        # if there are parameters for this endpoint, process them
        if paramsig:
            args = {}
            for k, l in flask.request.args.iterlists():
                if len(l) == 1:
                    args[k] = l[0]
                else:
                    args[k] = l

            # is this a valid set of params?
            try:
                argdict = validate(args, paramsig)
                found = urldict
                break
            except Exception as e:
                exc += str(e)
                continue
        else:
            if flask.request.args:
                continue
            found = urldict
            argdict = {}
            break

    if not found:
        return make_response(fmt, "", exc + "\n", 400)

    argdict["format"] = fmt or "plain"
    argdict["module"] = found["module"]
    argdict["perm"] = found["perm"]
    if pgid:
        argdict["pgid"] = pgid

    if not cmdtarget:
        cmdtarget = ("mon", "")

    app.logger.debug("sending command prefix %s argdict %s", prefix, argdict)
    ret, outbuf, outs = json_command(
        app.ceph_cluster, prefix=prefix, target=cmdtarget, inbuf=flask.request.data, argdict=argdict
    )
    if ret:
        return make_response(fmt, "", "Error: {0} ({1})".format(outs, ret), 400)

    response = make_response(fmt, outbuf, outs or "OK", 200)
    if fmt:
        contenttype = "application/" + fmt.replace("-pretty", "")
    else:
        contenttype = "text/plain"
    response.headers["Content-Type"] = contenttype
    return response
Пример #9
0
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:
            if sys.stdin.isatty():
                # do the command-interpreter looping
                # for raw_input to do readline cmd editing
                import readline

            while True:
                interactive_input = read_input()
                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 >> sys.stderr, \
                            'error handling command target: {0}'.format(e)
                    return 1, '', ''
                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)