Author: aconway
Date: Wed Dec 10 02:25:17 2014
New Revision: 1644318
URL: http://svn.apache.org/r1644318
Log:
DISPATCH-56: Improve qdmanage tool, add man page generation for qdmanage and
qdstat.
Got rid of JSON maps/lists on qdmanage command line. Use simple name=value
arguments for attributes.
Still allow JSON with the --stdin flag.
Man page generation, from the doc/man/README:
Command line tools --help option provides a very brief usage and list of
options.
Man pages should be more detailed, but we do not want to repeat the information
from --help as it will easily become out of date.
To solve this we generate man pages using the help2man utility.
For each tool there should be a tool.htm with extra details for the man page.
help2man will combine this with the --help otuput of the tool to create the
full man page.
See the help2man macro in CMakeLists.txt and the help2man documentation for
more details.
For building distributions when help2man is not available, the generated man
page for
each tool is checked in as "tool.8.in". When help2man is available, running make
will warn if the checked in version is not up to date with the generated
version.
To update the man page you MUST use help2man, do not edit the checked in file
as your edits will be lost.
Added:
qpid/dispatch/trunk/doc/man/check_help2man.py (contents, props changed)
- copied, changed from r1644302, qpid/dispatch/trunk/bin/test.sh
qpid/dispatch/trunk/doc/man/help2man.py (contents, props changed)
- copied, changed from r1644302, qpid/dispatch/trunk/bin/test.sh
qpid/dispatch/trunk/doc/man/qdmanage.8.in
qpid/dispatch/trunk/doc/man/qdmanage.h2m
qpid/dispatch/trunk/doc/man/qdstat.h2m
- copied, changed from r1644302, qpid/dispatch/trunk/doc/man/qdstat.8.in
qpid/dispatch/trunk/python/qpid_dispatch_internal/tools/command.py
Removed:
qpid/dispatch/trunk/python/qpid_dispatch_internal/tools/options.py
Modified:
qpid/dispatch/trunk/CMakeLists.txt
qpid/dispatch/trunk/bin/test.sh
qpid/dispatch/trunk/doc/man/CMakeLists.txt
qpid/dispatch/trunk/doc/man/README
qpid/dispatch/trunk/doc/man/qdstat.8.in
qpid/dispatch/trunk/python/qpid_dispatch_internal/management/agent.py
qpid/dispatch/trunk/python/qpid_dispatch_internal/management/schema.py
qpid/dispatch/trunk/tests/system_tests_qdmanage.py
qpid/dispatch/trunk/tools/qdmanage
qpid/dispatch/trunk/tools/qdstat
Modified: qpid/dispatch/trunk/CMakeLists.txt
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/CMakeLists.txt?rev=1644318&r1=1644317&r2=1644318&view=diff
==============================================================================
--- qpid/dispatch/trunk/CMakeLists.txt (original)
+++ qpid/dispatch/trunk/CMakeLists.txt Wed Dec 10 02:25:17 2014
@@ -64,6 +64,7 @@ set(SHARE_INSTALL_DIR share CACHE PATH "
set(DOC_INSTALL_DIR ${SHARE_INSTALL_DIR}/doc CACHE PATH "Shared read-only data
directory")
set(MAN_INSTALL_DIR share/man CACHE PATH "Manpage directory")
set(QPID_DISPATCH_HOME_INSTALLED ${CMAKE_INSTALL_PREFIX}/${QPID_DISPATCH_HOME})
+set(RUN ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/tests/run.py)
# define the configuration directory based on whether or not the install
prefix is defined
if(NOT DEFINED SYSCONF_INSTALL_DIR)
@@ -131,8 +132,8 @@ install(FILES
DESTINATION ${DOC_INSTALL_DIR}/qpid-dispatch)
-add_subdirectory(src) # Build src first so other subdirs can use
QPID_DISPATCH_LIB
+add_subdirectory(src) # Build src first so other subdirs can use
QPID_DISPATCH_LIB
add_subdirectory(tests)
add_subdirectory(python)
-add_subdirectory(doc)
add_subdirectory(router)
+add_subdirectory(doc) # doc last, may run executables via help2man
Modified: qpid/dispatch/trunk/bin/test.sh
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/bin/test.sh?rev=1644318&r1=1644317&r2=1644318&view=diff
==============================================================================
--- qpid/dispatch/trunk/bin/test.sh (original)
+++ qpid/dispatch/trunk/bin/test.sh Wed Dec 10 02:25:17 2014
@@ -18,14 +18,14 @@
# under the License.
#
-set -ev
-
if [[ -z "$SOURCE_DIR" ]]; then
echo "The devel environment isn't ready. Run 'source config.sh' from"
echo "the base of the dispatch source tree"
exit 1
fi
+set -ev
+
rm -rf $BUILD_DIR
rm -rf $INSTALL_DIR
Modified: qpid/dispatch/trunk/doc/man/CMakeLists.txt
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/CMakeLists.txt?rev=1644318&r1=1644317&r2=1644318&view=diff
==============================================================================
--- qpid/dispatch/trunk/doc/man/CMakeLists.txt (original)
+++ qpid/dispatch/trunk/doc/man/CMakeLists.txt Wed Dec 10 02:25:17 2014
@@ -17,24 +17,60 @@
## under the License.
##
-configure_file(qdrouterd.8.in ${CMAKE_CURRENT_BINARY_DIR}/qdrouterd.8)
-configure_file(qdstat.8.in ${CMAKE_CURRENT_BINARY_DIR}/qdstat.8)
+set(src ${CMAKE_CURRENT_SOURCE_DIR})
+set(bin ${CMAKE_CURRENT_BINARY_DIR})
+set(tools ${CMAKE_SOURCE_DIR}/tools)
+
+find_program(HELP2MAN help2man)
+
+if(HELP2MAN)
+
+ macro(help2man manpage h2mfile program)
+ string(REGEX MATCH "[0-9]*$" section ${manpage})
+ add_custom_command (
+ OUTPUT ${manpage}
+ COMMAND ${RUN} -s ${src}/help2man.py ${HELP2MAN} --version-string
${QPID_DISPATCH_VERSION} -s ${section} -i ${src}/${h2mfile} -N -o
${bin}/${manpage} ${program}
+ DEPENDS ${program} ${h2mfile}
+ )
+ endmacro()
+
+else(HELP2MAN)
+
+ message(WARNING "help2man is not avaliable, cannot update man pages")
+ macro(help2man manpage h2mfile program)
+ # Copy a pre-generated version of the man page.
+ configure_file(${manpage}.in ${manpage})
+ endmacro()
+
+endif(HELP2MAN)
+
+configure_file(qdrouterd.8.in ${bin}/qdrouterd.8)
+help2man(qdstat.8 qdstat.h2m ${tools}/qdstat)
+help2man(qdmanage.8 qdmanage.h2m ${tools}/qdmanage)
# Generate a man page from the qdrouter.json schema.
-set (QDROUTERD_CONF qdrouterd.conf.5)
+set (QDROUTER_CONF_MAN qdrouterd.conf.5)
-file (GLOB_RECURSE QDROUTERD_CONF_DEPENDS
- ${CMAKE_CURRENT_SOURCE_DIR}/qdrouterd_conf_man.py
+file (GLOB_RECURSE QDROUTER_CONF_MAN_DEPENDS
+ ${src}/qdrouterd_conf_man.py
${CMAKE_SOURCE_DIR}/python/qpid_router_internal/management/*.py
${CMAKE_SOURCE_DIR}/python/qpid_router/management/qdrouterd.json)
-add_custom_command (OUTPUT ${QDROUTERD_CONF}
- COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/tests/run.py -s
${CMAKE_CURRENT_SOURCE_DIR}/qdrouterd_conf_man.py ${QDROUTERD_CONF}
- DEPENDS ${QDROUTERD_CONF_DEPENDS})
+add_custom_command (OUTPUT ${QDROUTER_CONF_MAN}
+ COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_BINARY_DIR}/tests/run.py -s
${src}/qdrouterd_conf_man.py ${QDROUTER_CONF_MAN}
+ DEPENDS ${QDROUTER_CONF_MAN_DEPENDS})
+
+# Target to build the generated files by default
+add_custom_target(man ALL DEPENDS ${QDROUTER_CONF_MAN} ${bin}/qdmanage.8
${bin}/qdstat.8)
+
+# Target to check that checked-in versions of generated files are up to date.
+add_custom_target(check_man ALL DEPENDS man
+ COMMAND ${RUN} -s ${src}/check_help2man.py ${src} ${bin} qdmanage.8 qdstat.8)
-add_custom_target(man ALL DEPENDS ${QDROUTERD_CONF})
# Install man pages
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qdrouterd.8 DESTINATION
${MAN_INSTALL_DIR}/man8)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${QDROUTERD_CONF} DESTINATION
${MAN_INSTALL_DIR}/man5)
-install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qdstat.8 DESTINATION
${MAN_INSTALL_DIR}/man8)
+
+install(FILES ${bin}/qdrouterd.8 DESTINATION ${MAN_INSTALL_DIR}/man8)
+install(FILES ${bin}/${QDROUTER_CONF_MAN} DESTINATION ${MAN_INSTALL_DIR}/man5)
+install(FILES ${bin}/qdstat.8 DESTINATION ${MAN_INSTALL_DIR}/man8)
+install(FILES ${bin}/qdmanage.8 DESTINATION ${MAN_INSTALL_DIR}/man8)
Modified: qpid/dispatch/trunk/doc/man/README
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/README?rev=1644318&r1=1644317&r2=1644318&view=diff
==============================================================================
--- qpid/dispatch/trunk/doc/man/README (original)
+++ qpid/dispatch/trunk/doc/man/README Wed Dec 10 02:25:17 2014
@@ -17,6 +17,26 @@
;; under the License.
;;
+# How man pages are generated.
+
+Command line tools --help option provides a very brief usage and list of
options.
+
+Man pages should be more detailed, but we do not want to repeat the information
+from --help as it will easily become out of date.
+
+To solve this we generate man pages using the help2man utility.
+For each tool there should be a tool.htm with extra details for the man page.
+help2man will combine this with the --help otuput of the tool to create the
full man page.
+
+See the help2man macro in CMakeLists.txt and the help2man documentation for
more details.
+
+For building distributions when help2man is not available, the generated man
page for
+each tool is checked in as "tool.8.in". When help2man is available, running
make
+will warn if the checked in version is not up to date with the generated
version.
+
+To update the man page you MUST use help2man, do not edit the checked in file
+as your edits will be lost.
+
# A really quick guide to nroff and man-page macros
## The title heading
Copied: qpid/dispatch/trunk/doc/man/check_help2man.py (from r1644302,
qpid/dispatch/trunk/bin/test.sh)
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/check_help2man.py?p2=qpid/dispatch/trunk/doc/man/check_help2man.py&p1=qpid/dispatch/trunk/bin/test.sh&r1=1644302&r2=1644318&rev=1644318&view=diff
==============================================================================
--- qpid/dispatch/trunk/bin/test.sh (original)
+++ qpid/dispatch/trunk/doc/man/check_help2man.py Wed Dec 10 02:25:17 2014
@@ -1,4 +1,3 @@
-#!/usr/bin/env bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
@@ -15,28 +14,29 @@
# "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.
+# under the License
#
-set -ev
+"""Check that man page checkedd in to source tree matches genated file"""
-if [[ -z "$SOURCE_DIR" ]]; then
- echo "The devel environment isn't ready. Run 'source config.sh' from"
- echo "the base of the dispatch source tree"
- exit 1
-fi
-
-rm -rf $BUILD_DIR
-rm -rf $INSTALL_DIR
-
-mkdir $BUILD_DIR
-cd $BUILD_DIR
-
-cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR -DCMAKE_BUILD_TYPE=Debug $SOURCE_DIR
-make -j4
-make install
-cd tests
-# Run unit tests on the build.
-ctest -VV -E system_tests
-# Run system tests on the install.
-python $INSTALL_DIR/lib/qpid-dispatch/tests/run_system_tests.py
+import sys, os
+
+srcdir, bindir = sys.argv[1:3]
+files = sys.argv[3:]
+failed = []
+
+def normalize(f):
+ f.readline()
+ f.readline()
+ return f.read()
+
+for f in files:
+ src = os.path.join(srcdir, f+".in")
+ gen = os.path.join(bindir, f)
+ if normalize(open(src)) != normalize(open(gen)): failed.append((gen, src))
+
+if failed:
+ print "ERROR: generated man pages do not match checked in versions. To fix
do: "
+ for gen, src in failed:
+ print " cp %s %s" % (gen, src)
+ sys.exit(1)
Copied: qpid/dispatch/trunk/doc/man/help2man.py (from r1644302,
qpid/dispatch/trunk/bin/test.sh)
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/help2man.py?p2=qpid/dispatch/trunk/doc/man/help2man.py&p1=qpid/dispatch/trunk/bin/test.sh&r1=1644302&r2=1644318&rev=1644318&view=diff
==============================================================================
--- qpid/dispatch/trunk/bin/test.sh (original)
+++ qpid/dispatch/trunk/doc/man/help2man.py Wed Dec 10 02:25:17 2014
@@ -1,4 +1,3 @@
-#!/usr/bin/env bash
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
@@ -15,28 +14,11 @@
# "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.
+# under the License
#
-set -ev
+import sys, os
-if [[ -z "$SOURCE_DIR" ]]; then
- echo "The devel environment isn't ready. Run 'source config.sh' from"
- echo "the base of the dispatch source tree"
- exit 1
-fi
-
-rm -rf $BUILD_DIR
-rm -rf $INSTALL_DIR
-
-mkdir $BUILD_DIR
-cd $BUILD_DIR
-
-cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR -DCMAKE_BUILD_TYPE=Debug $SOURCE_DIR
-make -j4
-make install
-cd tests
-# Run unit tests on the build.
-ctest -VV -E system_tests
-# Run system tests on the install.
-python $INSTALL_DIR/lib/qpid-dispatch/tests/run_system_tests.py
+# Set COLUMNS env var to avoid line breaks in help output.
+os.environ['COLUMNS'] = '10000'
+os.execv(sys.argv[1], sys.argv[1:])
Added: qpid/dispatch/trunk/doc/man/qdmanage.8.in
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/qdmanage.8.in?rev=1644318&view=auto
==============================================================================
--- qpid/dispatch/trunk/doc/man/qdmanage.8.in (added)
+++ qpid/dispatch/trunk/doc/man/qdmanage.8.in Wed Dec 10 02:25:17 2014
@@ -0,0 +1,100 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH QDMANAGE "8" "December 2014" "qdmanage 0.3" "System Administration
Utilities"
+.SH NAME
+qdmanage \- A management tool for Dispatch routers.
+.SH SYNOPSIS
+.B qdmanage
+\fI<operation> \fR[\fIoptions\fR...] [\fIarguments\fR...]
+.SH DESCRIPTION
+
+An AMQP management client for use with qdrouterd. Sends AMQP management
+operations requests and prints the response in JSON format. This is a generic
AMQP
+management tool and can be used with any standard AMQP managed endpoint, not
just
+with qdrouter.
+.PP
+See <http://qpid.apache.org/components/dispatch-router/> for more
+information.
+.SH OPERATIONS
+.TP
+query [ATTR...]
+Prints the named attributes of all entities. With no arguments prints all
attributes.
+The --type option restricts the result to entities extending the type.
+.TP
+create [ATTR=VALUE...]
+Create a new entity with the specified attributes.
+With the --stdin option, read attributes from stdin. This can be a JSON
+map of attributes to create a single entity, or a JSON list of maps to create
multiple entitiees.
+.TP
+read
+Print the attributes of an entity specified by the --name or --identity
options.
+With the --stdin option, create entities based on data from stdin. This can be
a JSON
+map of attributes to create a single entity, or a JSON list of maps to create
multiple entitiees.
+.TP
+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.
+.TP
+delete
+Delete an entity specified by the --name or --identity options.
+.TP
+get\-types [TYPE]
+List entity types with their base types. With no arguments list all types.
+.TP
+get\-operations [TYPE]:
+List entity types with their operations. With no arguments list all types.
+.TP
+get\-attributes [TYPE]:
+List entity types with their attributes. With no arguments list all types.
+.TP
+get\-annotations [TYPE]:
+List entity types with their annotations. With no arguments list all types.
+.SH OPTIONS
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+show this help message and exit
+.TP
+\fB\-\-type\fR=\fITYPE\fR
+Type of entity to operate on.
+.TP
+\fB\-\-name\fR=\fINAME\fR
+Name of entity to operate on.
+.TP
+\fB\-\-identity\fR=\fIID\fR
+Identity of entity to operate on.
+.TP
+\fB\-\-indent\fR=\fIINDENT\fR
+Pretty\-printing indent. \fB\-1\fR means don't pretty\-print (default 2)
+.TP
+\fB\-\-stdin\fR
+Read attributes as JSON map or list of maps from stdin.
+.IP
+Connection Options:
+.TP
+\fB\-b\fR <url>, \fB\-\-bus=\fR<url>
+URL of the messaging bus to connect to (default 0.0.0.0)
+.TP
+\fB\-r\fR <router\-id>, \fB\-\-router=\fR<router\-id>
+Router to be queried
+.TP
+\fB\-t\fR <secs>, \fB\-\-timeout=\fR<secs>
+Maximum time to wait for connection in seconds (default 5)
+.TP
+\fB\-\-sasl\-mechanism=\fR<mech>
+Force SASL mechanism (e.g. EXTERNAL, ANONYMOUS, PLAIN, CRAM\-MD5, DIGEST\-MD5,
GSSAPI).
+.TP
+\fB\-\-ssl\-certificate=\fR<cert>
+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
+Copyright 2013 The Apache Software Foundation
+.SH "SEE ALSO"
+.BR qdrouterd (8),
+.BR qdstat (8),
+.BR qdrouterd.conf (5)
Added: qpid/dispatch/trunk/doc/man/qdmanage.h2m
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/qdmanage.h2m?rev=1644318&view=auto
==============================================================================
--- qpid/dispatch/trunk/doc/man/qdmanage.h2m (added)
+++ qpid/dispatch/trunk/doc/man/qdmanage.h2m Wed Dec 10 02:25:17 2014
@@ -0,0 +1,81 @@
+.\" -*-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]
+qdmanage \- A management tool for Dispatch routers.
+
+[=DESCRIPTION]
+
+An AMQP management client for use with qdrouterd. Sends AMQP management
+operations requests and prints the response in JSON format. This is a generic
AMQP
+management tool and can be used with any standard AMQP managed endpoint, not
just
+with qdrouter.
+.PP
+See <http://qpid.apache.org/components/dispatch-router/> for more
+information.
+.SH OPERATIONS
+.TP
+query [ATTR...]
+Prints the named attributes of all entities. With no arguments prints all
attributes.
+The --type option restricts the result to entities extending the type.
+.TP
+create [ATTR=VALUE...]
+Create a new entity with the specified attributes.
+With the --stdin option, read attributes from stdin. This can be a JSON
+map of attributes to create a single entity, or a JSON list of maps to create
multiple entitiees.
+.TP
+read
+Print the attributes of an entity specified by the --name or --identity
options.
+With the --stdin option, create entities based on data from stdin. This can be
a JSON
+map of attributes to create a single entity, or a JSON list of maps to create
multiple entitiees.
+.TP
+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.
+.TP
+delete
+Delete an entity specified by the --name or --identity options.
+.TP
+get\-types [TYPE]
+List entity types with their base types. With no arguments list all types.
+.TP
+get\-operations [TYPE]:
+List entity types with their operations. With no arguments list all types.
+.TP
+get\-attributes [TYPE]:
+List entity types with their attributes. With no arguments list all types.
+.TP
+get\-annotations [TYPE]:
+List entity types with their annotations. With no arguments list all types.
+
+[FILES]
+.I /etc/qpid-dispatch/qdstat.conf
+
+[SEE ALSO]
+.BR qdrouterd (8),
+.BR qdstat (8),
+.BR qdrouterd.conf (5)
+
+[AUTHOR]
+Apache Qpid <http://qpid.apache.org/>
+
+[COPYRIGHT]
+Copyright 2013 The Apache Software Foundation
Modified: qpid/dispatch/trunk/doc/man/qdstat.8.in
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/qdstat.8.in?rev=1644318&r1=1644317&r2=1644318&view=diff
==============================================================================
--- qpid/dispatch/trunk/doc/man/qdstat.8.in (original)
+++ qpid/dispatch/trunk/doc/man/qdstat.8.in Wed Dec 10 02:25:17 2014
@@ -1,27 +1,10 @@
-.\" -*- 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
-.\"
-.TH QDSTAT 8
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.44.1.
+.TH QDSTAT "8" "December 2014" "qdstat 0.3" "System Administration Utilities"
.SH NAME
qdstat \- A tool to inspect Dispatch router networks
.SH SYNOPSIS
-qdstat [OPTIONS]
+.B qdstat
+[\fIoptions\fR]
.SH DESCRIPTION
qdstat shows status information about networks of Dispatch routers.
It can display connections, network nodes and links, and router stats
@@ -30,39 +13,54 @@ such as memory use.
See <http://qpid.apache.org/components/dispatch-router/> for more
information.
.SH OPTIONS
-.IP "-b, --bus URL"
-The URL of the router network to connect to.
-.IP "-t, --timeout SECONDS"
-The maximum time to wait for connection, in seconds.
-.IP "--sasl-mechanism MECHANISM"
-The SASL mechanism to use for authentication. One of "EXTERNAL",
-"ANONYMOUS", "PLAIN", "CRAM-MD5", "DIGEST-MD5", or "GSSAPI". SASL
-automatically picks the most secure available mechanism. Use this
-option to override it.
-.IP "--ssl-certificate PATH"
-The path to the SSL certificate file, in PEM format.
-.IP "--ssl-key PATH"
-The path to the SSL private key file, in PEM format.
-.IP "-g, --general"
-Show general router stats.
-.IP "-c, --connections"
-Show connections.
-.IP "-l, --links"
-Show router links.
-.IP "-n, --nodes"
-Show router nodes.
-.IP "-a, --address"
-Show router addresses.
-.IP "-m, --memory"
-Show router memory stats.
-.IP "-h, --help"
-Display a brief usage message and exit.
+.TP
+\fB\-h\fR, \fB\-\-help\fR
+show this help message and exit
+.TP
+\fB\-g\fR, \fB\-\-general\fR
+Show General Router Stats
+.TP
+\fB\-c\fR, \fB\-\-connections\fR
+Show Connections
+.TP
+\fB\-l\fR, \fB\-\-links\fR
+Show Router Links
+.TP
+\fB\-n\fR, \fB\-\-nodes\fR
+Show Router Nodes
+.TP
+\fB\-a\fR, \fB\-\-address\fR
+Show Router Addresses
+.TP
+\fB\-m\fR, \fB\-\-memory\fR
+Show Broker Memory Stats
+.IP
+Connection Options:
+.TP
+\fB\-b\fR <url>, \fB\-\-bus=\fR<url>
+URL of the messaging bus to connect to (default 0.0.0.0)
+.TP
+\fB\-r\fR <router\-id>, \fB\-\-router=\fR<router\-id>
+Router to be queried
+.TP
+\fB\-t\fR <secs>, \fB\-\-timeout=\fR<secs>
+Maximum time to wait for connection in seconds (default 5)
+.TP
+\fB\-\-sasl\-mechanism=\fR<mech>
+Force SASL mechanism (e.g. EXTERNAL, ANONYMOUS, PLAIN, CRAM\-MD5, DIGEST\-MD5,
GSSAPI).
+.TP
+\fB\-\-ssl\-certificate=\fR<cert>
+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 SEE ALSO
-.BR qdrouterd (8),
-.BR qdrouterd.conf (5)
.SH AUTHOR
Apache Qpid <http://qpid.apache.org/>
.SH COPYRIGHT
Copyright 2013 The Apache Software Foundation
+.SH "SEE ALSO"
+.BR qdrouterd (8),
+.BR qdmanage (8),
+.BR qdrouterd.conf (5)
Copied: qpid/dispatch/trunk/doc/man/qdstat.h2m (from r1644302,
qpid/dispatch/trunk/doc/man/qdstat.8.in)
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/doc/man/qdstat.h2m?p2=qpid/dispatch/trunk/doc/man/qdstat.h2m&p1=qpid/dispatch/trunk/doc/man/qdstat.8.in&r1=1644302&r2=1644318&rev=1644318&view=diff
==============================================================================
--- qpid/dispatch/trunk/doc/man/qdstat.8.in (original)
+++ qpid/dispatch/trunk/doc/man/qdstat.h2m Wed Dec 10 02:25:17 2014
@@ -17,52 +17,28 @@
.\" specific language governing permissions and limitations
.\" under the License
.\"
-.TH QDSTAT 8
-.SH NAME
+
+[NAME]
qdstat \- A tool to inspect Dispatch router networks
-.SH SYNOPSIS
-qdstat [OPTIONS]
-.SH DESCRIPTION
+
+[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.
-.SH OPTIONS
-.IP "-b, --bus URL"
-The URL of the router network to connect to.
-.IP "-t, --timeout SECONDS"
-The maximum time to wait for connection, in seconds.
-.IP "--sasl-mechanism MECHANISM"
-The SASL mechanism to use for authentication. One of "EXTERNAL",
-"ANONYMOUS", "PLAIN", "CRAM-MD5", "DIGEST-MD5", or "GSSAPI". SASL
-automatically picks the most secure available mechanism. Use this
-option to override it.
-.IP "--ssl-certificate PATH"
-The path to the SSL certificate file, in PEM format.
-.IP "--ssl-key PATH"
-The path to the SSL private key file, in PEM format.
-.IP "-g, --general"
-Show general router stats.
-.IP "-c, --connections"
-Show connections.
-.IP "-l, --links"
-Show router links.
-.IP "-n, --nodes"
-Show router nodes.
-.IP "-a, --address"
-Show router addresses.
-.IP "-m, --memory"
-Show router memory stats.
-.IP "-h, --help"
-Display a brief usage message and exit.
-.SH FILES
+
+[FILES]
.I /etc/qpid-dispatch/qdstat.conf
-.SH SEE ALSO
+
+[SEE ALSO]
.BR qdrouterd (8),
+.BR qdmanage (8),
.BR qdrouterd.conf (5)
-.SH AUTHOR
+
+[AUTHOR]
Apache Qpid <http://qpid.apache.org/>
-.SH COPYRIGHT
+
+[COPYRIGHT]
Copyright 2013 The Apache Software Foundation
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=1644318&r1=1644317&r2=1644318&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 02:25:17 2014
@@ -274,9 +274,8 @@ class EntityCache(object):
if type is None:
return map(function, self.entities)
else:
- if isinstance(type, EntityType): type = type.name
- else: type = self.schema.long_name(type)
- return map(function, ifilter(lambda e: e.entity_type.name == type,
self.entities))
+ if not isinstance(type, EntityType): type =
self.schema.entity_type(type)
+ return map(function, ifilter(lambda e: e.entity_type.is_a(type),
self.entities))
def add(self, entity, pointer=None):
"""Add an entity. Provide pointer if it is associated with a C
entity"""
@@ -456,21 +455,35 @@ class Agent(object):
def query(self, request):
"""Management node query operation"""
- type = self.requested_type(request)
- attribute_names = request.body.get('attributeNames')
- if not attribute_names:
- if type:
- attribute_names = type.attributes.keys()
- else: # Every attribute in the schema!
- names = set()
- for e in self.schema.entity_types.itervalues():
- names.update(e.attributes.keys())
- attribute_names = list(names)
-
- attributes = self.entities.map_type(lambda e: e.attributes, type)
- results = [[attrs.get(name) for name in attribute_names]
- for attrs in attributes]
- return (OK, {'attributeNames': attribute_names, 'results': results})
+ entity_type = self.requested_type(request)
+ if entity_type:
+ all_attrs = set(entity_type.attributes.keys())
+ else:
+ all_attrs = self.schema.all_attributes
+
+ names = set(request.body.get('attributeNames'))
+ if names:
+ unknown = names - all_attrs
+ if unknown:
+ if entity_type:
+ for_type = " for type %s" % entity_type.name
+ else:
+ for_type = ""
+ raise NotFoundStatus("Unknown attributes %s%s." %
(list(unknown), for_type))
+ else:
+ names = all_attrs
+
+ results = []
+ def add_result(entity):
+ result = []
+ non_empty = False
+ for name in names:
+ result.append(entity.attributes.get(name))
+ if result[-1] is not None: non_empty = True
+ if non_empty: results.append(result)
+
+ self.entities.map_type(add_result, entity_type)
+ return (OK, {'attributeNames': list(names), 'results': results})
def create(self, request):
"""
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=1644318&r1=1644317&r2=1644318&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 02:25:17 2014
@@ -467,13 +467,20 @@ class Schema(object):
else:
self.prefix = self.prefixdot = ""
self.description = description
+ self.annotations = OrderedDict()
+ self.entity_types = OrderedDict()
+ self.all_attributes = set()
- def make_dict(klass, params):
- if not params: return OrderedDict()
- return OrderedDict((t.name, t) for t in (klass(k, self, **v) for
k, v in params.iteritems()))
- self.annotations = make_dict(Annotation, annotations)
- self.entity_types = make_dict(EntityType, entityTypes)
- for et in self.entity_types.itervalues(): et.init()
+ def add_defs(thing, mymap, defs):
+ for k, v in defs.iteritems():
+ t = thing(k, self, **v)
+ mymap[t.name] = t
+ add_defs(Annotation, self.annotations, annotations or {})
+ add_defs(EntityType, self.entity_types, entityTypes or {})
+
+ for e in self.entity_types.itervalues():
+ e.init()
+ self.all_attributes.update(e.attributes.keys())
def short_name(self, name):
"""Remove prefix from name if present"""
Added: qpid/dispatch/trunk/python/qpid_dispatch_internal/tools/command.py
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/python/qpid_dispatch_internal/tools/command.py?rev=1644318&view=auto
==============================================================================
--- qpid/dispatch/trunk/python/qpid_dispatch_internal/tools/command.py (added)
+++ qpid/dispatch/trunk/python/qpid_dispatch_internal/tools/command.py Wed Dec
10 02:25:17 2014
@@ -0,0 +1,94 @@
+#
+# 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
+#
+
+"""
+Utilities for command-line programs.
+"""
+
+import os, sys, json, optparse
+from collections import Sequence, Mapping
+
+class UsageError(Exception):
+ """
+ Raise this exception to indicate the usage message should be printed.
+ Handled by L{main}
+ """
+ pass
+
+def main(run, argv=sys.argv, op=None):
+ """
+ Call run(argv) with exception handling, do appropriate sys.exit().
+ @param op: an OptionParser to use for usage related error messages.
+ @return: exit value for sys.exit
+ """
+ try:
+ run(argv)
+ return 0
+ except KeyboardInterrupt:
+ print
+ except UsageError, e:
+ op.error(e)
+ except Exception, e:
+ print "%s: %s" % (type(e).__name__, e)
+ return 1
+
+def check_args(args, maxargs=0, minargs=0):
+ """
+ Check number of arguments, raise UsageError if in correct.
+ @param maxargs: max number of allowed args after command or None to skip
check.
+ @param minargs: min number of allowed args after command or None to skip
check.
+ """
+ if minargs is not None and len(args) < minargs:
+ raise UsageError("Not enough arguments, got %s need %s" % (len(args),
minargs))
+ if maxargs is not None and len(args) > maxargs:
+ raise UsageError("Unexpected arguments: %s" % ("
".join(args[maxargs:])))
+
+def connection_options(options, title="Connection Options"):
+ """Return an OptionGroup for connection options."""
+ group = optparse.OptionGroup(options, title)
+ group.add_option("-b", "--bus", action="store", type="string",
default="0.0.0.0",
+ metavar="<url>", help="URL of the messaging bus to
connect to (default %default)")
+ group.add_option("-r", "--router", action="store", type="string",
default=None,
+ metavar="<router-id>", help="Router to be queried")
+ group.add_option("-t", "--timeout", action="store", type="float",
default=5, metavar="<secs>",
+ help="Maximum time to wait for connection in seconds
(default %default)")
+ group.add_option("--sasl-mechanism", action="store", type="string",
metavar="<mech>",
+ help="Force SASL mechanism (e.g. EXTERNAL, ANONYMOUS,
PLAIN, CRAM-MD5, DIGEST-MD5, GSSAPI).")
+ group.add_option("--ssl-certificate", action="store", type="string",
metavar="<cert>",
+ help="Client SSL certificate (PEM Format)")
+ group.add_option("--ssl-key", action="store", type="string",
metavar="<key>",
+ help="Client SSL private key (PEM Format)")
+ return group
+
+class Option(optparse.Option):
+ """Addes two new types to optparse.Option: json_map, json_list"""
+
+ def check_json(option, opt, value):
+ """Validate a json value, for use with L{Option}"""
+ try:
+ result = json.loads(value)
+ if option.type == 'json_list' and not isinstance(result, Sequence)
or \
+ option.type == 'json_map' and not isinstance(result, Mapping):
+ raise ValueError()
+ return result
+ except ValueError:
+ raise optparse.OptionValueError("%s: invalid %s: %r" % (opt,
option.type, value))
+
+ TYPES = optparse.Option.TYPES + ("json_list", "json_map")
+ TYPE_CHECKER = dict(optparse.Option.TYPE_CHECKER, json_list=check_json,
json_map=check_json)
Modified: qpid/dispatch/trunk/tests/system_tests_qdmanage.py
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tests/system_tests_qdmanage.py?rev=1644318&r1=1644317&r2=1644318&view=diff
==============================================================================
--- qpid/dispatch/trunk/tests/system_tests_qdmanage.py (original)
+++ qpid/dispatch/trunk/tests/system_tests_qdmanage.py Wed Dec 10 02:25:17 2014
@@ -37,11 +37,9 @@ class QdmanageTest(TestCase):
def address(self): return self.router.hostports[0]
- 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()], []))
+ def run_qdmanage(self, cmd, input=None, expect=Process.EXIT_OK):
p = self.popen(
- ['qdmanage', cmd, '--bus', self.address(), '--indent=-1']+args,
+ ['qdmanage'] + cmd.split(' ') + ['--bus', self.address(),
'--indent=-1'],
stdin=PIPE, stdout=PIPE, stderr=STDOUT, expect=expect)
out = p.communicate(input)[0]
try:
@@ -51,10 +49,10 @@ class QdmanageTest(TestCase):
return out
def test_help(self):
- self.run_qdmanage('help', r'Usage: qdmanage', expect=Process.EXIT_FAIL)
+ help_out = self.run_qdmanage('--help', r'Usage: qdmanage',
expect=Process.EXIT_OK)
+ assert re.search('Usage: qdmanage', help_out)
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)
+ assert re.search(cmd, help_out)
def assert_entity_equal(self, expect, actual, copy=None):
"""Copy keys in copy from actual to idenity, then assert maps equal."""
@@ -69,38 +67,36 @@ class QdmanageTest(TestCase):
def test_crud(self):
def check(cmd, expect, copy=None, **kwargs):
- actual = json.loads(self.run_qdmanage(cmd, **kwargs))
+ actual = json.loads(self.run_qdmanage(cmd))
self.assert_entity_equal(expect, actual, copy=copy)
- expect = {'arg1': 'foo', 'type': DUMMY, 'name': 'mydummy2' }
+ expect = {'arg1': 'foo', 'type': DUMMY, 'name': 'mydummy2'}
# create with type, name in attributes
- check('create', expect, copy=['identity'],
attributes=json.dumps(expect))
+ check('create arg1=foo type=dummy name=mydummy2', expect,
copy=['identity'], attributes=json.dumps(expect))
# create with type, name as arguments
expect['name'] = 'mydummy'
- check('create', expect, copy=['identity'],
- type='dummy', name='mydummy', attributes='{"arg1" : "foo"}')
-
- check('read', expect, name="mydummy")
- check('read', expect, identity=expect['identity'])
+ check('create name=mydummy type=dummy arg1=foo', expect,
copy=['identity'])
+ check('read --name mydummy', expect)
+ check('read --identity %s' % expect['identity'], expect)
expect.update([], arg1='bar', num1=555)
- check('update', expect, attributes='{"name":"mydummy", "arg1" : "bar",
"num1":555}')
- check('read', expect, name="mydummy")
+ check('update name=mydummy arg1=bar num1=555', expect)
+ check('read --name=mydummy', expect)
expect.update([], arg1='xxx', num1=888)
# name outside attributes
- check('update', expect, name='mydummy', attributes='{"arg1": "xxx",
"num1": 888}')
- check('read', expect, name="mydummy")
- self.run_qdmanage('delete', name="mydummy")
- self.run_qdmanage('read', name="mydummy", expect=Process.EXIT_FAIL)
+ check('update name=mydummy arg1=xxx num1=888', expect)
+ check('read --name=mydummy', expect)
+ self.run_qdmanage('delete --name mydummy')
+ self.run_qdmanage('read --name=mydummy', expect=Process.EXIT_FAIL)
def test_stdin(self):
"""Test piping from stdin"""
def check(cmd, expect, input, copy=None):
- actual = json.loads(self.run_qdmanage(cmd, input=input,
stdin=None))
+ actual = json.loads(self.run_qdmanage(cmd + " --stdin",
input=input))
self.assert_entity_equal(expect, actual, copy=copy)
def check_list(cmd, expect_list, input, copy=None):
- actual = json.loads(self.run_qdmanage(cmd, input=input,
stdin=None))
+ actual = json.loads(self.run_qdmanage(cmd + " --stdin",
input=input))
self.assert_entities_equal(expect_list, actual, copy=copy)
expect = {'type': DUMMY, 'name': 'mydummyx', 'arg1': 'foo'}
@@ -120,19 +116,20 @@ class QdmanageTest(TestCase):
def test_query(self):
def long_type(name): return u'org.apache.qpid.dispatch.'+name
- TYPES=['listener', 'log', 'container', 'router', 'router.link']
- LONG_TYPES=[long_type(name) for name in TYPES]
+ types = ['listener', 'log', 'container', 'router', 'router.link']
+ long_types = [long_type(name) for name in types]
qall = json.loads(self.run_qdmanage('query'))
qall_types = set([e['type'] for e in qall])
- for t in LONG_TYPES: self.assertIn(t, qall_types)
+ for t in long_types: self.assertIn(t, qall_types)
- qlistener = json.loads(self.run_qdmanage('query', type='listener'))
+ qlistener = json.loads(self.run_qdmanage('query --type=listener'))
self.assertEqual([long_type('listener')], [e['type'] for e in
qlistener])
self.assertEqual(self.router.ports[0], int(qlistener[0]['port']))
qattr = json.loads(
- self.run_qdmanage('query', attribute_names='["type", "name"]'))
+ self.run_qdmanage('query type name'))
+
for e in qattr: self.assertEqual(2, len(e))
def name_type(entities):
Modified: qpid/dispatch/trunk/tools/qdmanage
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tools/qdmanage?rev=1644318&r1=1644317&r2=1644318&view=diff
==============================================================================
--- qpid/dispatch/trunk/tools/qdmanage (original)
+++ qpid/dispatch/trunk/tools/qdmanage Wed Dec 10 02:25:17 2014
@@ -19,209 +19,126 @@
# under the License.
#
-import optparse, sys, time, os, re, math, json
+import sys, json
import qpid_dispatch.site
-from qpid_dispatch.management import Node, Entity, Url
+from qpid_dispatch.management import Node, Url
from collections import Mapping, Sequence
+from optparse import OptionParser, OptionGroup
+from qpid_dispatch_internal.tools.command import Option, UsageError,
connection_options, check_args, main
-from qpid_dispatch_internal.tools.options import connection_options
+class QdManage():
-class QdManage(object):
- """
- Common options and logic for all commands. Subclasses provide additional
- options and execution logic.
- """
-
- class Commands(list):
- """Decorator to collect command names."""
- def __call__(self, func):
- self.append(func.__name__.replace('_', '-'));
- return func
-
- commands = Commands()
-
- class Option (optparse.Option):
- """Add json_map and json_list types to optparse.Option"""
-
- def check_json(option, opt, value):
- try:
- result = json.loads(value)
- if option.type == 'json_list' and not isinstance(result,
Sequence) or \
- option.type == 'json_map' and not isinstance(result,
Mapping):
- raise ValueError()
- return result
- except ValueError:
- raise optparse.OptionValueError("%s: invalid %s: %r" % (opt,
option.type, value))
-
- TYPES = optparse.Option.TYPES + ("json_list", "json_map")
- TYPE_CHECKER = dict(optparse.Option.TYPE_CHECKER,
json_list=check_json, json_map=check_json)
-
-
- class Usage(Exception):
- def __init__(self, prog):
- Exception.__init__(self, """
-Usage: %s <command> [options]
-
-Commands are:
- %s
-
-For help with a command: %s <command> --help
-""" % (prog, "\n ".join(QdManage.commands), prog))
-
-
- def __init__(self, argv):
- """Execute the command specified by argv"""
- self.node = None
- self.argv = argv
- if len(argv) <= 1 or argv[1] not in self.commands:
- raise self.Usage(os.path.basename(self.argv[0]))
- self.op=optparse.OptionParser("%s [options]" % argv[1],
option_class=self.Option)
- 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)")
- self.op.add_option_group(json_group)
- command = getattr(self, argv[1].replace('-', '_'))
- command() # Call the command method
-
- def setup(self, description, call_opts, other_opts=None):
- """Set up for executing a command
- @param description: Command description for help
- @param call_opts: (name, type, help) tuples for options passed to Node.
- @param other_opts: (name, type, help) tuples for options not passed to
Node.
- """
- self.op.description = description
- for (name, type, help) in call_opts + (other_opts or []):
- name = '--' + name
- if type:
- self.op.add_option(name, action="store", type=type, help=help,
metavar="<%s>" % type)
- else:
- self.op.add_option(name, action="store_true", help=help)
- self.optnames = [name.replace('-','_') for name, type, help in
call_opts]
- self.opts, self.args = self.op.parse_args(self.argv)
- if self.opts.indent == -1: self.opts.indent = None
- url = Url(self.opts.bus)
- self.node = Node(url, self.opts.router)
-
- def call_node(self, op):
- """Call node operation op with self.opts for opts in self.optnames"""
- kwargs = dict((k, getattr(self.opts, k)) for k in self.optnames)
- return getattr(self.node, op)(**kwargs)
-
- def call_node_attrs(self, op, attrs):
- """Call node operation op with attributes=attrs"""
- return getattr(self.node, op)(attributes=attrs)
+ def __init__(self):
+
+ self.operations = ['query', 'create', 'read', 'update', 'delete',
+ 'get-types', 'get-operations', 'get-attributes',
'get-annotations']
+ usage = "%prog <operation> [options...] [arguments...]\n\nOperations:"
+ for o in self.operations:
+ method = o.replace('-', '_')
+ usage += "\n %s" % getattr(self.__class__, method).__doc__
+
+ op = OptionParser(usage, option_class=Option)
+ op.add_option('--type', help='Type of entity to operate on.')
+ op.add_option('--name', help='Name of entity to operate on.')
+ op.add_option('--identity', help='Identity of entity to operate on.',
metavar="ID")
+ op.add_option("--indent", type="int", default=2,
+ help="Pretty-printing indent. -1 means don't pretty-print
(default %default)")
+ op.add_option('--stdin', action='store_true',
+ help='Read attributes as JSON map or list of maps from
stdin.')
+
+
+ op.add_option_group(connection_options(op))
+
+ self.op = op
+
+ def run(self, argv):
+ self.opts, self.args = self.op.parse_args(argv[1:])
+ if len(self.args) == 0: raise UsageError("No operation specified")
+ operation = self.args.pop(0)
+ if operation not in self.operations: raise UsageError("Unknown
operation: %s" % operation)
+ self.node = Node(Url(self.opts.bus), self.opts.router)
+ method = getattr(self, operation.replace('-','_'))
+ method()
+
+ def main(self, argv):
+ return main(self.run, argv, self.op)
def print_json(self, data):
"""Print data as JSON"""
print json.dumps(data, indent=self.opts.indent)
- @commands
- def query(self):
- self.setup(
- "Query for attributes of management entities. Print a JSON list of
attribute maps.",
- [('type', 'string', 'Query only for entities of <type>.'),
- ('attribute-names', 'json_list', 'Attribute names to include in
results.')])
- self.print_json(self.call_node('query').get_dicts(clean=True))
-
- # Used by several operations
- stdin_opt = [('stdin', None, 'Read JSON atttribute map or list of maps
from stdin. Other options are ignored.')]
-
- def do_stdin(self, op):
- """Call op for the attribute map or sequence of attribute maps on
stdin"""
- data = json.load(sys.stdin)
- if isinstance(data, Mapping):
- self.print_json(self.call_node_attrs(op, data).attributes)
- elif isinstance(data, Sequence):
- self.print_json([self.call_node_attrs(op, attrs).attributes
- for attrs in data])
- else: raise ValueError("stdin is not a JSON map or list")
+ def call_node(self, method, *argnames, **kwargs):
+ """Call method on node, use opts named in argnames"""
+ names = set(argnames)
+ for k in self.opts.__dict__:
+ if k in names and hasattr(self.opts, k):
+ kwargs[k] = getattr(self.opts, k)
+ return getattr(self.node, method)(**kwargs)
- @commands
- def create(self):
- self.setup(
- "Create a new entity. Print a JSON map of created attributes.",
- [('type', 'string', 'Type of new entity, can also be specified in
--attributes.'),
- ('name', 'string', 'Name of new entity, can also be specified in
--attributes.'),
- ('attributes', 'json_map', 'Attributes for new entity.')],
- self.stdin_opt)
+ def call_bulk(self, func):
+ """Call function for attributes from stdin or --attributes option"""
if self.opts.stdin:
- self.do_stdin('create')
+ data = json.load(sys.stdin)
+ if isinstance(data, Mapping):
+ self.print_json(func(data).attributes)
+ elif isinstance(data, Sequence):
+ self.print_json([func(attrs).attributes for attrs in data])
+ else: raise ValueError("stdin is not a JSON map or list")
else:
- self.print_json(self.call_node('create').attributes)
+ self.print_json(func(self.opts.attributes).attributes)
- # Used by several operations
- type_name_identity = [
- ('type', 'string', 'Entity type.'),
- ('name', 'string', 'Find by name.'),
- ('identity', 'string', 'Find by identity.')
- ]
+ def query(self):
+ """query [ATTR...] - Print attributes of entities."""
+ if self.args: self.opts.attribute_names = self.args
+ result = self.call_node('query', 'type', 'attribute_names')
+ self.print_json(result.get_dicts(clean=True))
+
+ 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.call_bulk(lambda attrs: self.call_node('create', 'type', 'name',
attributes=attrs))
- @commands
def read(self):
- self.setup(
- "Get the attributes of a single entity. Prints a JSON attribute
map.",
- self.type_name_identity)
- self.print_json(self.call_node('read').attributes)
+ """read - Print attributes of selected entity."""
+ check_args(self.args, 0)
+ self.print_json(self.call_node('read', 'type', 'name',
'identity').attributes)
- @commands
def update(self):
- self.setup(
- "Update an entity. Prints a JSON map of updated attributes.",
- [('type', 'string', 'Entity type, can also be specified in
--attributes.'),
- ('name', 'string', 'Find by name, can also be specified in
--attributes.'),
- ('identity', 'string', 'Find by identity, can also be specified
in --attributes.'),
- ('attributes', 'json_map', 'Attributes to update.')],
- self.stdin_opt)
- if self.opts.stdin:
- self.do_stdin('update')
- else:
- self.print_json(self.call_node('update').attributes)
+ """update [ATTR=VALUE...] - Update an entity."""
+ if self.args:
+ self.opts.attributes = dict(arg.split('=', 1) for arg in self.args)
+ self.call_bulk(
+ lambda attrs: self.call_node('update', 'type', 'name', 'identity',
attributes=attrs))
- @commands
def delete(self):
- self.setup("Delete an entity.", self.type_name_identity)
- self.call_node('delete')
+ """delete - Delete an entity"""
+ check_args(self.args, 0)
+ self.call_node('delete', 'type', 'name', 'identity')
- @commands
def get_types(self):
- self.setup(
- "Get the list of entity types with they types they extend. Prints
a JSON map of type names with base types",
- [('type', 'string', 'Restrict types implementing <type>.')])
- self.print_json(self.call_node('get_types'))
+ """get-types [TYPE] - List entity types with their base types."""
+ check_args(self.args, 1)
+ if self.args: self.opts.type = self.args[0]
+ self.print_json(self.call_node('get_types', 'type'))
- @commands
def get_annotations(self):
- self.setup(
- "Get the list of entity types with the annotations they include.
Prints a JSON map of type names and annotations.",
- [('type', 'string', 'Restrict types implementing <type>.')])
- self.print_json(self.call_node('get_annotations'))
+ """get-annotations [TYPE] - List entity types with the annotations
they implement."""
+ check_args(self.args, 1)
+ if self.args: self.opts.type = self.args[0]
+ self.print_json(self.call_node('get_annotations', 'type'))
- @commands
def get_attributes(self):
- self.setup(
- "Get the list of entity attribute names. Prints a JSON list of
attribute names.",
- [('type', 'string', 'If set return only attributes for <type>.')])
- self.print_json(self.call_node('get_attributes'))
+ """get-attributes [TYPE] - List entity types with their attributes."""
+ check_args(self.args, 1)
+ if self.args: self.opts.type = self.args[0]
+ self.print_json(self.call_node('get_attributes', 'type'))
- @commands
def get_operations(self):
- self.setup(
- "Get the list of entity operation names. Prints a JSON list of
operation names.",
- [('type', 'string', 'If set return only operations for <type>.')])
- self.print_json(self.call_node('get_operations'))
-
-
-def main(argv):
- try:
- QdManage(argv)
- return 0
- except QdManage.Usage, e:
- print e
- return 1
- except Exception, e:
- print "%s: %s" % (type(e).__name__, e)
- return 1
+ """get-operations [TYPE] - List entity types with their operations."""
+ check_args(self.args, 1)
+ if self.args: self.opts.type = self.args[0]
+ self.print_json(self.call_node('get_operations', 'type'))
if __name__ == "__main__":
- sys.exit(main(sys.argv))
+ sys.exit(QdManage().main(sys.argv))
Modified: qpid/dispatch/trunk/tools/qdstat
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/tools/qdstat?rev=1644318&r1=1644317&r2=1644318&view=diff
==============================================================================
--- qpid/dispatch/trunk/tools/qdstat (original)
+++ qpid/dispatch/trunk/tools/qdstat Wed Dec 10 02:25:17 2014
@@ -30,7 +30,7 @@ import qpid_dispatch.site
from qpid_dispatch.management import Url, Node, Entity
from qpid_dispatch_internal.management.qdrouter import QdSchema
from qpid_dispatch_internal.tools import Display, Header, Sorter, YN, Commas,
TimeLong
-from qpid_dispatch_internal.tools.options import connection_options
+from qpid_dispatch_internal.tools.command import connection_options, main
class Config:
@@ -50,31 +50,23 @@ def OptionsAndArguments(argv):
global config
global conn_options
- usage = \
-"""%prog -g [options]
- %prog -c [options]
- %prog -l [options]
- %prog -n [options]
- %prog -a [options]
- %prog -m [options]"""
+ usage = "%prog [options]"
parser = OptionParser(usage=usage)
parser.add_option_group(connection_options(parser))
- group2 = OptionGroup(parser, "Command Options")
- group2.add_option("-g", "--general", help="Show General Router Stats",
action="store_const", const="g", dest="show")
- group2.add_option("-c", "--connections", help="Show Connections",
action="store_const", const="c", dest="show")
- group2.add_option("-l", "--links", help="Show Router Links",
action="store_const", const="l", dest="show")
- group2.add_option("-n", "--nodes", help="Show Router Nodes",
action="store_const", const="n", dest="show")
- group2.add_option("-a", "--address", help="Show Router Addresses",
action="store_const", const="a", dest="show")
- group2.add_option("-m", "--memory", help="Show Broker Memory Stats",
action="store_const", const="m", dest="show")
- parser.add_option_group(group2)
+ parser.add_option("-g", "--general", help="Show General Router Stats",
action="store_const", const="g", dest="show")
+ parser.add_option("-c", "--connections", help="Show Connections",
action="store_const", const="c", dest="show")
+ parser.add_option("-l", "--links", help="Show Router Links",
action="store_const", const="l", dest="show")
+ parser.add_option("-n", "--nodes", help="Show Router Nodes",
action="store_const", const="n", dest="show")
+ parser.add_option("-a", "--address", help="Show Router Addresses",
action="store_const", const="a", dest="show")
+ parser.add_option("-m", "--memory", help="Show Broker Memory Stats",
action="store_const", const="m", dest="show")
opts, args = parser.parse_args(args=argv)
if not opts.show:
- parser.error("You must specify one of these options: -g, -c, -l, -n,
-a, or -m. For details, try $ qdstat --help")
+ parser.error("You must specify one of these options: -g, -c, -l, -n,
-a, -m or -h.")
config._types = opts.show
config._address = opts.bus
@@ -84,7 +76,6 @@ def OptionsAndArguments(argv):
return args
-
class BusManager(Node):
schema = QdSchema()
@@ -330,28 +321,13 @@ class BusManager(Node):
def display(self, names):
self.displayMain(names, config._types)
-
-def main(argv=None):
-
+def run(argv):
args = OptionsAndArguments(argv)
+ bm = BusManager(config._address, config._router)
try:
- bm = BusManager(config._address, config._router)
- try:
- bm.display(args)
- finally:
- bm.stop()
- return 0
- except KeyboardInterrupt:
- print
- except Timeout:
- if config._router:
- print "No response from router %s after timeout" % config._router
- else:
- print "No response after timeout"
- except Exception,e:
- print "%s: %s - %s" % (sys.argv[0], e.__class__.__name__, e)
-
- return 1
+ bm.display(args)
+ finally:
+ bm.stop()
if __name__ == "__main__":
- sys.exit(main())
+ sys.exit(main(run, sys.argv))
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]