diff options
author | Sage Weil <sage@inktank.com> | 2013-08-08 22:18:16 -0700 |
---|---|---|
committer | Sage Weil <sage@inktank.com> | 2013-08-08 22:18:16 -0700 |
commit | 7e285149fb2616d59f5f70d722a28d8a0bbfcdb7 (patch) | |
tree | 443d66b4b318b10df6f91238344d70f7e1250c7c | |
parent | 469d30b851584b90c7de4e36372a49c02f9a2043 (diff) | |
parent | b2515b9e0b1e5e709716308a515026b3e6ff23b5 (diff) | |
download | ceph-7e285149fb2616d59f5f70d722a28d8a0bbfcdb7.tar.gz |
Merge remote-tracking branch 'gh/next'
35 files changed, 386 insertions, 167 deletions
diff --git a/qa/workunits/cephtool/test.sh b/qa/workunits/cephtool/test.sh index d759d675276..7915e48a6ed 100755 --- a/qa/workunits/cephtool/test.sh +++ b/qa/workunits/cephtool/test.sh @@ -25,6 +25,29 @@ expect_false() if "$@"; then return 1; else return 0; fi } +TMPFILE=/tmp/test_invalid.$$ +trap "rm $TMPFILE" 0 + +function check_response() +{ + retcode=$1 + expected_retcode=$2 + expected_stderr_string=$3 + if [ $1 != $2 ] ; then + echo "return code invalid: got $1, expected $2" >&2 + exit 1 + fi + + if ! grep "$3" $TMPFILE >/dev/null 2>&1 ; then + echo "Didn't find $3 in stderr output" >&2 + echo "Stderr: " >&2 + cat $TMPFILE >&2 + exit 1 + fi +} + + + # # Assumes there are at least 3 MDSes and two OSDs # @@ -132,6 +155,14 @@ ceph osd scrub 0 ceph osd deep-scrub 0 ceph osd repair 0 +for f in noup nodown noin noout noscrub nodeep-scrub nobackfill norecover +do + ceph osd set $f + ceph osd unset $f +done +expect_false ceph osd set bogus +expect_false ceph osd unset bogus + ceph osd set noup ceph osd down 0 ceph osd dump | grep 'osd.0 down' @@ -204,6 +235,14 @@ ceph pg debug unfound_objects_exist ceph pg debug degraded_pgs_exist ceph pg deep-scrub 0.0 ceph pg dump +ceph pg dump pgs_brief --format=json +ceph pg dump pgs --format=json +ceph pg dump pools --format=json +ceph pg dump osds --format=json +ceph pg dump sum --format=json +ceph pg dump all --format=json +ceph pg dump pgs_brief osds --format=json +ceph pg dump pools osds pgs_brief --format=json ceph pg dump_json ceph pg dump_pools_json ceph pg dump_stuck inactive @@ -225,6 +264,8 @@ ceph pg set_nearfull_ratio 0.90 ceph pg dump --format=plain | grep '^nearfull_ratio 0.9' ceph pg set_nearfull_ratio 0.85 ceph pg stat | grep 'pgs:' +ceph pg 0.0 query +ceph tell 0.0 query ceph quorum enter ceph quorum_status ceph report | grep osd_stats @@ -255,4 +296,18 @@ ceph osd pool get rbd crush_ruleset | grep 'crush_ruleset: 2' ceph osd thrash 10 +set +e + +# expect error about missing 'pool' argument +ceph osd map 2>$TMPFILE; check_response $? 22 'pool' + +# expect error about unused argument foo +ceph osd ls foo 2>$TMPFILE; check_response $? 22 'unused' + +# expect "not in range" for invalid full ratio +ceph pg set_full_ratio 95 2>$TMPFILE; check_response $? 22 'not in range' + +# expect "not in range" for invalid overload percentage +ceph osd reweight-by-utilization 80 2>$TMPFILE; check_response $? 22 'not in range' + echo OK diff --git a/qa/workunits/cephtool/test_daemon.sh b/qa/workunits/cephtool/test_daemon.sh index 8d2bd27f700..f598708d019 100755 --- a/qa/workunits/cephtool/test_daemon.sh +++ b/qa/workunits/cephtool/test_daemon.sh @@ -24,4 +24,7 @@ new_ms=$(sudo ceph daemon mon.a config get debug_ms | grep debug_ms | \ sed -e 's/.*: //' -e 's/["\}\\]//g') [ "$new_ms" = "$old_ms" ] +# unregistered/non-existent command +expect_false sudo ceph daemon mon.a bogus_command_blah foo + echo OK diff --git a/qa/workunits/rest/test.py b/qa/workunits/rest/test.py index 3fcf3fd75fb..c40ec916016 100755 --- a/qa/workunits/rest/test.py +++ b/qa/workunits/rest/test.py @@ -32,7 +32,7 @@ def expect_nofail(url, method, respcode, contenttype, extra_hdrs=None, f = fdict[method.lower()] r = f(BASEURL + '/' + url, headers=extra_hdrs, data=data) - print '{0}: {1} {2}'.format(url, contenttype, r.status_code) + print '{0} {1}: {2} {3}'.format(method, url, contenttype, r.status_code) if r.status_code != respcode: return 'expected {0}, got {1}'.format(respcode, r.status_code), r @@ -330,10 +330,7 @@ if __name__ == '__main__': r = expect('osd/ls', 'GET', 200, 'json', JSONHDR) for osdid in r.myjson['output']: - # XXX no tell yet - # expect('tell?target=osd.{0}&args=version'.format(osdid), 'PUT', - # 200, '') - print >> sys.stderr, 'would be telling osd.{0} version'.format(osdid) + expect('tell/osd.{0}/version'.format(osdid), 'GET', 200, '') expect('pg/debug?debugop=unfound_objects_exist', 'GET', 200, '') expect('pg/debug?debugop=degraded_pgs_exist', 'GET', 200, '') @@ -378,6 +375,7 @@ if __name__ == '__main__': r = expect('pg/stat', 'GET', 200, 'xml', XMLHDR) assert(r.tree.find('output/pg_map/pg_stats_sum') is not None) + expect('tell/0.0/query', 'GET', 200, 'json', JSONHDR) expect('quorum?quorumcmd=enter', 'PUT', 200, 'json', JSONHDR) expect('quorum?quorumcmd=enter', 'PUT', 200, 'xml', XMLHDR) expect('quorum_status', 'GET', 200, 'json', JSONHDR) @@ -394,15 +392,13 @@ if __name__ == '__main__': r = expect('status', 'GET', 200, 'xml', XMLHDR) assert(r.tree.find('output/status/osdmap') is not None) - # XXX tell not implemented yet - # r = expect('tell?target=osd.0&args=version', 'PUT', 200, '') - # assert('ceph version' in r.content) - # expect('tell?target=osd.999&args=version', 'PUT', 400, '') - # expect('tell?target=osd.foo&args=version', 'PUT', 400, '') + r = expect('tell/osd.0/version', 'GET', 200, '') + assert('ceph version' in r.content) + expect('tell/osd.999/version', 'GET', 400, '') + expect('tell/osd.foo/version', 'GET', 400, '') - - # r = expect('tell?target=osd.0&args=dump_get_recovery_stats', 'PUT', '200', '') - # assert('Started' in r.content) + r = expect('tell/osd.0/dump_pg_recovery_stats', 'GET', 200, '') + assert('Started' in r.content) expect('osd/reweight?id=0&weight=0.9', 'PUT', 200, '') expect('osd/reweight?id=0&weight=-1', 'PUT', 400, '') diff --git a/src/auth/KeyRing.cc b/src/auth/KeyRing.cc index 56655392bae..5a8b2288e6a 100644 --- a/src/auth/KeyRing.cc +++ b/src/auth/KeyRing.cc @@ -157,8 +157,7 @@ void KeyRing::encode_formatted(string label, Formatter *f, bufferlist& bl) f->close_section(); /* auth_entities */ } f->close_section(); /* auth_dump */ - f->flush(os); - bl.append(os.str()); + f->flush(bl); } void KeyRing::decode_plaintext(bufferlist::iterator& bli) diff --git a/src/ceph.in b/src/ceph.in index 0ae8df77cd7..144704ee05b 100755 --- a/src/ceph.in +++ b/src/ceph.in @@ -54,7 +54,10 @@ import string import struct import subprocess -from ceph_argparse import * +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 @@ -318,7 +321,7 @@ def admin_socket(asok_path, cmd, format=''): sigdict = parse_json_funcsigs(cmd_json, 'cli') valid_dict = validate_command(sigdict, cmd) if not valid_dict: - return -errno.EINVAL + raise RuntimeError('invalid command') if format: valid_dict['format'] = format @@ -393,10 +396,15 @@ def new_style_command(parsed_args, cmdargs, target, sigdict, inbuf, verbose): target=target, argdict=valid_dict) if ret: - sys.stderr.write('Error {0}: {1}'.format(ret, outs)) - return ret, '', outs + 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 "invalid command" + print >> sys.stderr, "Invalid command" if verbose: print >> sys.stderr, "Submitting command ", valid_dict @@ -512,6 +520,7 @@ def main(): print admin_socket(childargs[1], childargs[2:], format) except Exception as e: print >> sys.stderr, 'admin_socket: {0}'.format(e) + return errno.EINVAL return 0 else: # try resolve daemon name @@ -520,10 +529,11 @@ def main(): print admin_socket(path, childargs[2:], format) except Exception as e: print >> sys.stderr, 'admin_socket: {0}'.format(e) + return errno.EINVAL return 0 else: print >> sys.stderr, 'Daemon requires at least 2 arguments' - return 1 + return errno.EINVAL # handle any 'generic' ceph arguments that we didn't parse here global cluster_handle diff --git a/src/client/Client.cc b/src/client/Client.cc index af465cb78bc..4b10cf5c1ba 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -117,8 +117,7 @@ bool Client::CommandHook::call(std::string command, cmdmap_t& cmdmap, else assert(0 == "bad command registered"); m_client->client_lock.Unlock(); - f->flush(ss); - out.append(ss); + f->flush(out); delete f; return true; } diff --git a/src/common/cmdparse.cc b/src/common/cmdparse.cc index 370591cb3bb..16c62349c40 100644 --- a/src/common/cmdparse.cc +++ b/src/common/cmdparse.cc @@ -27,7 +27,7 @@ using namespace std; */ void -dump_cmd_to_json(JSONFormatter *f, const string& cmd) +dump_cmd_to_json(Formatter *f, const string& cmd) { // put whole command signature in an already-opened container // elements are: "name", meaning "the typeless name that means a literal" @@ -77,7 +77,7 @@ dump_cmd_to_json(JSONFormatter *f, const string& cmd) } void -dump_cmd_and_help_to_json(JSONFormatter *jf, +dump_cmd_and_help_to_json(Formatter *jf, const string& secname, const string& cmdsig, const string& helptext) @@ -91,7 +91,7 @@ dump_cmd_and_help_to_json(JSONFormatter *jf, } void -dump_cmddesc_to_json(JSONFormatter *jf, +dump_cmddesc_to_json(Formatter *jf, const string& secname, const string& cmdsig, const string& helptext, diff --git a/src/common/cmdparse.h b/src/common/cmdparse.h index 58c66b46052..10e43ab0abe 100644 --- a/src/common/cmdparse.h +++ b/src/common/cmdparse.h @@ -20,12 +20,12 @@ class CephContext; typedef boost::variant<std::string, bool, int64_t, double, std::vector<std::string> > cmd_vartype; typedef std::map<std::string, cmd_vartype> cmdmap_t; -void dump_cmd_to_json(ceph::JSONFormatter *f, const std::string& cmd); -void dump_cmd_and_help_to_json(ceph::JSONFormatter *f, +void dump_cmd_to_json(ceph::Formatter *f, const std::string& cmd); +void dump_cmd_and_help_to_json(ceph::Formatter *f, const std::string& secname, const std::string& cmd, const std::string& helptext); -void dump_cmddesc_to_json(JSONFormatter *jf, +void dump_cmddesc_to_json(ceph::Formatter *jf, const std::string& secname, const std::string& cmdsig, const std::string& helptext, diff --git a/src/common/config_opts.h b/src/common/config_opts.h index 1c7a917602a..f67d0d1237d 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -426,7 +426,8 @@ OPTION(osd_default_data_pool_replay_window, OPT_INT, 45) OPTION(osd_preserve_trimmed_log, OPT_BOOL, false) OPTION(osd_auto_mark_unfound_lost, OPT_BOOL, false) OPTION(osd_recovery_delay_start, OPT_FLOAT, 0) -OPTION(osd_recovery_max_active, OPT_INT, 5) +OPTION(osd_recovery_max_active, OPT_INT, 60) +OPTION(osd_recovery_max_single_start, OPT_INT, 10) OPTION(osd_recovery_max_chunk, OPT_U64, 8<<20) // max size of push chunk OPTION(osd_push_per_object_cost, OPT_U64, 1000) // push cost per object OPTION(osd_max_push_cost, OPT_U64, 8<<20) // max size of push message @@ -489,9 +490,13 @@ OPTION(osd_leveldb_log, OPT_STR, "") // enable OSD leveldb log file * osd_client_op_priority/osd_recovery_op_priority determines the ratio of * available io between client and recovery. Each option may be set between * 1..63. + * + * osd_recovery_op_warn_multiple scales the normal warning threshhold, + * osd_op_complaint_time, so that slow recovery ops won't cause noise */ -OPTION(osd_client_op_priority, OPT_INT, 63) -OPTION(osd_recovery_op_priority, OPT_INT, 10) +OPTION(osd_client_op_priority, OPT_U32, 63) +OPTION(osd_recovery_op_priority, OPT_U32, 10) +OPTION(osd_recovery_op_warn_multiple, OPT_U32, 16) // Max time to wait between notifying mon of shutdown and shutting down OPTION(osd_mon_shutdown_timeout, OPT_DOUBLE, 5) diff --git a/src/include/buffer.h b/src/include/buffer.h index 99c1985e616..8c4dfb56e17 100644 --- a/src/include/buffer.h +++ b/src/include/buffer.h @@ -16,17 +16,18 @@ #define CEPH_BUFFER_H #if defined(__linux__) +#include <stdlib.h> #include <linux/types.h> #elif defined(__FreeBSD__) #include <sys/types.h> #include "include/inttypes.h" +#include <stdlib.h> #endif #ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 600 #endif -#include <stdlib.h> #include <stdio.h> #ifdef DARWIN diff --git a/src/mon/AuthMonitor.cc b/src/mon/AuthMonitor.cc index 629451b5eac..f165b8c9fc7 100644 --- a/src/mon/AuthMonitor.cc +++ b/src/mon/AuthMonitor.cc @@ -626,7 +626,6 @@ bool AuthMonitor::preprocess_command(MMonCommand *m) } else if (prefix == "auth list") { if (f) { mon->key_server.encode_formatted("auth", f.get(), rdata); - f->flush(rdata); } else { mon->key_server.encode_plaintext(rdata); if (rdata.length() > 0) diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h index 0980893bf9b..8e9c2bb333b 100644 --- a/src/mon/MonCommands.h +++ b/src/mon/MonCommands.h @@ -111,7 +111,7 @@ COMMAND("pg getmap", "get binary pg map to -o/stdout", "pg", "r", "cli,rest") COMMAND("pg send_pg_creates", "trigger pg creates to be issued",\ "pg", "rw", "cli,rest") COMMAND("pg dump " \ - "name=dumpcontents,type=CephChoices,strings=all|summary|sum|pools|osds|pgs,n=N,req=false", \ + "name=dumpcontents,type=CephChoices,strings=all|summary|sum|pools|osds|pgs|pgs_brief,n=N,req=false", \ "show human-readable versions of pg map", "pg", "r", "cli,rest") COMMAND("pg dump_json " \ "name=dumpcontents,type=CephChoices,strings=all|summary|sum|pools|osds|pgs,n=N,req=false", \ @@ -418,8 +418,7 @@ COMMAND("osd crush rule create-simple " \ "create crush rule <name> in <root> of type <type>", \ "osd", "rw", "cli,rest") COMMAND("osd crush rule rm " \ - "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] " \ - "name=name,type=CephString", \ + "name=name,type=CephString,goodchars=[A-Za-z0-9-_.] ", \ "remove crush rule <name>", "osd", "rw", "cli,rest") COMMAND("osd setmaxosd " \ "name=newmax,type=CephInt,range=0", \ @@ -427,10 +426,10 @@ COMMAND("osd setmaxosd " \ COMMAND("osd pause", "pause osd", "osd", "rw", "cli,rest") COMMAND("osd unpause", "unpause osd", "osd", "rw", "cli,rest") COMMAND("osd set " \ - "name=key,type=CephChoices,strings=pause|noup|nodown|noout|noin|nobackfile|norecover", \ + "name=key,type=CephChoices,strings=pause|noup|nodown|noout|noin|nobackfill|norecover|noscrub|nodeep-scrub", \ "set <key>", "osd", "rw", "cli,rest") COMMAND("osd unset " \ - "name=key,type=CephChoices,strings=pause|noup|nodown|noout|noin|nobackfile|norecover", \ + "name=key,type=CephChoices,strings=pause|noup|nodown|noout|noin|nobackfill|norecover|noscrub|nodeep-scrub", \ "unset <key>", "osd", "rw", "cli,rest") COMMAND("osd cluster_snap", "take cluster snapshot (disabled)", \ "osd", "r", "") diff --git a/src/mon/Monitor.cc b/src/mon/Monitor.cc index 118cf6f4a1e..a9d3e48a3be 100644 --- a/src/mon/Monitor.cc +++ b/src/mon/Monitor.cc @@ -1937,7 +1937,7 @@ void Monitor::handle_command(MMonCommand *m) cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); if (prefix == "get_command_descriptions") { int cmdnum = 0; - JSONFormatter *f = new JSONFormatter(); + Formatter *f = new_formatter("json"); f->open_object_section("command_descriptions"); for (MonCommand *cp = mon_commands; cp < &mon_commands[ARRAY_SIZE(mon_commands)]; cp++) { @@ -1952,9 +1952,8 @@ void Monitor::handle_command(MMonCommand *m) f->close_section(); // command_descriptions bufferlist rdata; - f->flush(ds); + f->flush(rdata); delete f; - rdata.append(ds); reply_command(m, 0, "", rdata, 0); return; } @@ -2016,13 +2015,13 @@ void Monitor::handle_command(MMonCommand *m) } if (prefix == "fsid") { - ds << monmap->fsid; if (f) { f->open_object_section("fsid"); f->dump_stream("fsid") << monmap->fsid; f->close_section(); f->flush(rdata); } else { + ds << monmap->fsid; rdata.append(ds); } reply_command(m, 0, "", rdata, 0); diff --git a/src/mon/OSDMonitor.cc b/src/mon/OSDMonitor.cc index c6db052a591..07022aec73b 100644 --- a/src/mon/OSDMonitor.cc +++ b/src/mon/OSDMonitor.cc @@ -1966,8 +1966,9 @@ bool OSDMonitor::preprocess_command(MMonCommand *m) if (prefix == "osd stat") { osdmap.print_summary(f.get(), ds); if (f) - f->flush(ds); - rdata.append(ds); + f->flush(rdata); + else + rdata.append(ds); } else if (prefix == "osd dump" || prefix == "osd tree" || @@ -2080,9 +2081,7 @@ bool OSDMonitor::preprocess_command(MMonCommand *m) f->dump_string(p->first.c_str(), p->second); f->close_section(); f->close_section(); - f->flush(ds); - ds << "\n"; - rdata.append(ds); + f->flush(rdata); } else if (prefix == "osd map") { string poolstr, objstr, namespacestr; cmd_getval(g_ceph_context, cmdmap, "pool", poolstr); @@ -3072,6 +3071,10 @@ bool OSDMonitor::prepare_command(MMonCommand *m) return prepare_set_flag(m, CEPH_OSDMAP_NOBACKFILL); else if (key == "norecover") return prepare_set_flag(m, CEPH_OSDMAP_NORECOVER); + else if (key == "noscrub") + return prepare_set_flag(m, CEPH_OSDMAP_NOSCRUB); + else if (key == "nodeep-scrub") + return prepare_set_flag(m, CEPH_OSDMAP_NODEEP_SCRUB); } else if (prefix == "osd unset") { string key; @@ -3090,6 +3093,10 @@ bool OSDMonitor::prepare_command(MMonCommand *m) return prepare_unset_flag(m, CEPH_OSDMAP_NOBACKFILL); else if (key == "norecover") return prepare_unset_flag(m, CEPH_OSDMAP_NORECOVER); + else if (key == "noscrub") + return prepare_unset_flag(m, CEPH_OSDMAP_NOSCRUB); + else if (key == "nodeep-scrub") + return prepare_unset_flag(m, CEPH_OSDMAP_NODEEP_SCRUB); } else if (prefix == "osd cluster_snap") { // ** DISABLE THIS FOR NOW ** diff --git a/src/mon/PGMap.cc b/src/mon/PGMap.cc index 86ad87bd929..f6b88fcbfe0 100644 --- a/src/mon/PGMap.cc +++ b/src/mon/PGMap.cc @@ -494,7 +494,7 @@ void PGMap::dirty_all(Incremental& inc) void PGMap::dump(Formatter *f) const { dump_basic(f); - dump_pg_stats(f); + dump_pg_stats(f, false); dump_pool_stats(f); dump_osd_stats(f); } @@ -521,7 +521,7 @@ void PGMap::dump_basic(Formatter *f) const f->close_section(); } -void PGMap::dump_pg_stats(Formatter *f) const +void PGMap::dump_pg_stats(Formatter *f, bool brief) const { f->open_array_section("pg_stats"); for (hash_map<pg_t,pg_stat_t>::const_iterator i = pg_stat.begin(); @@ -529,7 +529,10 @@ void PGMap::dump_pg_stats(Formatter *f) const ++i) { f->open_object_section("pg_stat"); f->dump_stream("pgid") << i->first; - i->second.dump(f); + if (brief) + i->second.dump_brief(f); + else + i->second.dump(f); f->close_section(); } f->close_section(); diff --git a/src/mon/PGMap.h b/src/mon/PGMap.h index 16c2f84b99e..e59d1b81a20 100644 --- a/src/mon/PGMap.h +++ b/src/mon/PGMap.h @@ -155,7 +155,7 @@ public: void dump(Formatter *f) const; void dump_basic(Formatter *f) const; - void dump_pg_stats(Formatter *f) const; + void dump_pg_stats(Formatter *f, bool brief) const; void dump_pool_stats(Formatter *f) const; void dump_osd_stats(Formatter *f) const; diff --git a/src/mon/PGMonitor.cc b/src/mon/PGMonitor.cc index 93b0b0b3828..29c77dbe0ed 100644 --- a/src/mon/PGMonitor.cc +++ b/src/mon/PGMonitor.cc @@ -1358,7 +1358,6 @@ bool PGMonitor::preprocess_command(MMonCommand *m) } else { ds << pg_map; } - rdata.append(ds); r = 0; } else if (prefix == "pg getmap") { pg_map.encode(rdata); @@ -1404,7 +1403,10 @@ bool PGMonitor::preprocess_command(MMonCommand *m) pg_map.dump_osd_stats(f.get()); } if (what.count("pgs")) { - pg_map.dump_pg_stats(f.get()); + pg_map.dump_pg_stats(f.get(), false); + } + if (what.count("pgs_brief")) { + pg_map.dump_pg_stats(f.get(), true); } } f->flush(ds); diff --git a/src/osd/OSD.cc b/src/osd/OSD.cc index 69c181862cc..1a77dae730a 100644 --- a/src/osd/OSD.cc +++ b/src/osd/OSD.cc @@ -3935,7 +3935,6 @@ void OSD::do_command(Connection *con, tid_t tid, vector<string>& cmd, bufferlist f->close_section(); // command_descriptions f->flush(ds); - odata.append(ds); delete f; goto out; } @@ -6633,11 +6632,12 @@ bool OSD::_recover_now() return true; } -void OSD::do_recovery(PG *pg) +void OSD::do_recovery(PG *pg, ThreadPool::TPHandle &handle) { // see how many we should try to start. note that this is a bit racy. recovery_wq.lock(); - int max = g_conf->osd_recovery_max_active - recovery_ops_active; + int max = MAX(g_conf->osd_recovery_max_active - recovery_ops_active, + g_conf->osd_recovery_max_single_start); if (max > 0) { dout(10) << "do_recovery can start " << max << " (" << recovery_ops_active << "/" << g_conf->osd_recovery_max_active << " rops)" << dendl; @@ -6653,7 +6653,7 @@ void OSD::do_recovery(PG *pg) recovery_wq.queue(pg); return; } else { - pg->lock(); + pg->lock_suspend_timeout(handle); if (pg->deleting || !(pg->is_active() && pg->is_primary())) { pg->unlock(); goto out; @@ -6665,7 +6665,7 @@ void OSD::do_recovery(PG *pg) #endif PG::RecoveryCtx rctx = create_context(); - int started = pg->start_recovery_ops(max, &rctx); + int started = pg->start_recovery_ops(max, &rctx, handle); dout(10) << "do_recovery started " << started << "/" << max << " on " << *pg << dendl; /* @@ -7053,7 +7053,7 @@ void OSD::OpWQ::_process(PGRef pg, ThreadPool::TPHandle &handle) if (!(pg_for_processing[&*pg].size())) pg_for_processing.erase(&*pg); } - osd->dequeue_op(pg, op); + osd->dequeue_op(pg, op, handle); pg->unlock(); } @@ -7066,7 +7066,9 @@ void OSDService::dequeue_pg(PG *pg, list<OpRequestRef> *dequeued) /* * NOTE: dequeue called in worker thread, with pg lock */ -void OSD::dequeue_op(PGRef pg, OpRequestRef op) +void OSD::dequeue_op( + PGRef pg, OpRequestRef op, + ThreadPool::TPHandle &handle) { utime_t latency = ceph_clock_now(g_ceph_context) - op->request->get_recv_stamp(); dout(10) << "dequeue_op " << op << " prio " << op->request->get_priority() @@ -7079,7 +7081,7 @@ void OSD::dequeue_op(PGRef pg, OpRequestRef op) op->mark_reached_pg(); - pg->do_request(op); + pg->do_request(op, handle); // finish dout(10) << "dequeue_op " << op << " finish" << dendl; @@ -7131,7 +7133,7 @@ void OSD::process_peering_events( ++i) { set<boost::intrusive_ptr<PG> > split_pgs; PG *pg = *i; - pg->lock(); + pg->lock_suspend_timeout(handle); curmap = service.get_osdmap(); if (pg->deleting) { pg->unlock(); diff --git a/src/osd/OSD.h b/src/osd/OSD.h index 5196a1dc1f3..82a251d9a80 100644 --- a/src/osd/OSD.h +++ b/src/osd/OSD.h @@ -915,7 +915,9 @@ private: } op_wq; void enqueue_op(PG *pg, OpRequestRef op); - void dequeue_op(PGRef pg, OpRequestRef op); + void dequeue_op( + PGRef pg, OpRequestRef op, + ThreadPool::TPHandle &handle); // -- peering queue -- struct PeeringWQ : public ThreadPool::BatchWorkQueue<PG> { @@ -1371,8 +1373,8 @@ protected: osd->recovery_queue.push_front(&pg->recovery_item); } } - void _process(PG *pg) { - osd->do_recovery(pg); + void _process(PG *pg, ThreadPool::TPHandle &handle) { + osd->do_recovery(pg, handle); pg->put("RecoveryWQ"); } void _clear() { @@ -1386,7 +1388,7 @@ protected: void start_recovery_op(PG *pg, const hobject_t& soid); void finish_recovery_op(PG *pg, const hobject_t& soid, bool dequeue); - void do_recovery(PG *pg); + void do_recovery(PG *pg, ThreadPool::TPHandle &handle); bool _recover_now(); // replay / delayed pg activation diff --git a/src/osd/OpRequest.cc b/src/osd/OpRequest.cc index a6cdc9ecffb..c694362a8a5 100644 --- a/src/osd/OpRequest.cc +++ b/src/osd/OpRequest.cc @@ -20,6 +20,22 @@ static ostream& _prefix(std::ostream* _dout) return *_dout << "--OSD::tracker-- "; } +OpRequest::OpRequest(Message *req, OpTracker *tracker) : + request(req), xitem(this), + rmw_flags(0), + warn_interval_multiplier(1), + lock("OpRequest::lock"), + tracker(tracker), + hit_flag_points(0), latest_flag_point(0), + seq(0) { + received_time = request->get_recv_stamp(); + tracker->register_inflight_op(&xitem); + if (req->get_priority() < g_conf->osd_client_op_priority) { + // don't warn as quickly for low priority ops + warn_interval_multiplier = g_conf->osd_recovery_op_warn_multiple; + } +} + void OpHistory::on_shutdown() { arrived.clear(); diff --git a/src/osd/OpRequest.h b/src/osd/OpRequest.h index a2014472432..e72f03d1d77 100644 --- a/src/osd/OpRequest.h +++ b/src/osd/OpRequest.h @@ -156,17 +156,7 @@ private: static const uint8_t flag_sub_op_sent = 1 << 4; static const uint8_t flag_commit_sent = 1 << 5; - OpRequest(Message *req, OpTracker *tracker) : - request(req), xitem(this), - rmw_flags(0), - warn_interval_multiplier(1), - lock("OpRequest::lock"), - tracker(tracker), - hit_flag_points(0), latest_flag_point(0), - seq(0) { - received_time = request->get_recv_stamp(); - tracker->register_inflight_op(&xitem); - } + OpRequest(Message *req, OpTracker *tracker); public: ~OpRequest() { assert(request); diff --git a/src/osd/PG.cc b/src/osd/PG.cc index f731441e8a4..8e78eaa7a16 100644 --- a/src/osd/PG.cc +++ b/src/osd/PG.cc @@ -1397,7 +1397,9 @@ void PG::queue_op(OpRequestRef op) osd->op_wq.queue(make_pair(PGRef(this), op)); } -void PG::do_request(OpRequestRef op) +void PG::do_request( + OpRequestRef op, + ThreadPool::TPHandle &handle) { // do any pending flush do_pending_flush(); @@ -1435,7 +1437,7 @@ void PG::do_request(OpRequestRef op) break; case MSG_OSD_PG_SCAN: - do_scan(op); + do_scan(op, handle); break; case MSG_OSD_PG_BACKFILL: @@ -4510,7 +4512,7 @@ void PG::start_flush(ObjectStore::Transaction *t, FlushStateRef flush_trigger( new FlushState(this, get_osdmap()->get_epoch())); t->nop(); - flushed = false; + assert(!flushed); on_applied->push_back(new ContainerContext<FlushStateRef>(flush_trigger)); on_safe->push_back(new ContainerContext<FlushStateRef>(flush_trigger)); } @@ -5217,6 +5219,7 @@ PG::RecoveryState::Reset::Reset(my_context ctx) state_name = "Reset"; context< RecoveryMachine >().log_enter(state_name); PG *pg = context< RecoveryMachine >().pg; + pg->flushed = false; pg->set_last_peering_reset(); } diff --git a/src/osd/PG.h b/src/osd/PG.h index 8f572c75e19..d4679ce4fd8 100644 --- a/src/osd/PG.h +++ b/src/osd/PG.h @@ -645,7 +645,9 @@ public: virtual void check_local() = 0; - virtual int start_recovery_ops(int max, RecoveryCtx *prctx) = 0; + virtual int start_recovery_ops( + int max, RecoveryCtx *prctx, + ThreadPool::TPHandle &handle) = 0; void purge_strays(); @@ -1804,12 +1806,18 @@ public: // abstract bits - void do_request(OpRequestRef op); + void do_request( + OpRequestRef op, + ThreadPool::TPHandle &handle + ); virtual void do_op(OpRequestRef op) = 0; virtual void do_sub_op(OpRequestRef op) = 0; virtual void do_sub_op_reply(OpRequestRef op) = 0; - virtual void do_scan(OpRequestRef op) = 0; + virtual void do_scan( + OpRequestRef op, + ThreadPool::TPHandle &handle + ) = 0; virtual void do_backfill(OpRequestRef op) = 0; virtual void do_push(OpRequestRef op) = 0; virtual void do_pull(OpRequestRef op) = 0; diff --git a/src/osd/ReplicatedPG.cc b/src/osd/ReplicatedPG.cc index 658ea7cb746..ab9c8099a44 100644 --- a/src/osd/ReplicatedPG.cc +++ b/src/osd/ReplicatedPG.cc @@ -1252,7 +1252,9 @@ void ReplicatedPG::do_sub_op_reply(OpRequestRef op) sub_op_modify_reply(op); } -void ReplicatedPG::do_scan(OpRequestRef op) +void ReplicatedPG::do_scan( + OpRequestRef op, + ThreadPool::TPHandle &handle) { MOSDPGScan *m = static_cast<MOSDPGScan*>(op->request); assert(m->get_header().type == MSG_OSD_PG_SCAN); @@ -1278,7 +1280,9 @@ void ReplicatedPG::do_scan(OpRequestRef op) BackfillInterval bi; osr->flush(); - scan_range(m->begin, g_conf->osd_backfill_scan_min, g_conf->osd_backfill_scan_max, &bi); + scan_range( + m->begin, g_conf->osd_backfill_scan_min, + g_conf->osd_backfill_scan_max, &bi, handle); MOSDPGScan *reply = new MOSDPGScan(MOSDPGScan::OP_SCAN_DIGEST, get_osdmap()->get_epoch(), m->query_epoch, info.pgid, bi.begin, bi.end); @@ -6875,7 +6879,9 @@ void ReplicatedPG::check_recovery_sources(const OSDMapRef osdmap) } -int ReplicatedPG::start_recovery_ops(int max, RecoveryCtx *prctx) +int ReplicatedPG::start_recovery_ops( + int max, RecoveryCtx *prctx, + ThreadPool::TPHandle &handle) { int started = 0; assert(is_primary()); @@ -6898,15 +6904,15 @@ int ReplicatedPG::start_recovery_ops(int max, RecoveryCtx *prctx) if (num_missing == num_unfound) { // All of the missing objects we have are unfound. // Recover the replicas. - started = recover_replicas(max); + started = recover_replicas(max, handle); } if (!started) { // We still have missing objects that we should grab from replicas. - started += recover_primary(max); + started += recover_primary(max, handle); } if (!started && num_unfound != get_num_unfound()) { // second chance to recovery replicas - started = recover_replicas(max); + started = recover_replicas(max, handle); } bool deferred_backfill = false; @@ -6931,7 +6937,7 @@ int ReplicatedPG::start_recovery_ops(int max, RecoveryCtx *prctx) } deferred_backfill = true; } else { - started += recover_backfill(max - started); + started += recover_backfill(max - started, handle); } } @@ -6993,7 +6999,7 @@ int ReplicatedPG::start_recovery_ops(int max, RecoveryCtx *prctx) * do one recovery op. * return true if done, false if nothing left to do. */ -int ReplicatedPG::recover_primary(int max) +int ReplicatedPG::recover_primary(int max, ThreadPool::TPHandle &handle) { assert(is_primary()); @@ -7012,6 +7018,7 @@ int ReplicatedPG::recover_primary(int max) map<version_t, hobject_t>::const_iterator p = missing.rmissing.lower_bound(pg_log.get_log().last_requested); while (p != missing.rmissing.end()) { + handle.reset_tp_timeout(); hobject_t soid; version_t v = p->first; @@ -7204,7 +7211,7 @@ int ReplicatedPG::prep_object_replica_pushes( return 1; } -int ReplicatedPG::recover_replicas(int max) +int ReplicatedPG::recover_replicas(int max, ThreadPool::TPHandle &handle) { dout(10) << __func__ << "(" << max << ")" << dendl; int started = 0; @@ -7226,6 +7233,7 @@ int ReplicatedPG::recover_replicas(int max) for (map<version_t, hobject_t>::const_iterator p = m.rmissing.begin(); p != m.rmissing.end() && started < max; ++p) { + handle.reset_tp_timeout(); const hobject_t soid(p->second); if (pushing.count(soid)) { @@ -7275,7 +7283,9 @@ int ReplicatedPG::recover_replicas(int max) * peer_info[backfill_target].last_backfill = MIN(peer_backfill_info.begin, * backfill_info.begin, backfills_in_flight) */ -int ReplicatedPG::recover_backfill(int max) +int ReplicatedPG::recover_backfill( + int max, + ThreadPool::TPHandle &handle) { dout(10) << "recover_backfill (" << max << ")" << dendl; assert(backfill_target >= 0); @@ -7305,7 +7315,7 @@ int ReplicatedPG::recover_backfill(int max) dout(10) << " rescanning local backfill_info from " << backfill_pos << dendl; backfill_info.clear(); osr->flush(); - scan_range(backfill_pos, local_min, local_max, &backfill_info); + scan_range(backfill_pos, local_min, local_max, &backfill_info, handle); int ops = 0; map<hobject_t, pair<eversion_t, eversion_t> > to_push; @@ -7319,7 +7329,8 @@ int ReplicatedPG::recover_backfill(int max) if (backfill_info.begin <= pbi.begin && !backfill_info.extends_to_end() && backfill_info.empty()) { osr->flush(); - scan_range(backfill_info.end, local_min, local_max, &backfill_info); + scan_range(backfill_info.end, local_min, local_max, &backfill_info, + handle); backfill_info.trim(); } backfill_pos = backfill_info.begin > pbi.begin ? pbi.begin : backfill_info.begin; @@ -7407,6 +7418,7 @@ int ReplicatedPG::recover_backfill(int max) for (map<hobject_t, eversion_t>::iterator i = to_remove.begin(); i != to_remove.end(); ++i) { + handle.reset_tp_timeout(); send_remove_op(i->first, i->second, backfill_target); } @@ -7414,6 +7426,7 @@ int ReplicatedPG::recover_backfill(int max) for (map<hobject_t, pair<eversion_t, eversion_t> >::iterator i = to_push.begin(); i != to_push.end(); ++i) { + handle.reset_tp_timeout(); prep_backfill_object_push( i->first, i->second.first, i->second.second, backfill_target, &pushes); } @@ -7480,7 +7493,9 @@ void ReplicatedPG::prep_backfill_object_push( put_object_context(obc); } -void ReplicatedPG::scan_range(hobject_t begin, int min, int max, BackfillInterval *bi) +void ReplicatedPG::scan_range( + hobject_t begin, int min, int max, BackfillInterval *bi, + ThreadPool::TPHandle &handle) { assert(is_locked()); dout(10) << "scan_range from " << begin << dendl; @@ -7496,6 +7511,7 @@ void ReplicatedPG::scan_range(hobject_t begin, int min, int max, BackfillInterva dout(20) << ls << dendl; for (vector<hobject_t>::iterator p = ls.begin(); p != ls.end(); ++p) { + handle.reset_tp_timeout(); ObjectContext *obc = NULL; if (is_primary()) obc = _lookup_object_context(*p); diff --git a/src/osd/ReplicatedPG.h b/src/osd/ReplicatedPG.h index 7b70b4381ea..41c8106ea00 100644 --- a/src/osd/ReplicatedPG.h +++ b/src/osd/ReplicatedPG.h @@ -759,10 +759,13 @@ protected: void _clear_recovery_state(); void queue_for_recovery(); - int start_recovery_ops(int max, RecoveryCtx *prctx); - int recover_primary(int max); - int recover_replicas(int max); - int recover_backfill(int max); + int start_recovery_ops( + int max, RecoveryCtx *prctx, + ThreadPool::TPHandle &handle); + + int recover_primary(int max, ThreadPool::TPHandle &handle); + int recover_replicas(int max, ThreadPool::TPHandle &handle); + int recover_backfill(int max, ThreadPool::TPHandle &handle); /** * scan a (hash) range of objects in the current pg @@ -772,7 +775,10 @@ protected: * @max return no more than this many items * @bi [out] resulting map of objects to eversion_t's */ - void scan_range(hobject_t begin, int min, int max, BackfillInterval *bi); + void scan_range( + hobject_t begin, int min, int max, BackfillInterval *bi, + ThreadPool::TPHandle &handle + ); void prep_backfill_object_push( hobject_t oid, eversion_t v, eversion_t have, int peer, @@ -939,7 +945,9 @@ public: void do_pg_op(OpRequestRef op); void do_sub_op(OpRequestRef op); void do_sub_op_reply(OpRequestRef op); - void do_scan(OpRequestRef op); + void do_scan( + OpRequestRef op, + ThreadPool::TPHandle &handle); void do_backfill(OpRequestRef op); void _do_push(OpRequestRef op); void _do_pull_response(OpRequestRef op); diff --git a/src/osd/osd_types.cc b/src/osd/osd_types.cc index fbd5cbbe9a0..0e8ecb99086 100644 --- a/src/osd/osd_types.cc +++ b/src/osd/osd_types.cc @@ -1190,6 +1190,19 @@ void pg_stat_t::dump(Formatter *f) const f->close_section(); } +void pg_stat_t::dump_brief(Formatter *f) const +{ + f->dump_string("state", pg_state_string(state)); + f->open_array_section("up"); + for (vector<int>::const_iterator p = up.begin(); p != up.end(); ++p) + f->dump_int("osd", *p); + f->close_section(); + f->open_array_section("acting"); + for (vector<int>::const_iterator p = acting.begin(); p != acting.end(); ++p) + f->dump_int("osd", *p); + f->close_section(); +} + void pg_stat_t::encode(bufferlist &bl) const { ENCODE_START(13, 8, bl); diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h index ca3dcc192b0..bf04e8e11e3 100644 --- a/src/osd/osd_types.h +++ b/src/osd/osd_types.h @@ -1079,6 +1079,7 @@ struct pg_stat_t { } void dump(Formatter *f) const; + void dump_brief(Formatter *f) const; void encode(bufferlist &bl) const; void decode(bufferlist::iterator &bl); static void generate_test_instances(list<pg_stat_t*>& o); diff --git a/src/osdc/Objecter.cc b/src/osdc/Objecter.cc index fc54daa3f27..eb490cef330 100644 --- a/src/osdc/Objecter.cc +++ b/src/osdc/Objecter.cc @@ -2334,9 +2334,8 @@ bool Objecter::RequestStateHook::call(std::string command, cmdmap_t& cmdmap, m_objecter->client_lock.Lock(); m_objecter->dump_requests(f); m_objecter->client_lock.Unlock(); - f->flush(ss); + f->flush(out); delete f; - out.append(ss); return true; } diff --git a/src/pybind/ceph_argparse.py b/src/pybind/ceph_argparse.py index 9a9db6758a5..9e56d38384c 100644 --- a/src/pybind/ceph_argparse.py +++ b/src/pybind/ceph_argparse.py @@ -15,6 +15,7 @@ Foundation. See file COPYING. import copy import json import os +import pprint import re import socket import stat @@ -46,6 +47,12 @@ class ArgumentValid(ArgumentError): """ pass +class ArgumentTooFew(ArgumentError): + """ + Fewer arguments than descriptors in signature; may mean to continue + the search, so gets a special exception type + """ + class ArgumentPrefix(ArgumentError): """ Special for mismatched prefix; less severe, don't report by default @@ -727,6 +734,55 @@ def matchnum(args, signature, partial=False): matchcnt += 1 return matchcnt +def get_next_arg(desc, args): + ''' + Get either the value matching key 'desc.name' or the next arg in + the non-dict list. Return None if args are exhausted. Used in + validate() below. + ''' + arg = None + if isinstance(args, dict): + arg = args.pop(desc.name, None) + # allow 'param=param' to be expressed as 'param' + if arg == '': + arg = desc.name + # Hack, or clever? If value is a list, keep the first element, + # push rest back onto myargs for later processing. + # Could process list directly, but nesting here is already bad + if arg and isinstance(arg, list): + args[desc.name] = arg[1:] + arg = arg[0] + elif args: + arg = args.pop(0) + if arg and isinstance(arg, list): + args = arg[1:] + args + arg = arg[0] + return arg + +def store_arg(desc, d): + ''' + Store argument described by, and held in, thanks to valid(), + desc into the dictionary d, keyed by desc.name. Three cases: + + 1) desc.N is set: value in d is a list + 2) prefix: multiple args are joined with ' ' into one d{} item + 3) single prefix or other arg: store as simple value + + Used in validate() below. + ''' + if desc.N: + # value should be a list + if desc.name in d: + d[desc.name] += [desc.instance.val] + else: + d[desc.name] = [desc.instance.val] + elif (desc.t == CephPrefix) and (desc.name in d): + # prefixes' values should be a space-joined concatenation + d[desc.name] += ' ' + desc.instance.val + else: + # if first CephPrefix or any other type, just set it + d[desc.name] = desc.instance.val + def validate(args, signature, partial=False): """ validate(args, signature, partial=False) @@ -748,85 +804,79 @@ def validate(args, signature, partial=False): myargs = copy.deepcopy(args) mysig = copy.deepcopy(signature) + reqsiglen = len([desc for desc in mysig if desc.req]) + matchcnt = 0 d = dict() for desc in mysig: setattr(desc, 'numseen', 0) while desc.numseen < desc.n: - myarg = None - if not myargs: - break - # get either the value matching key 'desc.name' or the next arg in - # the non-dict list - if isinstance(myargs, dict): - myarg = myargs.pop(desc.name, None) - # allow 'param=param' to be expressed as 'param' - if myarg == '': - myarg = desc.name - # Hack, or clever? If value is a list, keep the first element, - # push rest back onto myargs for later processing. - # Could process list directly, but nesting here is already bad - if myarg and isinstance(myarg, list): - myargs[desc.name] = myarg[1:] - myarg = myarg[0] - elif myargs: - myarg = myargs.pop(0) - if myarg and isinstance(myarg, list): - myargs = myarg[1:] + myargs - myarg = myarg[0] - - # no arg, but not required? March on + myarg = get_next_arg(desc, myargs) + + # no arg, but not required? Continue consuming mysig + # in case there are later required args if not myarg and not desc.req: break # out of arguments for a required param? + # Either return (if partial validation) or raise if not myarg and desc.req: if desc.N and desc.numseen < 1: # wanted N, didn't even get 1 if partial: return d - raise ArgumentNumber('saw {0} of {1}, expected at least 1'.format(desc.numseen, desc)) + raise ArgumentNumber( + 'saw {0} of {1}, expected at least 1'.\ + format(desc.numseen, desc) + ) elif not desc.N and desc.numseen < desc.n: # wanted n, got too few if partial: return d - raise ArgumentNumber('saw {0} of {1}, expected {2}'.format(desc.numseen, desc, desc.n)) + raise ArgumentNumber( + 'saw {0} of {1}, expected {2}'.\ + format(desc.numseen, desc, desc.n) + ) break - # not out of args; validate this one + # Have an arg; validate it try: validate_one(myarg, desc) valid = True - except Exception as e: + except ArgumentError as e: valid = False if not valid: # argument mismatch - # if not required, just push back for the next one if not desc.req: + # if not required, just push back; it might match + # the next arg + print >> sys.stderr, myarg, 'not valid: ', str(e) myargs.insert(0, myarg) break else: - # hm, but it was required, so quit + # hm, it was required, so time to return/raise if partial: return d raise e - # valid arg acquired. Store in dict, as a list if multivalued - if desc.N: - # value should be a list - if desc.name in d: - d[desc.name] += [desc.instance.val] - else: - d[desc.name] = [desc.instance.val] - elif (desc.t == CephPrefix) and (desc.name in d): - # prefixes' values should be a space-joined concatenation - d[desc.name] += ' ' + desc.instance.val - else: - # if first CephPrefix or any other type, just set it - d[desc.name] = desc.instance.val + # Whew, valid arg acquired. Store in dict + matchcnt += 1 + store_arg(desc, d) + + # Done with entire list of argdescs + if matchcnt < reqsiglen: + raise ArgumentTooFew("not enough arguments given") + if myargs and not partial: raise ArgumentError("unused arguments: " + str(myargs)) + + # Finally, success return d +def cmdsiglen(sig): + sigdict = sig.values() + assert len(sigdict) == 1 + return len(sig.values()[0]['sig']) + def validate_command(sigdict, args, verbose=False): """ turn args into a valid dictionary ready to be sent off as JSON, @@ -856,14 +906,19 @@ def validate_command(sigdict, args, verbose=False): best_match_cnt, cmdtag, concise_sig(sig)) bestcmds.append({cmdtag:cmd}) + # Sort bestcmds by number of args so we can try shortest first + # (relies on a cmdsig being key,val where val is a list of len 1) + bestcmds_sorted = sorted(bestcmds, + cmp=lambda x,y:cmp(cmdsiglen(x), cmdsiglen(y))) + if verbose: - print >> sys.stderr, "bestcmds: ", bestcmds + print >> sys.stderr, "bestcmds_sorted: " + pprint.PrettyPrinter(stream=sys.stderr).pprint(bestcmds_sorted) # for everything in bestcmds, look for a true match - for cmdsig in bestcmds: + for cmdsig in bestcmds_sorted: for cmd in cmdsig.itervalues(): sig = cmd['sig'] - helptext = cmd['help'] try: valid_dict = validate(args, sig) found = cmd @@ -872,14 +927,22 @@ def validate_command(sigdict, args, verbose=False): # ignore prefix mismatches; we just haven't found # the right command yet pass + except ArgumentTooFew: + # It looked like this matched the beginning, but it + # didn't have enough args supplied. If we're out of + # cmdsigs we'll fall out unfound; if we're not, maybe + # the next one matches completely. Whine, but pass. + if verbose: + print >> sys.stderr, 'Not enough args supplied for ', \ + concise_sig(sig) except ArgumentError as e: - # prefixes matched, but some other arg didn't; - # stop now, because we have the right command but + # Solid mismatch on an arg (type, range, etc.) + # Stop now, because we have the right command but # some other input is invalid print >> sys.stderr, "Invalid command: ", str(e) return {} - if found: - break + if found: + break if not found: print >> sys.stderr, 'no valid command found; 10 closest matches:' diff --git a/src/pybind/ceph_rest_api.py b/src/pybind/ceph_rest_api.py index 59e3f60a3a7..421cc59edcc 100755 --- a/src/pybind/ceph_rest_api.py +++ b/src/pybind/ceph_rest_api.py @@ -1,20 +1,20 @@ #!/usr/bin/python # vim: ts=4 sw=4 smarttab expandtab -import collections -import contextlib import errno import json import logging import logging.handlers -import os import rados import textwrap import xml.etree.ElementTree import xml.sax.saxutils import flask -from ceph_argparse import * +from ceph_argparse import \ + ArgumentError, CephPgid, CephOsdName, CephChoices, CephPrefix, \ + concise_sig, descsort, parse_funcsig, parse_json_funcsigs, \ + validate, json_command # # Globals and defaults diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index 364f60f78f7..2b8a716115b 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -2175,6 +2175,8 @@ next: assert(0); } encode_json("bounds", bounds, formatter); + formatter->flush(cout); + cout << std::endl; } if (opt_cmd == OPT_REPLICALOG_DELETE) { diff --git a/src/rgw/rgw_main.cc b/src/rgw/rgw_main.cc index 6c383d822c1..5270f21be22 100644 --- a/src/rgw/rgw_main.cc +++ b/src/rgw/rgw_main.cc @@ -318,12 +318,16 @@ void RGWProcess::handle_request(RGWRequest *req) RGWOp *op = NULL; int init_error = 0; - RGWHandler *handler = rest->get_handler(store, s, &client_io, &init_error); + bool should_log = false; + RGWRESTMgr *mgr; + RGWHandler *handler = rest->get_handler(store, s, &client_io, &mgr, &init_error); if (init_error != 0) { abort_early(s, init_error); goto done; } + should_log = mgr->get_logging(); + req->log(s, "getting op"); op = handler->get_op(store); if (!op) { @@ -384,7 +388,9 @@ void RGWProcess::handle_request(RGWRequest *req) op->execute(); op->complete(); done: - rgw_log_op(store, s, (op ? op->name() : "unknown"), olog); + if (should_log) { + rgw_log_op(store, s, (op ? op->name() : "unknown"), olog); + } int http_ret = s->err.http_ret; @@ -431,6 +437,12 @@ int usage() return 0; } +static RGWRESTMgr *set_logging(RGWRESTMgr *mgr) +{ + mgr->set_logging(true); + return mgr; +} + /* * start up the RADOS connection and then handle HTTP messages as they come in */ @@ -527,16 +539,16 @@ int main(int argc, const char **argv) } if (apis_map.count("s3") > 0) - rest.register_default_mgr(new RGWRESTMgr_S3); + rest.register_default_mgr(set_logging(new RGWRESTMgr_S3)); if (apis_map.count("swift") > 0) { do_swift = true; swift_init(g_ceph_context); - rest.register_resource(g_conf->rgw_swift_url_prefix, new RGWRESTMgr_SWIFT); + rest.register_resource(g_conf->rgw_swift_url_prefix, set_logging(new RGWRESTMgr_SWIFT)); } if (apis_map.count("swift_auth") > 0) - rest.register_resource(g_conf->rgw_swift_auth_entry, new RGWRESTMgr_SWIFT_Auth); + rest.register_resource(g_conf->rgw_swift_auth_entry, set_logging(new RGWRESTMgr_SWIFT_Auth)); if (apis_map.count("admin") > 0) { RGWRESTMgr_Admin *admin_resource = new RGWRESTMgr_Admin; diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index aba5cdf0ee2..222b79a7d2e 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -2551,7 +2551,7 @@ int RGWRados::copy_obj(void *ctx, conn = rest_master_conn; } else { map<string, RGWRESTConn *>::iterator iter = region_conn_map.find(src_bucket_info.region); - if (iter == zone_conn_map.end()) { + if (iter == region_conn_map.end()) { ldout(cct, 0) << "could not find region connection to region: " << source_zone << dendl; return -ENOENT; } diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index a0870708c44..ee73bb94fa5 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -1210,7 +1210,7 @@ int RGWREST::preprocess(struct req_state *s, RGWClientIO *cio) } RGWHandler *RGWREST::get_handler(RGWRados *store, struct req_state *s, RGWClientIO *cio, - int *init_error) + RGWRESTMgr **pmgr, int *init_error) { RGWHandler *handler; @@ -1224,6 +1224,9 @@ RGWHandler *RGWREST::get_handler(RGWRados *store, struct req_state *s, RGWClient return NULL; } + if (pmgr) + *pmgr = m; + handler = m->get_handler(s); if (!handler) { *init_error = -ERR_METHOD_NOT_ALLOWED; diff --git a/src/rgw/rgw_rest.h b/src/rgw/rgw_rest.h index ded5b88366a..b65efb3de3e 100644 --- a/src/rgw/rgw_rest.h +++ b/src/rgw/rgw_rest.h @@ -263,13 +263,14 @@ class RGWHandler_SWIFT_Auth; class RGWHandler_ObjStore_S3; class RGWRESTMgr { + bool should_log; protected: map<string, RGWRESTMgr *> resource_mgrs; multimap<size_t, string> resources_by_size; RGWRESTMgr *default_mgr; public: - RGWRESTMgr() : default_mgr(NULL) {} + RGWRESTMgr() : should_log(false), default_mgr(NULL) {} virtual ~RGWRESTMgr(); void register_resource(string resource, RGWRESTMgr *mgr); @@ -278,6 +279,9 @@ public: virtual RGWRESTMgr *get_resource_mgr(struct req_state *s, const string& uri, string *out_uri); virtual RGWHandler *get_handler(struct req_state *s) { return NULL; } virtual void put_handler(RGWHandler *handler) { delete handler; } + + void set_logging(bool _should_log) { should_log = _should_log; } + bool get_logging() { return should_log; } }; class RGWREST { @@ -287,7 +291,7 @@ class RGWREST { public: RGWREST() {} RGWHandler *get_handler(RGWRados *store, struct req_state *s, RGWClientIO *cio, - int *init_error); + RGWRESTMgr **pmgr, int *init_error); void put_handler(RGWHandler *handler) { mgr.put_handler(handler); } |