Author: aconway
Date: Wed Dec 10 17:26:08 2014
New Revision: 1644488

URL: http://svn.apache.org/r1644488
Log:
DISPATCH-74: Allow changes to logging configuration of a running router.

The qdmanage tool can change logging configuration, examples on the man page.

qdmanage has been made easier to use, so it's not clear a separate tool is 
justified.

Also some improvements to man page generation.

Added:
    qpid/dispatch/trunk/doc/man/qdmanage.h2m.in
      - copied, changed from r1644487, qpid/dispatch/trunk/doc/man/qdmanage.h2m
    qpid/dispatch/trunk/doc/man/qdstat.h2m.in
    qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.json.readme.txt
      - copied, changed from r1644487, 
qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.txt
Removed:
    qpid/dispatch/trunk/doc/man/qdmanage.h2m
    qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.txt
Modified:
    qpid/dispatch/trunk/doc/man/CMakeLists.txt
    qpid/dispatch/trunk/doc/man/qdmanage.8.in
    qpid/dispatch/trunk/doc/man/qdstat.8.in
    qpid/dispatch/trunk/python/CMakeLists.txt
    qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.json
    qpid/dispatch/trunk/python/qpid_dispatch_internal/management/agent.py
    qpid/dispatch/trunk/python/qpid_dispatch_internal/management/config.py
    qpid/dispatch/trunk/python/qpid_dispatch_internal/management/schema.py
    qpid/dispatch/trunk/router/src/main.c
    qpid/dispatch/trunk/src/log.c
    qpid/dispatch/trunk/tests/system_test.py
    qpid/dispatch/trunk/tests/system_tests_broker.py
    qpid/dispatch/trunk/tests/system_tests_management.py
    qpid/dispatch/trunk/tools/qdmanage

Modified: qpid/dispatch/trunk/doc/man/CMakeLists.txt
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/CMakeLists.txt?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/doc/man/CMakeLists.txt (original)
+++ qpid/dispatch/trunk/doc/man/CMakeLists.txt Wed Dec 10 17:26:08 2014
@@ -26,11 +26,12 @@ find_program(HELP2MAN help2man)
 if(HELP2MAN)
 
   macro(help2man manpage h2mfile program)
+    configure_file(${src}/${h2mfile}.in ${bin}/${h2mfile})
     string(REGEX MATCH "[0-9]*$" section ${manpage})
     add_custom_command (
       OUTPUT ${manpage}
-      COMMAND ${RUN} -s ${src}/help2man.py ${HELP2MAN} -s ${section} -i 
${src}/${h2mfile} -N -o ${bin}/${manpage} ${program}
-      DEPENDS ${program} ${h2mfile}
+      COMMAND ${RUN} -s ${src}/help2man.py ${HELP2MAN} -s ${section} -i 
${bin}/${h2mfile} -N -o ${bin}/${manpage} ${program}
+      DEPENDS ${program} ${bin}/${h2mfile}
       )
   endmacro()
 

Modified: qpid/dispatch/trunk/doc/man/qdmanage.8.in
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/qdmanage.8.in?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/doc/man/qdmanage.8.in (original)
+++ qpid/dispatch/trunk/doc/man/qdmanage.8.in Wed Dec 10 17:26:08 2014
@@ -34,6 +34,7 @@ update [ATTR=VALUE...]
 Update the attributes of an existing entity.
 With the --stdin option, read attributes from stdin. This can be a JSON
 map of attributes to update a single entity, or a JSON list of maps to update 
multiple entitiees.
+If an ATTR name is listed with no =VALUE, that attribute will be deleted from 
the entity.
 .TP
 delete
 Delete an entity specified by the --name or --identity options.
@@ -95,7 +96,21 @@ Client SSL certificate (PEM Format)
 \fB\-\-ssl\-key=\fR<key>
 Client SSL private key (PEM Format)
 .SH FILES
