Modified: qpid/dispatch/trunk/src/entity_private.h URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/entity_private.h?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/entity_private.h (original) +++ qpid/dispatch/trunk/src/entity_private.h Fri Oct 17 23:35:35 2014 @@ -22,6 +22,14 @@ #include <stdbool.h> #include <qpid/dispatch/dispatch.h> +/** + * @defgroup entity +xo * + * Holds attributes of a managed entity. + * @{ + */ + + void qd_entity_free(qd_entity_t* entity); /** True if the entity has this attribute. */ @@ -60,4 +68,35 @@ long qd_entity_opt_long(qd_entity_t *ent bool qd_entity_opt_bool(qd_entity_t *entity, const char *attribute, bool default_value); +/** Set a string valued attribute, entity makes a copy. + * If value is NULL clear the attribute. + */ +qd_error_t qd_entity_set_string(qd_entity_t *entity, const char* attribute, const char *value); + +/** Set a string valued attribute from a printf format */ +qd_error_t qd_entity_set_stringf(qd_entity_t *entity, const char* attribute, const char *format, ...); + +/** Set an integer valued attribute. */ +qd_error_t qd_entity_set_long(qd_entity_t *entity, const char* attribute, long value); + +/** Set a boolean valued attribute. */ +qd_error_t qd_entity_set_bool(qd_entity_t *entity, const char *attribute, bool value); + +/** Set an integer valued attribute. If value is NULL clear the attribute. */ +qd_error_t qd_entity_set_longp(qd_entity_t *entity, const char* attribute, const long *value); + +/** Set a boolean valued attribute. If value is NULL clear the attribute. */ +qd_error_t qd_entity_set_boolp(qd_entity_t *entity, const char *attribute, const bool *value); + +/** Clear the attribute */ +qd_error_t qd_entity_clear(qd_entity_t *entity, const char *attribute); + +/** + * Set the attribute to an empty list. Futher qd_entity_set* calls for the attribute + * will append values to the list. + */ +qd_error_t qd_entity_set_list(qd_entity_t *entity, const char *attribute); + +/// @} + #endif
Modified: qpid/dispatch/trunk/src/error.c URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/error.c?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/error.c (original) +++ qpid/dispatch/trunk/src/error.c Fri Oct 17 23:35:35 2014 @@ -19,13 +19,14 @@ #include <Python.h> #include <qpid/dispatch/error.h> +#include <qpid/dispatch/enum.h> #include <qpid/dispatch/log.h> #include <stdarg.h> #include <stdio.h> -#include "static_assert.h" #include "log_private.h" +#include "aprintf.h" -static const char *error_names[] = { +static const char *qd_error_names[] = { "No Error", "Not found", "Already exists", @@ -37,9 +38,7 @@ static const char *error_names[] = { "Value", "Run Time" }; - -STATIC_ASSERT(sizeof(error_names)/sizeof(error_names[0]) == QD_ERROR_ENUM_COUNT, - error_names_wrong_size); +ENUM_DEFINE(qd_error, qd_error_names); #define ERROR_MAX QD_LOG_TEXT_MAX const int QD_ERROR_MAX = ERROR_MAX; @@ -56,19 +55,22 @@ void qd_error_initialize() { log_source = qd_log_source("ERROR"); } -qd_error_t qd_error(qd_error_t code, const char *fmt, ...) { +qd_error_t qd_error_impl(qd_error_t code, const char *file, int line, const char *fmt, ...) { ts.error_code = code; if (code) { - int i = 0; - if (code < QD_ERROR_ENUM_COUNT) - i = snprintf(ts.error_message, ERROR_MAX,"%s: ", error_names[code]); + char *begin = ts.error_message; + char *end = begin + ERROR_MAX; + const char* name = qd_error_name(code); + if (name) + aprintf(&begin, end, "%s: ", name); else - i = snprintf(ts.error_message, ERROR_MAX, "%d: ", code); + aprintf(&begin, end, "%d: ", code); va_list arglist; va_start(arglist, fmt); - vsnprintf(ts.error_message+i, ERROR_MAX-i, fmt, arglist); + vaprintf(&begin, end, fmt, arglist); va_end(arglist); - qd_log(log_source, QD_LOG_ERROR, "%s", qd_error_message()); + // NOTE: Use the file/line from the qd_error macro, not this line in error.c + qd_log_impl(log_source, QD_LOG_ERROR, file, line, "%s", qd_error_message()); return code; } else @@ -95,7 +97,9 @@ static void py_set_item(PyObject *dict, Py_DECREF(py_name); } -static void log_trace_py(PyObject *type, PyObject *value, PyObject* trace, qd_log_level_t level) { +static void log_trace_py(PyObject *type, PyObject *value, PyObject* trace, qd_log_level_t level, + const char *file, int line) +{ if (!qd_log_enabled(log_source, level)) return; if (!(type && value && trace)) return; @@ -116,10 +120,11 @@ static void log_trace_py(PyObject *type, Py_DECREF(globals); Py_DECREF(locals); + if (result) { const char* trace = PyString_AsString(result); if (strlen(trace) < QD_LOG_TEXT_MAX) { - qd_log(log_source, level, "%s", trace); + qd_log_impl(log_source, level, file, line, "%s", trace); } else { // Keep as much of the the tail of the trace as we can. const char *tail = trace; @@ -127,14 +132,14 @@ static void log_trace_py(PyObject *type, tail = strchr(tail, '\n'); if (tail) ++tail; } - qd_log(log_source, level, "Traceback truncated:\n%s", tail ? tail : ""); + qd_log_impl(log_source, level, file, line, "Traceback truncated:\n%s", tail ? tail : ""); } Py_DECREF(result); } } -qd_error_t qd_error_py() { +qd_error_t qd_error_py_impl(const char *file, int line) { if (PyErr_Occurred()) { PyObject *type, *value, *trace; PyErr_Fetch(&type, &value, &trace); /* Note clears the python error indicator */ @@ -144,13 +149,13 @@ qd_error_t qd_error_py() { PyObject *value_str = value ? PyObject_Str(value) : NULL; const char* str = value_str ? PyString_AsString(value_str) : "Unknown"; if (type_name) - qd_error(QD_ERROR_PYTHON, "%s: %s", PyString_AsString(type_name), str); + qd_error_impl(QD_ERROR_PYTHON, file, line, "%s: %s", PyString_AsString(type_name), str); else - qd_error(QD_ERROR_PYTHON, "%s", str); + qd_error_impl(QD_ERROR_PYTHON, file, line, "%s", str); Py_XDECREF(value_str); Py_XDECREF(type_name); - log_trace_py(type, value, trace, QD_LOG_ERROR); + log_trace_py(type, value, trace, QD_LOG_ERROR, file, line); Py_XDECREF(type); Py_XDECREF(value); Modified: qpid/dispatch/trunk/src/log.c URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/log.c?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/log.c (original) +++ qpid/dispatch/trunk/src/log.c Fri Oct 17 23:35:35 2014 @@ -19,6 +19,7 @@ #include "log_private.h" #include "entity_private.h" +#include "aprintf.h" #include <qpid/dispatch/ctools.h> #include <qpid/dispatch/dispatch.h> #include <qpid/dispatch/alloc.h> @@ -133,7 +134,8 @@ struct qd_log_source_t { DEQ_LINKS(qd_log_source_t); const char *module; int mask; - int timestamp; + int timestamp; /* boolean or -1 means not set */ + int source; /* boolean or -1 means not set */ bool syslog; log_sink_t *sink; }; @@ -196,17 +198,30 @@ static qd_log_source_t* lookup_log_sourc return src; } -static void write_log(int level, qd_log_source_t *log_source, const char *fmt, ...) +static bool default_bool(int value, int default_value) { + return value == -1 ? default_value : value; +} + +static void write_log(qd_log_source_t *log_source, qd_log_entry_t *entry) { log_sink_t* sink = log_source->sink ? log_source->sink : default_log_source->sink; - if (!sink) return; char log_str[LOG_MAX]; - va_list arglist; - va_start(arglist, fmt); - vsnprintf(log_str, LOG_MAX, fmt, arglist); - va_end(arglist); + char *begin = log_str; + char *end = log_str + LOG_MAX; + + if (default_bool(log_source->timestamp, default_log_source->timestamp)) { + char buf[100]; + buf[0] = '\0'; + ctime_r(&entry->time, buf); + buf[strlen(buf)-1] = '\0'; /* Get rid of trailng \n */ + aprintf(&begin, end, "%s ", buf); + } + aprintf(&begin, end, "%s (%s) %s", entry->module, level_for_bit(entry->level)->name, entry->text); + if (default_bool(log_source->source, default_log_source->source)) + aprintf(&begin, end, " (%s:%d)", entry->file, entry->line); + aprintf(&begin, end, "\n"); if (sink->file) { if (fputs(log_str, sink->file) == EOF) { @@ -218,7 +233,7 @@ static void write_log(int level, qd_log_ fflush(sink->file); } if (sink->syslog) { - int syslog_level = level_for_bit(level)->syslog; + int syslog_level = level_for_bit(entry->level)->syslog; if (syslog_level != -1) syslog(syslog_level, "%s", log_str); } @@ -236,6 +251,7 @@ static qd_log_source_t *qd_log_source_lh log_source->module = module; log_source->mask = -1; log_source->timestamp = -1; + log_source->source = -1; log_source->sink = 0; DEQ_INSERT_TAIL(source_list, log_source); } @@ -273,22 +289,12 @@ void qd_log_impl(qd_log_source_t *source entry->file = file ? strdup(file) : 0; entry->line = line; time(&entry->time); - - char ctime[100]; - ctime[0] = '\0'; - bool timestamp = (source->timestamp == -1) ? - default_log_source->timestamp : source->timestamp; - assert(timestamp != -1); - if (timestamp) { - ctime_r(&entry->time, ctime); - ctime[24] = '\0'; - strcat(ctime, " "); - } va_list ap; va_start(ap, fmt); vsnprintf(entry->text, TEXT_MAX, fmt, ap); va_end(ap); - write_log(level, source, "%s%s (%s) %s\n", ctime, entry->module, level_for_bit(level)->name, entry->text); + + write_log(source, entry); sys_mutex_lock(log_lock); DEQ_INSERT_TAIL(entries, entry); @@ -314,6 +320,7 @@ void qd_log_initialize(void) // Only report errors until we have configured the logging system. default_log_source->mask = levels[INFO].mask; default_log_source->timestamp = 1; + default_log_source->source = 0; default_log_source->sink = log_sink_lh(SINK_STDERR); logging_log_source = qd_log_source(SOURCE_LOGGING); } Modified: qpid/dispatch/trunk/src/message.c URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/message.c?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/message.c (original) +++ qpid/dispatch/trunk/src/message.c Fri Oct 17 23:35:35 2014 @@ -25,6 +25,7 @@ #include <qpid/dispatch/log.h> #include "message_private.h" #include "compose_private.h" +#include "aprintf.h" #include <string.h> #include <ctype.h> #include <stdio.h> @@ -67,34 +68,29 @@ void qd_message_initialize() { int qd_message_repr_len() { return qd_log_max_len(); } // Quote non-printable characters suitable for log messages. Output in buffer. -static int quote(char* bytes, int n, char* buffer, int len) { - int i = 0; - for (char* p = bytes; p < bytes+n && i < len; ++p) { - if (isprint(*p) || isspace(*p)) { - buffer[i++] = *p; - } - else { - int d = snprintf(buffer+i, len-i, "\\%02hhx", *p); - i += d; - } +static void quote(char* bytes, int n, char **begin, char *end) { + for (char* p = bytes; p < bytes+n; ++p) { + if (isprint(*p) || isspace(*p)) + aprintf(begin, end, "%c", (int)*p); + else + aprintf(begin, end, "\\%02hhx", *p); } - return i; } /** Copy a message field for use in log messages. Output in buffer. */ -static int copy_field(qd_message_t *msg, int field, int max, char *pre, char *post, char *buffer, size_t len) { +static void copy_field(qd_message_t *msg, int field, int max, char *pre, char *post, + char **begin, char *end) +{ qd_field_iterator_t* iter = qd_message_field_iterator(msg, field); - int i = 0; if (iter) { - i += snprintf(buffer+i, len-i, "%s", pre); + aprintf(begin, end, "%s", pre); qd_field_iterator_reset(iter); - for (int j = 0; !qd_field_iterator_end(iter) && i < len && j < max; ++j) { + for (int j = 0; !qd_field_iterator_end(iter) && j < max; ++j) { char byte = qd_field_iterator_octet(iter); - i += quote(&byte, 1, buffer+i, len-i); + quote(&byte, 1, begin, end); } - i += snprintf(buffer+i, len-i, "%s", post); + aprintf(begin, end, "%s", post); } - return i; } static const char REPR_END[] = "}\0"; @@ -102,14 +98,13 @@ static const char REPR_END[] = "}\0"; /* TODO aconway 2014-05-13: more detailed message representation. */ char* qd_message_repr(qd_message_t *msg, char* buffer, size_t len) { qd_message_check(msg, QD_DEPTH_BODY); - int i = 0; - len -= sizeof(REPR_END); /* Save space for ending */ - i += snprintf(buffer+i, len-i, "Message(%p){", msg); - i += copy_field(msg, QD_FIELD_TO, INT_MAX, "to='", "'", buffer+i, len-i); - i += copy_field(msg, QD_FIELD_REPLY_TO, INT_MAX, " reply-to='", "'", buffer+i, len-i); - i += copy_field(msg, QD_FIELD_BODY, 16, " body='", "'", buffer+i, len-i); - assert(i <= len); - strcat(buffer, REPR_END); /* We saved space at the beginning. */ + char *begin = buffer; + char *end = buffer + len - sizeof(REPR_END); /* Save space for ending */ + aprintf(&begin, end, "Message(%p){", msg); + copy_field(msg, QD_FIELD_TO, INT_MAX, "to='", "'", &begin, end); + copy_field(msg, QD_FIELD_REPLY_TO, INT_MAX, " reply-to='", "'", &begin, end); + copy_field(msg, QD_FIELD_BODY, 16, " body='", "'", &begin, end); + aprintf(&begin, end, "%s", REPR_END); /* We saved space at the beginning. */ return buffer; } Modified: qpid/dispatch/trunk/src/python_embedded.c URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/python_embedded.c?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/python_embedded.c (original) +++ qpid/dispatch/trunk/src/python_embedded.c Fri Oct 17 23:35:35 2014 @@ -17,6 +17,7 @@ * under the License. */ +#include "c_entity.h" #include <qpid/dispatch/python_embedded.h> #include <qpid/dispatch/threading.h> #include <qpid/dispatch/log.h> @@ -679,7 +680,7 @@ static void qd_python_setup(void) if ((PyType_Ready(&LogAdapterType) < 0) || (PyType_Ready(&IoAdapterType) < 0)) { qd_error_py(); qd_log(log_source, QD_LOG_ERROR, "Unable to initialize Adapters"); - assert(0); + abort(); } else { PyObject *m = Py_InitModule3("dispatch", empty_methods, "Dispatch Adapter Module"); Modified: qpid/dispatch/trunk/src/router_agent.c URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/router_agent.c?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/router_agent.c (original) +++ qpid/dispatch/trunk/src/router_agent.c Fri Oct 17 23:35:35 2014 @@ -26,18 +26,74 @@ #include <qpid/dispatch/agent.h> #include "dispatch_private.h" #include "router_private.h" +#include "c_entity.h" +static const char *qd_router_mode_names[] = { + "standalone", + "interior", + "edge", + "endpoint" +}; +ENUM_DEFINE(qd_router_mode, qd_router_mode_names); -static const char *qd_router_addr_text(qd_address_t *addr) +qd_error_t qd_c_entity_update_router(qd_entity_t* entity, void *impl) { + qd_dispatch_t *qd = (qd_dispatch_t*) impl; + qd_router_t *router = qd->router; + if (qd_entity_set_string(entity, "name", router->router_id) == 0 && + qd_entity_set_string(entity, "identity", router->router_id) == 0 && + qd_entity_set_string(entity, "area", router->router_area) == 0 && + qd_entity_set_string(entity, "mode", qd_router_mode_name(router->router_mode)) == 0 && + qd_entity_set_long(entity, "addrCount", DEQ_SIZE(router->addrs)) == 0 && + qd_entity_set_long(entity, "linkCount", DEQ_SIZE(router->links)) == 0 && + qd_entity_set_long(entity, "nodeCount", DEQ_SIZE(router->routers)) == 0 + ) + return QD_ERROR_NONE; + return qd_error_code(); +} + +static const char *address_text(qd_address_t *addr) { - if (addr) { - const unsigned char *text = qd_hash_key_by_handle(addr->hash_handle); - if (text) - return (const char*) text; - } - return 0; + return addr ? (const char*) qd_hash_key_by_handle(addr->hash_handle) : 0; } +qd_error_t qd_c_entity_update_router_address(qd_entity_t* entity, void *impl) { + qd_address_t *addr = (qd_address_t*) impl; + if ((qd_entity_has(entity, "identity") || + qd_entity_set_string(entity, "identity", address_text(addr)) == 0) && + qd_entity_set_bool(entity, "inProcess", addr->handler != 0) == 0 && + qd_entity_set_long(entity, "subscriberCount", DEQ_SIZE(addr->rlinks)) == 0 && + qd_entity_set_long(entity, "remoteCount", DEQ_SIZE(addr->rnodes)) == 0 && + qd_entity_set_long(entity, "deliveriesIngress", addr->deliveries_ingress) == 0 && + qd_entity_set_long(entity, "deliveriesEgress", addr->deliveries_egress) == 0 && + qd_entity_set_long(entity, "deliveriesTransit", addr->deliveries_transit) == 0 && + qd_entity_set_long(entity, "deliveriesToContainer", addr->deliveries_to_container) == 0 && + qd_entity_set_long(entity, "deliveriesFromContainer", addr->deliveries_from_container) == 0 + ) + return QD_ERROR_NONE; + return qd_error_code(); +} + +#define CHECK(err) if (err != 0) return qd_error_code() + +qd_error_t qd_c_entity_update_router_node(qd_entity_t* entity, void *impl) { + qd_router_node_t *rnode = (qd_router_node_t*) impl; + + if (!qd_entity_has(entity, "identity")) { + CHECK(qd_entity_set_stringf(entity, "identity", "%s-%d", QD_ROUTER_NODE_TYPE, rnode->mask_bit)); + } + CHECK(qd_entity_set_string(entity, "addr", address_text(rnode->owning_addr))); + long next_hop = rnode->next_hop ? rnode->next_hop->mask_bit : 0; + CHECK(qd_entity_set_longp(entity, "nextHop", rnode->next_hop ? &next_hop : 0)); + long router_link = rnode->peer_link ? rnode->peer_link->mask_bit : 0; + CHECK(qd_entity_set_longp(entity, "routerLink", rnode->peer_link ? &router_link : 0)); + CHECK(qd_entity_set_list(entity, "validOrigins")); + for (uint32_t bit = 1; bit < qd_bitmask_width(); bit++) { + if (qd_bitmask_value(rnode->valid_origins, bit)) { + CHECK(qd_entity_set_long(entity, "validOrigins", bit)); + } + } + return QD_ERROR_NONE; +} static void router_attr_name(void *object_handle, void *cor, void *unused) { @@ -86,7 +142,6 @@ static void router_attr_nodeCount(void * } -static const char *ROUTER_TYPE = "org.apache.qpid.dispatch.router"; static const qd_agent_attribute_t ROUTER_ATTRIBUTES[] = {{"name", router_attr_name, 0}, {"identity", router_attr_name, 0}, @@ -107,7 +162,6 @@ static void qd_router_query_router(void sys_mutex_unlock(router->lock); } - static void link_attr_name(void *object_handle, void *cor, void *unused) { qd_router_link_t *link = (qd_router_link_t*) object_handle; @@ -140,7 +194,7 @@ static void link_attr_linkDir(void *obje static void link_attr_owningAddr(void *object_handle, void *cor, void *unused) { qd_router_link_t *link = (qd_router_link_t*) object_handle; - const char *text = qd_router_addr_text(link->owning_addr); + const char *text = address_text(link->owning_addr); if (text) qd_agent_value_string(cor, 0, text); else @@ -162,7 +216,6 @@ static void link_attr_msgFifoDepth(void } -static const char *LINK_TYPE = "org.apache.qpid.dispatch.router.link"; static const qd_agent_attribute_t LINK_ATTRIBUTES[] = {{"name", link_attr_name, 0}, {"identity", link_attr_name, 0}, @@ -173,6 +226,7 @@ static const qd_agent_attribute_t LINK_A {"msgFifoDepth", link_attr_msgFifoDepth, 0}, {0, 0, 0}}; + static void qd_router_query_link(void *context, void *cor) { qd_router_t *router = (qd_router_t*) context; @@ -188,6 +242,30 @@ static void qd_router_query_link(void *c sys_mutex_unlock(router->lock); } +static const char *qd_link_type_names[] = { "endpoint", "waypoint", "inter-router", "inter-area" }; +ENUM_DEFINE(qd_link_type, qd_link_type_names); + +static const char *qd_router_addr_text(qd_address_t *addr) +{ + return addr ? (const char*)qd_hash_key_by_handle(addr->hash_handle) : NULL; +} + +qd_error_t qd_c_entity_update_router_link(qd_entity_t* entity, void *impl) +{ + qd_router_link_t *link = (qd_router_link_t*) impl; + /* FIXME aconway 2014-10-17: old management used link->bit_mask as name/identity, + * but even when prefixed with router.link this is not unique. Let python agent + * generate a name for now, revisit with a better name later. + */ + if (!qd_entity_set_string(entity, "linkType", qd_link_type_name(link->link_type)) && + !qd_entity_set_string(entity, "linkDir", (link->link_direction == QD_INCOMING) ? "in": "out") && + !qd_entity_set_string(entity, "owningAddr", qd_router_addr_text(link->owning_addr)) && + !qd_entity_set_long(entity, "eventFifoDepth", DEQ_SIZE(link->event_fifo)) && + !qd_entity_set_long(entity, "msgFifoDepth", DEQ_SIZE(link->msg_fifo)) + ) + return QD_ERROR_NONE; + return qd_error_code(); +} static void node_attr_name(void *object_handle, void *cor, void *unused) { @@ -199,7 +277,7 @@ static void node_attr_name(void *object_ static void node_attr_addr(void *object_handle, void *cor, void *unused) { qd_router_node_t *node = (qd_router_node_t*) object_handle; - qd_agent_value_string(cor, 0, qd_router_addr_text(node->owning_addr)); + qd_agent_value_string(cor, 0, address_text(node->owning_addr)); } @@ -234,7 +312,6 @@ static void node_attr_validOrigins(void } -static const char *NODE_TYPE = "org.apache.qpid.dispatch.router.node"; static const qd_agent_attribute_t NODE_ATTRIBUTES[] = {{"name", node_attr_name, 0}, {"identity", node_attr_name, 0}, @@ -262,7 +339,7 @@ static void qd_router_query_node(void *c static void addr_attr_name(void *object_handle, void *cor, void *unused) { qd_address_t *addr = (qd_address_t*) object_handle; - qd_agent_value_string(cor, 0, qd_router_addr_text(addr)); + qd_agent_value_string(cor, 0, address_text(addr)); } @@ -322,7 +399,6 @@ static void addr_attr_deliveriesFromCont } -static const char *ADDRESS_TYPE = "org.apache.qpid.dispatch.router.address"; static const qd_agent_attribute_t ADDRESS_ATTRIBUTES[] = {{"name", addr_attr_name, 0}, {"identity", addr_attr_name, 0}, @@ -355,13 +431,13 @@ qd_error_t qd_router_agent_setup(qd_rout { qd_error_clear(); router->class_router = - qd_agent_register_class(router->qd, ROUTER_TYPE, router, ROUTER_ATTRIBUTES, qd_router_query_router); + qd_agent_register_class(router->qd, QD_ROUTER_TYPE, router, ROUTER_ATTRIBUTES, qd_router_query_router); router->class_link = - qd_agent_register_class(router->qd, LINK_TYPE, router, LINK_ATTRIBUTES, qd_router_query_link); + qd_agent_register_class(router->qd, QD_ROUTER_LINK_TYPE, router, LINK_ATTRIBUTES, qd_router_query_link); router->class_node = - qd_agent_register_class(router->qd, NODE_TYPE, router, NODE_ATTRIBUTES, qd_router_query_node); + qd_agent_register_class(router->qd, QD_ROUTER_NODE_TYPE, router, NODE_ATTRIBUTES, qd_router_query_node); router->class_address = - qd_agent_register_class(router->qd, ADDRESS_TYPE, router, ADDRESS_ATTRIBUTES, qd_router_query_address); + qd_agent_register_class(router->qd, QD_ROUTER_ADDRESS_TYPE, router, ADDRESS_ATTRIBUTES, qd_router_query_address); return qd_error_code(); } @@ -369,7 +445,7 @@ qd_error_t qd_router_agent_setup(qd_rout void qd_router_build_node_list(qd_dispatch_t *qd, qd_composed_field_t *field) { qd_router_t *router = qd->router; - char temp[1000]; // FIXME + char temp[1000]; sys_mutex_lock(router->lock); qd_router_node_t *rnode = DEQ_HEAD(router->routers); Modified: qpid/dispatch/trunk/src/router_node.c URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/router_node.c?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/router_node.c (original) +++ qpid/dispatch/trunk/src/router_node.c Fri Oct 17 23:35:35 2014 @@ -24,6 +24,7 @@ #include <stdlib.h> #include <qpid/dispatch.h> #include "dispatch_private.h" +#include "c_entity.h" #include "router_private.h" #include "waypoint_private.h" @@ -156,6 +157,7 @@ void qd_router_check_addr(qd_router_t *r // qd_hash_remove_by_handle2(router->addr_hash, addr->hash_handle, &key); DEQ_REMOVE(router->addrs, addr); + qd_c_entity_remove(QD_ROUTER_ADDRESS_TYPE, addr); qd_hash_handle_free(addr->hash_handle); free_qd_address_t(addr); } @@ -1002,6 +1004,7 @@ static int router_incoming_link_handler( sys_mutex_lock(router->lock); rlink->mask_bit = is_router ? qd_router_find_mask_bit_LH(router, link) : 0; + qd_c_entity_add(QD_ROUTER_LINK_TYPE, rlink); DEQ_INSERT_TAIL(router->links, rlink); sys_mutex_unlock(router->lock); @@ -1118,7 +1121,7 @@ static int router_outgoing_link_handler( // assign it an ephemeral and routable address. If it has a non-dynamic // address, that address needs to be set up in the address list. // - char temp_addr[1000]; // FIXME + char temp_addr[1000]; // TODO: Use pn_string or aprintf. if (is_dynamic) { qd_router_generate_temp_addr(router, temp_addr, 1000); @@ -1134,6 +1137,7 @@ static int router_outgoing_link_handler( qd_hash_insert(router->addr_hash, iter, addr, &addr->hash_handle); DEQ_INSERT_TAIL(router->addrs, addr); addr->semantics = semantics; + qd_c_entity_add(QD_ROUTER_ADDRESS_TYPE, addr); } rlink->owning_addr = addr; @@ -1146,7 +1150,7 @@ static int router_outgoing_link_handler( // propagate = (!is_dynamic) && (DEQ_SIZE(addr->rlinks) == 1); } - + qd_c_entity_add(QD_ROUTER_LINK_TYPE, rlink); DEQ_INSERT_TAIL(router->links, rlink); // @@ -1222,6 +1226,7 @@ static int router_link_detach_handler(vo // Remove the link from the master list-of-links. // DEQ_REMOVE(router->links, rlink); + qd_c_entity_remove(QD_ROUTER_LINK_TYPE, rlink); sys_mutex_unlock(router->lock); // @@ -1229,7 +1234,6 @@ static int router_link_detach_handler(vo // qd_router_check_addr(router, oaddr, 1); - // TODO - wrap the free to handle the recursive items if (rlink->target) free(rlink->target); free_qd_router_link_t(rlink); @@ -1311,6 +1315,7 @@ static void router_outbound_open_handler DEQ_INIT(rlink->msg_fifo); qd_link_set_context(receiver, rlink); + qd_c_entity_add(QD_ROUTER_LINK_TYPE, rlink); DEQ_INSERT_TAIL(router->links, rlink); // @@ -1348,6 +1353,7 @@ static void router_outbound_open_handler router->out_links_by_mask_bit[mask_bit] = rlink; qd_link_set_context(sender, rlink); + qd_c_entity_add(QD_ROUTER_LINK_TYPE, rlink); DEQ_INSERT_TAIL(router->links, rlink); sys_mutex_unlock(router->lock); @@ -1493,8 +1499,8 @@ void qd_router_free(qd_router_t *router) } qd_hash_handle_free(addr->hash_handle); - DEQ_REMOVE_HEAD(router->addrs); + qd_c_entity_remove(QD_ROUTER_ADDRESS_TYPE, addr); free_qd_address_t(addr); } @@ -1528,8 +1534,8 @@ qd_address_t *qd_router_register_address { char addr_string[1000]; qd_router_t *router = qd->router; - qd_address_t *addr; - qd_field_iterator_t *iter; + qd_address_t *addr = 0; + qd_field_iterator_t *iter = 0; strcpy(addr_string, global ? "M0" : "L"); strcat(addr_string, address); @@ -1543,6 +1549,7 @@ qd_address_t *qd_router_register_address qd_hash_insert(router->addr_hash, iter, addr, &addr->hash_handle); DEQ_ITEM_INIT(addr); DEQ_INSERT_TAIL(router->addrs, addr); + qd_c_entity_add(QD_ROUTER_ADDRESS_TYPE, addr); } qd_field_iterator_free(iter); @@ -1553,6 +1560,7 @@ qd_address_t *qd_router_register_address if (handler) qd_log(router->log_source, QD_LOG_INFO, "In-Process Address Registered: %s", address); + assert(addr); return addr; } Modified: qpid/dispatch/trunk/src/router_private.h URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/router_private.h?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/router_private.h (original) +++ qpid/dispatch/trunk/src/router_private.h Fri Oct 17 23:35:35 2014 @@ -24,6 +24,7 @@ *@internal */ +#include <qpid/dispatch/enum.h> #include <qpid/dispatch/router.h> #include <qpid/dispatch/message.h> #include <qpid/dispatch/bitmask.h> @@ -48,6 +49,7 @@ typedef enum { QD_ROUTER_MODE_EDGE, ///< Edge router. No transit-router capability. QD_ROUTER_MODE_ENDPOINT ///< No routing except for internal modules (agent, etc.). } qd_router_mode_t; +ENUM_DECLARE(qd_router_mode); typedef enum { QD_LINK_ENDPOINT, ///< A link to a connected endpoint @@ -55,7 +57,7 @@ typedef enum { QD_LINK_ROUTER, ///< A link to a peer router in the same area QD_LINK_AREA ///< A link to a peer router in a different area (area boundary) } qd_link_type_t; - +ENUM_DECLARE(qd_link_type); typedef struct qd_routed_event_t { DEQ_LINKS(struct qd_routed_event_t); Modified: qpid/dispatch/trunk/src/router_pynode.c URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/router_pynode.c?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/router_pynode.c (original) +++ qpid/dispatch/trunk/src/router_pynode.c Fri Oct 17 23:35:35 2014 @@ -26,6 +26,7 @@ #include "dispatch_private.h" #include "router_private.h" #include "waypoint_private.h" +#include "c_entity.h" static qd_address_semantics_t router_addr_semantics = QD_FANOUT_SINGLE | QD_BIAS_CLOSEST | QD_CONGESTION_DROP | QD_DROP_FOR_SLOW_CONSUMERS | QD_BYPASS_VALID_ORIGINS; @@ -81,6 +82,7 @@ static char *qd_add_router(qd_router_t * addr->semantics = router_addr_semantics; qd_hash_insert(router->addr_hash, iter, addr, &addr->hash_handle); DEQ_INSERT_TAIL(router->addrs, addr); + qd_c_entity_add(QD_ROUTER_ADDRESS_TYPE, addr); qd_field_iterator_free(iter); // @@ -96,6 +98,7 @@ static char *qd_add_router(qd_router_t * rnode->valid_origins = qd_bitmask(0); DEQ_INSERT_TAIL(router->routers, rnode); + qd_c_entity_add(QD_ROUTER_NODE_TYPE, rnode); // // Link the router record to the address record. @@ -139,6 +142,9 @@ static char *qd_del_router(qd_router_t * qd_address_t *oaddr = rnode->owning_addr; assert(oaddr); + qd_c_entity_remove(QD_ROUTER_ADDRESS_TYPE, oaddr); + qd_c_entity_remove(QD_ROUTER_NODE_TYPE, rnode); + // // Unlink the router node from the address record // @@ -387,6 +393,7 @@ static PyObject* qd_map_destination(PyOb addr->semantics = router_semantics_for_addr(router, iter, phase, &unused); DEQ_ITEM_INIT(addr); DEQ_INSERT_TAIL(router->addrs, addr); + qd_c_entity_add(QD_ROUTER_ADDRESS_TYPE, addr); } qd_field_iterator_free(iter); Modified: qpid/dispatch/trunk/src/server.c URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/server.c?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/server.c (original) +++ qpid/dispatch/trunk/src/server.c Fri Oct 17 23:35:35 2014 @@ -21,6 +21,8 @@ #include <qpid/dispatch/threading.h> #include <qpid/dispatch/log.h> #include <qpid/dispatch/amqp.h> +#include "entity_private.h" +#include "c_entity.h" #include "dispatch_private.h" #include "server_private.h" #include "timer_private.h" @@ -37,6 +39,14 @@ ALLOC_DEFINE(qd_connector_t); ALLOC_DEFINE(qd_connection_t); ALLOC_DEFINE(qd_user_fd_t); +static const char *conn_state_names[] = { + "connecting", + "opening", + "operational", + "failed", + "user" +}; +ENUM_DEFINE(conn_state, conn_state_names); static qd_thread_t *thread(qd_server_t *qd_server, int id) { @@ -53,6 +63,44 @@ static qd_thread_t *thread(qd_server_t * return thread; } +qd_error_t qd_entity_update_connection(qd_entity_t* entity, void *impl); + +static qd_error_t connection_entity_update_host(qd_entity_t* entity, qd_connection_t *conn) +{ + const qd_server_config_t *config; + if (conn->connector) { + config = conn->connector->config; + char host[strlen(config->host)+strlen(config->port)+2]; + snprintf(host, sizeof(host), "%s:%s", config->host, config->port); + return qd_entity_set_string(entity, "host", host); + } + else + return qd_entity_set_string(entity, "host", pn_connector_name(conn->pn_cxtr)); +} + +qd_error_t qd_c_entity_update_connection(qd_entity_t* entity, void *impl) +{ + qd_connection_t *conn = (qd_connection_t*)impl; + const qd_server_config_t *config = + conn->connector ? conn->connector->config : conn->listener->config; + + if ((qd_entity_has(entity, "identity") || + qd_entity_set_string(entity, "identity", pn_connector_name(conn->pn_cxtr)) == 0) && + qd_entity_set_string(entity, "state", conn_state_name(conn->state)) == 0 && + qd_entity_set_string( + entity, "container", + conn->pn_conn ? pn_connection_remote_container(conn->pn_conn) : 0) == 0 && + connection_entity_update_host(entity, conn) == 0 && + /* FIXME aconway 2014-10-14: change attr name to sasl-mechanisms for consistency? */ + qd_entity_set_string(entity, "sasl", config->sasl_mechanisms) == 0 && + qd_entity_set_string(entity, "role", config->role) == 0 && + qd_entity_set_string(entity, "dir", conn->connector ? "out" : "in") == 0) + return QD_ERROR_NONE; + return qd_error_code(); +} + + + static void thread_process_listeners(qd_server_t *qd_server) { @@ -93,6 +141,7 @@ static void thread_process_listeners(qd_ // qd_server->lock is already locked DEQ_INSERT_TAIL(qd_server->connections, ctx); + qd_c_entity_add(QD_CONNECTION_TYPE, ctx); // // Get a pointer to the transport so we can insert security components into it @@ -492,6 +541,7 @@ static void *thread_run(void *arg) // Check to see if the connector was closed during processing // if (pn_connector_closed(cxtr)) { + qd_c_entity_remove(QD_CONNECTION_TYPE, ctx); // // Connector is closed. Free the context and the connector. // @@ -508,6 +558,7 @@ static void *thread_run(void *arg) sys_mutex_lock(qd_server->lock); DEQ_REMOVE(qd_server->connections, ctx); + pn_connector_free(cxtr); if (conn) pn_connection_free(conn); @@ -607,6 +658,8 @@ static void cxtr_try_open(void *context) sys_mutex_lock(ct->server->lock); ctx->pn_cxtr = pn_connector(ct->server->driver, ct->config->host, ct->config->port, (void*) ctx); DEQ_INSERT_TAIL(ct->server->connections, ctx); + qd_c_entity_add(QD_CONNECTION_TYPE, ctx); + sys_mutex_unlock(ct->server->lock); ct->ctx = ctx; @@ -658,7 +711,7 @@ static void cxtr_try_open(void *context) } -qd_server_t *qd_server(int thread_count, const char *container_name) +qd_server_t *qd_server(qd_dispatch_t *qd, int thread_count, const char *container_name) { int i; @@ -667,6 +720,7 @@ qd_server_t *qd_server(int thread_count, return 0; DEQ_INIT(qd_server->connections); + qd_server->qd = qd; qd_server->log_source = qd_log_source("SERVER"); qd_server->thread_count = thread_count; qd_server->container_name = container_name; Modified: qpid/dispatch/trunk/src/server_private.h URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/server_private.h?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/server_private.h (original) +++ qpid/dispatch/trunk/src/server_private.h Fri Oct 17 23:35:35 2014 @@ -19,6 +19,7 @@ * under the License. */ +#include <qpid/dispatch/enum.h> #include <qpid/dispatch/server.h> #include <qpid/dispatch/user_fd.h> #include <qpid/dispatch/alloc.h> @@ -43,6 +44,7 @@ typedef enum { CONN_STATE_FAILED, CONN_STATE_USER } conn_state_t; +ENUM_DECLARE(conn_state); #define CONTEXT_NO_OWNER -1 @@ -127,6 +129,7 @@ DEQ_DECLARE(qd_work_item_t, qd_work_list struct qd_server_t { + qd_dispatch_t *qd; int thread_count; const char *container_name; pn_driver_t *driver; Modified: qpid/dispatch/trunk/src/waypoint.c URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/waypoint.c?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/src/waypoint.c (original) +++ qpid/dispatch/trunk/src/waypoint.c Fri Oct 17 23:35:35 2014 @@ -20,6 +20,7 @@ #include "waypoint_private.h" #include "dispatch_private.h" #include "router_private.h" +#include "c_entity.h" #include <qpid/dispatch/ctools.h> #include <qpid/dispatch/threading.h> #include <qpid/dispatch/connection_manager.h> @@ -68,6 +69,7 @@ static void qd_waypoint_visit_sink_LH(qd DEQ_INSERT_TAIL(router->addrs, addr); addr->waypoint = true; addr->semantics = router_semantics_for_addr(router, iter, wp->in_phase, &unused); + qd_c_entity_add(QD_ROUTER_ADDRESS_TYPE, addr); } wp->in_address = addr; @@ -97,6 +99,7 @@ static void qd_waypoint_visit_sink_LH(qd rlink->target = 0; DEQ_INIT(rlink->event_fifo); DEQ_INIT(rlink->msg_fifo); + qd_c_entity_add(QD_ROUTER_LINK_TYPE, rlink); DEQ_INSERT_TAIL(router->links, rlink); qd_link_set_context(wp->out_link, rlink); qd_router_add_link_ref_LH(&addr->rlinks, rlink); @@ -141,6 +144,7 @@ static void qd_waypoint_visit_source_LH( DEQ_INSERT_TAIL(router->addrs, addr); addr->waypoint = true; addr->semantics = router_semantics_for_addr(router, iter, wp->out_phase, &unused); + qd_c_entity_add(QD_ROUTER_ADDRESS_TYPE, addr); } wp->out_address = addr; @@ -170,6 +174,7 @@ static void qd_waypoint_visit_source_LH( rlink->target = 0; DEQ_INIT(rlink->event_fifo); DEQ_INIT(rlink->msg_fifo); + qd_c_entity_add(QD_ROUTER_LINK_TYPE, rlink); DEQ_INSERT_TAIL(router->links, rlink); qd_link_set_context(wp->in_link, rlink); Modified: qpid/dispatch/trunk/tests/management/client.py URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/management/client.py?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/tests/management/client.py (original) +++ qpid/dispatch/trunk/tests/management/client.py Fri Oct 17 23:35:35 2014 @@ -25,10 +25,10 @@ from qpid_dispatch.management import Url class UrlTest(unittest.TestCase): def test_url(self): - url = Url(scheme='amqp', user='me', password='secret', host='myhost', port=1234, path='foobar') + url = Url(scheme='amqp', username='me', password='secret', host='myhost', port=1234, path='foobar') self.assertEqual(str(url), "amqp://me:secret@myhost:1234/foobar") self.assertEqual( - [url.scheme, url.user, url.password, url.host, url.port, url.path], + [url.scheme, url.username, url.password, url.host, url.port, url.path], ['amqp', 'me', 'secret', 'myhost', 1234, 'foobar'] ) @@ -42,22 +42,13 @@ class UrlTest(unittest.TestCase): self.assertNotEqual(str(url), "amqp://me:secret@myhost:5555/foobar") # Check that we allow None for scheme, port - url = Url(user='me', password='secret', host='myhost', path='foobar') + url = Url(username='me', password='secret', host='myhost', path='foobar') self.assertEqual(str(url), "me:secret@myhost/foobar") self.assertEqual( - [url.scheme, url.user, url.password, url.host, url.port, url.path], + [url.scheme, url.username, url.password, url.host, url.port, url.path], [None, 'me', 'secret', 'myhost', None, 'foobar'] ) - # Scheme defaults - self.assertEqual(str(Url("me:secret@myhost/foobar").defaults()), - "amqp://me:secret@myhost:5672/foobar") - # Correct port for amqps vs. amqps - self.assertEqual(str(Url("amqps://me:secret@myhost/foobar").defaults()), - "amqps://me:secret@myhost:5671/foobar") - self.assertEqual(str(Url("amqp://me:secret@myhost/foobar").defaults()), - "amqp://me:secret@myhost:5672/foobar") - # Empty string for path self.assertEqual(Url("myhost/").path, "") self.assertIsNone(Url("myhost").path) Modified: qpid/dispatch/trunk/tests/management/qdrouter.py URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/management/qdrouter.py?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/tests/management/qdrouter.py (original) +++ qpid/dispatch/trunk/tests/management/qdrouter.py Fri Oct 17 23:35:35 2014 @@ -73,21 +73,21 @@ listener { content = conf._default_ids(content) self.assertEqual(content, [ - ["router", {"mode":"standalone", "name":"router0", "identity":"router0"}], + ["router", {"mode":"standalone", "name":"router:0", "identity":"router:0"}], ["listener", {"name":"l0", "identity":"l0", "sasl-mechanisms":"ANONYMOUS", "password":"secret"}], ["listener", {"name":"l1", "identity":"l1", "sasl-mechanisms":"ANONYMOUS", "port":"1234"}], - ["listener", {"name":"listener2", "identity":"listener2", "sasl-mechanisms":"ANONYMOUS", "port":"4567"}] + ["listener", {"name":"listener:2", "identity":"listener:2", "sasl-mechanisms":"ANONYMOUS", "port":"4567"}] ]) conf.load(conf_text.split("\n")) router = conf.by_type('router').next() - self.assertEqual(router['name'], 'router0') - self.assertEqual(router['identity'], 'router0') + self.assertEqual(router['name'], 'router:0') + self.assertEqual(router['identity'], 'router:0') listeners = list(conf.by_type('listener')) self.assertEqual(len(listeners), 3) self.assertEqual(listeners[0]['name'], 'l0') - self.assertEqual(listeners[2]['name'], 'listener2') - self.assertEqual(listeners[2]['identity'], 'listener2') + self.assertEqual(listeners[2]['name'], 'listener:2') + self.assertEqual(listeners[2]['identity'], 'listener:2') if __name__ == '__main__': unittest.main() Modified: qpid/dispatch/trunk/tests/management/schema.py URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/management/schema.py?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/tests/management/schema.py (original) +++ qpid/dispatch/trunk/tests/management/schema.py Fri Oct 17 23:35:35 2014 @@ -21,7 +21,7 @@ #pylint: disable=wildcard-import,missing-docstring,too-many-public-methods import unittest, json -from qpid_dispatch_internal.management.schema import Schema, BooleanType, EnumType, AttributeType, schema_file, ValidationError, EnumValue, EntityType +from qpid_dispatch_internal.management.schema import Schema, BooleanType, EnumType, AttributeType, ValidationError, EnumValue, EntityType import collections def replace_od(thing): @@ -152,14 +152,6 @@ class SchemaTest(unittest.TestCase): self.assertEqual({'identity': 'x', 'name': 'y'}, e.validate({'identity': 'x', 'name':'y'})) self.assertRaises(ValidationError, e.validate, {}) - qdrouter_json = schema_file('qdrouter.json') - - @staticmethod - def load_schema(fname=qdrouter_json): - with open(fname) as f: - j = json.load(f) - return Schema(**j) - def test_schema_dump(self): s = Schema(**SCHEMA_1) self.maxDiff = None # pylint: disable=invalid-name Modified: qpid/dispatch/trunk/tests/run.py.in URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/run.py.in?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/tests/run.py.in (original) +++ qpid/dispatch/trunk/tests/run.py.in Fri Oct 17 23:35:35 2014 @@ -99,7 +99,7 @@ def is_binary_exe(program): p = Popen(['file', '-bi', program], stdout=PIPE, stderr=PIPE) return p.communicate()[0].startswith('application/x-executable') -def with_valgrind(args): +def with_valgrind(args, outfile=None): if use_valgrind() and is_binary_exe(find_exe(args[0])): opts = ['--leak-check=full', '--demangle=yes', @@ -107,6 +107,7 @@ def with_valgrind(args): '--num-callers=12', '--error-exitcode=42', '--quiet'] + if outfile: opts.append('--log-file=%s' % outfile) return [valgrind_exe]+opts+args return args Modified: qpid/dispatch/trunk/tests/system_test.py URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/system_test.py?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/tests/system_test.py (original) +++ qpid/dispatch/trunk/tests/system_test.py Fri Oct 17 23:35:35 2014 @@ -208,7 +208,7 @@ class Process(subprocess.Popen): @classmethod def unique(cls, name): cls.unique_id += 1 - return name + str(cls.unique_id) + return "%s-%s" % (name, cls.unique_id) def __init__(self, args, name=None, expect=EXIT_OK, **kwargs): """ @@ -228,7 +228,7 @@ class Process(subprocess.Popen): self.torndown = False kwargs.setdefault('stdout', self.out) kwargs.setdefault('stderr', subprocess.STDOUT) - args = with_valgrind(args) + args = with_valgrind(args, self.outfile + '.vg') try: super(Process, self).__init__(args, **kwargs) except Exception, e: @@ -376,10 +376,11 @@ class Qdrouterd(Process): """ def check(): # FIXME aconway 2014-06-12: this should be a request by name, not a query. + # Need to rationalize addresses in management attributes. + # endswith check is because of M0/L/R prefixes addrs = self.management.query( type='org.apache.qpid.dispatch.router.address', attribute_names=['name', 'subscriberCount', 'remoteCount']).get_entities() - # FIXME aconway 2014-06-12: endswith check is because of M0/L prefixes addrs = [a for a in addrs if a['name'].endswith(address)] return addrs and addrs[0]['subscriberCount'] >= subscribers and addrs[0]['remoteCount'] >= remotes assert retry(check, **retry_kwargs) @@ -398,6 +399,12 @@ class Qdrouterd(Process): wait_ports(self.ports) self.wait_connectors() + def wait_connected(self, router_id): + """Wait till this router is connected to router with router-id""" + node = Node(self.addresses[0], router_id, timeout=0.2) + retry_exception(lambda: node.query('org.apache.qpid.dispatch.router')) + + class Qpidd(Process): """Run a Qpid Daemon""" Modified: qpid/dispatch/trunk/tests/system_tests_management.py URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/system_tests_management.py?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/tests/system_tests_management.py (original) +++ qpid/dispatch/trunk/tests/system_tests_management.py Fri Oct 17 23:35:35 2014 @@ -23,19 +23,24 @@ import unittest, system_test, re, os from qpid_dispatch.management import Node, ManagementError, Url, BadRequestStatus, NotImplementedStatus, NotFoundStatus, ForbiddenStatus from system_test import Qdrouterd, message, retry -LISTENER = 'org.apache.qpid.dispatch.listener' -CONNECTOR = 'org.apache.qpid.dispatch.connector' -FIXED_ADDRESS = 'org.apache.qpid.dispatch.fixed-address' -WAYPOINT = 'org.apache.qpid.dispatch.waypoint' -DUMMY = 'org.apache.qpid.dispatch.dummy' +DISPATCH = 'org.apache.qpid.dispatch' +LISTENER = DISPATCH + '.listener' +CONNECTOR = DISPATCH + '.connector' +FIXED_ADDRESS = DISPATCH + '.fixed-address' +WAYPOINT = DISPATCH + '.waypoint' +DUMMY = DISPATCH + '.dummy' +ROUTER = DISPATCH + '.router' +LINK = ROUTER + '.link' +ADDRESS = ROUTER + '.address' +NODE = ROUTER + '.node' -ADDRESS = 'org.apache.qpid.dispatch.router.address' class ManagementTest(system_test.TestCase): # pylint: disable=too-many-public-methods @classmethod def setUpClass(cls): super(ManagementTest, cls).setUpClass() + # Stand-alone router name = cls.__name__ cls.log_file = name+".log" conf = Qdrouterd.Config([ @@ -52,8 +57,6 @@ class ManagementTest(system_test.TestCas def setUp(self): super(ManagementTest, self).setUp() self.node = self.cleanup(Node(self.router.addresses[0])) - # Temporary access to separate new management address. - self.node2 = self.cleanup(Node(Url(self.router.addresses[0], path='$management2'))) self.maxDiff = None self.longMessage = True @@ -61,14 +64,12 @@ class ManagementTest(system_test.TestCas """Test that various badly formed queries get the proper response""" # No operation attribute self.assertRaises(BadRequestStatus, self.node.call, self.node.request()) - # Unknown operation - self.assertRaises(NotImplementedStatus, self.node.call, self.node.request(operation="nosuch")) - # No entityType or attributeList - self.assertRaises(BadRequestStatus, self.node.query) + self.assertRaises(NotImplementedStatus, self.node.call, + self.node.request(operation="nosuch", type="org.amqp.management")) def test_query_type(self): """Query with type only""" - response = self.node2.query(type=LISTENER) + response = self.node.query(type=LISTENER) for attr in ['type', 'name', 'identity', 'addr', 'port']: self.assertTrue(attr in response.attribute_names) for r in response.get_dicts(): @@ -80,7 +81,7 @@ class ManagementTest(system_test.TestCas def test_query_type_attributes(self): """Query with type and attribute names""" attribute_names=['type', 'name', 'port'] - response = self.node2.query(type=LISTENER, attribute_names=attribute_names) + response = self.node.query(type=LISTENER, attribute_names=attribute_names) self.assertEqual(attribute_names, response.attribute_names) expect = [[LISTENER, 'l%s' % i, str(self.router.ports[i])] for i in xrange(3)] for r in expect: # We might have extras in results due to create tests @@ -90,12 +91,12 @@ class ManagementTest(system_test.TestCas def test_query_attributes(self): """Query with attributes only""" attribute_names=['type', 'name', 'port'] - response = self.node2.query(attribute_names=attribute_names) + response = self.node.query(attribute_names=attribute_names) self.assertEqual(attribute_names, response.attribute_names) expect = [[LISTENER, 'l%s' % i, str(self.router.ports[i])] for i in xrange(3)] for r in expect: # We might have extras in results due to create tests self.assertTrue(r in response.results) - for name in ['router0', 'log0']: + for name in [self.router.name, 'log:0']: self.assertTrue([r for r in response.get_dicts() if r['name'] == name], msg="Can't find result with name '%s'" % name) @@ -105,7 +106,7 @@ class ManagementTest(system_test.TestCas assert not missing, "Not a subset, missing %s, sub=%s, super=%s"%(missing, small, big) def assert_create_ok(self, type, name, attributes): - entity = self.node2.create(attributes, type, name) + entity = self.node.create(attributes, type, name) self.assertMapSubset(attributes, entity.attributes) return entity @@ -120,20 +121,16 @@ class ManagementTest(system_test.TestCas self.assertEqual(entity['addr'], '0.0.0.0') # Connect via the new listener - node3 = self.cleanup(Node(Url(port=port, path='$management'))) - router = node3.query(type='org.apache.qpid.dispatch.router').get_entities() + node3 = self.cleanup(Node(Url(port=port))) + router = node3.query(type=ROUTER).get_entities() self.assertEqual(self.__class__.router.name, router[0]['name']) def test_create_log(self): """Create a log entity""" - # FIXME aconway 2014-07-04: rework log entity. - # - allow auto-assigned name/identity? Use module as name/identity? - # - 1 entity with full log state, allow updates. log = os.path.abspath("test_create_log.log") - # FIXME aconway 2014-09-08: PYAGENT->AGENT - self.assert_create_ok('log', 'log.1', dict(module='PYAGENT', level="error", output=log)) + self.assert_create_ok('log', 'log.1', dict(module='AGENT', level="error", output=log)) # Cause an error and verify it shows up in the log file. - self.assertRaises(ManagementError, self.node2.create, type='nosuch', name='nosuch') + self.assertRaises(ManagementError, self.node.create, type='nosuch', name='nosuch') f = self.cleanup(open(log)) logstr = f.read() self.assertTrue(re.search(r'ValidationError.*nosuch', logstr), @@ -191,21 +188,21 @@ class ManagementTest(system_test.TestCas f.close() def test_entity(self): - entity = self.node2.read(type=LISTENER, name='l0') + entity = self.node.read(type=LISTENER, name='l0') self.assertEqual('l0', entity.name) self.assertEqual('l0', entity.identity) self.assertEqual(str(self.router.ports[0]), entity.port) - entity = self.node2.read(type=LISTENER, identity='l1') + entity = self.node.read(type=LISTENER, identity='l1') self.assertEqual('l1', entity.name) self.assertEqual('l1', entity.identity) self.assertEqual(str(self.router.ports[1]), entity.port) # Bad type - self.assertRaises(NotFoundStatus, self.node2.read, type=CONNECTOR, name='l0') + self.assertRaises(NotFoundStatus, self.node.read, type=CONNECTOR, name='l0') # Unknown entity - self.assertRaises(NotFoundStatus, self.node2.read, type=LISTENER, name='nosuch') + self.assertRaises(NotFoundStatus, self.node.read, type=LISTENER, name='nosuch') # Update and delete are not allowed by the schema self.assertRaises(ForbiddenStatus, entity.update) @@ -215,7 +212,7 @@ class ManagementTest(system_test.TestCas self.assertRaises(ForbiddenStatus, entity.call, 'nosuchop', foo="bar") # Dummy entity supports all CRUD operations - dummy = self.node2.create({'arg1': 'START'}, type=DUMMY, name='MyDummy', ) + dummy = self.node.create({'arg1': 'START'}, type=DUMMY, name='MyDummy', ) self.assertEqual(dummy.type, DUMMY) self.assertEqual(dummy.name, 'MyDummy') self.assertEqual(dummy.arg1, 'START') @@ -237,7 +234,7 @@ class ManagementTest(system_test.TestCas dict(type=DUMMY, name='MyDummy', identity=identity, arg1='one', num1=42), dummy.attributes) - dummy2 = self.node2.read(type=DUMMY, name='MyDummy') + dummy2 = self.node.read(type=DUMMY, name='MyDummy') self.assertEqual(dummy.attributes, dummy2.attributes) self.assertEqual({'operation': 'callme', 'foo': 'bar', 'type': DUMMY, 'identity': identity}, @@ -247,19 +244,87 @@ class ManagementTest(system_test.TestCas self.assertRaises(BadRequestStatus, dummy.update) dummy.delete() - self.assertRaises(NotFoundStatus, self.node2.read, type=DUMMY, name='MyDummy') + self.assertRaises(NotFoundStatus, self.node.read, type=DUMMY, name='MyDummy') + + def test_link(self): + """Verify we can find our own reply-to address in links""" + response = self.node.query(type=LINK) + path = self.node.reply_to.split('/')[-1] + mylink = [l for l in response.get_dicts() + if l['owningAddr'] and l['owningAddr'].endswith(path)] + self.assertTrue(mylink) + + def test_connection(self): + """Verify there is at least one connection""" + response = self.node.query(type='connection') + self.assertTrue(response.get_dicts()) + + def test_router(self): + """Verify router counts match entity counts""" + entities = self.node.query().get_entities() + routers = [e for e in entities if e.type == ROUTER] + self.assertEqual(1, len(routers)) + router = routers[0] + self.assertEqual(router.linkCount, len([e for e in entities if e.type == LINK])) + self.assertEqual(router.addrCount, len([e for e in entities if e.type == ADDRESS])) + + def test_router_node(self): + """Test node entity in a pair of linked routers""" + # Pair of linked interior routers + conf1 = Qdrouterd.Config([ + ('log', {'module':'DEFAULT', 'level':'trace', 'output':'router1.log'}), + ('router', { 'mode': 'interior', 'router-id': 'router1'}), + ('listener', {'port':self.get_port(), 'role':'normal'}), + ('listener', {'port':self.get_port(), 'role':'inter-router'}) + ]) + conf2 = Qdrouterd.Config([ + ('log', {'module':'DEFAULT', 'level':'trace', 'output':'router2.log'}), + ('router', { 'mode': 'interior', 'router-id': 'router2'}), + ('listener', {'port':self.get_port(), 'role':'normal'}), + ('connector', {'port':conf1.sections('listener')[1]['port'], 'role':'inter-router'}) + ]) + routers = [self.qdrouterd('router1', conf1, wait=False), + self.qdrouterd('router2', conf2, wait=False)] + for r in routers: r.wait_ready() + routers[0].wait_connected('router2') + routers[1].wait_connected('router1') + + nodes = [self.cleanup(Node(Url(r.addresses[0]))) for r in routers] + + class RNodes(list): + def __call__(self): + self[:] = sum([n.query(type=NODE).get_entities() for n in nodes], []) + return self + rnodes = RNodes() + + assert retry(lambda: len(rnodes()) >= 2) + self.assertEqual(['Rrouter2', 'Rrouter1'], [r.addr for r in rnodes]) + # FIXME aconway 2014-10-15: verify nextHop and validOrigins updated correctly + self.assertEqual([u'amqp:/_topo/0/router2/$management', u'amqp:/_topo/0/router1/$management'], + sum([n.get_mgmt_nodes() for n in nodes], [])) - def test_get_types(self): - self.assertRaises(NotImplementedStatus, self.node2.get_types) - def test_get_attributes(self): - self.assertRaises(NotImplementedStatus, self.node2.get_attributes) + + def test_get_types(self): + types = self.node.get_types() + self.assertIn('org.apache.qpid.dispatch.listener', types) + self.assertIn('org.apache.qpid.dispatch.waypoint', types) + self.assertIn('org.apache.qpid.dispatch.router.link', types) def test_get_operations(self): - self.assertRaises(NotImplementedStatus, self.node2.get_operations) + result = self.node.get_operations(type=DUMMY) + self.assertEqual({DUMMY: ["CREATE", "READ", "UPDATE", "DELETE", "CALLME"]}, result) + result = self.node.get_operations() + for type in LISTENER, WAYPOINT, LINK: self.assertIn(type, result) + self.assertEqual(["READ"], result[LINK]) + self.assertEqual(["CREATE", "READ"], result[WAYPOINT]) - def test_get_mgmt_nodes(self): - self.assertRaises(NotImplementedStatus, self.node2.get_mgmt_nodes) + def test_get_attributes(self): + result = self.node.get_attributes(type=DUMMY) + self.assertEqual({DUMMY: [u'arg1', u'arg2', u'num1', u'num2', u'name', u'identity', u'type']}, result) + result = self.node.get_attributes() + for type in LISTENER, WAYPOINT, LINK: self.assertIn(type, result) + for a in ['linkType', 'linkDir', 'owningAddr']: self.assertIn(a, result[LINK]) if __name__ == '__main__': unittest.main() Modified: qpid/dispatch/trunk/tests/system_tests_one_router.py URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/system_tests_one_router.py?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/tests/system_tests_one_router.py (original) +++ qpid/dispatch/trunk/tests/system_tests_one_router.py Fri Oct 17 23:35:35 2014 @@ -546,7 +546,7 @@ class RouterTest(TestCase): M.recv() M.get(response) - self.assertEqual(response.properties['statusCode'], 200) + assert response.properties['statusCode'] == 200, response.properties['statusDescription'] self.assertEqual(response.correlation_id, "C1") self.assertEqual(response.body, []) @@ -578,156 +578,6 @@ class RouterTest(TestCase): M.stop() - def test_09a_management_get_types(self): - addr = "amqp:/_local/$management" - - M = Messenger() - M.timeout = 2.0 - M.start() - M.route("amqp:/*", self.address+"/$1") - sub = M.subscribe("amqp:/#") - reply = sub.address - - request = Message() - response = Message() - - ## - ## Unrestricted request - ## - request.address = addr - request.reply_to = reply - request.properties = {u'type':u'org.amqp.management', u'name':u'self', u'operation':u'GET-TYPES'} - - M.put(request) - M.send() - M.recv() - M.get(response) - - self.assertEqual(response.properties['statusCode'], 200) - self.assertEqual(response.body.__class__, dict) - self.assertTrue('org.apache.qpid.dispatch.router' in response.body.keys()) - self.assertTrue(len(response.body.keys()) > 2) - - ## - ## Restricted Request one match - ## - request.address = addr - request.reply_to = reply - request.properties = {u'type':u'org.amqp.management', u'name':u'self', u'operation':u'GET-TYPES', - u'entityType':'org.apache.qpid.dispatch.connection'} - - M.put(request) - M.send() - M.recv() - M.get(response) - - self.assertEqual(response.properties['statusCode'], 200) - self.assertEqual(response.body.__class__, dict) - self.assertTrue('org.apache.qpid.dispatch.connection' in response.body.keys()) - self.assertEqual(len(response.body.keys()), 1) - - ## - ## Restricted Request with no matches - ## - request.address = addr - request.reply_to = reply - request.properties = {u'type':u'org.amqp.management', u'name':u'self', u'operation':u'GET-TYPES', - u'entityType':'com.profitron.item'} - - M.put(request) - M.send() - M.recv() - M.get(response) - - self.assertEqual(response.properties['statusCode'], 200) - self.assertEqual(response.body, {}) - - ## - ## Error Request - ## - request.address = addr - request.reply_to = reply - request.properties = {u'type':u'org.amqp.management', u'name':u'self', u'operation':u'GET-TYPES', - u'entityType':['one', 'two']} - - M.put(request) - M.send() - M.recv() - M.get(response) - - self.assertEqual(response.properties['statusCode'], 400) - - M.stop() - - - def test_09b_management_get_attributes(self): - addr = "amqp:/_local/$management" - - M = Messenger() - M.timeout = 2.0 - M.start() - M.route("amqp:/*", self.address+"/$1") - sub = M.subscribe("amqp:/#") - reply = sub.address - - request = Message() - response = Message() - - ## - ## Unrestricted request - ## - request.address = addr - request.reply_to = reply - request.properties = {u'type':u'org.amqp.management', u'name':u'self', u'operation':u'GET-ATTRIBUTES'} - - M.put(request) - M.send() - M.recv() - M.get(response) - - self.assertEqual(response.properties['statusCode'], 200) - self.assertEqual(response.body.__class__, dict) - self.assertTrue('org.apache.qpid.dispatch.router' in response.body.keys()) - self.assertTrue(len(response.body.keys()) > 2) - self.assertTrue(response.body['org.apache.qpid.dispatch.router'].__class__, list) - - ## - ## Restricted Request with a match - ## - request.address = addr - request.reply_to = reply - request.properties = {u'type':u'org.amqp.management', u'name':u'self', u'operation':u'GET-ATTRIBUTES', - u'entityType':'org.apache.qpid.dispatch.router'} - - M.put(request) - M.send() - M.recv() - M.get(response) - - self.assertEqual(response.properties['statusCode'], 200) - self.assertEqual(response.body.__class__, dict) - self.assertTrue('org.apache.qpid.dispatch.router' in response.body.keys()) - self.assertEqual(len(response.body.keys()), 1) - self.assertTrue('mode' in response.body['org.apache.qpid.dispatch.router']) - - ## - ## Restricted Request with no matches - ## - request.address = addr - request.reply_to = reply - request.properties = {u'type':u'org.amqp.management', u'name':u'self', u'operation':u'GET-ATTRIBUTES', - u'entityType':'com.profitron.item'} - - M.put(request) - M.send() - M.recv() - M.get(response) - - self.assertEqual(response.properties['statusCode'], 200) - self.assertEqual(response.body, {}) - - M.stop() - def test_09c_management_get_operations(self): addr = "amqp:/_local/$management" Modified: qpid/dispatch/trunk/tests/system_tests_qdmanage.py URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/system_tests_qdmanage.py?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/tests/system_tests_qdmanage.py (original) +++ qpid/dispatch/trunk/tests/system_tests_qdmanage.py Fri Oct 17 23:35:35 2014 @@ -20,7 +20,7 @@ import re, json, unittest from system_test import TestCase, Process, Qdrouterd from subprocess import PIPE, STDOUT -from copy import copy + DUMMY = "org.apache.qpid.dispatch.dummy" @@ -33,28 +33,26 @@ class QdmanageTest(TestCase): config = Qdrouterd.Config([ ('listener', {'port': cls.tester.get_port()}) ]) - cls.router = cls.tester.qdrouterd('test-router', config) + cls.router = cls.tester.qdrouterd('test-router', config, wait=True) def run_qdmanage(self, cmd, input=None, expect=Process.EXIT_OK, **kwargs): args = filter(None, sum([["--%s" % k.replace('_','-'), v] for k, v in kwargs.iteritems()], [])) p = self.popen( - ['qdmanage', cmd, '--bus', self.router.hostports[0]+"/$management2", - '--indent=-1']+args, + ['qdmanage', cmd, '--bus', self.router.hostports[0], '--indent=-1']+args, stdin=PIPE, stdout=PIPE, stderr=STDOUT, expect=expect) out = p.communicate(input)[0] - if expect == Process.EXIT_OK: - assert p.returncode == 0, "%s exit %s, output:\n%s" % (p.args, p.returncode, out) - else: - assert p.returncode != 0, "%s expected to fail but exit 0" %(p.args) + try: + p.teardown() + except Exception, e: + raise Exception("%s\n%s" % (e, out)) return out def test_help(self): self.run_qdmanage('help', r'Usage: qdmanage', expect=Process.EXIT_FAIL) for cmd in ['create', 'read', 'update', 'delete', 'query']: out = self.run_qdmanage(cmd, help=None) - assert re.search('Usage: %s \[options\]' % cmd, out, re.I), \ - "Can't find '%s' in '%s'" % (regexp, out) + assert re.search('Usage: %s \[options\]' % cmd, out, re.I) def assert_entity_equal(self, expect, actual, copy=None): """Copy keys in copy from actual to idenity, then assert maps equal.""" @@ -119,11 +117,12 @@ class QdmanageTest(TestCase): def test_query(self): def long_type(name): return u'org.apache.qpid.dispatch.'+name - TYPES=['listener', 'log', 'container', 'router'] + TYPES=['listener', 'log', 'container', 'router', 'router.link'] LONG_TYPES=[long_type(name) for name in TYPES] qall = json.loads(self.run_qdmanage('query')) - self.assertTrue(set(LONG_TYPES) <= set([e['type'] for e in qall])) + qall_types = set([e['type'] for e in qall]) + for t in LONG_TYPES: self.assertIn(t, qall_types) qlistener = json.loads(self.run_qdmanage('query', type='listener')) self.assertEqual([long_type('listener')], [e['type'] for e in qlistener]) @@ -132,10 +131,12 @@ class QdmanageTest(TestCase): qattr = json.loads( self.run_qdmanage('query', attribute_names='["type", "name"]')) for e in qattr: self.assertEqual(2, len(e)) - self.assertEqual( - set([(e['name'], e['type']) for e in qall]), - set([(e['name'], e['type']) for e in qattr])) + def name_type(entities): + ignore_types = [long_type(t) for t in ['router.link', 'connection', 'router.address']] + return set((e['name'], e['type']) for e in entities + if e['type'] not in ignore_types) + self.assertEqual(name_type(qall), name_type(qattr)) if __name__ == '__main__': unittest.main() Modified: qpid/dispatch/trunk/tests/system_tests_two_routers.py URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/system_tests_two_routers.py?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/tests/system_tests_two_routers.py (original) +++ qpid/dispatch/trunk/tests/system_tests_two_routers.py Fri Oct 17 23:35:35 2014 @@ -19,8 +19,8 @@ import unittest, os from proton import Message, PENDING, ACCEPTED, REJECTED, RELEASED, SSLDomain, SSLUnavailable -from system_test import TestCase, Qdrouterd, retry_exception -from qpid_dispatch.management import Node +from system_test import TestCase, Qdrouterd + class RouterTest(TestCase): @classmethod @@ -50,12 +50,8 @@ class RouterTest(TestCase): router('B', 'client', ('connector', {'role': 'inter-router', 'port': cls.routers[0].ports[1]})) - def query_through(address, router): - n = Node(address, router, timeout=0.2) - retry_exception(lambda: n.query('org.apache.qpid.dispatch.router')) - # Wait till we can query through each router to the other. - query_through(cls.routers[0].addresses[0], 'QDR.B') - query_through(cls.routers[1].addresses[0], 'QDR.A') + cls.routers[0].wait_connected('QDR.B') + cls.routers[1].wait_connected('QDR.A') def test_00_discard(self): @@ -474,8 +470,8 @@ class RouterTest(TestCase): M.recv() M.get(response) - self.assertEqual(response.properties['statusCode'], 200) - self.assertTrue('amqp:/_topo/0/QDR.B/$management' in response.body) + assert response.properties['statusCode'] == 200, response.properties['statusDescription'] + self.assertIn('amqp:/_topo/0/QDR.B/$management', response.body) request.address = "amqp:/_topo/0/QDR.B/$management" request.reply_to = reply Modified: qpid/dispatch/trunk/tools/qdmanage URL: http://svn.apache.org/viewvc/qpid/dispatch/trunk/tools/qdmanage?rev=1632696&r1=1632695&r2=1632696&view=diff ============================================================================== --- qpid/dispatch/trunk/tools/qdmanage (original) +++ qpid/dispatch/trunk/tools/qdmanage Fri Oct 17 23:35:35 2014 @@ -34,7 +34,9 @@ class QdManage(object): class Commands(list): """Decorator to collect command names.""" - def __call__(self, func): self.append(func.__name__); return func + def __call__(self, func): + self.append(func.__name__.replace('_', '-')); + return func commands = Commands() @@ -77,9 +79,9 @@ For help with a command: %s <command> -- self.op.add_option_group(connection_options(self.op)) json_group = optparse.OptionGroup(self.op, "JSON Formatting options") json_group.add_option("--indent", action="store", type="int", default=2, metavar="<spaces>", - help="Indent for pretty-printing output. -1 means don't pretty-print (default %default)") + help="Indent for pretty-printing output. -1 means don't pretty-print (default %default)") self.op.add_option_group(json_group) - command = getattr(self, argv[1]) + command = getattr(self, argv[1].replace('-', '_')) command() # Call the command method def setup(self, description, call_opts, other_opts=None): --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