-.I /etc/qpid-dispatch/qdstat.conf
+.I /usr/local/etc/qpid-dispatch/qdrouter.json
+Management schema for qdrouterd.
+.SH EXAMPLES
+.TP
+Show the logging configuratoin
+qdmanage query --type=log
+.TP
+Change the default log level to debug
+qdmanage udpdate name=log/DEFAULT level=debug
+.TP
+Change the MESSAGE log level to trace and direct MESSAGE logs to the file 
"test.log"
+qdmanage udpdate name=log/MESSAGE level=trace output=test.log
+.TP
+Set the MESSAGE log level back to the default (delete the log/MESSAGE level 
attribute)
+qdmanage udpdate name=log/MESSAGE level
 .SH AUTHOR
 Apache Qpid <http://qpid.apache.org/>
 .SH COPYRIGHT

Copied: qpid/dispatch/trunk/doc/man/qdmanage.h2m.in (from r1644487, 
qpid/dispatch/trunk/doc/man/qdmanage.h2m)
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/qdmanage.h2m.in?p2=qpid/dispatch/trunk/doc/man/qdmanage.h2m.in&p1=qpid/dispatch/trunk/doc/man/qdmanage.h2m&r1=1644487&r2=1644488&rev=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/doc/man/qdmanage.h2m (original)
+++ qpid/dispatch/trunk/doc/man/qdmanage.h2m.in Wed Dec 10 17:26:08 2014
@@ -50,6 +50,7 @@ update [ATTR=VALUE...]
 Update the attributes of an existing entity.
 With the --stdin option, read attributes from stdin. This can be a JSON
 map of attributes to update a single entity, or a JSON list of maps to update 
multiple entitiees.
+If an ATTR name is listed with no =VALUE, that attribute will be deleted from 
the entity.
 .TP
 delete
 Delete an entity specified by the --name or --identity options.
@@ -68,9 +69,24 @@ List entity types with their annotations
 .TP
 get\-mgmt\-nodes
 List all other known management nodes connected to this one.
+[EXAMPLES]
+.TP
+Show the logging configuratoin
+qdmanage query --type=log
+.TP
+Change the default log level to debug
+qdmanage udpdate name=log/DEFAULT level=debug
+.TP
+Change the MESSAGE log level to trace and direct MESSAGE logs to the file 
"test.log"
+qdmanage udpdate name=log/MESSAGE level=trace output=test.log
+.TP
+Set the MESSAGE log level back to the default (delete the log/MESSAGE level 
attribute)
+qdmanage udpdate name=log/MESSAGE level
 [FILES]
-.I /etc/qpid-dispatch/qdstat.conf
-
+.I ${QPID_DISPATCH_CONFDIR}/qdrouter.json
+Management schema for qdrouterd.
+.I ${QPID_DISPATCH_CONFDIR}/qdrouter.json.readme.txt
+Explanation of the management schema.
 [SEE ALSO]
 .BR qdrouterd (8),
 .BR qdstat (8),

Modified: qpid/dispatch/trunk/doc/man/qdstat.8.in
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/qdstat.8.in?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/doc/man/qdstat.8.in (original)
+++ qpid/dispatch/trunk/doc/man/qdstat.8.in Wed Dec 10 17:26:08 2014
@@ -57,8 +57,6 @@ Client SSL certificate (PEM Format)
 .TP
 \fB\-\-ssl\-key=\fR<key>
 Client SSL private key (PEM Format)
-.SH FILES
-.I /etc/qpid-dispatch/qdstat.conf
 .SH AUTHOR
 Apache Qpid <http://qpid.apache.org/>
 .SH COPYRIGHT

Added: qpid/dispatch/trunk/doc/man/qdstat.h2m.in
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/qdstat.h2m.in?rev=1644488&view=auto
==============================================================================
--- qpid/dispatch/trunk/doc/man/qdstat.h2m.in (added)
+++ qpid/dispatch/trunk/doc/man/qdstat.h2m.in Wed Dec 10 17:26:08 2014
@@ -0,0 +1,41 @@
+.\" -*- nroff -*-
+.\"
+.\" Licensed to the Apache Software Foundation (ASF) under one
+.\" or more contributor license agreements.  See the NOTICE file
+.\" distributed with this work for additional information
+.\" regarding copyright ownership.  The ASF licenses this file
+.\" to you under the Apache License, Version 2.0 (the
+.\" "License"); you may not use this file except in compliance
+.\" with the License.  You may obtain a copy of the License at
+.\"
+.\"   http://www.apache.org/licenses/LICENSE-2.0
+.\"
+.\" Unless required by applicable law or agreed to in writing,
+.\" software distributed under the License is distributed on an
+.\" "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+.\" KIND, either express or implied.  See the License for the
+.\" specific language governing permissions and limitations
+.\" under the License
+.\"
+
+[NAME]
+qdstat \- A tool to inspect Dispatch router networks
+
+[DESCRIPTION]
+qdstat shows status information about networks of Dispatch routers.
+It can display connections, network nodes and links, and router stats
+such as memory use.
+.PP
+See <http://qpid.apache.org/components/dispatch-router/> for more
+information.
+
+[SEE ALSO]
+.BR qdrouterd (8),
+.BR qdmanage (8),
+.BR qdrouterd.conf (5)
+
+[AUTHOR]
+Apache Qpid <http://qpid.apache.org/>
+
+[COPYRIGHT]
+Copyright 2013 The Apache Software Foundation

Modified: qpid/dispatch/trunk/python/CMakeLists.txt
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/python/CMakeLists.txt?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/python/CMakeLists.txt (original)
+++ qpid/dispatch/trunk/python/CMakeLists.txt Wed Dec 10 17:26:08 2014
@@ -28,3 +28,9 @@ configure_file(${CMAKE_CURRENT_SOURCE_DI
 
 # Install script for public python modules
 install(SCRIPT install_python.cmake)
+install(
+  FILES
+  ${CMAKE_CURRENT_SOURCE_DIR}/qpid_dispatch/management/qdrouter.json
+  ${CMAKE_CURRENT_SOURCE_DIR}/qpid_dispatch/management/qdrouter.json.readme.txt
+  DESTINATION ${QPID_DISPATCH_CONFDIR}
+  )

Modified: qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.json
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.json?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.json (original)
+++ qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.json Wed Dec 
10 17:26:08 2014
@@ -253,7 +253,7 @@
         "log": {
             "description": "Set the level of logging output from a particular 
module.",
             "extends": "configurationEntity",
-            "operations": ["CREATE", "READ", "UPDATE", "DELETE"],
+            "operations": ["CREATE", "READ", "UPDATE"],
             "attributes": {
                 "module": {
                     "type":[
@@ -268,7 +268,7 @@
                         "DISPATCH"
                     ],
                     "required": true,
-                    "description": "Module to configure logging level. The 
special module 'DEFAULT' specifies logging for modules that don't have explicit 
log sections."
+                    "description": "Module to configure logging level. The 
special module 'DEFAULT' specifies logging defaults for modules that don't have 
explicit log configuration."
                 },
                 "level": {
                     "type": [
@@ -281,17 +281,14 @@
                         "error",
                         "critical"
                     ],
-                    "default": "info",
                     "description": "Indicates the minimum logging level for 
the module. E.g. 'warning' means log warning, error and critical messages. 
'trace' logs all messages. 'none' disables logging for the module."
                 },
                 "timestamp": {
                     "type": "Boolean",
-                    "default": true,
                     "description": "Include timestamp in log messages."
                 },
                 "source": {
                     "type": "Boolean",
-                    "default": false,
                     "description": "Include source file and line number in log 
messages."
                 },
                 "output": {

Copied: 
qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.json.readme.txt 
(from r1644487, 
qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.txt)
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.json.readme.txt?p2=qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.json.readme.txt&p1=qpid/dispatch/trunk/python/qpid_dispatch/management/qdrouter.txt&r1=1644487&r2=1644488&rev=1644488&view=diff
==============================================================================
    (empty)

Modified: qpid/dispatch/trunk/python/qpid_dispatch_internal/management/agent.py
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/python/qpid_dispatch_internal/management/agent.py?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/python/qpid_dispatch_internal/management/agent.py 
(original)
+++ qpid/dispatch/trunk/python/qpid_dispatch_internal/management/agent.py Wed 
Dec 10 17:26:08 2014
@@ -122,7 +122,7 @@ class AgentEntity(SchemaEntity):
             return True
         self.__dict__['_refresh'] = _do_refresh
 
-    def create(self, request):
+    def create(self):
         """Subclasses can add extra create actions here"""
         pass
 
@@ -156,19 +156,28 @@ class AgentEntity(SchemaEntity):
         """Subclasses implement delete logic here"""
         pass
 
-class ContainerEntity(AgentEntity): pass
-
+class ContainerEntity(AgentEntity):
+    def create(self):
+        self._qd.qd_dispatch_configure_container(self._dispatch, self)
 
 class RouterEntity(AgentEntity):
     def __init__(self, agent, entity_type, attributes=None):
         super(RouterEntity, self).__init__(agent, entity_type, attributes, 
validate=False, base_id=attributes.get('routerId'))
         self._set_pointer(self._dispatch)
 
+    def create(self):
+        self._qd.qd_dispatch_configure_router(self._dispatch, self)
+
+
 class LogEntity(AgentEntity):
     def __init__(self, agent, entity_type, attributes=None, validate=True):
-        super(LogEntity, self).__init__(agent, entity_type, attributes, 
validate, base_id=attributes.get('module'))
+        # Special defaults for DEFAULT module. 
+        if attributes.get("module") == "DEFAULT":
+            defaults = dict(level="info", timestamp=True, source=False, 
output="stderr")
+            attributes = dict(defaults, **attributes)
+        super(LogEntity, self).__init__(agent, entity_type, attributes, 
validate=True, base_id=attributes.get('module'))
 
-    def create(self, request):
+    def create(self):
         self._qd.qd_log_entity(self)
 
     def _update(self):
@@ -179,24 +188,24 @@ class LogEntity(AgentEntity):
         self._qd.qd_log_source_reset(self.attributes['module'])
 
 class ListenerEntity(AgentEntity):
-    def create(self, request):
+    def create(self):
         self._qd.qd_dispatch_configure_listener(self._dispatch, self)
         self._qd.qd_connection_manager_start(self._dispatch)
 
 
 class ConnectorEntity(AgentEntity):
-    def create(self, request):
+    def create(self):
         self._qd.qd_dispatch_configure_connector(self._dispatch, self)
         self._qd.qd_connection_manager_start(self._dispatch)
 
 
 class FixedAddressEntity(AgentEntity):
-    def create(self, request):
+    def create(self):
         self._qd.qd_dispatch_configure_address(self._dispatch, self)
 
 
 class WaypointEntity(AgentEntity):
-    def create(self, request):
+    def create(self):
         self._qd.qd_dispatch_configure_waypoint(self._dispatch, self)
         self._qd.qd_waypoint_activate_all(self._dispatch)
 
@@ -204,7 +213,7 @@ class DummyEntity(AgentEntity):
 
     id_count = AtomicCount()
 
-    def create(self, request):
+    def create(self):
         self['identity'] = self.next_id()
 
     def next_id(self): return self.type+str(self.id_count.next())
@@ -347,7 +356,7 @@ class EntityCache(object):
 class Agent(object):
     """AMQP managment agent"""
 
-    def __init__(self, dispatch, attribute_maps=None):
+    def __init__(self, dispatch):
         self.qd = dispatch_c.instance()
         self.dispatch = dispatch
         self.schema = QdSchema()
@@ -356,9 +365,6 @@ class Agent(object):
         self.type = 'org.amqp.management' # AMQP management node type
         self.request_lock = Lock()
         self.log_adapter = None
-        for attributes in attribute_maps or []:
-            # Note calls self.log, log messages are dropped.
-            self.add_entity(self.create_entity(attributes))
 
     def log(self, level, text):
         if self.log_adapter:
@@ -484,22 +490,23 @@ class Agent(object):
         self.entities.map_type(add_result, entity_type)
         return (OK, {'attributeNames': list(names), 'results': results})
 
-    def create(self, request):
+    def create(self, request=None, attributes=None):
         """
         Create is special: it is directed at an entity but the entity
         does not yet exist so it is handled initially by the agent and
         then delegated to the new entity.
         """
-        attributes = request.body
-        for a in ['type', 'name']:
-            value = required_property(a, request)
-            if a in attributes and attributes[a] != value:
-                raise BadRequestStatus("Conflicting values for '%s'"%a)
-            attributes[a] = value
+        if request:
+            attributes = request.body
+            for a in ['type', 'name']:
+                value = required_property(a, request)
+                if a in attributes and attributes[a] != value:
+                    raise BadRequestStatus("Conflicting values for '%s'"%a)
+                attributes[a] = value
+        self.schema.entity_type(attributes['type']).allowed('create')
         entity = self.create_entity(attributes)
-        entity.entity_type.allowed('create')
-        entity.create(request)  # Send the create request to the entity
         self.add_entity(entity)
+        entity.create()
         return (CREATED, entity.attributes)
 
     def add_entity(self, entity): self.entities.add(entity)

Modified: qpid/dispatch/trunk/python/qpid_dispatch_internal/management/config.py
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/python/qpid_dispatch_internal/management/config.py?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/python/qpid_dispatch_internal/management/config.py 
(original)
+++ qpid/dispatch/trunk/python/qpid_dispatch_internal/management/config.py Wed 
Dec 10 17:26:08 2014
@@ -21,7 +21,7 @@
 Configuration file parsing
 """
 
-import json, re, sys
+import json, re, sys, time
 from copy import copy
 from qpid_dispatch.management.entity import camelcase
 from .schema import ValidationError
@@ -141,38 +141,43 @@ class Config(object):
         for e in self.entities:
             if e['type'] == entity_type: yield e
 
+    def remove(self, entity):
+        self.entities.remove(entity)
+
+
 def configure_dispatch(dispatch, filename):
     """Called by C router code to load configuration file and do 
configuration"""
     qd = dispatch_c.instance()
     dispatch = qd.qd_dispatch_p(dispatch)
     config = Config(filename)
 
-    # Configure any DEFAULT log entities first so we can report errors in non-
-    # default log configurations to the correct place.
-    for l in config.by_type('log'):
-        if l['module'].upper() == 'DEFAULT': qd.qd_log_entity(l)
-    for l in config.by_type('log'):
-        if l['module'].upper() != 'DEFAULT': qd.qd_log_entity(l)
-
     # NOTE: Can't import agent till till dispatch C extension module is 
initialized.
     from .agent import Agent
-    agent = Agent(dispatch, config.entities)
+    agent = Agent(dispatch)
     qd.qd_dispatch_set_agent(dispatch, agent)
 
-    # Configure and prepare container and router before activating agent
-    qd.qd_dispatch_configure_container(dispatch, 
config.by_type('container').next())
-    qd.qd_dispatch_configure_router(dispatch, config.by_type('router').next())
-    qd.qd_dispatch_prepare(dispatch)
+    def configure(attributes):
+        """Configure an entity and remove it from config"""
+        agent.create(attributes=attributes)
+        config.remove(attributes)
 
+    modules = 
set(agent.schema.entity_type("log").attributes["module"].atype.tags)
+    for l in config.by_type('log'):
+        configure(l)
+        modules.remove(l["module"])
+    # Add default entities for any log modules not configured.
+    for m in modules: agent.create(attributes=dict(type="log", module=m))
+
+    # Configure and prepare container and router before we can activate the 
agent.
+    configure(config.by_type('container').next())
+    configure(config.by_type('router').next())
+    qd.qd_dispatch_prepare(dispatch)
     agent.activate("$management")
+    qd.qd_router_setup_late(dispatch) # Actions requiring active management 
agent.
 
-    qd.qd_router_setup_late(dispatch) # Actions requiring management agent.
+    # Remaining configuration
+    for t in "fixedAddress", "listener", "connector", "waypoint":
+        for a in list(config.by_type(t)): configure(a)
+    for e in list(config.entities): configure(e)
 
-    # Note must configure addresses, waypoints, listeners and connectors after 
qd_dispatch_prepare
-    for a in config.by_type('fixedAddress'): 
qd.qd_dispatch_configure_address(dispatch, a)
-    for w in config.by_type('waypoint'): 
qd.qd_dispatch_configure_waypoint(dispatch, w)
-    for l in config.by_type('listener'): 
qd.qd_dispatch_configure_listener(dispatch, l)
-    for c in config.by_type('connector'): 
qd.qd_dispatch_configure_connector(dispatch, c)
-    qd.qd_connection_manager_start(dispatch)
-    qd.qd_waypoint_activate_all(dispatch)
 

Modified: qpid/dispatch/trunk/python/qpid_dispatch_internal/management/schema.py
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/python/qpid_dispatch_internal/management/schema.py?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/python/qpid_dispatch_internal/management/schema.py 
(original)
+++ qpid/dispatch/trunk/python/qpid_dispatch_internal/management/schema.py Wed 
Dec 10 17:26:08 2014
@@ -132,7 +132,7 @@ class EnumType(Type):
                 return EnumValue(self.tags[i], i)
             except (ValueError, IndexError):
                 pass
-        raise ValidationError("Invalid value for %s: '%r'"%(self.name, value))
+        raise ValidationError("Invalid value for %s: %r"%(self.name, value))
 
     def dump(self):
         """
@@ -414,9 +414,11 @@ class EntityType(AttrsAndOps):
         try:
             # Add missing values
             for attr in self.attributes.itervalues():
-                if attr.name not in attributes:
+                if attr.name not in attributes or attributes[attr.name] is 
None:
                     value = attr.missing_value(**kwargs)
                     if value is not None: attributes[attr.name] = value
+                    if value is None and attr.name in attributes:
+                        del attributes[attr.name]
 
             # Validate attributes.
             for name, value in attributes.iteritems():

Modified: qpid/dispatch/trunk/router/src/main.c
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/router/src/main.c?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/router/src/main.c (original)
+++ qpid/dispatch/trunk/router/src/main.c Wed Dec 10 17:26:08 2014
@@ -263,10 +263,22 @@ static void daemon_process(const char *c
     }
 }
 
+#define DEFAULT_DISPATCH_PYTHON_DIR QPID_DISPATCH_HOME_INSTALLED "/python"
+
+void usage(char **argv) {
+    fprintf(stderr, "Usage: %s [OPTIONS]\n\n", argv[0]);
+    fprintf(stderr, "  -c, --config=PATH (%s)\n", DEFAULT_CONFIG_PATH);
+    fprintf(stderr, "                             Load configuration from file 
at PATH\n");
+    fprintf(stderr, "  -I, --include=PATH (%s)\n", 
DEFAULT_DISPATCH_PYTHON_DIR);
+    fprintf(stderr, "                             Location of Dispatch's 
Python library\n");
+    fprintf(stderr, "  -d, --daemon               Run process as a SysV-style 
daemon\n");
+    fprintf(stderr, "  -P, --pidfile              If daemon, the file for the 
stored daemon pid\n");
+    fprintf(stderr, "  -U, --user                 If daemon, the username to 
run as\n");
+    fprintf(stderr, "  -h, --help                 Print this help\n");
+}
 
 int main(int argc, char **argv)
 {
-#define DEFAULT_DISPATCH_PYTHON_DIR QPID_DISPATCH_HOME_INSTALLED "/python"
     const char *config_path   = DEFAULT_CONFIG_PATH;
     const char *python_pkgdir = DEFAULT_DISPATCH_PYTHON_DIR;
     const char *pidfile = 0;
@@ -310,22 +322,21 @@ int main(int argc, char **argv)
             break;
 
         case 'h' :
-            printf("Usage: %s [OPTIONS]\n\n", argv[0]);
-            printf("  -c, --config=PATH (%s)\n", DEFAULT_CONFIG_PATH);
-            printf("                             Load configuration from file 
at PATH\n");
-            printf("  -I, --include=PATH (%s)\n", DEFAULT_DISPATCH_PYTHON_DIR);
-            printf("                             Location of Dispatch's Python 
library\n");
-            printf("  -d, --daemon               Run process as a SysV-style 
daemon\n");
-            printf("  -P, --pidfile              If daemon, the file for the 
stored daemon pid\n");
-            printf("  -U, --user                 If daemon, the username to 
run as\n");
-            printf("  -h, --help                 Print this help\n");
+            usage(argv);
             exit(0);
 
         case '?' :
+            usage(argv);
             exit(1);
         }
     }
-
+    if (optind < argc) {
+        fprintf(stderr, "Unexpected arguments:");
+        for (; optind < argc; ++optind) fprintf(stderr, " %s", argv[optind]);
+        fprintf(stderr, "\n\n");
+        usage(argv);
+        exit(1);
+    }
     if (daemon_mode)
         daemon_process(config_path, python_pkgdir, pidfile, user);
     else

Modified: qpid/dispatch/trunk/src/log.c
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/log.c?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/log.c (original)
+++ qpid/dispatch/trunk/src/log.c Wed Dec 10 17:26:08 2014
@@ -332,7 +332,7 @@ void qd_log_initialize(void)
 
     default_log_source = qd_log_source(SOURCE_DEFAULT);
     default_log_source->mask = levels[INFO].mask;
-    default_log_source->timestamp = 1;
+    default_log_source->timestamp = true;
     default_log_source->source = 0;
     default_log_source->sink = log_sink_lh(SINK_STDERR);
     logging_log_source = qd_log_source(SOURCE_LOGGING);
@@ -359,9 +359,12 @@ qd_error_t qd_log_entity(qd_entity_t *en
     sys_mutex_unlock(log_source_lock);
     free(module);
 
-    char *level = qd_entity_get_string(entity, "level"); QD_ERROR_RET();
-    copy.mask = level_for_name(level)->mask;
-    free(level);
+    if (qd_entity_has(entity, "level")) {
+        char *level = qd_entity_get_string(entity, "level");
+        copy.mask = level_for_name(level)->mask;
+        free(level);
+    }
+    QD_ERROR_RET();
 
     if (qd_entity_has(entity, "timestamp"))
         copy.timestamp = qd_entity_get_bool(entity, "timestamp");
@@ -372,7 +375,7 @@ qd_error_t qd_log_entity(qd_entity_t *en
     QD_ERROR_RET();
 
     if (qd_entity_has(entity, "output")) {
-        log_sink_free_lh(copy.sink); /* DEFAULT source may already have a sink 
*/
+         log_sink_free_lh(copy.sink); /* DEFAULT source may already have a 
sink */
         char* output = qd_entity_get_string(entity, "output"); QD_ERROR_RET();
         copy.sink = log_sink_lh(output);
         free(output);

Modified: qpid/dispatch/trunk/tests/system_test.py
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/system_test.py?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/system_test.py (original)
+++ qpid/dispatch/trunk/tests/system_test.py Wed Dec 10 17:26:08 2014
@@ -393,7 +393,7 @@ class Qdrouterd(Process):
         @param retry_kwargs: keyword args for L{retry}
         """
         for c in self.config.sections('connector'):
-            assert retry(lambda: self.is_connected(c['port']), **retry_kwargs)
+            assert retry(lambda: self.is_connected(c['port']), 
**retry_kwargs), "Port not connected %s" % c['port']
 
     def wait_ready(self):
         """Wait for ports and connectors to be ready"""

Modified: qpid/dispatch/trunk/tests/system_tests_broker.py
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/system_tests_broker.py?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/system_tests_broker.py (original)
+++ qpid/dispatch/trunk/tests/system_tests_broker.py Wed Dec 10 17:26:08 2014
@@ -98,7 +98,7 @@ class DistributedQueueTest(system_test.T
                     rconf += [
                         ('connector', {'name':q.name, 'port':q.port}),
                         ('waypoint', {'address':self.testq, 'out-phase':1, 
'in-phase':0, 'connector':q.name})]
-                return self.qdrouterd(name, rconf)
+                return self.qdrouterd(name, rconf, wait=False)
             routers = [router(i) for i in xrange(len(self.qpidds))]
             for r in routers: r.wait_ready()
             addrs = [r.addresses[0]+"/"+self.testq for r in routers]

Modified: qpid/dispatch/trunk/tests/system_tests_management.py
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/system_tests_management.py?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/system_tests_management.py (original)
+++ qpid/dispatch/trunk/tests/system_tests_management.py Wed Dec 10 17:26:08 
2014
@@ -152,25 +152,14 @@ class ManagementTest(system_test.TestCas
 
         # Create a log entity, verify logging is as expected
         log = os.path.abspath("test_log.log")
-        agent_log = self.assert_create_ok('log', 'log/AGENT', 
dict(module='AGENT', level="error", output=log))
+        self.node.update(dict(level="error", output=log), name="log/AGENT")
         check_log(log)
 
         # Update the log entity to output to a different file
         log = os.path.abspath("test_log2.log")
-        self.node.update(dict(module='AGENT', level="error", output=log), 
identity='log/AGENT')
+        self.node.update(dict(level="error", output=log), identity='log/AGENT')
         check_log(log)
 
-        # Delete the log entity - return to default state.
-        self.node.delete(identity='log/AGENT')
-        self.assertRaises(AssertionError, check_log, log, 'nosuch2')
-
-        # Verify that debug logging shows up if enabled for a module
-        self.node.create(dict(module='AGENT', level="debug", output=log), 
type='log', name="log/AGENT")
-        logstr = self.cleanup(open(log)).read()
-        self.assertTrue(re.search(r'AGENT \(debug\)', logstr),
-                        msg="Can't find 'AGENT (debug)' messages in '%s'" % 
(logstr))
-
-
     def test_create_fixed_address(self):
         self.assert_create_ok(FIXED_ADDRESS, 'fixed1', dict(prefix='fixed1'))
         msgr = self.messenger()

Modified: qpid/dispatch/trunk/tools/qdmanage
URL: 
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tools/qdmanage?rev=1644488&r1=1644487&r2=1644488&view=diff
==============================================================================
--- qpid/dispatch/trunk/tools/qdmanage (original)
+++ qpid/dispatch/trunk/tools/qdmanage Wed Dec 10 17:26:08 2014
@@ -26,6 +26,12 @@ from collections import Mapping, Sequenc
 from optparse import OptionGroup
 from qpid_dispatch_internal.tools.command import OptionParser, Option, 
UsageError, connection_options, check_args, main
 
+def attr_split(attrstr):
+    """Split an attribute string of the form name=value or name to indicate 
None"""
+    nv = attrstr.split("=", 1)
+    if len(nv) == 1: return [nv[0], None]
+    else: return nv
+
 class QdManage():
 
     def __init__(self):
@@ -98,7 +104,7 @@ class QdManage():
     def create(self):
         """create [ATTR=VALUE...] - Create a new entity."""
         if self.args:
-            self.opts.attributes = dict(arg.split('=', 1) for arg in self.args)
+            self.opts.attributes = dict(attr_split(arg) for arg in self.args)
         self.call_bulk(lambda attrs: self.call_node('create', 'type', 'name', 
attributes=attrs))
 
     def read(self):
@@ -109,7 +115,7 @@ class QdManage():
     def update(self):
         """update [ATTR=VALUE...] - Update an entity."""
         if self.args:
-            self.opts.attributes = dict(arg.split('=', 1) for arg in self.args)
+            self.opts.attributes = dict(attr_split(arg) for arg in self.args)
         self.call_bulk(
             lambda attrs: self.call_node('update', 'type', 'name', 'identity', 
attributes=attrs))
 



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to