diff options
author | Rafael H. Schloming <rhs@apache.org> | 2010-02-14 14:59:24 +0000 |
---|---|---|
committer | Rafael H. Schloming <rhs@apache.org> | 2010-02-14 14:59:24 +0000 |
commit | 074811c4bf1531f04b11db25f348e6c520bc4799 (patch) | |
tree | dd46e4aa9bdaca64974bbddc810f3212d935edd5 /python | |
parent | a025819835829ea7658e4886ddb6e5e488f916eb (diff) | |
download | qpid-python-074811c4bf1531f04b11db25f348e6c520bc4799.tar.gz |
moved qpid-* tools out of qpid/python into qpid/tools; moved qmf library into extras/qmf
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk/qpid@910016 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'python')
26 files changed, 4 insertions, 13224 deletions
diff --git a/python/Makefile b/python/Makefile index 59d38bd53f..ebae6a8ea4 100644 --- a/python/Makefile +++ b/python/Makefile @@ -31,7 +31,7 @@ else AMQP_SPEC_DIR=$(PWD)/$(DATA_DIR)/amqp endif -DIRS=qmf qpid mllib examples +DIRS=qpid mllib examples SRCS=$(shell find $(DIRS) -name "*.py") qpid_config.py BUILD=build TARGETS=$(SRCS:%.py=$(BUILD)/%.py) @@ -71,12 +71,8 @@ install: build install -pm 0644 $(BUILD)/qpid/tests/*.* $(PYTHON_LIB)/qpid/tests $(PYCC) $(PYTHON_LIB)/qpid - install -d $(PYTHON_LIB)/qmf - install -pm 0644 LICENSE.txt NOTICE.txt qmf/*.* $(PYTHON_LIB)/qmf - $(PYCC) $(PYTHON_LIB)/qmf - install -d $(EXEC_PREFIX) - install -pm 0755 qpid-python-test commands/* $(EXEC_PREFIX) + install -pm 0755 qpid-python-test $(EXEC_PREFIX) clean: rm -rf $(BUILD) diff --git a/python/commands/qpid-cluster b/python/commands/qpid-cluster deleted file mode 100755 index 6d64765184..0000000000 --- a/python/commands/qpid-cluster +++ /dev/null @@ -1,327 +0,0 @@ -#!/usr/bin/env python - -# -# 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. -# - -import os -import getopt -import sys -import locale -import socket -import re -from qmf.console import Session - -class Config: - def __init__(self): - self._host = "localhost" - self._connTimeout = 10 - self._stopId = None - self._stopAll = False - self._force = False - self._numeric = False - self._showConn = False - self._delConn = None - -def usage (): - print "Usage: qpid-cluster [OPTIONS] [broker-addr]" - print - print " broker-addr is in the form: [username/password@] hostname | ip-address [:<port>]" - print " ex: localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost" - print - print "Options:" - print " --timeout seconds (10) Maximum time to wait for broker connection" - print " -C [--all-connections] View client connections to all cluster members" - print " -c [--connections] ID View client connections to specified member" - print " -d [--del-connection] HOST:PORT" - print " Disconnect a client connection" - print " -s [--stop] ID Stop one member of the cluster by its ID" - print " -k [--all-stop] Shut down the whole cluster" - print " -f [--force] Suppress the 'are-you-sure?' prompt" - print " -n [--numeric] Don't resolve names" - print - -class IpAddr: - def __init__(self, text): - if text.find("@") != -1: - tokens = text.split("@") - text = tokens[1] - if text.find(":") != -1: - tokens = text.split(":") - text = tokens[0] - self.port = int(tokens[1]) - else: - self.port = 5672 - self.dottedQuad = socket.gethostbyname(text) - nums = self.dottedQuad.split(".") - self.addr = (int(nums[0]) << 24) + (int(nums[1]) << 16) + (int(nums[2]) << 8) + int(nums[3]) - - def bestAddr(self, addrPortList): - bestDiff = 0xFFFFFFFFL - bestAddr = None - for addrPort in addrPortList: - diff = IpAddr(addrPort[0]).addr ^ self.addr - if diff < bestDiff: - bestDiff = diff - bestAddr = addrPort - return bestAddr - -class BrokerManager: - def __init__(self, config): - self.config = config - self.brokerName = None - self.qmf = None - self.broker = None - - def SetBroker(self, brokerUrl): - self.url = brokerUrl - self.qmf = Session() - self.broker = self.qmf.addBroker(brokerUrl, self.config._connTimeout) - agents = self.qmf.getAgents() - for a in agents: - if a.getAgentBank() == 0: - self.brokerAgent = a - - def Disconnect(self): - if self.broker: - self.qmf.delBroker(self.broker) - - def _getClusters(self): - packages = self.qmf.getPackages() - if "org.apache.qpid.cluster" not in packages: - raise Exception("Clustering is not installed on the broker.") - - clusters = self.qmf.getObjects(_class="cluster", _agent=self.brokerAgent) - if len(clusters) == 0: - raise Exception("Clustering is installed but not enabled on the broker.") - - return clusters - - def _getHostList(self, urlList): - hosts = [] - hostAddr = IpAddr(self.config._host) - for url in urlList: - if url.find("amqp:") != 0: - raise Exception("Invalid URL 1") - url = url[5:] - addrs = str(url).split(",") - addrList = [] - for addr in addrs: - tokens = addr.split(":") - if len(tokens) != 3: - raise Exception("Invalid URL 2") - addrList.append((tokens[1], tokens[2])) - - # Find the address in the list that is most likely to be in the same subnet as the address - # with which we made the original QMF connection. This increases the probability that we will - # be able to reach the cluster member. - - best = hostAddr.bestAddr(addrList) - bestUrl = best[0] + ":" + best[1] - hosts.append(bestUrl) - return hosts - - def overview(self): - clusters = self._getClusters() - cluster = clusters[0] - memberList = cluster.members.split(";") - idList = cluster.memberIDs.split(";") - - print " Cluster Name: %s" % cluster.clusterName - print "Cluster Status: %s" % cluster.status - print " Cluster Size: %d" % cluster.clusterSize - print " Members: ID=%s URL=%s" % (idList[0], memberList[0]) - for idx in range(1,len(idList)): - print " : ID=%s URL=%s" % (idList[idx], memberList[idx]) - - def stopMember(self, id): - clusters = self._getClusters() - cluster = clusters[0] - idList = cluster.memberIDs.split(";") - if id not in idList: - raise Exception("No member with matching ID found") - - if not self.config._force: - prompt = "Warning: " - if len(idList) == 1: - prompt += "This command will shut down the last running cluster member." - else: - prompt += "This command will shut down a cluster member." - prompt += " Are you sure? [N]: " - - confirm = raw_input(prompt) - if len(confirm) == 0 or confirm[0].upper() != 'Y': - raise Exception("Operation canceled") - - cluster.stopClusterNode(id) - - def stopAll(self): - clusters = self._getClusters() - if not self.config._force: - prompt = "Warning: This command will shut down the entire cluster." - prompt += " Are you sure? [N]: " - - confirm = raw_input(prompt) - if len(confirm) == 0 or confirm[0].upper() != 'Y': - raise Exception("Operation canceled") - - cluster = clusters[0] - cluster.stopFullCluster() - - def showConnections(self): - clusters = self._getClusters() - cluster = clusters[0] - memberList = cluster.members.split(";") - idList = cluster.memberIDs.split(";") - displayList = [] - hostList = self._getHostList(memberList) - self.qmf.delBroker(self.broker) - self.broker = None - self.brokers = [] - - idx = 0 - for host in hostList: - if self.config._showConn == "all" or self.config._showConn == idList[idx] or self.config._delConn: - self.brokers.append(self.qmf.addBroker(host, self.config._connTimeout)) - displayList.append(idList[idx]) - idx += 1 - - idx = 0 - found = False - for broker in self.brokers: - if not self.config._delConn: - print "Clients on Member: ID=%s:" % displayList[idx] - connList = self.qmf.getObjects(_class="connection", _package="org.apache.qpid.broker", _broker=broker) - for conn in connList: - if not conn.shadow: - if self.config._numeric or self.config._delConn: - a = conn.address - else: - tokens = conn.address.split(":") - try: - hostList = socket.gethostbyaddr(tokens[0]) - host = hostList[0] - except: - host = tokens[0] - a = host + ":" + tokens[1] - if self.config._delConn: - tokens = self.config._delConn.split(":") - ip = socket.gethostbyname(tokens[0]) - toDelete = ip + ":" + tokens[1] - if a == toDelete: - print "Closing connection from client: %s" % a - conn.close() - found = True - else: - print " %s" % a - idx += 1 - if not self.config._delConn: - print - if self.config._delConn and not found: - print "Client connection '%s' not found" % self.config._delConn - - for broker in self.brokers: - self.qmf.delBroker(broker) - - -def main(argv=None): - if argv is None: argv = sys.argv - try: - config = Config() - try: - longOpts = ("stop=", "all-stop", "force", "connections=", "all-connections" "del-connection=", "numeric", "timeout=") - (optlist, encArgs) = getopt.gnu_getopt(argv[1:], "s:kfCc:d:n", longOpts) - except: - usage() - return 1 - - try: - encoding = locale.getpreferredencoding() - cargs = [a.decode(encoding) for a in encArgs] - except: - cargs = encArgs - - count = 0 - for opt in optlist: - if opt[0] == "--timeout": - config._connTimeout = int(opt[1]) - if config._connTimeout == 0: - config._connTimeout = None - if opt[0] == "-s" or opt[0] == "--stop": - config._stopId = opt[1] - if len(config._stopId.split(":")) != 2: - raise Exception("Member ID must be of form: <host or ip>:<number>") - count += 1 - if opt[0] == "-k" or opt[0] == "--all-stop": - config._stopAll = True - count += 1 - if opt[0] == "-f" or opt[0] == "--force": - config._force = True - if opt[0] == "-n" or opt[0] == "--numeric": - config._numeric = True - if opt[0] == "-C" or opt[0] == "--all-connections": - config._showConn = "all" - count += 1 - if opt[0] == "-c" or opt[0] == "--connections": - config._showConn = opt[1] - if len(config._showConn.split(":")) != 2: - raise Exception("Member ID must be of form: <host or ip>:<number>") - count += 1 - if opt[0] == "-d" or opt[0] == "--del-connection": - config._delConn = opt[1] - if len(config._delConn.split(":")) != 2: - raise Exception("Connection must be of form: <host or ip>:<port>") - count += 1 - - if count > 1: - print "Only one command option may be supplied" - print - usage() - return 1 - - nargs = len(cargs) - bm = BrokerManager(config) - - if nargs == 1: - config._host = cargs[0] - - try: - bm.SetBroker(config._host) - if config._stopId: - bm.stopMember(config._stopId) - elif config._stopAll: - bm.stopAll() - elif config._showConn or config._delConn: - bm.showConnections() - else: - bm.overview() - except KeyboardInterrupt: - print - except Exception,e: - if str(e).find("connection aborted") > 0: - # we expect this when asking the connected broker to shut down - return 0 - raise Exception("Failed: %s - %s" % (e.__class__.__name__, e)) - - bm.Disconnect() - except Exception, e: - print str(e) - return 1 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/python/commands/qpid-config b/python/commands/qpid-config deleted file mode 100755 index 0db42bc6c7..0000000000 --- a/python/commands/qpid-config +++ /dev/null @@ -1,572 +0,0 @@ -#!/usr/bin/env python - -# -# 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. -# - -import os -import getopt -import sys -import locale -from qmf.console import Session - -_recursive = False -_host = "localhost" -_connTimeout = 10 -_altern_ex = None -_passive = False -_durable = False -_clusterDurable = False -_if_empty = True -_if_unused = True -_fileCount = 8 -_fileSize = 24 -_maxQueueSize = None -_maxQueueCount = None -_limitPolicy = None -_order = None -_msgSequence = False -_ive = False -_eventGeneration = None -_file = None - -FILECOUNT = "qpid.file_count" -FILESIZE = "qpid.file_size" -MAX_QUEUE_SIZE = "qpid.max_size" -MAX_QUEUE_COUNT = "qpid.max_count" -POLICY_TYPE = "qpid.policy_type" -CLUSTER_DURABLE = "qpid.persist_last_node" -LVQ = "qpid.last_value_queue" -LVQNB = "qpid.last_value_queue_no_browse" -MSG_SEQUENCE = "qpid.msg_sequence" -IVE = "qpid.ive" -QUEUE_EVENT_GENERATION = "qpid.queue_event_generation" - -def Usage (): - print "Usage: qpid-config [OPTIONS]" - print " qpid-config [OPTIONS] exchanges [filter-string]" - print " qpid-config [OPTIONS] queues [filter-string]" - print " qpid-config [OPTIONS] add exchange <type> <name> [AddExchangeOptions]" - print " qpid-config [OPTIONS] del exchange <name>" - print " qpid-config [OPTIONS] add queue <name> [AddQueueOptions]" - print " qpid-config [OPTIONS] del queue <name> [DelQueueOptions]" - print " qpid-config [OPTIONS] bind <exchange-name> <queue-name> [binding-key]" - print " <for type xml> [-f -|filename]" - print " <for type header> [all|any] k1=v1 [, k2=v2...]" - print " qpid-config [OPTIONS] unbind <exchange-name> <queue-name> [binding-key]" - print - print "Options:" - print " --timeout seconds (10) Maximum time to wait for broker connection" - print " -b [ --bindings ] Show bindings in queue or exchange list" - print " -a [ --broker-addr ] Address (localhost) Address of qpidd broker" - print " broker-addr is in the form: [username/password@] hostname | ip-address [:<port>]" - print " ex: localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost" - print - print "Add Queue Options:" - print " --alternate-exchange [name of the alternate exchange]" - print " The alternate-exchange field specifies how messages on this queue should" - print " be treated when they are rejected by a subscriber, or when they are" - print " orphaned by queue deletion. When present, rejected or orphaned messages" - print " MUST be routed to the alternate-exchange. In all cases the messages MUST" - print " be removed from the queue." - print " --passive Do not actually change the broker state (queue will not be created)" - print " --durable Queue is durable" - print " --cluster-durable Queue becomes durable if there is only one functioning cluster node" - print " --file-count N (8) Number of files in queue's persistence journal" - print " --file-size N (24) File size in pages (64Kib/page)" - print " --max-queue-size N Maximum in-memory queue size as bytes" - print " --max-queue-count N Maximum in-memory queue size as a number of messages" - print " --limit-policy [none | reject | flow-to-disk | ring | ring-strict]" - print " Action taken when queue limit is reached:" - print " none (default) - Use broker's default policy" - print " reject - Reject enqueued messages" - print " flow-to-disk - Page messages to disk" - print " ring - Replace oldest unacquired message with new" - print " ring-strict - Replace oldest message, reject if oldest is acquired" - print " --order [fifo | lvq | lvq-no-browse]" - print " Set queue ordering policy:" - print " fifo (default) - First in, first out" - print " lvq - Last Value Queue ordering, allows queue browsing" - print " lvq-no-browse - Last Value Queue ordering, browsing clients may lose data" - print " --generate-queue-events N" - print " If set to 1, every enqueue will generate an event that can be processed by" - print " registered listeners (e.g. for replication). If set to 2, events will be" - print " generated for enqueues and dequeues" - print - print "Del Queue Options:" - print " --force Force delete of queue even if it's currently used or it's not empty" - print " --force-if-not-empty Force delete of queue even if it's not empty" - print " --force-if-used Force delete of queue even if it's currently used" - print - print "Add Exchange <type> values:" - print " direct Direct exchange for point-to-point communication" - print " fanout Fanout exchange for broadcast communication" - print " topic Topic exchange that routes messages using binding keys with wildcards" - print " headers Headers exchange that matches header fields against the binding keys" - print - print "Add Exchange Options:" - print " --alternate-exchange [name of the alternate exchange]" - print " In the event that a message cannot be routed, this is the name of the exchange to" - print " which the message will be sent. Messages transferred using message.transfer will" - print " be routed to the alternate-exchange only if they are sent with the \"none\"" - print " accept-mode, and the discard-unroutable delivery property is set to false, and" - print " there is no queue to route to for the given message according to the bindings" - print " on this exchange." - print " --passive Do not actually change the broker state (exchange will not be created)" - print " --durable Exchange is durable" - print " --sequence Exchange will insert a 'qpid.msg_sequence' field in the message header" - print " with a value that increments for each message forwarded." - print " --ive Exchange will behave as an 'initial-value-exchange', keeping a reference" - print " to the last message forwarded and enqueuing that message to newly bound" - print " queues." - print - sys.exit (1) - - -# -# helpers for the arg parsing in bind(). return multiple values; "ok" -# followed by the resultant args - -# -# accept -f followed by either -# a filename or "-", for stdin. pull the bits into a string, to be -# passed to the xml binding. -# -def snarf_xquery_args(): - if not _file: - print "Invalid args to bind xml: need an input file or stdin" - return [False] - if _file == "-": - res = sys.stdin.read() - else: - f = open(_file) # let this signal if it can't find it - res = f.read() - f.close() - return [True, res] - -# -# look for "any"/"all" and grok the rest of argv into a map -# -def snarf_header_args(cargs): - if len(cargs) < 2: - print "Invalid args to bind headers: need 'any'/'all' plus conditions" - return [False] - op = cargs[0] - if op == "all" or op == "any": - kv = {} - for thing in cargs[1:]: - k_and_v = thing.split("=") - kv[k_and_v[0]] = k_and_v[1] - return [True, op, kv] - else: - print "Invalid condition arg to bind headers, need 'any' or 'all', not '" + op + "'" - return [False] - -class BrokerManager: - def __init__ (self): - self.brokerName = None - self.qmf = None - self.broker = None - - def SetBroker (self, brokerUrl): - self.url = brokerUrl - self.qmf = Session() - self.broker = self.qmf.addBroker(brokerUrl, _connTimeout) - agents = self.qmf.getAgents() - for a in agents: - if a.getAgentBank() == 0: - self.brokerAgent = a - - def Disconnect(self): - if self.broker: - self.qmf.delBroker(self.broker) - - def Overview (self): - exchanges = self.qmf.getObjects(_class="exchange", _agent=self.brokerAgent) - queues = self.qmf.getObjects(_class="queue", _agent=self.brokerAgent) - print "Total Exchanges: %d" % len (exchanges) - etype = {} - for ex in exchanges: - if ex.type not in etype: - etype[ex.type] = 1 - else: - etype[ex.type] = etype[ex.type] + 1 - for typ in etype: - print "%15s: %d" % (typ, etype[typ]) - - print - print " Total Queues: %d" % len (queues) - _durable = 0 - for queue in queues: - if queue.durable: - _durable = _durable + 1 - print " durable: %d" % _durable - print " non-durable: %d" % (len (queues) - _durable) - - def ExchangeList (self, filter): - exchanges = self.qmf.getObjects(_class="exchange", _agent=self.brokerAgent) - caption1 = "Type " - caption2 = "Exchange Name" - maxNameLen = len(caption2) - for ex in exchanges: - if self.match(ex.name, filter): - if len(ex.name) > maxNameLen: maxNameLen = len(ex.name) - print "%s%-*s Attributes" % (caption1, maxNameLen, caption2) - line = "" - for i in range(((maxNameLen + len(caption1)) / 5) + 5): - line += "=====" - print line - - for ex in exchanges: - if self.match (ex.name, filter): - print "%-10s%-*s " % (ex.type, maxNameLen, ex.name), - args = ex.arguments - if ex.durable: print "--durable", - if MSG_SEQUENCE in args and args[MSG_SEQUENCE] == 1: print "--sequence", - if IVE in args and args[IVE] == 1: print "--ive", - if ex.altExchange: - print "--alternate-exchange=%s" % ex._altExchange_.name, - print - - def ExchangeListRecurse (self, filter): - exchanges = self.qmf.getObjects(_class="exchange", _agent=self.brokerAgent) - bindings = self.qmf.getObjects(_class="binding", _agent=self.brokerAgent) - queues = self.qmf.getObjects(_class="queue", _agent=self.brokerAgent) - for ex in exchanges: - if self.match (ex.name, filter): - print "Exchange '%s' (%s)" % (ex.name, ex.type) - for bind in bindings: - if bind.exchangeRef == ex.getObjectId(): - qname = "<unknown>" - queue = self.findById (queues, bind.queueRef) - if queue != None: - qname = queue.name - print " bind [%s] => %s" % (bind.bindingKey, qname) - - - def QueueList (self, filter): - queues = self.qmf.getObjects(_class="queue", _agent=self.brokerAgent) - - caption = "Queue Name" - maxNameLen = len(caption) - for q in queues: - if self.match (q.name, filter): - if len(q.name) > maxNameLen: maxNameLen = len(q.name) - print "%-*s Attributes" % (maxNameLen, caption) - line = "" - for i in range((maxNameLen / 5) + 5): - line += "=====" - print line - - for q in queues: - if self.match (q.name, filter): - print "%-*s " % (maxNameLen, q.name), - args = q.arguments - if q.durable: print "--durable", - if CLUSTER_DURABLE in args and args[CLUSTER_DURABLE] == 1: print "--cluster-durable", - if q.autoDelete: print "auto-del", - if q.exclusive: print "excl", - if FILESIZE in args: print "--file-size=%d" % args[FILESIZE], - if FILECOUNT in args: print "--file-count=%d" % args[FILECOUNT], - if MAX_QUEUE_SIZE in args: print "--max-queue-size=%d" % args[MAX_QUEUE_SIZE], - if MAX_QUEUE_COUNT in args: print "--max-queue-count=%d" % args[MAX_QUEUE_COUNT], - if POLICY_TYPE in args: print "--limit-policy=%s" % args[POLICY_TYPE].replace("_", "-"), - if LVQ in args and args[LVQ] == 1: print "--order lvq", - if LVQNB in args and args[LVQNB] == 1: print "--order lvq-no-browse", - if QUEUE_EVENT_GENERATION in args: print "--generate-queue-events=%d" % args[QUEUE_EVENT_GENERATION], - if q.altExchange: - print "--alternate-exchange=%s" % q._altExchange_.name, - print - - def QueueListRecurse (self, filter): - exchanges = self.qmf.getObjects(_class="exchange", _agent=self.brokerAgent) - bindings = self.qmf.getObjects(_class="binding", _agent=self.brokerAgent) - queues = self.qmf.getObjects(_class="queue", _agent=self.brokerAgent) - for queue in queues: - if self.match (queue.name, filter): - print "Queue '%s'" % queue.name - for bind in bindings: - if bind.queueRef == queue.getObjectId(): - ename = "<unknown>" - ex = self.findById (exchanges, bind.exchangeRef) - if ex != None: - ename = ex.name - if ename == "": - ename = "''" - print " bind [%s] => %s" % (bind.bindingKey, ename) - - def AddExchange (self, args): - if len (args) < 2: - Usage () - etype = args[0] - ename = args[1] - declArgs = {} - if _msgSequence: - declArgs[MSG_SEQUENCE] = 1 - if _ive: - declArgs[IVE] = 1 - if _altern_ex != None: - self.broker.getAmqpSession().exchange_declare (exchange=ename, type=etype, alternate_exchange=_altern_ex, passive=_passive, durable=_durable, arguments=declArgs) - else: - self.broker.getAmqpSession().exchange_declare (exchange=ename, type=etype, passive=_passive, durable=_durable, arguments=declArgs) - - def DelExchange (self, args): - if len (args) < 1: - Usage () - ename = args[0] - self.broker.getAmqpSession().exchange_delete (exchange=ename) - - def AddQueue (self, args): - if len (args) < 1: - Usage () - qname = args[0] - declArgs = {} - if _durable: - declArgs[FILECOUNT] = _fileCount - declArgs[FILESIZE] = _fileSize - - if _maxQueueSize: - declArgs[MAX_QUEUE_SIZE] = _maxQueueSize - if _maxQueueCount: - declArgs[MAX_QUEUE_COUNT] = _maxQueueCount - if _limitPolicy: - if _limitPolicy == "none": - pass - elif _limitPolicy == "reject": - declArgs[POLICY_TYPE] = "reject" - elif _limitPolicy == "flow-to-disk": - declArgs[POLICY_TYPE] = "flow_to_disk" - elif _limitPolicy == "ring": - declArgs[POLICY_TYPE] = "ring" - elif _limitPolicy == "ring-strict": - declArgs[POLICY_TYPE] = "ring_strict" - - if _clusterDurable: - declArgs[CLUSTER_DURABLE] = 1 - if _order: - if _order == "fifo": - pass - elif _order == "lvq": - declArgs[LVQ] = 1 - elif _order == "lvq-no-browse": - declArgs[LVQNB] = 1 - if _eventGeneration: - declArgs[QUEUE_EVENT_GENERATION] = _eventGeneration - - if _altern_ex != None: - self.broker.getAmqpSession().queue_declare (queue=qname, alternate_exchange=_altern_ex, passive=_passive, durable=_durable, arguments=declArgs) - else: - self.broker.getAmqpSession().queue_declare (queue=qname, passive=_passive, durable=_durable, arguments=declArgs) - - def DelQueue (self, args): - if len (args) < 1: - Usage () - qname = args[0] - self.broker.getAmqpSession().queue_delete (queue=qname, if_empty=_if_empty, if_unused=_if_unused) - - def Bind (self, args): - if len (args) < 2: - Usage () - ename = args[0] - qname = args[1] - key = "" - if len (args) > 2: - key = args[2] - - # query the exchange to determine its type. - res = self.broker.getAmqpSession().exchange_query(ename) - - # type of the xchg determines the processing of the rest of - # argv. if it's an xml xchg, we want to find a file - # containing an x-query, and pass that. if it's a headers - # exchange, we need to pass either "any" or all, followed by a - # map containing key/value pairs. if neither of those, extra - # args are ignored. - ok = True - args = None - if res.type == "xml": - # this checks/imports the -f arg - [ok, xquery] = snarf_xquery_args() - args = { "xquery" : xquery } - # print args - else: - if res.type == "headers": - [ok, op, kv] = snarf_header_args(cargs[4:]) - args = kv - args["x-match"] = op - - if not ok: - sys.exit(1) - - self.broker.getAmqpSession().exchange_bind (queue=qname, - exchange=ename, - binding_key=key, - arguments=args) - - def Unbind (self, args): - if len (args) < 2: - Usage () - ename = args[0] - qname = args[1] - key = "" - if len (args) > 2: - key = args[2] - self.broker.getAmqpSession().exchange_unbind (queue=qname, exchange=ename, binding_key=key) - - def findById (self, items, id): - for item in items: - if item.getObjectId() == id: - return item - return None - - def match (self, name, filter): - if filter == "": - return True - if name.find (filter) == -1: - return False - return True - -def YN (bool): - if bool: - return 'Y' - return 'N' - - -## -## Main Program -## - -try: - longOpts = ("durable", "cluster-durable", "bindings", "broker-addr=", "file-count=", - "file-size=", "max-queue-size=", "max-queue-count=", "limit-policy=", - "order=", "sequence", "ive", "generate-queue-events=", "force", "force-if-not-empty", - "force_if_used", "alternate-exchange=", "passive", "timeout=", "file=") - (optlist, encArgs) = getopt.gnu_getopt (sys.argv[1:], "a:bf:", longOpts) -except: - Usage () - -try: - encoding = locale.getpreferredencoding() - cargs = [a.decode(encoding) for a in encArgs] -except: - cargs = encArgs - -for opt in optlist: - if opt[0] == "-b" or opt[0] == "--bindings": - _recursive = True - if opt[0] == "-a" or opt[0] == "--broker-addr": - _host = opt[1] - if opt[0] == "-f" or opt[0] == "--file": - _file = opt[1] - if opt[0] == "--timeout": - _connTimeout = int(opt[1]) - if _connTimeout == 0: - _connTimeout = None - if opt[0] == "--alternate-exchange": - _altern_ex = opt[1] - if opt[0] == "--passive": - _passive = True - if opt[0] == "--durable": - _durable = True - if opt[0] == "--cluster-durable": - _clusterDurable = True - if opt[0] == "--file-count": - _fileCount = int (opt[1]) - if opt[0] == "--file-size": - _fileSize = int (opt[1]) - if opt[0] == "--max-queue-size": - _maxQueueSize = int (opt[1]) - if opt[0] == "--max-queue-count": - _maxQueueCount = int (opt[1]) - if opt[0] == "--limit-policy": - _limitPolicy = opt[1] - if _limitPolicy not in ("none", "reject", "flow-to-disk", "ring", "ring-strict"): - print "Error: Invalid --limit-policy argument" - sys.exit(1) - if opt[0] == "--order": - _order = opt[1] - if _order not in ("fifo", "lvq", "lvq-no-browse"): - print "Error: Invalid --order argument" - sys.exit(1) - if opt[0] == "--sequence": - _msgSequence = True - if opt[0] == "--ive": - _ive = True - if opt[0] == "--generate-queue-events": - _eventGeneration = int (opt[1]) - if opt[0] == "--force": - _if_empty = False - _if_unused = False - if opt[0] == "--force-if-not-empty": - _if_empty = False - if opt[0] == "--force-if-used": - _if_unused = False - - -nargs = len (cargs) -bm = BrokerManager () - -try: - bm.SetBroker(_host) - if nargs == 0: - bm.Overview () - else: - cmd = cargs[0] - modifier = "" - if nargs > 1: - modifier = cargs[1] - if cmd == "exchanges": - if _recursive: - bm.ExchangeListRecurse (modifier) - else: - bm.ExchangeList (modifier) - elif cmd == "queues": - if _recursive: - bm.QueueListRecurse (modifier) - else: - bm.QueueList (modifier) - elif cmd == "add": - if modifier == "exchange": - bm.AddExchange (cargs[2:]) - elif modifier == "queue": - bm.AddQueue (cargs[2:]) - else: - Usage () - elif cmd == "del": - if modifier == "exchange": - bm.DelExchange (cargs[2:]) - elif modifier == "queue": - bm.DelQueue (cargs[2:]) - else: - Usage () - elif cmd == "bind": - bm.Bind (cargs[1:]) - elif cmd == "unbind": - bm.Unbind (cargs[1:]) - else: - Usage () -except KeyboardInterrupt: - print -except IOError, e: - print e - sys.exit(1) -except Exception,e: - print "Failed: %s: %s" % (e.__class__.__name__, e) - sys.exit(1) - -bm.Disconnect() diff --git a/python/commands/qpid-printevents b/python/commands/qpid-printevents deleted file mode 100755 index 0c1b618a1f..0000000000 --- a/python/commands/qpid-printevents +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python - -# -# 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. -# - -import os -import optparse -import sys -import socket -from time import time, strftime, gmtime, sleep -from qmf.console import Console, Session - -class EventConsole(Console): - def event(self, broker, event): - print event - - def brokerConnected(self, broker): - print strftime("%c", gmtime(time())), "NOTIC qpid-printevents:brokerConnected broker=%s" % broker.getUrl() - - def brokerDisconnected(self, broker): - print strftime("%c", gmtime(time())), "NOTIC qpid-printevents:brokerDisconnected broker=%s" % broker.getUrl() - - -## -## Main Program -## -def main(): - _usage = "%prog [options] [broker-addr]..." - _description = \ -"""Collect and print events from one or more Qpid message brokers. If no broker-addr is -supplied, %prog will connect to 'localhost:5672'. -broker-addr is of the form: [username/password@] hostname | ip-address [:<port>] -ex: localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost -""" - p = optparse.OptionParser(usage=_usage, description=_description) - - options, arguments = p.parse_args() - if len(arguments) == 0: - arguments.append("localhost") - - console = EventConsole() - session = Session(console, rcvObjects=False, rcvHeartbeats=False, manageConnections=True) - brokers = [] - for host in arguments: - brokers.append(session.addBroker(host)) - - try: - while (True): - sleep(10) - except KeyboardInterrupt: - for broker in brokers: - session.delBroker(broker) - print - sys.exit(0) - -if __name__ == '__main__': - main() - diff --git a/python/commands/qpid-queue-stats b/python/commands/qpid-queue-stats deleted file mode 100755 index 3b8a0dcb19..0000000000 --- a/python/commands/qpid-queue-stats +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python - -# -# 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. -# - -import os -import optparse -import sys -import re -import socket -import qpid -from threading import Condition -from qmf.console import Session, Console -from qpid.peer import Closed -from qpid.connection import Connection, ConnectionFailed -from time import sleep - -class BrokerManager(Console): - def __init__(self, host): - self.url = host - self.objects = {} - self.filter = None - self.session = Session(self, rcvEvents=False, rcvHeartbeats=False, - userBindings=True, manageConnections=True) - self.broker = self.session.addBroker(self.url) - self.firstError = True - - def setFilter(self,filter): - self.filter = filter - - def brokerConnected(self, broker): - if not self.firstError: - print "*** Broker connected" - self.firstError = False - - def brokerDisconnected(self, broker): - print "*** Broker connection lost - %s, retrying..." % broker.getError() - self.firstError = False - self.objects.clear() - - def objectProps(self, broker, record): - className = record.getClassKey().getClassName() - if className != "queue": - return - - id = record.getObjectId().__repr__() - if id not in self.objects: - self.objects[id] = (record.name, None, None) - - def objectStats(self, broker, record): - className = record.getClassKey().getClassName() - if className != "queue": - return - - id = record.getObjectId().__repr__() - if id not in self.objects: - return - - (name, first, last) = self.objects[id] - if first == None: - self.objects[id] = (name, record, None) - return - - if len(self.filter) > 0 : - match = False - - for x in self.filter: - if x.match(name): - match = True - break - if match == False: - return - - if last == None: - lastSample = first - else: - lastSample = last - - self.objects[id] = (name, first, record) - - deltaTime = float (record.getTimestamps()[0] - lastSample.getTimestamps()[0]) - if deltaTime < 1000000000.0: - return - enqueueRate = float (record.msgTotalEnqueues - lastSample.msgTotalEnqueues) / \ - (deltaTime / 1000000000.0) - dequeueRate = float (record.msgTotalDequeues - lastSample.msgTotalDequeues) / \ - (deltaTime / 1000000000.0) - print "%-41s%10.2f%11d%13.2f%13.2f" % \ - (name, deltaTime / 1000000000, record.msgDepth, enqueueRate, dequeueRate) - sys.stdout.flush() - - - def Display (self): - self.session.bindClass("org.apache.qpid.broker", "queue") - print "Queue Name Sec Depth Enq Rate Deq Rate" - print "========================================================================================" - sys.stdout.flush() - try: - while True: - sleep (1) - if self.firstError and self.broker.getError(): - self.firstError = False - print "*** Error: %s, retrying..." % self.broker.getError() - except KeyboardInterrupt: - print - self.session.delBroker(self.broker) - -## -## Main Program -## -def main(): - p = optparse.OptionParser() - p.add_option('--broker-address','-a', default='localhost' , help='broker-addr is in the form: [username/password@] hostname | ip-address [:<port>] \n ex: localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost') - p.add_option('--filter','-f' ,default=None ,help='a list of comma separated queue names (regex are accepted) to show') - - options, arguments = p.parse_args() - - host = options.broker_address - filter = [] - if options.filter != None: - for s in options.filter.split(","): - filter.append(re.compile(s)) - - bm = BrokerManager(host) - bm.setFilter(filter) - bm.Display() - -if __name__ == '__main__': - main() - diff --git a/python/commands/qpid-route b/python/commands/qpid-route deleted file mode 100755 index 9965047000..0000000000 --- a/python/commands/qpid-route +++ /dev/null @@ -1,524 +0,0 @@ -#!/usr/bin/env python - -# -# 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. -# - -import getopt -import sys -import socket -import os -import locale -from qmf.console import Session, BrokerURL - -def Usage(): - print "Usage: qpid-route [OPTIONS] dynamic add <dest-broker> <src-broker> <exchange> [tag] [exclude-list]" - print " qpid-route [OPTIONS] dynamic del <dest-broker> <src-broker> <exchange>" - print - print " qpid-route [OPTIONS] route add <dest-broker> <src-broker> <exchange> <routing-key> [tag] [exclude-list]" - print " qpid-route [OPTIONS] route del <dest-broker> <src-broker> <exchange> <routing-key>" - print " qpid-route [OPTIONS] queue add <dest-broker> <src-broker> <exchange> <queue>" - print " qpid-route [OPTIONS] queue del <dest-broker> <src-broker> <exchange> <queue>" - print " qpid-route [OPTIONS] route list [<dest-broker>]" - print " qpid-route [OPTIONS] route flush [<dest-broker>]" - print " qpid-route [OPTIONS] route map [<broker>]" - print - print " qpid-route [OPTIONS] link add <dest-broker> <src-broker>" - print " qpid-route [OPTIONS] link del <dest-broker> <src-broker>" - print " qpid-route [OPTIONS] link list [<dest-broker>]" - print - print "Options:" - print " --timeout seconds (10) Maximum time to wait for broker connection" - print " -v [ --verbose ] Verbose output" - print " -q [ --quiet ] Quiet output, don't print duplicate warnings" - print " -d [ --durable ] Added configuration shall be durable" - print " -e [ --del-empty-link ] Delete link after deleting last route on the link" - print " -s [ --src-local ] Make connection to source broker (push route)" - print " --ack N Acknowledge transfers over the bridge in batches of N" - print " -t <transport> [ --transport <transport>]" - print " Specify transport to use for links, defaults to tcp" - print - print " dest-broker and src-broker are in the form: [username/password@] hostname | ip-address [:<port>]" - print " ex: localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost" - print - sys.exit(1) - -_verbose = False -_quiet = False -_durable = False -_dellink = False -_srclocal = False -_transport = "tcp" -_ack = 0 -_connTimeout = 10 - -class RouteManager: - def __init__(self, localBroker): - self.local = BrokerURL(localBroker) - self.remote = None - self.qmf = Session() - self.broker = self.qmf.addBroker(localBroker, _connTimeout) - - def disconnect(self): - self.qmf.delBroker(self.broker) - - def getLink(self): - links = self.qmf.getObjects(_class="link") - for link in links: - if self.remote.match(link.host, link.port): - return link - return None - - def addLink(self, remoteBroker): - self.remote = BrokerURL(remoteBroker) - if self.local.match(self.remote.host, self.remote.port): - raise Exception("Linking broker to itself is not permitted") - - brokers = self.qmf.getObjects(_class="broker") - broker = brokers[0] - link = self.getLink() - if link == None: - if not self.remote.authName or self.remote.authName == "anonymous": - mech = "ANONYMOUS" - else: - mech = "PLAIN" - res = broker.connect(self.remote.host, self.remote.port, _durable, - mech, self.remote.authName or "", self.remote.authPass or "", - _transport) - if _verbose: - print "Connect method returned:", res.status, res.text - - def delLink(self, remoteBroker): - self.remote = BrokerURL(remoteBroker) - brokers = self.qmf.getObjects(_class="broker") - broker = brokers[0] - link = self.getLink() - if link == None: - raise Exception("Link not found") - - res = link.close() - if _verbose: - print "Close method returned:", res.status, res.text - - def listLinks(self): - links = self.qmf.getObjects(_class="link") - if len(links) == 0: - print "No Links Found" - else: - print - print "Host Port Transport Durable State Last Error" - print "=============================================================================" - for link in links: - print "%-16s%-8d%-13s%c %-18s%s" % \ - (link.host, link.port, link.transport, YN(link.durable), link.state, link.lastError) - - def mapRoutes(self): - qmf = self.qmf - print - print "Finding Linked Brokers:" - - brokerList = {} - brokerList[self.local.name()] = self.broker - print " %s... Ok" % self.local - - added = True - while added: - added = False - links = qmf.getObjects(_class="link") - for link in links: - url = BrokerURL("%s:%d" % (link.host, link.port)) - if url.name() not in brokerList: - print " %s..." % url.name(), - try: - b = qmf.addBroker("%s:%d" % (link.host, link.port), _connTimeout) - brokerList[url.name()] = b - added = True - print "Ok" - except Exception, e: - print e - - print - print "Dynamic Routes:" - bridges = qmf.getObjects(_class="bridge", dynamic=True) - fedExchanges = [] - for bridge in bridges: - if bridge.src not in fedExchanges: - fedExchanges.append(bridge.src) - if len(fedExchanges) == 0: - print " none found" - print - - for ex in fedExchanges: - print " Exchange %s:" % ex - pairs = [] - for bridge in bridges: - if bridge.src == ex: - link = bridge._linkRef_ - fromUrl = "%s:%s" % (link.host, link.port) - toUrl = bridge.getBroker().getUrl() - found = False - for pair in pairs: - if pair.matches(fromUrl, toUrl): - found = True - if not found: - pairs.append(RoutePair(fromUrl, toUrl)) - for pair in pairs: - print " %s" % pair - print - - print "Static Routes:" - bridges = qmf.getObjects(_class="bridge", dynamic=False) - if len(bridges) == 0: - print " none found" - print - - for bridge in bridges: - link = bridge._linkRef_ - fromUrl = "%s:%s" % (link.host, link.port) - toUrl = bridge.getBroker().getUrl() - leftType = "ex" - rightType = "ex" - if bridge.srcIsLocal: - arrow = "=>" - left = bridge.src - right = bridge.dest - if bridge.srcIsQueue: - leftType = "queue" - else: - arrow = "<=" - left = bridge.dest - right = bridge.src - if bridge.srcIsQueue: - rightType = "queue" - - if bridge.srcIsQueue: - print " %s(%s=%s) %s %s(%s=%s)" % \ - (toUrl, leftType, left, arrow, fromUrl, rightType, right) - else: - print " %s(%s=%s) %s %s(%s=%s) key=%s" % \ - (toUrl, leftType, left, arrow, fromUrl, rightType, right, bridge.key) - print - - for broker in brokerList: - if broker != self.local.name(): - qmf.delBroker(brokerList[broker]) - - - def addRoute(self, remoteBroker, exchange, routingKey, tag, excludes, dynamic=False): - if dynamic and _srclocal: - raise Exception("--src-local is not permitted on dynamic routes") - - self.addLink(remoteBroker) - link = self.getLink() - if link == None: - raise Exception("Link failed to create") - - bridges = self.qmf.getObjects(_class="bridge") - for bridge in bridges: - if bridge.linkRef == link.getObjectId() and \ - bridge.dest == exchange and bridge.key == routingKey and not bridge.srcIsQueue: - if not _quiet: - raise Exception("Duplicate Route - ignoring: %s(%s)" % (exchange, routingKey)) - sys.exit(0) - - if _verbose: - print "Creating inter-broker binding..." - res = link.bridge(_durable, exchange, exchange, routingKey, tag, excludes, False, _srclocal, dynamic, _ack) - if res.status != 0: - raise Exception(res.text) - if _verbose: - print "Bridge method returned:", res.status, res.text - - def addQueueRoute(self, remoteBroker, exchange, queue): - self.addLink(remoteBroker) - link = self.getLink() - if link == None: - raise Exception("Link failed to create") - - bridges = self.qmf.getObjects(_class="bridge") - for bridge in bridges: - if bridge.linkRef == link.getObjectId() and \ - bridge.dest == exchange and bridge.src == queue and bridge.srcIsQueue: - if not _quiet: - raise Exception("Duplicate Route - ignoring: %s(%s)" % (exchange, queue)) - sys.exit(0) - - if _verbose: - print "Creating inter-broker binding..." - res = link.bridge(_durable, queue, exchange, "", "", "", True, _srclocal, False, _ack) - if res.status != 0: - raise Exception(res.text) - if _verbose: - print "Bridge method returned:", res.status, res.text - - def delQueueRoute(self, remoteBroker, exchange, queue): - self.remote = BrokerURL(remoteBroker) - link = self.getLink() - if link == None: - if not _quiet: - raise Exception("No link found from %s to %s" % (self.remote.name(), self.local.name())) - sys.exit(0) - - bridges = self.qmf.getObjects(_class="bridge") - for bridge in bridges: - if bridge.linkRef == link.getObjectId() and \ - bridge.dest == exchange and bridge.src == queue and bridge.srcIsQueue: - if _verbose: - print "Closing bridge..." - res = bridge.close() - if res.status != 0: - raise Exception("Error closing bridge: %d - %s" % (res.status, res.text)) - if len(bridges) == 1 and _dellink: - link = self.getLink() - if link == None: - sys.exit(0) - if _verbose: - print "Last bridge on link, closing link..." - res = link.close() - if res.status != 0: - raise Exception("Error closing link: %d - %s" % (res.status, res.text)) - sys.exit(0) - if not _quiet: - raise Exception("Route not found") - - def delRoute(self, remoteBroker, exchange, routingKey, dynamic=False): - self.remote = BrokerURL(remoteBroker) - link = self.getLink() - if link == None: - if not _quiet: - raise Exception("No link found from %s to %s" % (self.remote.name(), self.local.name())) - sys.exit(0) - - bridges = self.qmf.getObjects(_class="bridge") - for bridge in bridges: - if bridge.linkRef == link.getObjectId() and bridge.dest == exchange and bridge.key == routingKey \ - and bridge.dynamic == dynamic: - if _verbose: - print "Closing bridge..." - res = bridge.close() - if res.status != 0: - raise Exception("Error closing bridge: %d - %s" % (res.status, res.text)) - if len(bridges) == 1 and _dellink: - link = self.getLink() - if link == None: - sys.exit(0) - if _verbose: - print "Last bridge on link, closing link..." - res = link.close() - if res.status != 0: - raise Exception("Error closing link: %d - %s" % (res.status, res.text)) - sys.exit(0) - if not _quiet: - raise Exception("Route not found") - - def listRoutes(self): - links = self.qmf.getObjects(_class="link") - bridges = self.qmf.getObjects(_class="bridge") - - for bridge in bridges: - myLink = None - for link in links: - if bridge.linkRef == link.getObjectId(): - myLink = link - break - if myLink != None: - if bridge.dynamic: - keyText = "<dynamic>" - else: - keyText = bridge.key - print "%s %s:%d %s %s" % (self.local.name(), myLink.host, myLink.port, bridge.dest, keyText) - - def clearAllRoutes(self): - links = self.qmf.getObjects(_class="link") - bridges = self.qmf.getObjects(_class="bridge") - - for bridge in bridges: - if _verbose: - myLink = None - for link in links: - if bridge.linkRef == link.getObjectId(): - myLink = link - break - if myLink != None: - print "Deleting Bridge: %s:%d %s %s... " % (myLink.host, myLink.port, bridge.dest, bridge.key), - res = bridge.close() - if res.status != 0: - print "Error: %d - %s" % (res.status, res.text) - elif _verbose: - print "Ok" - - if _dellink: - links = self.qmf.getObjects(_class="link") - for link in links: - if _verbose: - print "Deleting Link: %s:%d... " % (link.host, link.port), - res = link.close() - if res.status != 0: - print "Error: %d - %s" % (res.status, res.text) - elif _verbose: - print "Ok" - -class RoutePair: - def __init__(self, fromUrl, toUrl): - self.fromUrl = fromUrl - self.toUrl = toUrl - self.bidir = False - - def __repr__(self): - if self.bidir: - delimit = "<=>" - else: - delimit = " =>" - return "%s %s %s" % (self.fromUrl, delimit, self.toUrl) - - def matches(self, fromUrl, toUrl): - if fromUrl == self.fromUrl and toUrl == self.toUrl: - return True - if toUrl == self.fromUrl and fromUrl == self.toUrl: - self.bidir = True - return True - return False - - -def YN(val): - if val == 1: - return 'Y' - return 'N' - -## -## Main Program -## - -try: - longOpts = ("verbose", "quiet", "durable", "del-empty-link", "src-local", "transport=", "ack=", "timeout=") - (optlist, encArgs) = getopt.gnu_getopt(sys.argv[1:], "vqdest:", longOpts) -except: - Usage() - -try: - encoding = locale.getpreferredencoding() - cargs = [a.decode(encoding) for a in encArgs] -except: - cargs = encArgs - -for opt in optlist: - if opt[0] == "--timeout": - _connTimeout = int(opt[1]) - if _connTimeout == 0: - _connTimeout = None - if opt[0] == "-v" or opt[0] == "--verbose": - _verbose = True - if opt[0] == "-q" or opt[0] == "--quiet": - _quiet = True - if opt[0] == "-d" or opt[0] == "--durable": - _durable = True - if opt[0] == "-e" or opt[0] == "--del-empty-link": - _dellink = True - if opt[0] == "-s" or opt[0] == "--src-local": - _srclocal = True - if opt[0] == "-t" or opt[0] == "--transport": - _transport = opt[1] - if opt[0] == "--ack": - _ack = int(opt[1]) - -nargs = len(cargs) -if nargs < 2: - Usage() -if nargs == 2: - localBroker = "localhost" -else: - if _srclocal: - localBroker = cargs[3] - remoteBroker = cargs[2] - else: - localBroker = cargs[2] - if nargs > 3: - remoteBroker = cargs[3] - -group = cargs[0] -cmd = cargs[1] - -try: - rm = RouteManager(localBroker) - if group == "link": - if cmd == "add": - if nargs != 4: - Usage() - rm.addLink(remoteBroker) - elif cmd == "del": - if nargs != 4: - Usage() - rm.delLink(remoteBroker) - elif cmd == "list": - rm.listLinks() - - elif group == "dynamic": - if cmd == "add": - if nargs < 5 or nargs > 7: - Usage() - - tag = "" - excludes = "" - if nargs > 5: tag = cargs[5] - if nargs > 6: excludes = cargs[6] - rm.addRoute(remoteBroker, cargs[4], "", tag, excludes, dynamic=True) - elif cmd == "del": - if nargs != 5: - Usage() - else: - rm.delRoute(remoteBroker, cargs[4], "", dynamic=True) - - elif group == "route": - if cmd == "add": - if nargs < 6 or nargs > 8: - Usage() - - tag = "" - excludes = "" - if nargs > 6: tag = cargs[6] - if nargs > 7: excludes = cargs[7] - rm.addRoute(remoteBroker, cargs[4], cargs[5], tag, excludes, dynamic=False) - elif cmd == "del": - if nargs != 6: - Usage() - rm.delRoute(remoteBroker, cargs[4], cargs[5], dynamic=False) - elif cmd == "map": - rm.mapRoutes() - else: - if cmd == "list": - rm.listRoutes() - elif cmd == "flush": - rm.clearAllRoutes() - else: - Usage() - - elif group == "queue": - if nargs != 6: - Usage() - if cmd == "add": - rm.addQueueRoute(remoteBroker, exchange=cargs[4], queue=cargs[5]) - elif cmd == "del": - rm.delQueueRoute(remoteBroker, exchange=cargs[4], queue=cargs[5]) - else: - Usage() - -except Exception,e: - print "Failed: %s - %s" % (e.__class__.__name__, e) - sys.exit(1) - -rm.disconnect() diff --git a/python/commands/qpid-stat b/python/commands/qpid-stat deleted file mode 100755 index c6fc5ef0da..0000000000 --- a/python/commands/qpid-stat +++ /dev/null @@ -1,459 +0,0 @@ -#!/usr/bin/env python - -# -# 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. -# - -import os -import getopt -import sys -import locale -import socket -import re -from qmf.console import Session, Console -from qpid.disp import Display, Header, Sorter - -_host = "localhost" -_connTimeout = 10 -_types = "" -_limit = 50 -_increasing = False -_sortcol = None - -def Usage (): - print "Usage: qpid-stat [OPTIONS] [broker-addr]" - print - print " broker-addr is in the form: [username/password@] hostname | ip-address [:<port>]" - print " ex: localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost" - print - print "General Options:" - print " --timeout seconds (10) Maximum time to wait for broker connection" -# print " -n [--numeric] Don't resolve names" - print - print "Display Options:" - print - print " -b Show Brokers" - print " -c Show Connections" -# print " -s Show Sessions" - print " -e Show Exchanges" - print " -q Show Queues" - print - print " -S [--sort-by] COLNAME Sort by column name" - print " -I [--increasing] Sort by increasing value (default = decreasing)" - print " -L [--limit] NUM Limit output to NUM rows (default = 50)" - print - sys.exit (1) - -class IpAddr: - def __init__(self, text): - if text.find("@") != -1: - tokens = text.split("@") - text = tokens[1] - if text.find(":") != -1: - tokens = text.split(":") - text = tokens[0] - self.port = int(tokens[1]) - else: - self.port = 5672 - self.dottedQuad = socket.gethostbyname(text) - nums = self.dottedQuad.split(".") - self.addr = (int(nums[0]) << 24) + (int(nums[1]) << 16) + (int(nums[2]) << 8) + int(nums[3]) - - def bestAddr(self, addrPortList): - bestDiff = 0xFFFFFFFFL - bestAddr = None - for addrPort in addrPortList: - diff = IpAddr(addrPort[0]).addr ^ self.addr - if diff < bestDiff: - bestDiff = diff - bestAddr = addrPort - return bestAddr - -class Broker(object): - def __init__(self, qmf, broker): - self.broker = broker - - agents = qmf.getAgents() - for a in agents: - if a.getAgentBank() == 0: - self.brokerAgent = a - - bobj = qmf.getObjects(_class="broker", _package="org.apache.qpid.broker", _agent=self.brokerAgent)[0] - self.currentTime = bobj.getTimestamps()[0] - try: - self.uptime = bobj.uptime - except: - self.uptime = 0 - self.connections = {} - self.sessions = {} - self.exchanges = {} - self.queues = {} - package = "org.apache.qpid.broker" - - list = qmf.getObjects(_class="connection", _package=package, _agent=self.brokerAgent) - for conn in list: - if not conn.shadow: - self.connections[conn.getObjectId()] = conn - - list = qmf.getObjects(_class="session", _package=package, _agent=self.brokerAgent) - for sess in list: - if sess.connectionRef in self.connections: - self.sessions[sess.getObjectId()] = sess - - list = qmf.getObjects(_class="exchange", _package=package, _agent=self.brokerAgent) - for exchange in list: - self.exchanges[exchange.getObjectId()] = exchange - - list = qmf.getObjects(_class="queue", _package=package, _agent=self.brokerAgent) - for queue in list: - self.queues[queue.getObjectId()] = queue - - def getName(self): - return self.broker.getUrl() - - def getCurrentTime(self): - return self.currentTime - - def getUptime(self): - return self.uptime - -class BrokerManager(Console): - def __init__(self): - self.brokerName = None - self.qmf = None - self.broker = None - self.brokers = [] - self.cluster = None - - def SetBroker(self, brokerUrl): - self.url = brokerUrl - self.qmf = Session() - self.broker = self.qmf.addBroker(brokerUrl, _connTimeout) - agents = self.qmf.getAgents() - for a in agents: - if a.getAgentBank() == 0: - self.brokerAgent = a - - def Disconnect(self): - if self.broker: - self.qmf.delBroker(self.broker) - - def _getCluster(self): - packages = self.qmf.getPackages() - if "org.apache.qpid.cluster" not in packages: - return None - - clusters = self.qmf.getObjects(_class="cluster", _agent=self.brokerAgent) - if len(clusters) == 0: - print "Clustering is installed but not enabled on the broker." - return None - - self.cluster = clusters[0] - - def _getHostList(self, urlList): - hosts = [] - hostAddr = IpAddr(_host) - for url in urlList: - if url.find("amqp:") != 0: - raise Exception("Invalid URL 1") - url = url[5:] - addrs = str(url).split(",") - addrList = [] - for addr in addrs: - tokens = addr.split(":") - if len(tokens) != 3: - raise Exception("Invalid URL 2") - addrList.append((tokens[1], tokens[2])) - - # Find the address in the list that is most likely to be in the same subnet as the address - # with which we made the original QMF connection. This increases the probability that we will - # be able to reach the cluster member. - - best = hostAddr.bestAddr(addrList) - bestUrl = best[0] + ":" + best[1] - hosts.append(bestUrl) - return hosts - - def displaySubs(self, subs, indent, broker=None, conn=None, sess=None, exchange=None, queue=None): - if len(subs) == 0: - return - this = subs[0] - remaining = subs[1:] - newindent = indent + " " - if this == 'b': - pass - elif this == 'c': - if broker: - for oid in broker.connections: - iconn = broker.connections[oid] - self.printConnSub(indent, broker.getName(), iconn) - self.displaySubs(remaining, newindent, broker=broker, conn=iconn, - sess=sess, exchange=exchange, queue=queue) - elif this == 's': - pass - elif this == 'e': - pass - elif this == 'q': - pass - print - - def displayBroker(self, subs): - disp = Display(prefix=" ") - heads = [] - heads.append(Header('broker')) - heads.append(Header('cluster')) - heads.append(Header('uptime', Header.DURATION)) - heads.append(Header('conn', Header.KMG)) - heads.append(Header('sess', Header.KMG)) - heads.append(Header('exch', Header.KMG)) - heads.append(Header('queue', Header.KMG)) - rows = [] - for broker in self.brokers: - if self.cluster: - ctext = "%s(%s)" % (self.cluster.clusterName, self.cluster.status) - else: - ctext = "<standalone>" - row = (broker.getName(), ctext, broker.getUptime(), - len(broker.connections), len(broker.sessions), - len(broker.exchanges), len(broker.queues)) - rows.append(row) - title = "Brokers" - if _sortcol: - sorter = Sorter(heads, rows, _sortcol, _limit, _increasing) - dispRows = sorter.getSorted() - else: - dispRows = rows - disp.formattedTable(title, heads, dispRows) - - def displayConn(self, subs): - disp = Display(prefix=" ") - heads = [] - if self.cluster: - heads.append(Header('broker')) - heads.append(Header('client-addr')) - heads.append(Header('cproc')) - heads.append(Header('cpid')) - heads.append(Header('auth')) - heads.append(Header('connected', Header.DURATION)) - heads.append(Header('idle', Header.DURATION)) - heads.append(Header('msgIn', Header.KMG)) - heads.append(Header('msgOut', Header.KMG)) - rows = [] - for broker in self.brokers: - for oid in broker.connections: - conn = broker.connections[oid] - row = [] - if self.cluster: - row.append(broker.getName()) - row.append(conn.address) - row.append(conn.remoteProcessName) - row.append(conn.remotePid) - row.append(conn.authIdentity) - row.append(broker.getCurrentTime() - conn.getTimestamps()[1]) - idle = broker.getCurrentTime() - conn.getTimestamps()[0] - row.append(broker.getCurrentTime() - conn.getTimestamps()[0]) - row.append(conn.framesFromClient) - row.append(conn.framesToClient) - rows.append(row) - title = "Connections" - if self.cluster: - title += " for cluster '%s'" % self.cluster.clusterName - if _sortcol: - sorter = Sorter(heads, rows, _sortcol, _limit, _increasing) - dispRows = sorter.getSorted() - else: - dispRows = rows - disp.formattedTable(title, heads, dispRows) - - def displaySession(self, subs): - disp = Display(prefix=" ") - - def displayExchange(self, subs): - disp = Display(prefix=" ") - heads = [] - if self.cluster: - heads.append(Header('broker')) - heads.append(Header("exchange")) - heads.append(Header("type")) - heads.append(Header("dur", Header.Y)) - heads.append(Header("bind", Header.KMG)) - heads.append(Header("msgIn", Header.KMG)) - heads.append(Header("msgOut", Header.KMG)) - heads.append(Header("msgDrop", Header.KMG)) - heads.append(Header("byteIn", Header.KMG)) - heads.append(Header("byteOut", Header.KMG)) - heads.append(Header("byteDrop", Header.KMG)) - rows = [] - for broker in self.brokers: - for oid in broker.exchanges: - ex = broker.exchanges[oid] - row = [] - if self.cluster: - row.append(broker.getName()) - row.append(ex.name) - row.append(ex.type) - row.append(ex.durable) - row.append(ex.bindingCount) - row.append(ex.msgReceives) - row.append(ex.msgRoutes) - row.append(ex.msgDrops) - row.append(ex.byteReceives) - row.append(ex.byteRoutes) - row.append(ex.byteDrops) - rows.append(row) - title = "Exchanges" - if self.cluster: - title += " for cluster '%s'" % self.cluster.clusterName - if _sortcol: - sorter = Sorter(heads, rows, _sortcol, _limit, _increasing) - dispRows = sorter.getSorted() - else: - dispRows = rows - disp.formattedTable(title, heads, dispRows) - - def displayQueue(self, subs): - disp = Display(prefix=" ") - heads = [] - if self.cluster: - heads.append(Header('broker')) - heads.append(Header("queue")) - heads.append(Header("dur", Header.Y)) - heads.append(Header("autoDel", Header.Y)) - heads.append(Header("excl", Header.Y)) - heads.append(Header("msg", Header.KMG)) - heads.append(Header("msgIn", Header.KMG)) - heads.append(Header("msgOut", Header.KMG)) - heads.append(Header("bytes", Header.KMG)) - heads.append(Header("bytesIn", Header.KMG)) - heads.append(Header("bytesOut", Header.KMG)) - heads.append(Header("cons", Header.KMG)) - heads.append(Header("bind", Header.KMG)) - rows = [] - for broker in self.brokers: - for oid in broker.queues: - q = broker.queues[oid] - row = [] - if self.cluster: - row.append(broker.getName()) - row.append(q.name) - row.append(q.durable) - row.append(q.autoDelete) - row.append(q.exclusive) - row.append(q.msgDepth) - row.append(q.msgTotalEnqueues) - row.append(q.msgTotalDequeues) - row.append(q.byteDepth) - row.append(q.byteTotalEnqueues) - row.append(q.byteTotalDequeues) - row.append(q.consumerCount) - row.append(q.bindingCount) - rows.append(row) - title = "Queues" - if self.cluster: - title += " for cluster '%s'" % self.cluster.clusterName - if _sortcol: - sorter = Sorter(heads, rows, _sortcol, _limit, _increasing) - dispRows = sorter.getSorted() - else: - dispRows = rows - disp.formattedTable(title, heads, dispRows) - - def displayMain(self, main, subs): - if main == 'b': self.displayBroker(subs) - elif main == 'c': self.displayConn(subs) - elif main == 's': self.displaySession(subs) - elif main == 'e': self.displayExchange(subs) - elif main == 'q': self.displayQueue(subs) - - def display(self): - self._getCluster() - if self.cluster: - memberList = self.cluster.members.split(";") - hostList = self._getHostList(memberList) - self.qmf.delBroker(self.broker) - self.broker = None - if _host.find("@") > 0: - authString = _host.split("@")[0] + "@" - else: - authString = "" - for host in hostList: - b = self.qmf.addBroker(authString + host, _connTimeout) - self.brokers.append(Broker(self.qmf, b)) - else: - self.brokers.append(Broker(self.qmf, self.broker)) - - self.displayMain(_types[0], _types[1:]) - - -## -## Main Program -## - -try: - longOpts = ("top", "numeric", "sort-by=", "limit=", "increasing", "timeout=") - (optlist, encArgs) = getopt.gnu_getopt(sys.argv[1:], "bceqS:L:I", longOpts) -except: - Usage() - -try: - encoding = locale.getpreferredencoding() - cargs = [a.decode(encoding) for a in encArgs] -except: - cargs = encArgs - -for opt in optlist: - if opt[0] == "--timeout": - _connTimeout = int(opt[1]) - if _connTimeout == 0: - _connTimeout = None - elif opt[0] == "-n" or opt[0] == "--numeric": - _numeric = True - elif opt[0] == "-S" or opt[0] == "--sort-by": - _sortcol = opt[1] - elif opt[0] == "-I" or opt[0] == "--increasing": - _increasing = True - elif opt[0] == "-L" or opt[0] == "--limit": - _limit = int(opt[1]) - elif len(opt[0]) == 2: - char = opt[0][1] - if "bcseq".find(char) != -1: - _types += char - else: - Usage() - else: - Usage() - -if len(_types) == 0: - Usage() - -nargs = len(cargs) -bm = BrokerManager() - -if nargs == 1: - _host = cargs[0] - -try: - bm.SetBroker(_host) - bm.display() -except KeyboardInterrupt: - print -except Exception,e: - print "Failed: %s - %s" % (e.__class__.__name__, e) - sys.exit(1) - -bm.Disconnect() diff --git a/python/commands/qpid-tool b/python/commands/qpid-tool deleted file mode 100755 index 05afcc9732..0000000000 --- a/python/commands/qpid-tool +++ /dev/null @@ -1,197 +0,0 @@ -#!/usr/bin/env python - -# -# 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. -# - -import os -import getopt -import sys -import socket -from cmd import Cmd -from qpid.connection import ConnectionFailed, Timeout -from qpid.managementdata import ManagementData -from shlex import split -from qpid.disp import Display -from qpid.peer import Closed - -class Mcli (Cmd): - """ Management Command Interpreter """ - - def __init__ (self, dataObject, dispObject): - Cmd.__init__ (self) - self.dataObject = dataObject - self.dispObject = dispObject - self.dataObject.setCli (self) - self.prompt = "qpid: " - - def emptyline (self): - pass - - def setPromptMessage (self, p): - if p == None: - self.prompt = "qpid: " - else: - self.prompt = "qpid[%s]: " % p - - def do_help (self, data): - print "Management Tool for QPID" - print - print "Commands:" - print " list - Print summary of existing objects by class" - print " list <className> - Print list of objects of the specified class" - print " list <className> active - Print list of non-deleted objects of the specified class" - print " show <className> - Print contents of all objects of specified class" - print " show <className> active - Print contents of all non-deleted objects of specified class" - print " show <list-of-IDs> - Print contents of one or more objects (infer className)" - print " show <className> <list-of-IDs> - Print contents of one or more objects" - print " list is space-separated, ranges may be specified (i.e. 1004-1010)" - print " call <ID> <methodName> [<args>] - Invoke a method on an object" - print " schema - Print summary of object classes seen on the target" - print " schema <className> - Print details of an object class" - print " set time-format short - Select short timestamp format (default)" - print " set time-format long - Select long timestamp format" - print " id [<ID>] - Display translations of display object ids" - print " quit or ^D - Exit the program" - print - - def complete_set (self, text, line, begidx, endidx): - """ Command completion for the 'set' command """ - tokens = split (line) - if len (tokens) < 2: - return ["time-format "] - elif tokens[1] == "time-format": - if len (tokens) == 2: - return ["long", "short"] - elif len (tokens) == 3: - if "long".find (text) == 0: - return ["long"] - elif "short".find (text) == 0: - return ["short"] - elif "time-format".find (text) == 0: - return ["time-format "] - return [] - - def do_set (self, data): - tokens = split (data) - try: - if tokens[0] == "time-format": - self.dispObject.do_setTimeFormat (tokens[1]) - except: - pass - - def do_id (self, data): - self.dataObject.do_id(data) - - def complete_schema (self, text, line, begidx, endidx): - tokens = split (line) - if len (tokens) > 2: - return [] - return self.dataObject.classCompletions (text) - - def do_schema (self, data): - self.dataObject.do_schema (data) - - def complete_list (self, text, line, begidx, endidx): - tokens = split (line) - if len (tokens) > 2: - return [] - return self.dataObject.classCompletions (text) - - def do_list (self, data): - self.dataObject.do_list (data) - - def do_show (self, data): - self.dataObject.do_show (data) - - def do_call (self, data): - try: - self.dataObject.do_call (data) - except ValueError, e: - print "ValueError:", e - - def do_EOF (self, data): - print "quit" - try: - self.dataObject.do_exit () - except: - pass - return True - - def do_quit (self, data): - try: - self.dataObject.do_exit () - except: - pass - return True - - def postcmd (self, stop, line): - return stop - - def postloop (self): - print "Exiting..." - self.dataObject.close () - -def Usage (): - print "Usage: qpid-tool [[<username>/<password>@]<target-host>[:<tcp-port>]]" - print - sys.exit (1) - -#========================================================= -# Main Program -#========================================================= - -# Get host name and port if specified on the command line -cargs = sys.argv[1:] -_host = "localhost" - -if len (cargs) > 0: - _host = cargs[0] - -if _host[0] == '-': - Usage() - -disp = Display () - -# Attempt to make a connection to the target broker -try: - data = ManagementData (disp, _host) -except socket.error, e: - print "Socket Error (%s):" % _host, e[1] - sys.exit (1) -except IOError, e: - print "IOError: %d - %s: %s" % (e.errno, e.strerror, e.filename) - sys.exit (1) -except ConnectionFailed, e: - print "Connect Failed %d - %s" % (e[0], e[1]) - sys.exit(1) -except Exception, e: - if str(e).find ("Exchange not found") != -1: - print "Management not enabled on broker: Use '-m yes' option on broker startup." - else: - print "Failed: %s - %s" % (e.__class__.__name__, e) - sys.exit(1) - -# Instantiate the CLI interpreter and launch it. -cli = Mcli (data, disp) -print ("Management Tool for QPID") -try: - cli.cmdloop () -except Closed, e: - print "Connection to Broker Lost:", e - sys.exit (1) diff --git a/python/qmf/__init__.py b/python/qmf/__init__.py deleted file mode 100644 index 31d5a2ef58..0000000000 --- a/python/qmf/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# 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. -# diff --git a/python/qmf/console.py b/python/qmf/console.py deleted file mode 100644 index 45004716a8..0000000000 --- a/python/qmf/console.py +++ /dev/null @@ -1,1972 +0,0 @@ -# -# 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. -# - -""" Console API for Qpid Management Framework """ - -import os -import platform -import qpid -import struct -import socket -import re -from qpid.datatypes import UUID -from qpid.datatypes import timestamp -from qpid.datatypes import datetime -from qpid.exceptions import Closed -from qpid.session import SessionDetached -from qpid.connection import Connection, ConnectionFailed, Timeout -from qpid.datatypes import Message, RangedSet, UUID -from qpid.util import connect, ssl, URL -from qpid.codec010 import StringCodec as Codec -from threading import Lock, Condition, Thread -from time import time, strftime, gmtime -from cStringIO import StringIO - -#import qpid.log -#qpid.log.enable(name="qpid.io.cmd", level=qpid.log.DEBUG) - -class Console: - """ To access the asynchronous operations, a class must be derived from - Console with overrides of any combination of the available methods. """ - - def brokerConnected(self, broker): - """ Invoked when a connection is established to a broker """ - pass - - def brokerDisconnected(self, broker): - """ Invoked when the connection to a broker is lost """ - pass - - def newPackage(self, name): - """ Invoked when a QMF package is discovered. """ - pass - - def newClass(self, kind, classKey): - """ Invoked when a new class is discovered. Session.getSchema can be - used to obtain details about the class.""" - pass - - def newAgent(self, agent): - """ Invoked when a QMF agent is discovered. """ - pass - - def delAgent(self, agent): - """ Invoked when a QMF agent disconects. """ - pass - - def objectProps(self, broker, record): - """ Invoked when an object is updated. """ - pass - - def objectStats(self, broker, record): - """ Invoked when an object is updated. """ - pass - - def event(self, broker, event): - """ Invoked when an event is raised. """ - pass - - def heartbeat(self, agent, timestamp): - """ Invoked when an agent heartbeat is received. """ - pass - - def brokerInfo(self, broker): - """ Invoked when the connection sequence reaches the point where broker information is available. """ - pass - - def methodResponse(self, broker, seq, response): - """ Invoked when a method response from an asynchronous method call is received. """ - pass - -class BrokerURL(URL): - def __init__(self, text): - URL.__init__(self, text) - if self.port is None: - if self.scheme == URL.AMQPS: - self.port = 5671 - else: - self.port = 5672 - self.authName = None - self.authPass = None - if self.user: - self.authName = str(self.user) - if self.password: - self.authPass = str(self.password) - - def name(self): - return self.host + ":" + str(self.port) - - def match(self, host, port): - return socket.getaddrinfo(self.host, self.port)[0][4] == socket.getaddrinfo(host, port)[0][4] - -class Object(object): - """ This class defines a 'proxy' object representing a real managed object on an agent. - Actions taken on this proxy are remotely affected on the real managed object. - """ - def __init__(self, session, broker, schema, codec, prop, stat, managed=True, kwargs={}): - self._session = session - self._broker = broker - self._schema = schema - self._managed = managed - if self._managed: - self._currentTime = codec.read_uint64() - self._createTime = codec.read_uint64() - self._deleteTime = codec.read_uint64() - self._objectId = ObjectId(codec) - else: - self._currentTime = None - self._createTime = None - self._deleteTime = None - self._objectId = None - self._properties = [] - self._statistics = [] - if codec: - if prop: - notPresent = self._parsePresenceMasks(codec, schema) - for property in schema.getProperties(): - if property.name in notPresent: - self._properties.append((property, None)) - else: - self._properties.append((property, self._session._decodeValue(codec, property.type, broker))) - if stat: - for statistic in schema.getStatistics(): - self._statistics.append((statistic, self._session._decodeValue(codec, statistic.type, broker))) - else: - for property in schema.getProperties(): - if property.optional: - self._properties.append((property, None)) - else: - self._properties.append((property, self._session._defaultValue(property, broker, kwargs))) - for statistic in schema.getStatistics(): - self._statistics.append((statistic, self._session._defaultValue(statistic, broker, kwargs))) - - def getBroker(self): - """ Return the broker from which this object was sent """ - return self._broker - - def getObjectId(self): - """ Return the object identifier for this object """ - return self._objectId - - def getClassKey(self): - """ Return the class-key that references the schema describing this object. """ - return self._schema.getKey() - - def getSchema(self): - """ Return the schema that describes this object. """ - return self._schema - - def getMethods(self): - """ Return a list of methods available for this object. """ - return self._schema.getMethods() - - def getTimestamps(self): - """ Return the current, creation, and deletion times for this object. """ - return self._currentTime, self._createTime, self._deleteTime - - def isDeleted(self): - """ Return True iff this object has been deleted. """ - return self._deleteTime != 0 - - def isManaged(self): - """ Return True iff this object is a proxy for a managed object on an agent. """ - return self._managed - - def getIndex(self): - """ Return a string describing this object's primary key. """ - result = u"" - for property, value in self._properties: - if property.index: - if result != u"": - result += u":" - try: - valstr = unicode(self._session._displayValue(value, property.type)) - except: - valstr = u"<undecodable>" - result += valstr - return result - - def getProperties(self): - """ Return a list of object properties """ - return self._properties - - def getStatistics(self): - """ Return a list of object statistics """ - return self._statistics - - def mergeUpdate(self, newer): - """ Replace properties and/or statistics with a newly received update """ - if not self.isManaged(): - raise Exception("Object is not managed") - if self._objectId != newer._objectId: - raise Exception("Objects with different object-ids") - if len(newer.getProperties()) > 0: - self._properties = newer.getProperties() - if len(newer.getStatistics()) > 0: - self._statistics = newer.getStatistics() - - def update(self): - """ Contact the agent and retrieve the lastest property and statistic values for this object. """ - if not self.isManaged(): - raise Exception("Object is not managed") - obj = self._session.getObjects(_objectId = self._objectId, _broker=self._broker) - if obj: - self.mergeUpdate(obj[0]) - else: - raise Exception("Underlying object no longer exists") - - def __repr__(self): - if self.isManaged(): - id = self.getObjectId().__repr__() - else: - id = "unmanaged" - key = self.getClassKey() - return key.getPackageName() + ":" + key.getClassName() +\ - "[" + id + "] " + self.getIndex().encode("utf8") - - def __getattr__(self, name): - for method in self._schema.getMethods(): - if name == method.name: - return lambda *args, **kwargs : self._invoke(name, args, kwargs) - for property, value in self._properties: - if name == property.name: - return value - if name == "_" + property.name + "_" and property.type == 10: # Dereference references - deref = self._session.getObjects(_objectId=value, _broker=self._broker) - if len(deref) != 1: - return None - else: - return deref[0] - for statistic, value in self._statistics: - if name == statistic.name: - return value - raise Exception("Type Object has no attribute '%s'" % name) - - def __setattr__(self, name, value): - if name[0] == '_': - super.__setattr__(self, name, value) - return - - for prop, unusedValue in self._properties: - if name == prop.name: - newprop = (prop, value) - newlist = [] - for old, val in self._properties: - if name == old.name: - newlist.append(newprop) - else: - newlist.append((old, val)) - self._properties = newlist - return - super.__setattr__(self, name, value) - - def _sendMethodRequest(self, name, args, kwargs, synchronous=False, timeWait=None): - for method in self._schema.getMethods(): - if name == method.name: - aIdx = 0 - sendCodec = Codec() - seq = self._session.seqMgr._reserve((method, synchronous)) - self._broker._setHeader(sendCodec, 'M', seq) - self._objectId.encode(sendCodec) - self._schema.getKey().encode(sendCodec) - sendCodec.write_str8(name) - - count = 0 - for arg in method.arguments: - if arg.dir.find("I") != -1: - count += 1 - if count != len(args): - raise Exception("Incorrect number of arguments: expected %d, got %d" % (count, len(args))) - - for arg in method.arguments: - if arg.dir.find("I") != -1: - self._session._encodeValue(sendCodec, args[aIdx], arg.type) - aIdx += 1 - if timeWait: - ttl = timeWait * 1000 - else: - ttl = None - smsg = self._broker._message(sendCodec.encoded, "agent.%d.%d" % - (self._objectId.getBrokerBank(), self._objectId.getAgentBank()), - ttl=ttl) - if synchronous: - try: - self._broker.cv.acquire() - self._broker.syncInFlight = True - finally: - self._broker.cv.release() - self._broker._send(smsg) - return seq - return None - - def _invoke(self, name, args, kwargs): - if not self.isManaged(): - raise Exception("Object is not managed") - if "_timeout" in kwargs: - timeout = kwargs["_timeout"] - else: - timeout = self._broker.SYNC_TIME - - if "_async" in kwargs and kwargs["_async"]: - sync = False - if "_timeout" not in kwargs: - timeout = None - else: - sync = True - - seq = self._sendMethodRequest(name, args, kwargs, sync, timeout) - if seq: - if not sync: - return seq - try: - self._broker.cv.acquire() - starttime = time() - while self._broker.syncInFlight and self._broker.error == None: - self._broker.cv.wait(timeout) - if time() - starttime > timeout: - self._session.seqMgr._release(seq) - raise RuntimeError("Timed out waiting for method to respond") - finally: - self._broker.cv.release() - if self._broker.error != None: - errorText = self._broker.error - self._broker.error = None - raise Exception(errorText) - return self._broker.syncResult - raise Exception("Invalid Method (software defect) [%s]" % name) - - def _encodeUnmanaged(self, codec): - - codec.write_uint8(20) - codec.write_str8(self._schema.getKey().getPackageName()) - codec.write_str8(self._schema.getKey().getClassName()) - codec.write_bin128(self._schema.getKey().getHash()) - - # emit presence masks for optional properties - mask = 0 - bit = 0 - for prop, value in self._properties: - if prop.optional: - if bit == 0: - bit = 1 - if value: - mask |= bit - bit = bit << 1 - if bit == 256: - bit = 0 - codec.write_uint8(mask) - mask = 0 - if bit != 0: - codec.write_uint8(mask) - - # encode properties - for prop, value in self._properties: - if value != None: - self._session._encodeValue(codec, value, prop.type) - - # encode statistics - for stat, value in self._statistics: - self._session._encodeValue(codec, value, stat.type) - - def _parsePresenceMasks(self, codec, schema): - excludeList = [] - bit = 0 - for property in schema.getProperties(): - if property.optional: - if bit == 0: - mask = codec.read_uint8() - bit = 1 - if (mask & bit) == 0: - excludeList.append(property.name) - bit *= 2 - if bit == 256: - bit = 0 - return excludeList - -class Session: - """ - An instance of the Session class represents a console session running - against one or more QMF brokers. A single instance of Session is needed - to interact with the management framework as a console. - """ - _CONTEXT_SYNC = 1 - _CONTEXT_STARTUP = 2 - _CONTEXT_MULTIGET = 3 - - DEFAULT_GET_WAIT_TIME = 60 - - ENCODINGS = { - str: 7, - timestamp: 8, - datetime: 8, - int: 9, - long: 9, - float: 13, - UUID: 14, - Object: 20, - list: 21 - } - - def __init__(self, console=None, rcvObjects=True, rcvEvents=True, rcvHeartbeats=True, - manageConnections=False, userBindings=False): - """ - Initialize a session. If the console argument is provided, the - more advanced asynchronous features are available. If console is - defaulted, the session will operate in a simpler, synchronous manner. - - The rcvObjects, rcvEvents, and rcvHeartbeats arguments are meaningful only if 'console' - is provided. They control whether object updates, events, and agent-heartbeats are - subscribed to. If the console is not interested in receiving one or more of the above, - setting the argument to False will reduce tha bandwidth used by the API. - - If manageConnections is set to True, the Session object will manage connections to - the brokers. This means that if a broker is unreachable, it will retry until a connection - can be established. If a connection is lost, the Session will attempt to reconnect. - - If manageConnections is set to False, the user is responsible for handing failures. In - this case, an unreachable broker will cause addBroker to raise an exception. - - If userBindings is set to False (the default) and rcvObjects is True, the console will - receive data for all object classes. If userBindings is set to True, the user must select - which classes the console shall receive by invoking the bindPackage or bindClass methods. - This allows the console to be configured to receive only information that is relavant to - a particular application. If rcvObjects id False, userBindings has no meaning. - """ - self.console = console - self.brokers = [] - self.packages = {} - self.seqMgr = SequenceManager() - self.cv = Condition() - self.syncSequenceList = [] - self.getResult = [] - self.getSelect = [] - self.error = None - self.rcvObjects = rcvObjects - self.rcvEvents = rcvEvents - self.rcvHeartbeats = rcvHeartbeats - self.userBindings = userBindings - if self.console == None: - self.rcvObjects = False - self.rcvEvents = False - self.rcvHeartbeats = False - self.bindingKeyList = self._bindingKeys() - self.manageConnections = manageConnections - - if self.userBindings and not self.rcvObjects: - raise Exception("userBindings can't be set unless rcvObjects is set and a console is provided") - - def __repr__(self): - return "QMF Console Session Manager (brokers: %d)" % len(self.brokers) - - def addBroker(self, target="localhost", timeout=None, mechanisms=None): - """ Connect to a Qpid broker. Returns an object of type Broker. """ - url = BrokerURL(target) - broker = Broker(self, url.host, url.port, mechanisms, url.authName, url.authPass, - ssl = url.scheme == URL.AMQPS, connTimeout=timeout) - - self.brokers.append(broker) - if not self.manageConnections: - self.getObjects(broker=broker, _class="agent") - return broker - - def delBroker(self, broker): - """ Disconnect from a broker. The 'broker' argument is the object - returned from the addBroker call """ - if self.console: - for agent in broker.getAgents(): - self.console.delAgent(agent) - broker._shutdown() - self.brokers.remove(broker) - del broker - - def getPackages(self): - """ Get the list of known QMF packages """ - for broker in self.brokers: - broker._waitForStable() - list = [] - for package in self.packages: - list.append(package) - return list - - def getClasses(self, packageName): - """ Get the list of known classes within a QMF package """ - for broker in self.brokers: - broker._waitForStable() - list = [] - if packageName in self.packages: - for pkey in self.packages[packageName]: - list.append(self.packages[packageName][pkey].getKey()) - return list - - def getSchema(self, classKey): - """ Get the schema for a QMF class """ - for broker in self.brokers: - broker._waitForStable() - pname = classKey.getPackageName() - pkey = classKey.getPackageKey() - if pname in self.packages: - if pkey in self.packages[pname]: - return self.packages[pname][pkey] - - def bindPackage(self, packageName): - """ Request object updates for all table classes within a package. """ - if not self.userBindings or not self.rcvObjects: - raise Exception("userBindings option not set for Session") - key = "console.obj.*.*.%s.#" % packageName - self.bindingKeyList.append(key) - for broker in self.brokers: - if broker.isConnected(): - broker.amqpSession.exchange_bind(exchange="qpid.management", queue=broker.topicName, - binding_key=key) - - def bindClass(self, pname, cname): - """ Request object updates for a particular table class by package and class name. """ - if not self.userBindings or not self.rcvObjects: - raise Exception("userBindings option not set for Session") - key = "console.obj.*.*.%s.%s.#" % (pname, cname) - self.bindingKeyList.append(key) - for broker in self.brokers: - if broker.isConnected(): - broker.amqpSession.exchange_bind(exchange="qpid.management", queue=broker.topicName, - binding_key=key) - - def bindClassKey(self, classKey): - """ Request object updates for a particular table class by class key. """ - pname = classKey.getPackageName() - cname = classKey.getClassName() - self.bindClass(pname, cname) - - def getAgents(self, broker=None): - """ Get a list of currently known agents """ - brokerList = [] - if broker == None: - for b in self.brokers: - brokerList.append(b) - else: - brokerList.append(broker) - - for b in brokerList: - b._waitForStable() - agentList = [] - for b in brokerList: - for a in b.getAgents(): - agentList.append(a) - return agentList - - def makeObject(self, classKey, broker=None, **kwargs): - """ Create a new, unmanaged object of the schema indicated by classKey """ - schema = self.getSchema(classKey) - if schema == None: - raise Exception("Schema not found for classKey") - return Object(self, broker, schema, None, True, True, False, kwargs) - - def getObjects(self, **kwargs): - """ Get a list of objects from QMF agents. - All arguments are passed by name(keyword). - - The class for queried objects may be specified in one of the following ways: - - _schema = <schema> - supply a schema object returned from getSchema. - _key = <key> - supply a classKey from the list returned by getClasses. - _class = <name> - supply a class name as a string. If the class name exists - in multiple packages, a _package argument may also be supplied. - _objectId = <id> - get the object referenced by the object-id - - If objects should be obtained from only one agent, use the following argument. - Otherwise, the query will go to all agents. - - _agent = <agent> - supply an agent from the list returned by getAgents. - - If the get query is to be restricted to one broker (as opposed to all connected brokers), - add the following argument: - - _broker = <broker> - supply a broker as returned by addBroker. - - The default timeout for this synchronous operation is 60 seconds. To change the timeout, - use the following argument: - - _timeout = <time in seconds> - - If additional arguments are supplied, they are used as property selectors. For example, - if the argument name="test" is supplied, only objects whose "name" property is "test" - will be returned in the result. - """ - if "_broker" in kwargs: - brokerList = [] - brokerList.append(kwargs["_broker"]) - else: - brokerList = self.brokers - for broker in brokerList: - broker._waitForStable() - if broker.isConnected(): - if "_package" not in kwargs or "_class" not in kwargs or \ - kwargs["_package"] != "org.apache.qpid.broker" or \ - kwargs["_class"] != "agent": - self.getObjects(_package = "org.apache.qpid.broker", _class = "agent", - _agent = broker.getAgent(1,0)) - - agentList = [] - if "_agent" in kwargs: - agent = kwargs["_agent"] - if agent.broker not in brokerList: - raise Exception("Supplied agent is not accessible through the supplied broker") - if agent.broker.isConnected(): - agentList.append(agent) - else: - if "_objectId" in kwargs: - oid = kwargs["_objectId"] - for broker in brokerList: - for agent in broker.getAgents(): - if agent.getBrokerBank() == oid.getBrokerBank() and agent.getAgentBank() == oid.getAgentBank(): - agentList.append(agent) - else: - for broker in brokerList: - for agent in broker.getAgents(): - if agent.broker.isConnected(): - agentList.append(agent) - - if len(agentList) == 0: - return [] - - pname = None - cname = None - hash = None - classKey = None - if "_schema" in kwargs: classKey = kwargs["_schema"].getKey() - elif "_key" in kwargs: classKey = kwargs["_key"] - elif "_class" in kwargs: - cname = kwargs["_class"] - if "_package" in kwargs: - pname = kwargs["_package"] - if cname == None and classKey == None and "_objectId" not in kwargs: - raise Exception("No class supplied, use '_schema', '_key', '_class', or '_objectId' argument") - - map = {} - self.getSelect = [] - if "_objectId" in kwargs: - map["_objectid"] = kwargs["_objectId"].__repr__() - else: - if cname == None: - cname = classKey.getClassName() - pname = classKey.getPackageName() - hash = classKey.getHash() - map["_class"] = cname - if pname != None: map["_package"] = pname - if hash != None: map["_hash"] = hash - for item in kwargs: - if item[0] != '_': - self.getSelect.append((item, kwargs[item])) - - self.getResult = [] - for agent in agentList: - broker = agent.broker - sendCodec = Codec() - try: - self.cv.acquire() - seq = self.seqMgr._reserve(self._CONTEXT_MULTIGET) - self.syncSequenceList.append(seq) - finally: - self.cv.release() - broker._setHeader(sendCodec, 'G', seq) - sendCodec.write_map(map) - smsg = broker._message(sendCodec.encoded, "agent.%d.%d" % (agent.brokerBank, agent.agentBank)) - broker._send(smsg) - - starttime = time() - timeout = False - if "_timeout" in kwargs: - waitTime = kwargs["_timeout"] - else: - waitTime = self.DEFAULT_GET_WAIT_TIME - try: - self.cv.acquire() - while len(self.syncSequenceList) > 0 and self.error == None: - self.cv.wait(waitTime) - if time() - starttime > waitTime: - for pendingSeq in self.syncSequenceList: - self.seqMgr._release(pendingSeq) - self.syncSequenceList = [] - timeout = True - finally: - self.cv.release() - - if self.error: - errorText = self.error - self.error = None - raise Exception(errorText) - - if len(self.getResult) == 0 and timeout: - raise RuntimeError("No agent responded within timeout period") - return self.getResult - - def setEventFilter(self, **kwargs): - """ """ - pass - - def _bindingKeys(self): - keyList = [] - keyList.append("schema.#") - if self.rcvObjects and self.rcvEvents and self.rcvHeartbeats and not self.userBindings: - keyList.append("console.#") - else: - if self.rcvObjects and not self.userBindings: - keyList.append("console.obj.#") - else: - keyList.append("console.obj.*.*.org.apache.qpid.broker.agent") - if self.rcvEvents: - keyList.append("console.event.#") - if self.rcvHeartbeats: - keyList.append("console.heartbeat.#") - return keyList - - def _handleBrokerConnect(self, broker): - if self.console: - for agent in broker.getAgents(): - self.console.newAgent(agent) - self.console.brokerConnected(broker) - - def _handleBrokerDisconnect(self, broker): - if self.console: - for agent in broker.getAgents(): - self.console.delAgent(agent) - self.console.brokerDisconnected(broker) - - def _handleBrokerResp(self, broker, codec, seq): - broker.brokerId = codec.read_uuid() - if self.console != None: - self.console.brokerInfo(broker) - - # Send a package request - # (effectively inc and dec outstanding by not doing anything) - sendCodec = Codec() - seq = self.seqMgr._reserve(self._CONTEXT_STARTUP) - broker._setHeader(sendCodec, 'P', seq) - smsg = broker._message(sendCodec.encoded) - broker._send(smsg) - - def _handlePackageInd(self, broker, codec, seq): - pname = str(codec.read_str8()) - notify = False - try: - self.cv.acquire() - if pname not in self.packages: - self.packages[pname] = {} - notify = True - finally: - self.cv.release() - if notify and self.console != None: - self.console.newPackage(pname) - - # Send a class request - broker._incOutstanding() - sendCodec = Codec() - seq = self.seqMgr._reserve(self._CONTEXT_STARTUP) - broker._setHeader(sendCodec, 'Q', seq) - sendCodec.write_str8(pname) - smsg = broker._message(sendCodec.encoded) - broker._send(smsg) - - def _handleCommandComplete(self, broker, codec, seq): - code = codec.read_uint32() - text = codec.read_str8() - context = self.seqMgr._release(seq) - if context == self._CONTEXT_STARTUP: - broker._decOutstanding() - elif context == self._CONTEXT_SYNC and seq == broker.syncSequence: - try: - broker.cv.acquire() - broker.syncInFlight = False - broker.cv.notify() - finally: - broker.cv.release() - elif context == self._CONTEXT_MULTIGET and seq in self.syncSequenceList: - try: - self.cv.acquire() - self.syncSequenceList.remove(seq) - if len(self.syncSequenceList) == 0: - self.cv.notify() - finally: - self.cv.release() - - def _handleClassInd(self, broker, codec, seq): - kind = codec.read_uint8() - classKey = ClassKey(codec) - unknown = False - - try: - self.cv.acquire() - if classKey.getPackageName() in self.packages: - if classKey.getPackageKey() not in self.packages[classKey.getPackageName()]: - unknown = True - finally: - self.cv.release() - - if unknown: - # Send a schema request for the unknown class - broker._incOutstanding() - sendCodec = Codec() - seq = self.seqMgr._reserve(self._CONTEXT_STARTUP) - broker._setHeader(sendCodec, 'S', seq) - classKey.encode(sendCodec) - smsg = broker._message(sendCodec.encoded) - broker._send(smsg) - - def _handleMethodResp(self, broker, codec, seq): - code = codec.read_uint32() - text = codec.read_str16() - outArgs = {} - pair = self.seqMgr._release(seq) - if pair == None: - return - method, synchronous = pair - if code == 0: - for arg in method.arguments: - if arg.dir.find("O") != -1: - outArgs[arg.name] = self._decodeValue(codec, arg.type, broker) - result = MethodResult(code, text, outArgs) - if synchronous: - try: - broker.cv.acquire() - broker.syncResult = result - broker.syncInFlight = False - broker.cv.notify() - finally: - broker.cv.release() - else: - if self.console: - self.console.methodResponse(broker, seq, result) - - def _handleHeartbeatInd(self, broker, codec, seq, msg): - brokerBank = 1 - agentBank = 0 - dp = msg.get("delivery_properties") - if dp: - key = dp["routing_key"] - keyElements = key.split(".") - if len(keyElements) == 4: - brokerBank = int(keyElements[2]) - agentBank = int(keyElements[3]) - - agent = broker.getAgent(brokerBank, agentBank) - timestamp = codec.read_uint64() - if self.console != None and agent != None: - self.console.heartbeat(agent, timestamp) - - def _handleEventInd(self, broker, codec, seq): - if self.console != None: - event = Event(self, broker, codec) - self.console.event(broker, event) - - def _handleSchemaResp(self, broker, codec, seq): - kind = codec.read_uint8() - classKey = ClassKey(codec) - _class = SchemaClass(kind, classKey, codec, self) - try: - self.cv.acquire() - self.packages[classKey.getPackageName()][classKey.getPackageKey()] = _class - finally: - self.cv.release() - - self.seqMgr._release(seq) - broker._decOutstanding() - if self.console != None: - self.console.newClass(kind, classKey) - - def _handleContentInd(self, broker, codec, seq, prop=False, stat=False): - classKey = ClassKey(codec) - try: - self.cv.acquire() - pname = classKey.getPackageName() - if pname not in self.packages: - return - pkey = classKey.getPackageKey() - if pkey not in self.packages[pname]: - return - schema = self.packages[pname][pkey] - finally: - self.cv.release() - - object = Object(self, broker, schema, codec, prop, stat) - if pname == "org.apache.qpid.broker" and classKey.getClassName() == "agent" and prop: - broker._updateAgent(object) - - try: - self.cv.acquire() - if seq in self.syncSequenceList: - if object.getTimestamps()[2] == 0 and self._selectMatch(object): - self.getResult.append(object) - return - finally: - self.cv.release() - - if self.console and self.rcvObjects: - if prop: - self.console.objectProps(broker, object) - if stat: - self.console.objectStats(broker, object) - - def _handleError(self, error): - try: - self.cv.acquire() - if len(self.syncSequenceList) > 0: - self.error = error - self.syncSequenceList = [] - self.cv.notify() - finally: - self.cv.release() - - def _selectMatch(self, object): - """ Check the object against self.getSelect to check for a match """ - for key, value in self.getSelect: - for prop, propval in object.getProperties(): - if key == prop.name and value != propval: - return False - return True - - def _decodeValue(self, codec, typecode, broker=None): - """ Decode, from the codec, a value based on its typecode. """ - if typecode == 1: data = codec.read_uint8() # U8 - elif typecode == 2: data = codec.read_uint16() # U16 - elif typecode == 3: data = codec.read_uint32() # U32 - elif typecode == 4: data = codec.read_uint64() # U64 - elif typecode == 6: data = codec.read_str8() # SSTR - elif typecode == 7: data = codec.read_str16() # LSTR - elif typecode == 8: data = codec.read_int64() # ABSTIME - elif typecode == 9: data = codec.read_uint64() # DELTATIME - elif typecode == 10: data = ObjectId(codec) # REF - elif typecode == 11: data = codec.read_uint8() != 0 # BOOL - elif typecode == 12: data = codec.read_float() # FLOAT - elif typecode == 13: data = codec.read_double() # DOUBLE - elif typecode == 14: data = codec.read_uuid() # UUID - elif typecode == 16: data = codec.read_int8() # S8 - elif typecode == 17: data = codec.read_int16() # S16 - elif typecode == 18: data = codec.read_int32() # S32 - elif typecode == 19: data = codec.read_int64() # S63 - elif typecode == 15: data = codec.read_map() # FTABLE - elif typecode == 20: # OBJECT - # Peek at the type, and if it is still 20 pull it decode. If - # Not, call back into self. - inner_type_code = codec.read_uint8() - if inner_type_code == 20: - classKey = ClassKey(codec) - try: - self.cv.acquire() - pname = classKey.getPackageName() - if pname not in self.packages: - return None - pkey = classKey.getPackageKey() - if pkey not in self.packages[pname]: - return None - schema = self.packages[pname][pkey] - finally: - self.cv.release() - data = Object(self, broker, schema, codec, True, True, False) - else: - data = self._decodeValue(codec, inner_type_code, broker) - elif typecode == 21: # List - #taken from codec10.read_list - sc = Codec(codec.read_vbin32()) - count = sc.read_uint32() - data = [] - while count > 0: - type = sc.read_uint8() - data.append(self._decodeValue(sc,type,broker)) - count -= 1 - elif typecode == 22: #Array - #taken from codec10.read_array - sc = Codec(codec.read_vbin32()) - count = sc.read_uint32() - type = sc.read_uint8() - data = [] - while count > 0: - data.append(self._decodeValue(sc,type,broker)) - count -= 1 - else: - raise ValueError("Invalid type code: %d" % typecode) - return data - - def _encodeValue(self, codec, value, typecode): - """ Encode, into the codec, a value based on its typecode. """ - if typecode == 1: codec.write_uint8 (int(value)) # U8 - elif typecode == 2: codec.write_uint16 (int(value)) # U16 - elif typecode == 3: codec.write_uint32 (long(value)) # U32 - elif typecode == 4: codec.write_uint64 (long(value)) # U64 - elif typecode == 6: codec.write_str8 (value) # SSTR - elif typecode == 7: codec.write_str16 (value) # LSTR - elif typecode == 8: codec.write_int64 (long(value)) # ABSTIME - elif typecode == 9: codec.write_uint64 (long(value)) # DELTATIME - elif typecode == 10: value.encode (codec) # REF - elif typecode == 11: codec.write_uint8 (int(value)) # BOOL - elif typecode == 12: codec.write_float (float(value)) # FLOAT - elif typecode == 13: codec.write_double (float(value)) # DOUBLE - elif typecode == 14: codec.write_uuid (value.bytes) # UUID - elif typecode == 16: codec.write_int8 (int(value)) # S8 - elif typecode == 17: codec.write_int16 (int(value)) # S16 - elif typecode == 18: codec.write_int32 (int(value)) # S32 - elif typecode == 19: codec.write_int64 (int(value)) # S64 - elif typecode == 20: value._encodeUnmanaged(codec) # OBJECT - elif typecode == 15: codec.write_map (value) # FTABLE - elif typecode == 21: # List - sc = Codec() - self._encodeValue(sc, len(value), 3) - for o in value: - ltype=self.encoding(o) - self._encodeValue(sc,ltype,1) - self._encodeValue(sc, o, ltype) - codec.write_vbin32(sc.encoded) - elif typecode == 22: # Array - sc = Codec() - self._encodeValue(sc, len(value), 3) - if len(value) > 0: - ltype = self.encoding(value[0]) - self._encodeValue(sc,ltype,1) - for o in value: - self._encodeValue(sc, o, ltype) - codec.write_vbin32(sc.encoded) - else: - raise ValueError ("Invalid type code: %d" % typecode) - - def encoding(self, value): - return self._encoding(value.__class__) - - def _encoding(self, klass): - if Session.ENCODINGS.has_key(klass): - return self.ENCODINGS[klass] - for base in klass.__bases__: - result = self._encoding(base, obj) - if result != None: - return result - - def _displayValue(self, value, typecode): - """ """ - if typecode == 1: return unicode(value) - elif typecode == 2: return unicode(value) - elif typecode == 3: return unicode(value) - elif typecode == 4: return unicode(value) - elif typecode == 6: return value - elif typecode == 7: return value - elif typecode == 8: return unicode(strftime("%c", gmtime(value / 1000000000))) - elif typecode == 9: return unicode(value) - elif typecode == 10: return unicode(value.__repr__()) - elif typecode == 11: - if value: return u"T" - else: return u"F" - elif typecode == 12: return unicode(value) - elif typecode == 13: return unicode(value) - elif typecode == 14: return unicode(value.__repr__()) - elif typecode == 15: return unicode(value.__repr__()) - elif typecode == 16: return unicode(value) - elif typecode == 17: return unicode(value) - elif typecode == 18: return unicode(value) - elif typecode == 19: return unicode(value) - elif typecode == 20: return unicode(value.__repr__()) - elif typecode == 21: return unicode(value.__repr__()) - elif typecode == 22: return unicode(value.__repr__()) - else: - raise ValueError ("Invalid type code: %d" % typecode) - - def _defaultValue(self, stype, broker=None, kwargs={}): - """ """ - typecode = stype.type - if typecode == 1: return 0 - elif typecode == 2: return 0 - elif typecode == 3: return 0 - elif typecode == 4: return 0 - elif typecode == 6: return "" - elif typecode == 7: return "" - elif typecode == 8: return 0 - elif typecode == 9: return 0 - elif typecode == 10: return ObjectId(None) - elif typecode == 11: return False - elif typecode == 12: return 0.0 - elif typecode == 13: return 0.0 - elif typecode == 14: return UUID([0 for i in range(16)]) - elif typecode == 15: return {} - elif typecode == 16: return 0 - elif typecode == 17: return 0 - elif typecode == 18: return 0 - elif typecode == 19: return 0 - elif typecode == 21: return [] - elif typecode == 22: return [] - elif typecode == 20: - try: - if "classKeys" in kwargs: - keyList = kwargs["classKeys"] - else: - keyList = None - classKey = self._bestClassKey(stype.refPackage, stype.refClass, keyList) - if classKey: - return self.makeObject(classKey, broker, kwargs) - except: - pass - return None - else: - raise ValueError ("Invalid type code: %d" % typecode) - - def _bestClassKey(self, pname, cname, preferredList): - """ """ - if pname == None or cname == None: - if len(preferredList) == 0: - return None - return preferredList[0] - for p in preferredList: - if p.getPackageName() == pname and p.getClassName() == cname: - return p - clist = self.getClasses(pname) - for c in clist: - if c.getClassName() == cname: - return c - return None - - def _sendMethodRequest(self, broker, schemaKey, objectId, name, argList): - """ This function can be used to send a method request to an object given only the - broker, schemaKey, and objectId. This is an uncommon usage pattern as methods are - normally invoked on the object itself. - """ - schema = self.getSchema(schemaKey) - for method in schema.getMethods(): - if name == method.name: - aIdx = 0 - sendCodec = Codec() - seq = self.seqMgr._reserve((method, False)) - broker._setHeader(sendCodec, 'M', seq) - objectId.encode(sendCodec) - schemaKey.encode(sendCodec) - sendCodec.write_str8(name) - - count = 0 - for arg in method.arguments: - if arg.dir.find("I") != -1: - count += 1 - if count != len(argList): - raise Exception("Incorrect number of arguments: expected %d, got %d" % (count, len(argList))) - - for arg in method.arguments: - if arg.dir.find("I") != -1: - self._encodeValue(sendCodec, argList[aIdx], arg.type) - aIdx += 1 - smsg = broker._message(sendCodec.encoded, "agent.%d.%d" % - (objectId.getBrokerBank(), objectId.getAgentBank())) - broker._send(smsg) - return seq - return None - -class Package: - """ """ - def __init__(self, name): - self.name = name - -class ClassKey: - """ A ClassKey uniquely identifies a class from the schema. """ - def __init__(self, constructor): - if type(constructor) == str: - # construct from __repr__ string - try: - self.pname, cls = constructor.split(":") - self.cname, hsh = cls.split("(") - hsh = hsh.strip(")") - hexValues = hsh.split("-") - h0 = int(hexValues[0], 16) - h1 = int(hexValues[1], 16) - h2 = int(hexValues[2], 16) - h3 = int(hexValues[3], 16) - self.hash = struct.pack("!LLLL", h0, h1, h2, h3) - except: - raise Exception("Invalid ClassKey format") - else: - # construct from codec - codec = constructor - self.pname = str(codec.read_str8()) - self.cname = str(codec.read_str8()) - self.hash = codec.read_bin128() - - def encode(self, codec): - codec.write_str8(self.pname) - codec.write_str8(self.cname) - codec.write_bin128(self.hash) - - def getPackageName(self): - return self.pname - - def getClassName(self): - return self.cname - - def getHash(self): - return self.hash - - def getHashString(self): - return "%08x-%08x-%08x-%08x" % struct.unpack ("!LLLL", self.hash) - - def getPackageKey(self): - return (self.cname, self.hash) - - def __repr__(self): - return self.pname + ":" + self.cname + "(" + self.getHashString() + ")" - -class SchemaClass: - """ """ - CLASS_KIND_TABLE = 1 - CLASS_KIND_EVENT = 2 - - def __init__(self, kind, key, codec, session): - self.kind = kind - self.classKey = key - self.properties = [] - self.statistics = [] - self.methods = [] - self.arguments = [] - self.session = session - - hasSupertype = 0 #codec.read_uint8() - if self.kind == self.CLASS_KIND_TABLE: - propCount = codec.read_uint16() - statCount = codec.read_uint16() - methodCount = codec.read_uint16() - if hasSupertype == 1: - self.superTypeKey = ClassKey(codec) - else: - self.superTypeKey = None ; - for idx in range(propCount): - self.properties.append(SchemaProperty(codec)) - for idx in range(statCount): - self.statistics.append(SchemaStatistic(codec)) - for idx in range(methodCount): - self.methods.append(SchemaMethod(codec)) - - elif self.kind == self.CLASS_KIND_EVENT: - argCount = codec.read_uint16() - if (hasSupertype): - self.superTypeKey = ClassKey(codec) - else: - self.superTypeKey = None ; - for idx in range(argCount): - self.arguments.append(SchemaArgument(codec, methodArg=False)) - - def __repr__(self): - if self.kind == self.CLASS_KIND_TABLE: - kindStr = "Table" - elif self.kind == self.CLASS_KIND_EVENT: - kindStr = "Event" - else: - kindStr = "Unsupported" - result = "%s Class: %s " % (kindStr, self.classKey.__repr__()) - return result - - def getKey(self): - """ Return the class-key for this class. """ - return self.classKey - - def getProperties(self): - """ Return the list of properties for the class. """ - if (self.superTypeKey == None): - return self.properties - else: - return self.properties + self.session.getSchema(self.superTypeKey).getProperties() - - def getStatistics(self): - """ Return the list of statistics for the class. """ - if (self.superTypeKey == None): - return self.statistics - else: - return self.statistics + self.session.getSchema(self.superTypeKey).getStatistics() - - def getMethods(self): - """ Return the list of methods for the class. """ - if (self.superTypeKey == None): - return self.methods - else: - return self.methods + self.session.getSchema(self.superTypeKey).getMethods() - - def getArguments(self): - """ Return the list of events for the class. """ - """ Return the list of methods for the class. """ - if (self.superTypeKey == None): - return self.arguments - else: - return self.arguments + self.session.getSchema(self.superTypeKey).getArguments() - -class SchemaProperty: - """ """ - def __init__(self, codec): - map = codec.read_map() - self.name = str(map["name"]) - self.type = map["type"] - self.access = str(map["access"]) - self.index = map["index"] != 0 - self.optional = map["optional"] != 0 - self.refPackage = None - self.refClass = None - self.unit = None - self.min = None - self.max = None - self.maxlen = None - self.desc = None - - for key, value in map.items(): - if key == "unit" : self.unit = value - elif key == "min" : self.min = value - elif key == "max" : self.max = value - elif key == "maxlen" : self.maxlen = value - elif key == "desc" : self.desc = value - elif key == "refPackage" : self.refPackage = value - elif key == "refClass" : self.refClass = value - - def __repr__(self): - return self.name - -class SchemaStatistic: - """ """ - def __init__(self, codec): - map = codec.read_map() - self.name = str(map["name"]) - self.type = map["type"] - self.unit = None - self.desc = None - - for key, value in map.items(): - if key == "unit" : self.unit = value - elif key == "desc" : self.desc = value - - def __repr__(self): - return self.name - -class SchemaMethod: - """ """ - def __init__(self, codec): - map = codec.read_map() - self.name = str(map["name"]) - argCount = map["argCount"] - if "desc" in map: - self.desc = map["desc"] - else: - self.desc = None - self.arguments = [] - - for idx in range(argCount): - self.arguments.append(SchemaArgument(codec, methodArg=True)) - - def __repr__(self): - result = self.name + "(" - first = True - for arg in self.arguments: - if arg.dir.find("I") != -1: - if first: - first = False - else: - result += ", " - result += arg.name - result += ")" - return result - -class SchemaArgument: - """ """ - def __init__(self, codec, methodArg): - map = codec.read_map() - self.name = str(map["name"]) - self.type = map["type"] - if methodArg: - self.dir = str(map["dir"]).upper() - self.unit = None - self.min = None - self.max = None - self.maxlen = None - self.desc = None - self.default = None - self.refPackage = None - self.refClass = None - - for key, value in map.items(): - if key == "unit" : self.unit = value - elif key == "min" : self.min = value - elif key == "max" : self.max = value - elif key == "maxlen" : self.maxlen = value - elif key == "desc" : self.desc = value - elif key == "default" : self.default = value - elif key == "refPackage" : self.refPackage = value - elif key == "refClass" : self.refClass = value - -class ObjectId: - """ Object that represents QMF object identifiers """ - def __init__(self, codec, first=0, second=0): - if codec: - self.first = codec.read_uint64() - self.second = codec.read_uint64() - else: - self.first = first - self.second = second - - def __cmp__(self, other): - if other == None or not isinstance(other, ObjectId) : - return 1 - if self.first < other.first: - return -1 - if self.first > other.first: - return 1 - if self.second < other.second: - return -1 - if self.second > other.second: - return 1 - return 0 - - def __repr__(self): - return "%d-%d-%d-%d-%d" % (self.getFlags(), self.getSequence(), - self.getBrokerBank(), self.getAgentBank(), self.getObject()) - - def index(self): - return (self.first, self.second) - - def getFlags(self): - return (self.first & 0xF000000000000000) >> 60 - - def getSequence(self): - return (self.first & 0x0FFF000000000000) >> 48 - - def getBrokerBank(self): - return (self.first & 0x0000FFFFF0000000) >> 28 - - def getAgentBank(self): - return self.first & 0x000000000FFFFFFF - - def getObject(self): - return self.second - - def isDurable(self): - return self.getSequence() == 0 - - def encode(self, codec): - codec.write_uint64(self.first) - codec.write_uint64(self.second) - - def __hash__(self): - return (self.first, self.second).__hash__() - - def __eq__(self, other): - return (self.first, self.second).__eq__(other) - -class MethodResult(object): - """ """ - def __init__(self, status, text, outArgs): - """ """ - self.status = status - self.text = text - self.outArgs = outArgs - - def __getattr__(self, name): - if name in self.outArgs: - return self.outArgs[name] - - def __repr__(self): - return "%s (%d) - %s" % (self.text, self.status, self.outArgs) - -class ManagedConnection(Thread): - """ Thread class for managing a connection. """ - DELAY_MIN = 1 - DELAY_MAX = 128 - DELAY_FACTOR = 2 - - def __init__(self, broker): - Thread.__init__(self) - self.broker = broker - self.cv = Condition() - self.canceled = False - - def stop(self): - """ Tell this thread to stop running and return. """ - try: - self.cv.acquire() - self.canceled = True - self.cv.notify() - finally: - self.cv.release() - - def disconnected(self): - """ Notify the thread that the connection was lost. """ - try: - self.cv.acquire() - self.cv.notify() - finally: - self.cv.release() - - def run(self): - """ Main body of the running thread. """ - delay = self.DELAY_MIN - while True: - try: - self.broker._tryToConnect() - try: - self.cv.acquire() - while (not self.canceled) and self.broker.connected: - self.cv.wait() - if self.canceled: - return - delay = self.DELAY_MIN - finally: - self.cv.release() - except socket.error: - if delay < self.DELAY_MAX: - delay *= self.DELAY_FACTOR - except SessionDetached: - if delay < self.DELAY_MAX: - delay *= self.DELAY_FACTOR - except Closed: - if delay < self.DELAY_MAX: - delay *= self.DELAY_FACTOR - - try: - self.cv.acquire() - self.cv.wait(delay) - if self.canceled: - return - finally: - self.cv.release() - -class Broker: - """ This object represents a connection (or potential connection) to a QMF broker. """ - SYNC_TIME = 60 - nextSeq = 1 - - def __init__(self, session, host, port, authMechs, authUser, authPass, ssl=False, connTimeout=None): - self.session = session - self.host = host - self.port = port - self.mechanisms = authMechs - self.ssl = ssl - self.connTimeout = connTimeout - self.authUser = authUser - self.authPass = authPass - self.cv = Condition() - self.error = None - self.brokerId = None - self.connected = False - self.amqpSessionId = "%s.%d.%d" % (platform.uname()[1], os.getpid(), Broker.nextSeq) - Broker.nextSeq += 1 - if self.session.manageConnections: - self.thread = ManagedConnection(self) - self.thread.start() - else: - self.thread = None - self._tryToConnect() - - def isConnected(self): - """ Return True if there is an active connection to the broker. """ - return self.connected - - def getError(self): - """ Return the last error message seen while trying to connect to the broker. """ - return self.error - - def getBrokerId(self): - """ Get broker's unique identifier (UUID) """ - return self.brokerId - - def getBrokerBank(self): - """ Return the broker-bank value. This is the value that the broker assigns to - objects within its control. This value appears as a field in the ObjectId - of objects created by agents controlled by this broker. """ - return 1 - - def getAgent(self, brokerBank, agentBank): - """ Return the agent object associated with a particular broker and agent bank value.""" - bankKey = (brokerBank, agentBank) - if bankKey in self.agents: - return self.agents[bankKey] - return None - - def getSessionId(self): - """ Get the identifier of the AMQP session to the broker """ - return self.amqpSessionId - - def getAgents(self): - """ Get the list of agents reachable via this broker """ - return self.agents.values() - - def getAmqpSession(self): - """ Get the AMQP session object for this connected broker. """ - return self.amqpSession - - def getUrl(self): - """ """ - return "%s:%d" % (self.host, self.port) - - def getFullUrl(self, noAuthIfGuestDefault=True): - """ """ - ssl = "" - if self.ssl: - ssl = "s" - auth = "%s/%s@" % (self.authUser, self.authPass) - if self.authUser == "" or \ - (noAuthIfGuestDefault and self.authUser == "guest" and self.authPass == "guest"): - auth = "" - return "amqp%s://%s%s:%d" % (ssl, auth, self.host, self.port or 5672) - - def __repr__(self): - if self.connected: - return "Broker connected at: %s" % self.getUrl() - else: - return "Disconnected Broker" - - def _tryToConnect(self): - try: - self.agents = {} - self.agents[(1,0)] = Agent(self, 0, "BrokerAgent") - self.topicBound = False - self.syncInFlight = False - self.syncRequest = 0 - self.syncResult = None - self.reqsOutstanding = 1 - - sock = connect(self.host, self.port) - sock.settimeout(5) - oldTimeout = sock.gettimeout() - sock.settimeout(self.connTimeout) - if self.ssl: - connSock = ssl(sock) - else: - connSock = sock - self.conn = Connection(connSock, username=self.authUser, password=self.authPass, - mechanism = self.mechanisms, host=self.host, service="qpidd") - def aborted(): - raise Timeout("Waiting for connection to be established with broker") - oldAborted = self.conn.aborted - self.conn.aborted = aborted - self.conn.start() - sock.settimeout(oldTimeout) - self.conn.aborted = oldAborted - - self.replyName = "reply-%s" % self.amqpSessionId - self.amqpSession = self.conn.session(self.amqpSessionId) - self.amqpSession.auto_sync = True - self.amqpSession.queue_declare(queue=self.replyName, exclusive=True, auto_delete=True) - self.amqpSession.exchange_bind(exchange="amq.direct", - queue=self.replyName, binding_key=self.replyName) - self.amqpSession.message_subscribe(queue=self.replyName, destination="rdest", - accept_mode=self.amqpSession.accept_mode.none, - acquire_mode=self.amqpSession.acquire_mode.pre_acquired) - self.amqpSession.incoming("rdest").listen(self._replyCb, self._exceptionCb) - self.amqpSession.message_set_flow_mode(destination="rdest", flow_mode=1) - self.amqpSession.message_flow(destination="rdest", unit=0, value=0xFFFFFFFFL) - self.amqpSession.message_flow(destination="rdest", unit=1, value=0xFFFFFFFFL) - - self.topicName = "topic-%s" % self.amqpSessionId - self.amqpSession.queue_declare(queue=self.topicName, exclusive=True, auto_delete=True) - self.amqpSession.message_subscribe(queue=self.topicName, destination="tdest", - accept_mode=self.amqpSession.accept_mode.none, - acquire_mode=self.amqpSession.acquire_mode.pre_acquired) - self.amqpSession.incoming("tdest").listen(self._replyCb) - self.amqpSession.message_set_flow_mode(destination="tdest", flow_mode=1) - self.amqpSession.message_flow(destination="tdest", unit=0, value=0xFFFFFFFFL) - self.amqpSession.message_flow(destination="tdest", unit=1, value=0xFFFFFFFFL) - - self.connected = True - self.session._handleBrokerConnect(self) - - codec = Codec() - self._setHeader(codec, 'B') - msg = self._message(codec.encoded) - self._send(msg) - - except socket.error, e: - self.error = "Socket Error %s - %s" % (e.__class__.__name__, e) - raise - except Closed, e: - self.error = "Connect Failed %s - %s" % (e.__class__.__name__, e) - raise - except ConnectionFailed, e: - self.error = "Connect Failed %s - %s" % (e.__class__.__name__, e) - raise - - def _updateAgent(self, obj): - bankKey = (obj.brokerBank, obj.agentBank) - if obj._deleteTime == 0: - if bankKey not in self.agents: - agent = Agent(self, obj.agentBank, obj.label) - self.agents[bankKey] = agent - if self.session.console != None: - self.session.console.newAgent(agent) - else: - agent = self.agents.pop(bankKey, None) - if agent != None and self.session.console != None: - self.session.console.delAgent(agent) - - def _setHeader(self, codec, opcode, seq=0): - """ Compose the header of a management message. """ - codec.write_uint8(ord('A')) - codec.write_uint8(ord('M')) - codec.write_uint8(ord('2')) - codec.write_uint8(ord(opcode)) - codec.write_uint32(seq) - - def _checkHeader(self, codec): - """ Check the header of a management message and extract the opcode and class. """ - try: - octet = chr(codec.read_uint8()) - if octet != 'A': - return None, None - octet = chr(codec.read_uint8()) - if octet != 'M': - return None, None - octet = chr(codec.read_uint8()) - if octet != '2': - return None, None - opcode = chr(codec.read_uint8()) - seq = codec.read_uint32() - return opcode, seq - except: - return None, None - - def _message (self, body, routing_key="broker", ttl=None): - dp = self.amqpSession.delivery_properties() - dp.routing_key = routing_key - if ttl: - dp.ttl = ttl - mp = self.amqpSession.message_properties() - mp.content_type = "x-application/qmf" - mp.user_id = self.authUser - mp.reply_to = self.amqpSession.reply_to("amq.direct", self.replyName) - return Message(dp, mp, body) - - def _send(self, msg, dest="qpid.management"): - self.amqpSession.message_transfer(destination=dest, message=msg) - - def _shutdown(self): - if self.thread: - self.thread.stop() - self.thread.join() - if self.connected: - self.amqpSession.incoming("rdest").stop() - if self.session.console != None: - self.amqpSession.incoming("tdest").stop() - self.amqpSession.close() - self.conn.close() - self.connected = False - - def _waitForStable(self): - try: - self.cv.acquire() - if not self.connected: - return - if self.reqsOutstanding == 0: - return - self.syncInFlight = True - starttime = time() - while self.reqsOutstanding != 0: - self.cv.wait(self.SYNC_TIME) - if time() - starttime > self.SYNC_TIME: - raise RuntimeError("Timed out waiting for broker to synchronize") - finally: - self.cv.release() - - def _incOutstanding(self): - try: - self.cv.acquire() - self.reqsOutstanding += 1 - finally: - self.cv.release() - - def _decOutstanding(self): - try: - self.cv.acquire() - self.reqsOutstanding -= 1 - if self.reqsOutstanding == 0 and not self.topicBound: - self.topicBound = True - for key in self.session.bindingKeyList: - self.amqpSession.exchange_bind(exchange="qpid.management", - queue=self.topicName, binding_key=key) - if self.reqsOutstanding == 0 and self.syncInFlight: - self.syncInFlight = False - self.cv.notify() - finally: - self.cv.release() - - def _replyCb(self, msg): - codec = Codec(msg.body) - while True: - opcode, seq = self._checkHeader(codec) - if opcode == None: return - if opcode == 'b': self.session._handleBrokerResp (self, codec, seq) - elif opcode == 'p': self.session._handlePackageInd (self, codec, seq) - elif opcode == 'z': self.session._handleCommandComplete (self, codec, seq) - elif opcode == 'q': self.session._handleClassInd (self, codec, seq) - elif opcode == 'm': self.session._handleMethodResp (self, codec, seq) - elif opcode == 'h': self.session._handleHeartbeatInd (self, codec, seq, msg) - elif opcode == 'e': self.session._handleEventInd (self, codec, seq) - elif opcode == 's': self.session._handleSchemaResp (self, codec, seq) - elif opcode == 'c': self.session._handleContentInd (self, codec, seq, prop=True) - elif opcode == 'i': self.session._handleContentInd (self, codec, seq, stat=True) - elif opcode == 'g': self.session._handleContentInd (self, codec, seq, prop=True, stat=True) - self.session.receiver._completed.add(msg.id) - self.session.channel.session_completed(self.session.receiver._completed) - - def _exceptionCb(self, data): - self.connected = False - self.error = data - try: - self.cv.acquire() - if self.syncInFlight: - self.cv.notify() - finally: - self.cv.release() - self.session._handleError(self.error) - self.session._handleBrokerDisconnect(self) - if self.thread: - self.thread.disconnected() - -class Agent: - """ """ - def __init__(self, broker, agentBank, label): - self.broker = broker - self.brokerBank = broker.getBrokerBank() - self.agentBank = agentBank - self.label = label - - def __repr__(self): - return "Agent at bank %d.%d (%s)" % (self.brokerBank, self.agentBank, self.label) - - def getBroker(self): - return self.broker - - def getBrokerBank(self): - return self.brokerBank - - def getAgentBank(self): - return self.agentBank - -class Event: - """ """ - def __init__(self, session, broker, codec): - self.session = session - self.broker = broker - self.classKey = ClassKey(codec) - self.timestamp = codec.read_int64() - self.severity = codec.read_uint8() - self.schema = None - pname = self.classKey.getPackageName() - pkey = self.classKey.getPackageKey() - if pname in session.packages: - if pkey in session.packages[pname]: - self.schema = session.packages[pname][pkey] - self.arguments = {} - for arg in self.schema.arguments: - self.arguments[arg.name] = session._decodeValue(codec, arg.type, broker) - - def __repr__(self): - if self.schema == None: - return "<uninterpretable>" - out = strftime("%c", gmtime(self.timestamp / 1000000000)) - out += " " + self._sevName() + " " + self.classKey.getPackageName() + ":" + self.classKey.getClassName() - out += " broker=" + self.broker.getUrl() - for arg in self.schema.arguments: - disp = self.session._displayValue(self.arguments[arg.name], arg.type).encode("utf8") - if " " in disp: - disp = "\"" + disp + "\"" - out += " " + arg.name + "=" + disp - return out - - def _sevName(self): - if self.severity == 0 : return "EMER " - if self.severity == 1 : return "ALERT" - if self.severity == 2 : return "CRIT " - if self.severity == 3 : return "ERROR" - if self.severity == 4 : return "WARN " - if self.severity == 5 : return "NOTIC" - if self.severity == 6 : return "INFO " - if self.severity == 7 : return "DEBUG" - return "INV-%d" % self.severity - - def getClassKey(self): - return self.classKey - - def getArguments(self): - return self.arguments - - def getTimestamp(self): - return self.timestamp - - def getName(self): - return self.name - - def getSchema(self): - return self.schema - -class SequenceManager: - """ Manage sequence numbers for asynchronous method calls """ - def __init__(self): - self.lock = Lock() - self.sequence = 0 - self.pending = {} - - def _reserve(self, data): - """ Reserve a unique sequence number """ - try: - self.lock.acquire() - result = self.sequence - self.sequence = self.sequence + 1 - self.pending[result] = data - finally: - self.lock.release() - return result - - def _release(self, seq): - """ Release a reserved sequence number """ - data = None - try: - self.lock.acquire() - if seq in self.pending: - data = self.pending[seq] - del self.pending[seq] - finally: - self.lock.release() - return data - - -class DebugConsole(Console): - """ """ - def brokerConnected(self, broker): - print "brokerConnected:", broker - - def brokerDisconnected(self, broker): - print "brokerDisconnected:", broker - - def newPackage(self, name): - print "newPackage:", name - - def newClass(self, kind, classKey): - print "newClass:", kind, classKey - - def newAgent(self, agent): - print "newAgent:", agent - - def delAgent(self, agent): - print "delAgent:", agent - - def objectProps(self, broker, record): - print "objectProps:", record - - def objectStats(self, broker, record): - print "objectStats:", record - - def event(self, broker, event): - print "event:", event - - def heartbeat(self, agent, timestamp): - print "heartbeat:", agent - - def brokerInfo(self, broker): - print "brokerInfo:", broker - diff --git a/python/qmf2/__init__.py b/python/qmf2/__init__.py deleted file mode 100644 index 31d5a2ef58..0000000000 --- a/python/qmf2/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# 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. -# diff --git a/python/qmf2/agent.py b/python/qmf2/agent.py deleted file mode 100644 index a6b3c39ad1..0000000000 --- a/python/qmf2/agent.py +++ /dev/null @@ -1,961 +0,0 @@ -# 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. -# - -import sys -import logging -import datetime -import time -import Queue -from threading import Thread, Lock, currentThread, Event -from qpid.messaging import Connection, Message, Empty, SendError -from uuid import uuid4 -from common import (make_subject, parse_subject, OpCode, QmfQuery, - SchemaObjectClass, MsgKey, QmfData, QmfAddress, - SchemaClass, SchemaClassId, WorkItem, SchemaMethod, - timedelta_to_secs) - -# global flag that indicates which thread (if any) is -# running the agent notifier callback -_callback_thread=None - - ##============================================================================== - ## METHOD CALL - ##============================================================================== - -class _MethodCallHandle(object): - """ - Private class used to hold context when handing off a method call to the - application. Given to the app in a WorkItem, provided to the agent when - method_response() is invoked. - """ - def __init__(self, correlation_id, reply_to, meth_name, _oid=None, - _schema_id=None): - self.correlation_id = correlation_id - self.reply_to = reply_to - self.meth_name = meth_name - self.oid = _oid - self.schema_id = _schema_id - -class MethodCallParams(object): - """ - """ - def __init__(self, name, _oid=None, _schema_id=None, _in_args=None, - _user_id=None): - self._meth_name = name - self._oid = _oid - self._schema_id = _schema_id - self._in_args = _in_args - self._user_id = _user_id - - def get_name(self): - return self._meth_name - - def get_object_id(self): - return self._oid - - def get_schema_id(self): - return self._schema_id - - def get_args(self): - return self._in_args - - def get_user_id(self): - return self._user_id - - - - ##============================================================================== - ## AGENT - ##============================================================================== - -class Agent(Thread): - def __init__(self, name, _domain=None, _notifier=None, _heartbeat_interval=30, - _max_msg_size=0, _capacity=10): - Thread.__init__(self) - self._running = False - self._ready = Event() - - self.name = str(name) - self._domain = _domain - self._address = QmfAddress.direct(self.name, self._domain) - self._notifier = _notifier - self._heartbeat_interval = _heartbeat_interval - # @todo: currently, max # of objects in a single reply message, would - # be better if it were max bytesize of per-msg content... - self._max_msg_size = _max_msg_size - self._capacity = _capacity - - self._conn = None - self._session = None - self._direct_receiver = None - self._topic_receiver = None - self._direct_sender = None - self._topic_sender = None - - self._lock = Lock() - self._packages = {} - self._schema_timestamp = long(0) - self._schema = {} - # _described_data holds QmfData objects that are associated with schema - # it is index by schema_id, object_id - self._described_data = {} - # _undescribed_data holds unstructured QmfData objects - these objects - # have no schema. it is indexed by object_id only. - self._undescribed_data = {} - self._work_q = Queue.Queue() - self._work_q_put = False - - - def destroy(self, timeout=None): - """ - Must be called before the Agent is deleted. - Frees up all resources and shuts down all background threads. - - @type timeout: float - @param timeout: maximum time in seconds to wait for all background threads to terminate. Default: forever. - """ - logging.debug("Destroying Agent %s" % self.name) - if self._conn: - self.remove_connection(timeout) - logging.debug("Agent Destroyed") - - - def get_name(self): - return self.name - - def set_connection(self, conn): - self._conn = conn - self._session = self._conn.session() - - # for messages directly addressed to me - self._direct_receiver = self._session.receiver(str(self._address) + - ";{create:always," - " node-properties:" - " {type:topic," - " x-properties:" - " {type:direct}}}", - capacity=self._capacity) - logging.debug("my direct addr=%s" % self._direct_receiver.source) - - # for sending directly addressed messages. - self._direct_sender = self._session.sender(str(self._address.get_node()) + - ";{create:always," - " node-properties:" - " {type:topic," - " x-properties:" - " {type:direct}}}") - logging.debug("my default direct send addr=%s" % self._direct_sender.target) - - # for receiving "broadcast" messages from consoles - default_addr = QmfAddress.topic(QmfAddress.SUBJECT_CONSOLE_IND + ".#", - self._domain) - self._topic_receiver = self._session.receiver(str(default_addr) + - ";{create:always," - " node-properties:" - " {type:topic}}", - capacity=self._capacity) - logging.debug("console.ind addr=%s" % self._topic_receiver.source) - - # for sending to topic subscribers - ind_addr = QmfAddress.topic(QmfAddress.SUBJECT_AGENT_IND, - self._domain) - self._topic_sender = self._session.sender(str(ind_addr) + - ";{create:always," - " node-properties:" - " {type:topic}}") - logging.debug("agent.ind addr=%s" % self._topic_sender.target) - - self._running = True - self.start() - self._ready.wait(10) - if not self._ready.isSet(): - raise Exception("Agent managment thread failed to start.") - - def remove_connection(self, timeout=None): - # tell connection thread to shutdown - self._running = False - if self.isAlive(): - # kick my thread to wake it up - try: - msg = Message(properties={"method":"request", - "qmf.subject":make_subject(OpCode.noop)}, - subject=self.name, - content={"noop":"noop"}) - - # TRACE - #logging.error("!!! sending wakeup to myself: %s" % msg) - self._direct_sender.send( msg, sync=True ) - except SendError, e: - logging.error(str(e)) - logging.debug("waiting for agent receiver thread to exit") - self.join(timeout) - if self.isAlive(): - logging.error( "Agent thread '%s' is hung..." % self.name) - self._direct_receiver.close() - self._direct_receiver = None - self._direct_sender.close() - self._direct_sender = None - self._topic_receiver.close() - self._topic_receiver = None - self._topic_sender.close() - self._topic_sender = None - self._session.close() - self._session = None - self._conn = None - logging.debug("agent connection removal complete") - - def register_object_class(self, schema): - """ - Register an instance of a SchemaClass with this agent - """ - # @todo: need to update subscriptions - # @todo: need to mark schema as "non-const" - if not isinstance(schema, SchemaClass): - raise TypeError("SchemaClass instance expected") - - classId = schema.get_class_id() - pname = classId.get_package_name() - cname = classId.get_class_name() - hstr = classId.get_hash_string() - if not hstr: - raise Exception("Schema hash is not set.") - - self._lock.acquire() - try: - if pname not in self._packages: - self._packages[pname] = [cname] - else: - if cname not in self._packages[pname]: - self._packages[pname].append(cname) - self._schema[classId] = schema - self._schema_timestamp = long(time.time() * 1000) - finally: - self._lock.release() - - def register_event_class(self, schema): - return self.register_object_class(schema) - - def raise_event(self, qmfEvent): - """ - TBD - """ - if not self._topic_sender: - raise Exception("No connection available") - - # @todo: should we validate against the schema? - _map = {"_name": self.get_name(), - "_event": qmfEvent.map_encode()} - msg = Message(subject=QmfAddress.SUBJECT_AGENT_EVENT + "." + - qmfEvent.get_severity() + "." + self.name, - properties={"method":"response", - "qmf.subject":make_subject(OpCode.event_ind)}, - content={MsgKey.event:_map}) - # TRACE - # logging.error("!!! Agent %s sending Event (%s)" % - # (self.name, str(msg))) - self._topic_sender.send(msg) - - def add_object(self, data): - """ - Register an instance of a QmfAgentData object. - """ - # @todo: need to update subscriptions - # @todo: need to mark schema as "non-const" - if not isinstance(data, QmfAgentData): - raise TypeError("QmfAgentData instance expected") - - oid = data.get_object_id() - if not oid: - raise TypeError("No identifier assigned to QmfAgentData!") - - sid = data.get_schema_class_id() - - self._lock.acquire() - try: - if sid: - if sid not in self._described_data: - self._described_data[sid] = {oid: data} - else: - self._described_data[sid][oid] = data - else: - self._undescribed_data[oid] = data - finally: - self._lock.release() - - def get_object(self, oid, schema_id): - data = None - self._lock.acquire() - try: - if schema_id: - data = self._described_data.get(schema_id) - if data: - data = data.get(oid) - else: - data = self._undescribed_data.get(oid) - finally: - self._lock.release() - return data - - - def method_response(self, handle, _out_args=None, _error=None): - """ - """ - if not isinstance(handle, _MethodCallHandle): - raise TypeError("Invalid handle passed to method_response!") - - _map = {SchemaMethod.KEY_NAME:handle.meth_name} - if handle.oid is not None: - _map[QmfData.KEY_OBJECT_ID] = handle.oid - if handle.schema_id is not None: - _map[QmfData.KEY_SCHEMA_ID] = handle.schema_id.map_encode() - if _out_args is not None: - _map[SchemaMethod.KEY_ARGUMENTS] = _out_args.copy() - if _error is not None: - if not isinstance(_error, QmfData): - raise TypeError("Invalid type for error - must be QmfData") - _map[SchemaMethod.KEY_ERROR] = _error.map_encode() - - msg = Message( properties={"method":"response", - "qmf.subject":make_subject(OpCode.response)}, - content={MsgKey.method:_map}) - msg.correlation_id = handle.correlation_id - - self._send_reply(msg, handle.reply_to) - - def get_workitem_count(self): - """ - Returns the count of pending WorkItems that can be retrieved. - """ - return self._work_q.qsize() - - def get_next_workitem(self, timeout=None): - """ - Obtains the next pending work item, or None if none available. - """ - try: - wi = self._work_q.get(True, timeout) - except Queue.Empty: - return None - return wi - - def release_workitem(self, wi): - """ - Releases a WorkItem instance obtained by getNextWorkItem(). Called when - the application has finished processing the WorkItem. - """ - pass - - - def run(self): - global _callback_thread - next_heartbeat = datetime.datetime.utcnow() - batch_limit = 10 # a guess - - self._ready.set() - - while self._running: - - now = datetime.datetime.utcnow() - # print("now=%s next_heartbeat=%s" % (now, next_heartbeat)) - if now >= next_heartbeat: - ind = self._makeAgentIndMsg() - ind.subject = QmfAddress.SUBJECT_AGENT_HEARTBEAT - # TRACE - #logging.error("!!! Agent %s sending Heartbeat (%s)" % - # (self.name, str(ind))) - self._topic_sender.send(ind) - logging.debug("Agent Indication Sent") - next_heartbeat = now + datetime.timedelta(seconds = self._heartbeat_interval) - - timeout = timedelta_to_secs(next_heartbeat - now) - # print("now=%s next_heartbeat=%s timeout=%s" % (now, next_heartbeat, timeout)) - try: - self._session.next_receiver(timeout=timeout) - except Empty: - continue - - for i in range(batch_limit): - try: - msg = self._topic_receiver.fetch(timeout=0) - except Empty: - break - # TRACE - # logging.error("!!! Agent %s: msg on %s [%s]" % - # (self.name, self._topic_receiver.source, msg)) - self._dispatch(msg, _direct=False) - - for i in range(batch_limit): - try: - msg = self._direct_receiver.fetch(timeout=0) - except Empty: - break - # TRACE - # logging.error("!!! Agent %s: msg on %s [%s]" % - # (self.name, self._direct_receiver.source, msg)) - self._dispatch(msg, _direct=True) - - if self._work_q_put and self._notifier: - # new stuff on work queue, kick the the application... - self._work_q_put = False - _callback_thread = currentThread() - logging.info("Calling agent notifier.indication") - self._notifier.indication() - _callback_thread = None - - # - # Private: - # - - def _makeAgentIndMsg(self): - """ - Create an agent indication message identifying this agent - """ - _map = {"_name": self.get_name(), - "_schema_timestamp": self._schema_timestamp} - return Message(properties={"method":"response", - "qmf.subject":make_subject(OpCode.agent_ind)}, - content={MsgKey.agent_info: _map}) - - def _send_reply(self, msg, reply_to): - """ - Send a reply message to the given reply_to address - """ - if not isinstance(reply_to, QmfAddress): - try: - reply_to = QmfAddress.from_string(str(reply_to)) - except ValueError: - logging.error("Invalid reply-to address '%s'" % reply_to) - - msg.subject = reply_to.get_subject() - - try: - if reply_to.is_direct(): - # TRACE - #logging.error("!!! Agent %s direct REPLY-To:%s (%s)" % - # (self.name, str(reply_to), str(msg))) - self._direct_sender.send(msg) - else: - # TRACE - # logging.error("!!! Agent %s topic REPLY-To:%s (%s)" % - # (self.name, str(reply_to), str(msg))) - self._topic_sender.send(msg) - logging.debug("reply msg sent to [%s]" % str(reply_to)) - except SendError, e: - logging.error("Failed to send reply msg '%s' (%s)" % (msg, str(e))) - - def _send_query_response(self, subject, msgkey, cid, reply_to, objects): - """ - Send a response to a query, breaking the result into multiple - messages based on the agent's _max_msg_size config parameter - """ - - total = len(objects) - if self._max_msg_size: - max_count = self._max_msg_size - else: - max_count = total - - start = 0 - end = min(total, max_count) - while end <= total: - m = Message(properties={"qmf.subject":subject, - "method":"response"}, - correlation_id = cid, - content={msgkey:objects[start:end]}) - self._send_reply(m, reply_to) - if end == total: - break; - start = end - end = min(total, end + max_count) - - # response terminator - last message has empty object array - if total: - m = Message(properties={"qmf.subject":subject, - "method":"response"}, - correlation_id = cid, - content={msgkey: []} ) - self._send_reply(m, reply_to) - - def _dispatch(self, msg, _direct=False): - """ - Process a message from a console. - - @param _direct: True if msg directly addressed to this agent. - """ - logging.debug( "Message received from Console! [%s]" % msg ) - try: - version,opcode = parse_subject(msg.properties.get("qmf.subject")) - except: - logging.warning("Ignoring unrecognized message '%s'" % msg.subject) - return - - cmap = {}; props={} - if msg.content_type == "amqp/map": - cmap = msg.content - if msg.properties: - props = msg.properties - - if opcode == OpCode.agent_locate: - self._handleAgentLocateMsg( msg, cmap, props, version, _direct ) - elif opcode == OpCode.get_query: - self._handleQueryMsg( msg, cmap, props, version, _direct ) - elif opcode == OpCode.method_req: - self._handleMethodReqMsg(msg, cmap, props, version, _direct) - elif opcode == OpCode.cancel_subscription: - logging.warning("!!! CANCEL_SUB TBD !!!") - elif opcode == OpCode.create_subscription: - logging.warning("!!! CREATE_SUB TBD !!!") - elif opcode == OpCode.renew_subscription: - logging.warning("!!! RENEW_SUB TBD !!!") - elif opcode == OpCode.schema_query: - logging.warning("!!! SCHEMA_QUERY TBD !!!") - elif opcode == OpCode.noop: - logging.debug("No-op msg received.") - else: - logging.warning("Ignoring message with unrecognized 'opcode' value: '%s'" - % opcode) - - def _handleAgentLocateMsg( self, msg, cmap, props, version, direct ): - """ - Process a received agent-locate message - """ - logging.debug("_handleAgentLocateMsg") - - reply = True - if "method" in props and props["method"] == "request": - query = cmap.get(MsgKey.query) - if query is not None: - # fake a QmfData containing my identifier for the query compare - tmpData = QmfData.create({QmfQuery.KEY_AGENT_NAME: - self.get_name()}, - _object_id="my-name") - reply = QmfQuery.from_map(query).evaluate(tmpData) - - if reply: - m = self._makeAgentIndMsg() - m.correlation_id = msg.correlation_id - self._send_reply(m, msg.reply_to) - else: - logging.debug("agent-locate msg not mine - no reply sent") - - - def _handleQueryMsg(self, msg, cmap, props, version, _direct ): - """ - Handle received query message - """ - logging.debug("_handleQueryMsg") - - if "method" in props and props["method"] == "request": - qmap = cmap.get(MsgKey.query) - if qmap: - query = QmfQuery.from_map(qmap) - target = query.get_target() - if target == QmfQuery.TARGET_PACKAGES: - self._queryPackages( msg, query ) - elif target == QmfQuery.TARGET_SCHEMA_ID: - self._querySchema( msg, query, _idOnly=True ) - elif target == QmfQuery.TARGET_SCHEMA: - self._querySchema( msg, query) - elif target == QmfQuery.TARGET_AGENT: - logging.warning("!!! @todo: Query TARGET=AGENT TBD !!!") - elif target == QmfQuery.TARGET_OBJECT_ID: - self._queryData(msg, query, _idOnly=True) - elif target == QmfQuery.TARGET_OBJECT: - self._queryData(msg, query) - else: - logging.warning("Unrecognized query target: '%s'" % str(target)) - - - - def _handleMethodReqMsg(self, msg, cmap, props, version, _direct): - """ - Process received Method Request - """ - if "method" in props and props["method"] == "request": - mname = cmap.get(SchemaMethod.KEY_NAME) - if not mname: - logging.warning("Invalid method call from '%s': no name" - % msg.reply_to) - return - - in_args = cmap.get(SchemaMethod.KEY_ARGUMENTS) - oid = cmap.get(QmfData.KEY_OBJECT_ID) - schema_id = cmap.get(QmfData.KEY_SCHEMA_ID) - if schema_id: - schema_id = SchemaClassId.from_map(schema_id) - handle = _MethodCallHandle(msg.correlation_id, - msg.reply_to, - mname, - oid, schema_id) - param = MethodCallParams( mname, oid, schema_id, in_args, - msg.user_id) - - # @todo: validate the method against the schema: - # if self._schema: - # # validate - # _in_args = _in_args.copy() - # ms = self._schema.get_method(name) - # if ms is None: - # raise ValueError("Method '%s' is undefined." % name) - - # for aname,prop in ms.get_arguments().iteritems(): - # if aname not in _in_args: - # if prop.get_default(): - # _in_args[aname] = prop.get_default() - # elif not prop.is_optional(): - # raise ValueError("Method '%s' requires argument '%s'" - # % (name, aname)) - # for aname in _in_args.iterkeys(): - # prop = ms.get_argument(aname) - # if prop is None: - # raise ValueError("Method '%s' does not define argument" - # " '%s'" % (name, aname)) - # if "I" not in prop.get_direction(): - # raise ValueError("Method '%s' argument '%s' is not an" - # " input." % (name, aname)) - - # # @todo check if value is correct (type, range, etc) - - self._work_q.put(WorkItem(WorkItem.METHOD_CALL, handle, param)) - self._work_q_put = True - - def _queryPackages(self, msg, query): - """ - Run a query against the list of known packages - """ - pnames = [] - self._lock.acquire() - try: - for name in self._packages.iterkeys(): - qmfData = QmfData.create({SchemaClassId.KEY_PACKAGE:name}, - _object_id="_package") - if query.evaluate(qmfData): - pnames.append(name) - finally: - self._lock.release() - - self._send_query_response(make_subject(OpCode.data_ind), - MsgKey.package_info, - msg.correlation_id, - msg.reply_to, - pnames) - - def _querySchema( self, msg, query, _idOnly=False ): - """ - """ - schemas = [] - # if querying for a specific schema, do a direct lookup - if query.get_selector() == QmfQuery.ID: - found = None - self._lock.acquire() - try: - found = self._schema.get(query.get_id()) - finally: - self._lock.release() - if found: - if _idOnly: - schemas.append(query.get_id().map_encode()) - else: - schemas.append(found.map_encode()) - else: # otherwise, evaluate all schema - self._lock.acquire() - try: - for sid,val in self._schema.iteritems(): - if query.evaluate(val): - if _idOnly: - schemas.append(sid.map_encode()) - else: - schemas.append(val.map_encode()) - finally: - self._lock.release() - - if _idOnly: - msgkey = MsgKey.schema_id - else: - msgkey = MsgKey.schema - - self._send_query_response(make_subject(OpCode.data_ind), - msgkey, - msg.correlation_id, - msg.reply_to, - schemas) - - - def _queryData( self, msg, query, _idOnly=False ): - """ - """ - data_objs = [] - # extract optional schema_id from target params - sid = None - t_params = query.get_target_param() - if t_params: - sid = t_params.get(QmfData.KEY_SCHEMA_ID) - # if querying for a specific object, do a direct lookup - if query.get_selector() == QmfQuery.ID: - oid = query.get_id() - found = None - self._lock.acquire() - try: - if sid and not sid.get_hash_string(): - # wildcard schema_id match, check each schema - for name,db in self._described_data.iteritems(): - if (name.get_class_name() == sid.get_class_name() - and name.get_package_name() == sid.get_package_name()): - found = db.get(oid) - if found: - if _idOnly: - data_objs.append(oid) - else: - data_objs.append(found.map_encode()) - else: - if sid: - db = self._described_data.get(sid) - if db: - found = db.get(oid) - else: - found = self._undescribed_data.get(oid) - if found: - if _idOnly: - data_objs.append(oid) - else: - data_objs.append(found.map_encode()) - finally: - self._lock.release() - else: # otherwise, evaluate all data - self._lock.acquire() - try: - if sid and not sid.get_hash_string(): - # wildcard schema_id match, check each schema - for name,db in self._described_data.iteritems(): - if (name.get_class_name() == sid.get_class_name() - and name.get_package_name() == sid.get_package_name()): - for oid,data in db.iteritems(): - if query.evaluate(data): - if _idOnly: - data_objs.append(oid) - else: - data_objs.append(data.map_encode()) - else: - if sid: - db = self._described_data.get(sid) - else: - db = self._undescribed_data - - if db: - for oid,data in db.iteritems(): - if query.evaluate(data): - if _idOnly: - data_objs.append(oid) - else: - data_objs.append(data.map_encode()) - finally: - self._lock.release() - - if _idOnly: - msgkey = MsgKey.object_id - else: - msgkey = MsgKey.data_obj - - self._send_query_response(make_subject(OpCode.data_ind), - msgkey, - msg.correlation_id, - msg.reply_to, - data_objs) - - - - ##============================================================================== - ## DATA MODEL - ##============================================================================== - - -class QmfAgentData(QmfData): - """ - A managed data object that is owned by an agent. - """ - - def __init__(self, agent, _values={}, _subtypes={}, _tag=None, - _object_id=None, _schema=None): - schema_id = None - if _schema: - schema_id = _schema.get_class_id() - - if _object_id is None: - if not isinstance(_schema, SchemaObjectClass): - raise Exception("An object_id must be provided if the object" - "doesn't have an associated schema.") - ids = _schema.get_id_names() - if not ids: - raise Exception("Object must have an Id or a schema that" - " provides an Id") - _object_id = u"" - for key in ids: - value = _values.get(key) - if value is None: - raise Exception("Object must have a value for key" - " attribute '%s'" % str(key)) - try: - _object_id += unicode(value) - except: - raise Exception("Cannot create object_id from key" - " value '%s'" % str(value)) - - # timestamp in millisec since epoch UTC - ctime = long(time.time() * 1000) - super(QmfAgentData, self).__init__(_values=_values, _subtypes=_subtypes, - _tag=_tag, _ctime=ctime, - _utime=ctime, _object_id=_object_id, - _schema_id=schema_id, _const=False) - self._agent = agent - self._validated = False - - def destroy(self): - self._dtime = long(time.time() * 1000) - # @todo: publish change - - def is_deleted(self): - return self._dtime == 0 - - def set_value(self, _name, _value, _subType=None): - super(QmfAgentData, self).set_value(_name, _value, _subType) - # @todo: publish change - - def inc_value(self, name, delta=1): - """ add the delta to the property """ - # @todo: need to take write-lock - val = self.get_value(name) - try: - val += delta - except: - raise - self.set_value(name, val) - - def dec_value(self, name, delta=1): - """ subtract the delta from the property """ - # @todo: need to take write-lock - logging.error(" TBD!!!") - - def validate(self): - """ - Compares this object's data against the associated schema. Throws an - exception if the data does not conform to the schema. - """ - props = self._schema.get_properties() - for name,val in props.iteritems(): - # @todo validate: type compatible with amqp_type? - # @todo validate: primary keys have values - if name not in self._values: - if val._isOptional: - # ok not to be present, put in dummy value - # to simplify access - self._values[name] = None - else: - raise Exception("Required property '%s' not present." % name) - self._validated = True - - - -################################################################################ -################################################################################ -################################################################################ -################################################################################ - -if __name__ == '__main__': - # static test cases - no message passing, just exercise API - from common import (AgentName, SchemaProperty, qmfTypes, SchemaEventClass) - - logging.getLogger().setLevel(logging.INFO) - - logging.info( "Create an Agent" ) - _agent_name = AgentName("redhat.com", "agent", "tross") - _agent = Agent(str(_agent_name)) - - logging.info( "Get agent name: '%s'" % _agent.get_name()) - - logging.info( "Create SchemaObjectClass" ) - - _schema = SchemaObjectClass(SchemaClassId("MyPackage", "MyClass"), - _desc="A test data schema", - _object_id_names=["index1", "index2"]) - # add properties - _schema.add_property("index1", SchemaProperty(qmfTypes.TYPE_UINT8)) - _schema.add_property("index2", SchemaProperty(qmfTypes.TYPE_LSTR)) - - # these two properties are statistics - _schema.add_property("query_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - _schema.add_property("method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - # These two properties can be set via the method call - _schema.add_property("set_string", SchemaProperty(qmfTypes.TYPE_LSTR)) - _schema.add_property("set_int", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # add method - _meth = SchemaMethod(_desc="Method to set string and int in object." ) - _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) ) - _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) ) - _schema.add_method( "set_meth", _meth ) - - # Add schema to Agent - - print("Schema Map='%s'" % str(_schema.map_encode())) - - _agent.register_object_class(_schema) - - # instantiate managed data objects matching the schema - - logging.info( "Create QmfAgentData" ) - - _obj = QmfAgentData( _agent, _schema=_schema ) - _obj.set_value("index1", 100) - _obj.set_value("index2", "a name" ) - _obj.set_value("set_string", "UNSET") - _obj.set_value("set_int", 0) - _obj.set_value("query_count", 0) - _obj.set_value("method_call_count", 0) - - print("Obj1 Map='%s'" % str(_obj.map_encode())) - - _agent.add_object( _obj ) - - _obj = QmfAgentData( _agent, - _values={"index1":99, - "index2": "another name", - "set_string": "UNSET", - "set_int": 0, - "query_count": 0, - "method_call_count": 0}, - _schema=_schema) - - print("Obj2 Map='%s'" % str(_obj.map_encode())) - - _agent.add_object(_obj) - - ############## - - - - logging.info( "Create SchemaEventClass" ) - - _event = SchemaEventClass(SchemaClassId("MyPackage", "MyEvent", - stype=SchemaClassId.TYPE_EVENT), - _desc="A test data schema", - _props={"edata_1": SchemaProperty(qmfTypes.TYPE_UINT32)}) - _event.add_property("edata_2", SchemaProperty(qmfTypes.TYPE_LSTR)) - - print("Event Map='%s'" % str(_event.map_encode())) - - _agent.register_event_class(_event) diff --git a/python/qmf2/common.py b/python/qmf2/common.py deleted file mode 100644 index 8107b86666..0000000000 --- a/python/qmf2/common.py +++ /dev/null @@ -1,1943 +0,0 @@ -# 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. -# -import time -from logging import getLogger -from threading import Lock -from threading import Condition -try: - import hashlib - _md5Obj = hashlib.md5 -except ImportError: - import md5 - _md5Obj = md5.new - -log = getLogger("qmf") -log_query = getLogger("qmf.query") - - -## -## Constants -## - -AMQP_QMF_SUBJECT = "qmf" -AMQP_QMF_VERSION = 4 -AMQP_QMF_SUBJECT_FMT = "%s%d.%s" - -class MsgKey(object): - agent_info = "agent_info" - query = "query" - package_info = "package_info" - schema_id = "schema_id" - schema = "schema" - object_id="object_id" - data_obj="object" - method="method" - event="event" - - -class OpCode(object): - noop = "noop" - - # codes sent by a console and processed by the agent - agent_locate = "agent-locate" - cancel_subscription = "cancel-subscription" - create_subscription = "create-subscription" - get_query = "get-query" - method_req = "method" - renew_subscription = "renew-subscription" - schema_query = "schema-query" # @todo: deprecate - - # codes sent by the agent to a console - agent_ind = "agent" - data_ind = "data" - event_ind = "event" - managed_object = "managed-object" - object_ind = "object" - response = "response" - schema_ind="schema" # @todo: deprecate - - - - -def make_subject(_code): - """ - Create a message subject field value. - """ - return AMQP_QMF_SUBJECT_FMT % (AMQP_QMF_SUBJECT, AMQP_QMF_VERSION, _code) - - -def parse_subject(_sub): - """ - Deconstruct a subject field, return version,opcode values - """ - if _sub[:3] != "qmf": - raise Exception("Non-QMF message received") - - return _sub[3:].split('.', 1) - -def timedelta_to_secs(td): - """ - Convert a time delta to a time interval in seconds (float) - """ - return td.days * 86400 + td.seconds + td.microseconds/1000000.0 - - -##============================================================================== -## Async Event Model -##============================================================================== - - -class Notifier(object): - """ - Virtual base class that defines a call back which alerts the application that - a QMF Console notification is pending. - """ - def indication(self): - """ - Called when one or more items are ready for the application to process. - This method may be called by an internal QMF library thread. Its purpose is to - indicate that the application should process pending work items. - """ - raise Exception("The indication method must be overridden by the application!") - - - -class WorkItem(object): - """ - Describes an event that has arrived for the application to process. The - Notifier is invoked when one or more of these WorkItems become available - for processing. - """ - # Enumeration of the types of WorkItems produced on the Console - AGENT_ADDED=1 - AGENT_DELETED=2 - NEW_PACKAGE=3 - NEW_CLASS=4 - OBJECT_UPDATE=5 - EVENT_RECEIVED=7 - AGENT_HEARTBEAT=8 - QUERY_COMPLETE=9 - METHOD_RESPONSE=10 - # Enumeration of the types of WorkItems produced on the Agent - METHOD_CALL=1000 - QUERY=1001 - SUBSCRIBE=1002 - UNSUBSCRIBE=1003 - - def __init__(self, kind, handle, _params=None): - """ - Used by the Console to create a work item. - - @type kind: int - @param kind: work item type - """ - self._kind = kind - self._handle = handle - self._params = _params - - def get_type(self): - return self._kind - - def get_handle(self): - return self._handle - - def get_params(self): - return self._params - - - -##============================================================================== -## Addressing -##============================================================================== - -class QmfAddress(object): - """ - Address format: "qmf.<domain>.[topic|direct]/<subject>" - TBD - """ - - TYPE_DIRECT = "direct" - TYPE_TOPIC = "topic" - - ADDRESS_FMT = "qmf.%s.%s/%s" - DEFAULT_DOMAIN = "default" - - # Directly-addressed messages: - # agent's direct address: "qmf.<domain>.direct/<agent-name> - # console's direct address: "qmf.<domain>.direct/<console-name> - - # Well-known Topic Addresses: - # "qmf.<domain>.topic/<subject> - # Where <subject> has the following format: - # "console.ind#" - indications sent from consoles - # "agent.ind#" - indications sent from agents - # - # The following "well known" subjects are defined: - # - # console.ind.locate[.<agent-name>] - agent discovery request - # agent.ind.heartbeat[.<agent-name>"] - agent heartbeats - # agent.ind.event[.<severity>.<agent-name>] - events - # agent.ind.schema[TBD] - schema updates - # - SUBJECT_AGENT_IND="agent.ind" - SUBJECT_AGENT_HEARTBEAT = "agent.ind.heartbeat" - SUBJECT_AGENT_EVENT="agent.ind.event" - SUBJECT_AGENT_SCHEMA="agent.ind.schema" - - SUBJECT_CONSOLE_IND="console.ind" - SUBJECT_CONSOLE_LOCATE_AGENT="console.ind.locate" - - - - def __init__(self, subject, domain, type_): - if '/' in domain or '.' in domain: - raise Exception("domain string must not contain '/' or '.'" - " characters.") - - self._subject = subject - self._domain = domain - self._type = type_ - - def _direct(cls, subject, _domain=None): - if _domain is None: - _domain = QmfAddress.DEFAULT_DOMAIN - return cls(subject, _domain, type_=QmfAddress.TYPE_DIRECT) - direct = classmethod(_direct) - - def _topic(cls, subject, _domain=None): - if _domain is None: - _domain = QmfAddress.DEFAULT_DOMAIN - return cls(subject, _domain, type_=QmfAddress.TYPE_TOPIC) - topic = classmethod(_topic) - - def __from_string(cls, address): - node,subject = address.split('/',1) - qmf,domain,type_ = node.split('.',2) - - if qmf != "qmf" or (type_ != QmfAddress.TYPE_DIRECT and - type_ != QmfAddress.TYPE_TOPIC): - raise ValueError("invalid QmfAddress format: %s" % address) - - return cls(subject, domain, type_) - from_string = classmethod(__from_string) - - def get_address(self): - """ - Return the QMF address as a string, suitable for use with the AMQP - messaging API. - """ - return str(self) - - def get_node(self): - """ - Return the 'node' portion of the address. - """ - return self.get_address().split('/',1)[0] - - def get_subject(self): - """ - Return the 'subject' portion of the address. - """ - return self.get_address().split('/',1)[1] - - def get_domain(self): - return self._domain - - def is_direct(self): - return self._type == self.TYPE_DIRECT - - def __repr__(self): - return QmfAddress.ADDRESS_FMT % (self._domain, self._type, self._subject) - - - - -class AgentName(object): - """ - Uniquely identifies a management agent within the management domain. - """ - _separator = ":" - - def __init__(self, vendor, product, name, _str=None): - """ - Note: this object must be immutable, as it is used to index into a dictionary - """ - if _str is not None: - # construct from string representation - if _str.count(AgentName._separator) < 2: - raise TypeError("AgentName string format must be 'vendor.product.name'") - self._vendor, self._product, self._name = _str.split(AgentName._separator) - else: - self._vendor = vendor - self._product = product - self._name = name - - - def _from_str(cls, str_): - return cls(None, None, None, str_=str_) - from_str = classmethod(_from_str) - - def vendor(self): - return self._vendor - - def product(self): - return self._product - - def name(self): - return self._name - - def __cmp__(self, other): - if not isinstance(other, AgentName) : - raise TypeError("Invalid types for compare") - # return 1 - me = str(self) - them = str(other) - - if me < them: - return -1 - if me > them: - return 1 - return 0 - - def __hash__(self): - return (self._vendor, self._product, self._name).__hash__() - - def __repr__(self): - return self._vendor + AgentName._separator + \ - self._product + AgentName._separator + \ - self._name - - - -##============================================================================== -## DATA MODEL -##============================================================================== - - -class _mapEncoder(object): - """ - virtual base class for all objects that support being converted to a map - """ - - def map_encode(self): - raise Exception("The map_encode method my be overridden.") - - -class QmfData(_mapEncoder): - """ - Base class representing management data. - - Map format: - map["_values"] = map of unordered "name"=<value> pairs (optional) - map["_subtype"] = map of unordered "name"="subtype string" pairs (optional) - map["_tag"] = application-specific tag for this instance (optional) - """ - KEY_VALUES = "_values" - KEY_SUBTYPES = "_subtypes" - KEY_TAG="_tag" - KEY_OBJECT_ID = "_object_id" - KEY_SCHEMA_ID = "_schema_id" - KEY_UPDATE_TS = "_update_ts" - KEY_CREATE_TS = "_create_ts" - KEY_DELETE_TS = "_delete_ts" - - def __init__(self, - _values={}, _subtypes={}, _tag=None, - _object_id=None, _schema_id=None, - _ctime = 0, _utime = 0, _dtime = 0, - _map=None, _const=False): - """ - @type _values: dict - @param _values: dictionary of initial name=value pairs for object's - named data. - @type _subtypes: dict - @param _subtype: dictionary of subtype strings for each of the object's - named data. - @type _desc: string - @param _desc: Human-readable description of this data object. - @type _const: boolean - @param _const: if true, this object cannot be modified - """ - if _map is not None: - # construct from map - _tag = _map.get(self.KEY_TAG, _tag) - _values = _map.get(self.KEY_VALUES, _values) - _subtypes = _map.get(self.KEY_SUBTYPES, _subtypes) - _object_id = _map.get(self.KEY_OBJECT_ID, _object_id) - sid = _map.get(self.KEY_SCHEMA_ID) - if sid: - _schema_id = SchemaClassId.from_map(sid) - _ctime = long(_map.get(self.KEY_CREATE_TS, _ctime)) - _utime = long(_map.get(self.KEY_UPDATE_TS, _utime)) - _dtime = long(_map.get(self.KEY_DELETE_TS, _dtime)) - - if _object_id is None: - raise Exception("An object_id must be provided.") - - self._values = _values.copy() - self._subtypes = _subtypes.copy() - self._tag = _tag - self._ctime = _ctime - self._utime = _utime - self._dtime = _dtime - self._const = _const - self._schema_id = _schema_id - self._object_id = str(_object_id) - - - def __create(cls, values, _subtypes={}, _tag=None, _object_id=None, - _schema_id=None, _const=False): - # timestamp in millisec since epoch UTC - ctime = long(time.time() * 1000) - return cls(_values=values, _subtypes=_subtypes, _tag=_tag, - _ctime=ctime, _utime=ctime, - _object_id=_object_id, _schema_id=_schema_id, _const=_const) - create = classmethod(__create) - - def __from_map(cls, map_, _const=False): - return cls(_map=map_, _const=_const) - from_map = classmethod(__from_map) - - def is_managed(self): - return self._object_id is not None - - def is_described(self): - return self._schema_id is not None - - def get_tag(self): - return self._tag - - def get_value(self, name): - """ - Will throw an AttributeError exception if the named value does not exist. - """ - # meta-properties first: - if name == SchemaClassId.KEY_PACKAGE: - if self._schema_id: - return self._schema_id.get_package_name() - return None - if name == SchemaClassId.KEY_CLASS: - if self._schema_id: - return self._schema_id.get_class_name() - return None - if name == SchemaClassId.KEY_TYPE: - if self._schema_id: - return self._schema_id.get_type() - return None - if name == SchemaClassId.KEY_HASH: - if self._schema_id: - return self._schema_id.get_hash_string() - return None - if name == self.KEY_SCHEMA_ID: - return self._schema_id - if name == self.KEY_OBJECT_ID: - return self._object_id - if name == self.KEY_TAG: - return self._tag - if name == self.KEY_UPDATE_TS: - return self._utime - if name == self.KEY_CREATE_TS: - return self._ctime - if name == self.KEY_DELETE_TS: - return self._dtime - - try: - return self._values[name] - except KeyError: - raise AttributeError("no value named '%s' in this object" % name) - - def has_value(self, name): - - if name in [SchemaClassId.KEY_PACKAGE, SchemaClassId.KEY_CLASS, - SchemaClassId.KEY_TYPE, SchemaClassId.KEY_HASH, - self.KEY_SCHEMA_ID]: - return self._schema_id is not None - if name in [self.KEY_UPDATE_TS, self.KEY_CREATE_TS, - self.KEY_DELETE_TS]: - return True - if name == self.KEY_OBJECT_ID: - return self._object_id is not None - if name == self.KEY_TAG: - return self._tag is not None - - return name in self._values - - def set_value(self, _name, _value, _subType=None): - if self._const: - raise Exception("cannot modify constant data object") - self._values[_name] = _value - if _subType: - self._subtypes[_name] = _subType - return _value - - def get_subtype(self, _name): - return self._subtypes.get(_name) - - def get_schema_class_id(self): - """ - @rtype: class SchemaClassId - @returns: the identifier of the Schema that describes the structure of the data. - """ - return self._schema_id - - def get_object_id(self): - """ - Get the instance's identification string. - @rtype: str - @returns: the identification string, or None if not assigned and id. - """ - return self._object_id - - def map_encode(self): - _map = {} - if self._tag: - _map[self.KEY_TAG] = self._tag - - # data in the _values map may require recursive map_encode() - vmap = {} - for name,val in self._values.iteritems(): - if isinstance(val, _mapEncoder): - vmap[name] = val.map_encode() - else: - # otherwise, just toss in the native type... - vmap[name] = val - - _map[self.KEY_VALUES] = vmap - # subtypes are never complex, so safe to just copy - _map[self.KEY_SUBTYPES] = self._subtypes.copy() - if self._object_id: - _map[self.KEY_OBJECT_ID] = self._object_id - if self._schema_id: - _map[self.KEY_SCHEMA_ID] = self._schema_id.map_encode() - return _map - - def __repr__(self): - return "QmfData=<<" + str(self.map_encode()) + ">>" - - - def __setattr__(self, _name, _value): - # ignore private data members - if _name[0] == '_': - return super(QmfData, self).__setattr__(_name, _value) - if _name in self._values: - return self.set_value(_name, _value) - return super(QmfData, self).__setattr__(_name, _value) - - def __getattr__(self, _name): - if _name != "_values" and _name in self._values: - return self._values[_name] - raise AttributeError("no value named '%s' in this object" % _name) - - def __getitem__(self, _name): - return self.__getattr__(_name) - - def __setitem__(self, _name, _value): - return self.__setattr__(_name, _value) - - - -class QmfEvent(QmfData): - """ - A QMF Event is a type of described data that is not managed. Events are - notifications that are sent by Agents. An event notifies a Console of a - change in some aspect of the system under managment. - """ - KEY_TIMESTAMP = "_timestamp" - KEY_SEVERITY = "_severity" - - SEV_EMERG = "emerg" - SEV_ALERT = "alert" - SEV_CRIT = "crit" - SEV_ERR = "err" - SEV_WARNING = "warning" - SEV_NOTICE = "notice" - SEV_INFO = "info" - SEV_DEBUG = "debug" - - def __init__(self, _timestamp=None, _sev=SEV_NOTICE, _values={}, - _subtypes={}, _tag=None, - _map=None, - _schema_id=None, _const=True): - """ - @type _map: dict - @param _map: if not None, construct instance from map representation. - @type _timestamp: int - @param _timestamp: moment in time when event occurred, expressed - as milliseconds since Midnight, Jan 1, 1970 UTC. - @type _agentId: class AgentId - @param _agentId: Identifies agent issuing this event. - @type _schema: class Schema - @param _schema: - @type _schemaId: class SchemaClassId (event) - @param _schemaId: identi - """ - - if _map is not None: - # construct from map - super(QmfEvent, self).__init__(_map=_map, _const=_const, - _object_id="_event") - _timestamp = _map.get(self.KEY_TIMESTAMP, _timestamp) - _sev = _map.get(self.KEY_SEVERITY, _sev) - else: - super(QmfEvent, self).__init__(_object_id="_event", - _values=_values, - _subtypes=_subtypes, _tag=_tag, - _schema_id=_schema_id, - _const=_const) - if _timestamp is None: - raise TypeError("QmfEvent: a valid timestamp is required.") - - try: - self._timestamp = long(_timestamp) - except: - raise TypeError("QmfEvent: a numeric timestamp is required.") - - self._severity = _sev - - def _create(cls, timestamp, severity, values, - _subtypes={}, _tag=None, _schema_id=None, _const=False): - return cls(_timestamp=timestamp, _sev=severity, _values=values, - _subtypes=_subtypes, _tag=_tag, _schema_id=_schema_id, _const=_const) - create = classmethod(_create) - - def _from_map(cls, map_, _const=False): - return cls(_map=map_, _const=_const) - from_map = classmethod(_from_map) - - def get_timestamp(self): - return self._timestamp - - def get_severity(self): - return self._severity - - def map_encode(self): - _map = super(QmfEvent, self).map_encode() - _map[self.KEY_TIMESTAMP] = self._timestamp - _map[self.KEY_SEVERITY] = self._severity - return _map - - - - - -#============================================================================== -#============================================================================== -#============================================================================== - - - - -class Arguments(object): - def __init__(self, map): - pass -# self.map = map -# self._by_hash = {} -# key_count = self.map.keyCount() -# a = 0 -# while a < key_count: -# self._by_hash[self.map.key(a)] = self.by_key(self.map.key(a)) -# a += 1 - - -# def __getitem__(self, key): -# return self._by_hash[key] - - -# def __setitem__(self, key, value): -# self._by_hash[key] = value -# self.set(key, value) - - -# def __iter__(self): -# return self._by_hash.__iter__ - - -# def __getattr__(self, name): -# if name in self._by_hash: -# return self._by_hash[name] -# return super.__getattr__(self, name) - - -# def __setattr__(self, name, value): -# # -# # ignore local data members -# # -# if (name[0] == '_' or -# name == 'map'): -# return super.__setattr__(self, name, value) - -# if name in self._by_hash: -# self._by_hash[name] = value -# return self.set(name, value) - -# return super.__setattr__(self, name, value) - - -# def by_key(self, key): -# val = self.map.byKey(key) -# vType = val.getType() -# if vType == TYPE_UINT8: return val.asUint() -# elif vType == TYPE_UINT16: return val.asUint() -# elif vType == TYPE_UINT32: return val.asUint() -# elif vType == TYPE_UINT64: return val.asUint64() -# elif vType == TYPE_SSTR: return val.asString() -# elif vType == TYPE_LSTR: return val.asString() -# elif vType == TYPE_ABSTIME: return val.asInt64() -# elif vType == TYPE_DELTATIME: return val.asUint64() -# elif vType == TYPE_REF: return ObjectId(val.asObjectId()) -# elif vType == TYPE_BOOL: return val.asBool() -# elif vType == TYPE_FLOAT: return val.asFloat() -# elif vType == TYPE_DOUBLE: return val.asDouble() -# elif vType == TYPE_UUID: return val.asUuid() -# elif vType == TYPE_INT8: return val.asInt() -# elif vType == TYPE_INT16: return val.asInt() -# elif vType == TYPE_INT32: return val.asInt() -# elif vType == TYPE_INT64: return val.asInt64() -# else: -# # when TYPE_MAP -# # when TYPE_OBJECT -# # when TYPE_LIST -# # when TYPE_ARRAY -# logging.error( "Unsupported Type for Get? '%s'" % str(val.getType())) -# return None - - -# def set(self, key, value): -# val = self.map.byKey(key) -# vType = val.getType() -# if vType == TYPE_UINT8: return val.setUint(value) -# elif vType == TYPE_UINT16: return val.setUint(value) -# elif vType == TYPE_UINT32: return val.setUint(value) -# elif vType == TYPE_UINT64: return val.setUint64(value) -# elif vType == TYPE_SSTR: -# if value: -# return val.setString(value) -# else: -# return val.setString('') -# elif vType == TYPE_LSTR: -# if value: -# return val.setString(value) -# else: -# return val.setString('') -# elif vType == TYPE_ABSTIME: return val.setInt64(value) -# elif vType == TYPE_DELTATIME: return val.setUint64(value) -# elif vType == TYPE_REF: return val.setObjectId(value.impl) -# elif vType == TYPE_BOOL: return val.setBool(value) -# elif vType == TYPE_FLOAT: return val.setFloat(value) -# elif vType == TYPE_DOUBLE: return val.setDouble(value) -# elif vType == TYPE_UUID: return val.setUuid(value) -# elif vType == TYPE_INT8: return val.setInt(value) -# elif vType == TYPE_INT16: return val.setInt(value) -# elif vType == TYPE_INT32: return val.setInt(value) -# elif vType == TYPE_INT64: return val.setInt64(value) -# else: -# # when TYPE_MAP -# # when TYPE_OBJECT -# # when TYPE_LIST -# # when TYPE_ARRAY -# logging.error("Unsupported Type for Set? '%s'" % str(val.getType())) -# return None - - - -#class MethodResponse(object): -# def __init__(self, impl): -# pass -# self.impl = qmfengine.MethodResponse(impl) - - -# def status(self): -# return self.impl.getStatus() - - -# def exception(self): -# return self.impl.getException() - - -# def text(self): -# return exception().asString() - - -# def args(self): -# return Arguments(self.impl.getArgs()) - - -# def __getattr__(self, name): -# myArgs = self.args() -# return myArgs.__getattr__(name) - - -# def __setattr__(self, name, value): -# if name == 'impl': -# return super.__setattr__(self, name, value) - -# myArgs = self.args() -# return myArgs.__setattr__(name, value) - - - -# ##============================================================================== -# ## QUERY -# ##============================================================================== - - - -# def _doQuery(predicate, params ): -# """ -# Given the predicate from a query, and a map of named parameters, apply the predicate -# to the parameters, and return True or False. -# """ -# if type(predicate) != list or len(predicate) < 1: -# return False - -# elif opr == Query._LOGIC_AND: -# logging.debug("_doQuery() AND: [%s]" % predicate ) -# rc = False -# for exp in predicate[1:]: -# rc = _doQuery( exp, params ) -# if not rc: -# break -# return rc - -# elif opr == Query._LOGIC_OR: -# logging.debug("_doQuery() OR: [%s]" % predicate ) -# rc = False -# for exp in predicate[1:]: -# rc = _doQuery( exp, params ) -# if rc: -# break -# return rc - -# elif opr == Query._LOGIC_NOT: -# logging.debug("_doQuery() NOT: [%s]" % predicate ) -# if len(predicate) != 2: -# logging.warning("Malformed query not-expression received: '%s'" % predicate) -# return False -# return not _doQuery( predicate[1:], params ) - - - -# else: -# logging.warning("Unknown query operator received: '%s'" % opr) -# return False - - - -class QmfQuery(_mapEncoder): - - KEY_TARGET="what" - KEY_PREDICATE="where" - KEY_ID="id" - - ### Query Types - ID=1 - PREDICATE=2 - - #### Query Targets #### - TARGET_PACKAGES="schema_package" - # (returns just package names) - # allowed predicate key(s): - # - # SchemaClassId.KEY_PACKAGE - - TARGET_SCHEMA_ID="schema_id" - TARGET_SCHEMA="schema" - # allowed id: value: - # SchemaClassId - # - # allowed predicate key(s): - # SchemaClassId.KEY_PACKAGE - # SchemaClassId.KEY_CLASS - # SchemaClassId.KEY_TYPE - # SchemaClassId.KEY_HASH - # SchemaClass.KEY_SCHEMA_ID - # name of property (exist test only) - # name of method (exist test only) - - TARGET_AGENT="agent" - # allowed id: value: - # string name of agent - # allowed predicate keys(s): - # - KEY_AGENT_NAME="_name" - - TARGET_OBJECT_ID="object_id" - TARGET_OBJECT="object" - # If object is described by a schema, the value of the target map must - # include a "_schema_id": {map encoded schema id} value. - # - # allowed id: value: - # object_id string - # - # allowed predicate keys(s): - # - # QmfData.KEY_OBJECT_ID - # QmfData.KEY_UPDATE_TS - # QmfData.KEY_CREATE_TS - # QmfData.KEY_DELETE_TS - # <name of data value> - - # supported predicate operators - - # evaluation operators - QUOTE="quote" - UNQUOTE="unquote" - # boolean operators - EQ="eq" - NE="ne" - LT="lt" - LE="le" - GT="gt" - GE="ge" - RE_MATCH="re_match" - EXISTS="exists" - TRUE="true" - FALSE="false" - # logic operators - AND="and" - OR="or" - NOT="not" - - _valid_targets = [TARGET_PACKAGES, TARGET_OBJECT_ID, TARGET_SCHEMA, TARGET_SCHEMA_ID, - TARGET_OBJECT, TARGET_AGENT] - _valid_bool_ops = [EQ, NE, LT, GT, LE, GE, EXISTS, RE_MATCH, TRUE, FALSE] - _valid_logic_ops = [AND, OR, NOT] - _valid_eval_ops = [QUOTE, UNQUOTE] - - def __init__(self, _target=None, _target_params=None, _predicate=None, - _id=None, _map=None): - """ - """ - if _map is not None: - target_map = _map.get(self.KEY_TARGET) - if not target_map: - raise TypeError("QmfQuery requires a target map") - - _target = None - for key in target_map.iterkeys(): - if key in self._valid_targets: - _target = key - break - if _target is None: - raise TypeError("Invalid QmfQuery target: '%s'" % - str(target_map)) - - # convert target params from map format - _target_params = target_map.get(_target) - if _target_params: - if not isinstance(_target_params, type({})): - raise TypeError("target params must be a map: '%s'" % - str(_target_params)) - t_params = {} - for name,value in _target_params.iteritems(): - if name == QmfData.KEY_SCHEMA_ID: - t_params[name] = SchemaClassId.from_map(value) - else: - t_params[name] = value - _target_params = t_params - - _id = _map.get(self.KEY_ID) - if _id is not None: - # Convert identifier to native type if necessary - if _target == self.TARGET_SCHEMA: - _id = SchemaClassId.from_map(_id) - else: - _predicate = _map.get(self.KEY_PREDICATE, _predicate) - - self._target = _target - if not self._target: - raise TypeError("QmfQuery requires a target value") - self._target_params = _target_params - self._predicate = _predicate - self._id = _id - - # constructors - def _create_wildcard(cls, target, _target_params=None): - return cls(_target=target, _target_params=_target_params) - create_wildcard = classmethod(_create_wildcard) - - def _create_wildcard_object_id(cls, schema_id): - """ - Create a wildcard to match all object_ids for a given schema. - """ - if not isinstance(schema_id, SchemaClassId): - raise TypeError("class SchemaClassId expected") - params = {QmfData.KEY_SCHEMA_ID: schema_id} - return cls(_target=QmfQuery.TARGET_OBJECT_ID, - _target_params=params) - create_wildcard_object_id = classmethod(_create_wildcard_object_id) - - def _create_wildcard_object(cls, schema_id): - """ - Create a wildcard to match all objects for a given schema. - """ - if not isinstance(schema_id, SchemaClassId): - raise TypeError("class SchemaClassId expected") - params = {QmfData.KEY_SCHEMA_ID: schema_id} - return cls(_target=QmfQuery.TARGET_OBJECT, - _target_params=params) - create_wildcard_object = classmethod(_create_wildcard_object) - - def _create_predicate(cls, target, predicate, _target_params=None): - return cls(_target=target, _target_params=_target_params, - _predicate=predicate) - create_predicate = classmethod(_create_predicate) - - def _create_id(cls, target, ident, _target_params=None): - return cls(_target=target, _target_params=_target_params, _id=ident) - create_id = classmethod(_create_id) - - def _create_id_object(cls, object_id, _schema_id=None): - """ - Create a ID Query for an object (schema optional). - """ - if _schema_id is not None: - if not isinstance(_schema_id, SchemaClassId): - raise TypeError("class SchemaClassId expected") - params = {QmfData.KEY_SCHEMA_ID: _schema_id} - else: - params = None - return cls(_target=QmfQuery.TARGET_OBJECT, - _id=object_id, - _target_params=params) - create_id_object = classmethod(_create_id_object) - - def _create_id_object_id(cls, object_id, _schema_id=None): - """ - Create a ID Query for object_ids (schema optional). - """ - if _schema_id is not None: - if not isinstance(_schema_id, SchemaClassId): - raise TypeError("class SchemaClassId expected") - params = {QmfData.KEY_SCHEMA_ID: _schema_id} - else: - params = None - return cls(_target=QmfQuery.TARGET_OBJECT_ID, - _id=object_id, - _target_params=params) - create_id_object_id = classmethod(_create_id_object_id) - - def _from_map(cls, map_): - return cls(_map=map_) - from_map = classmethod(_from_map) - # end constructors - - def get_target(self): - return self._target - - def get_target_param(self): - return self._target_params - - def get_selector(self): - if self._id: - return QmfQuery.ID - else: - return QmfQuery.PREDICATE - - def get_id(self): - return self._id - - def get_predicate(self): - """ - """ - return self._predicate - - def evaluate(self, qmfData): - """ - """ - if self._id: - if self._target == self.TARGET_SCHEMA: - return (qmfData.has_value(qmfData.KEY_SCHEMA_ID) and - qmfData.get_value(qmfData.KEY_SCHEMA_ID) == self._id) - elif self._target == self.TARGET_OBJECT: - return (qmfData.has_value(qmfData.KEY_OBJECT_ID) and - qmfData.get_value(qmfData.KEY_OBJECT_ID) == self._id) - elif self._target == self.TARGET_AGENT: - return (qmfData.has_value(self.KEY_AGENT_NAME) and - qmfData.get_value(self.KEY_AGENT_NAME) == self._id) - - raise Exception("Unsupported query target '%s'" % str(self._target)) - - if self._predicate: - return self._eval_pred(self._predicate, qmfData) - # no predicate and no id - always match - return True - - def map_encode(self): - t_params = {} - if self._target_params: - for name,value in self._target_params.iteritems(): - if isinstance(value, _mapEncoder): - t_params[name] = value.map_encode() - else: - t_params[name] = value - if t_params: - _map = {self.KEY_TARGET: {self._target: t_params}} - else: - _map = {self.KEY_TARGET: {self._target: None}} - - if self._id is not None: - if isinstance(self._id, _mapEncoder): - _map[self.KEY_ID] = self._id.map_encode() - else: - _map[self.KEY_ID] = self._id - elif self._predicate is not None: - _map[self.KEY_PREDICATE] = self._predicate - return _map - - def _eval_pred(self, pred, qmfData): - """ - Evaluate the predicate expression against a QmfData object. - """ - if not isinstance(qmfData, QmfData): - raise TypeError("Query expects to evaluate QmfData types.") - - if not isinstance(pred, type([])): - log_query.warning("Invalid type for predicate expression: '%s'" % str(pred)) - return False - - # empty predicate - match all??? - if len(pred) == 0: - return True - - oper = pred[0] - if oper == QmfQuery.TRUE: - log_query.debug("query evaluate TRUE") - return True - - if oper == QmfQuery.FALSE: - log_query.debug("query evaluate FALSE") - return False - - if oper == QmfQuery.AND: - log_query.debug("query evaluate AND: '%s'" % str(pred)) - for exp in pred[1:]: - if not self._eval_pred(exp, qmfData): - log_query.debug("---> False") - return False - log_query.debug("---> True") - return True - - if oper == QmfQuery.OR: - log_query.debug("query evaluate OR: [%s]" % str(pred)) - for exp in pred[1:]: - if self._eval_pred(exp, qmfData): - log_query.debug("---> True") - return True - log_query.debug("---> False") - return False - - if oper == QmfQuery.NOT: - log_query.debug("query evaluate NOT: [%s]" % str(pred)) - for exp in pred[1:]: - if self._eval_pred(exp, qmfData): - log_query.debug("---> False") - return False - log_query.debug("---> True") - return True - - if oper == QmfQuery.EXISTS: - if len(pred) != 2: - log_query.warning("Malformed query: 'exists' operator" - " - bad arguments '%s'" % str(pred)) - return False - ### Q: Should we assume "quote", or should it be explicit? - ### "foo" or ["quote" "foo"] - ### my guess is "explicit" - log_query.debug("query evaluate EXISTS: [%s]" % str(pred)) - try: - arg = self._fetch_pred_arg(pred[1], qmfData) - except AttributeError: - log_query.debug("query parameter not found: '%s'" % str(pred)) - return False - v = qmfData.has_value(arg) - log_query.debug("---> %s" % str(v)) - return v - - # binary operators - if oper in [QmfQuery.EQ, QmfQuery.NE, QmfQuery.LT, - QmfQuery.LE, QmfQuery.GT, QmfQuery.GE, - QmfQuery.RE_MATCH]: - if len(pred) != 3: - log_query.warning("Malformed query: '%s' operator" - " - requires 2 arguments '%s'" % - (oper, str(pred))) - return False - # @todo: support regular expression match - log_query.debug("query evaluate binary op: [%s]" % str(pred)) - try: - arg1 = self._fetch_pred_arg(pred[1], qmfData) - arg2 = self._fetch_pred_arg(pred[2], qmfData) - except AttributeError: - log_query.debug("query parameter not found: '%s'" % str(pred)) - return False - log_query.debug("query evaluate %s: %s, %s" % (oper, str(arg1), str(arg2))) - v = False - try: - if oper == QmfQuery.EQ: v = arg1 == arg2 - elif oper == QmfQuery.NE: v = arg1 != arg2 - elif oper == QmfQuery.LT: v = arg1 < arg2 - elif oper == QmfQuery.LE: v = arg1 <= arg2 - elif oper == QmfQuery.GT: v = arg1 > arg2 - elif oper == QmfQuery.GE: v = arg1 >= arg2 - except TypeError: - log_query.warning("query comparison failed: '%s'" % str(pred)) - log_query.debug("---> %s" % str(v)) - return v - - log_query.warning("Unrecognized query operator: [%s]" % str(pred[0])) - return False - - def _fetch_pred_arg(self, arg, qmfData): - """ - Determine the value of a predicate argument by evaluating quoted - arguments. - """ - if isinstance(arg, basestring): - return qmfData.get_value(arg) - if isinstance(arg, type([])) and len(arg) == 2: - if arg[0] == QmfQuery.QUOTE: - return arg[1] - if arg[0] == QmfQuery.UNQUOTE: - return qmfData.get_value(arg[1]) - return arg - - def __repr__(self): - return "QmfQuery=<<" + str(self.map_encode()) + ">>" - - - - - -##============================================================================== -## SCHEMA -##============================================================================== - - -# Argument typecodes, access, and direction qualifiers - -class qmfTypes(object): - TYPE_UINT8 = 1 - TYPE_UINT16 = 2 - TYPE_UINT32 = 3 - TYPE_UINT64 = 4 - - TYPE_SSTR = 6 - TYPE_LSTR = 7 - - TYPE_ABSTIME = 8 - TYPE_DELTATIME = 9 - - TYPE_REF = 10 - - TYPE_BOOL = 11 - - TYPE_FLOAT = 12 - TYPE_DOUBLE = 13 - - TYPE_UUID = 14 - - TYPE_MAP = 15 - - TYPE_INT8 = 16 - TYPE_INT16 = 17 - TYPE_INT32 = 18 - TYPE_INT64 = 19 - - TYPE_OBJECT = 20 - - TYPE_LIST = 21 - - TYPE_ARRAY = 22 - -# New subtypes: -# integer (for time, duration, signed/unsigned) -# double (float) -# bool -# string -# map (ref, qmfdata) -# list -# uuid - - -class qmfAccess(object): - READ_CREATE = 1 - READ_WRITE = 2 - READ_ONLY = 3 - - -class qmfDirection(object): - DIR_IN = 1 - DIR_OUT = 2 - DIR_IN_OUT = 3 - - - -def _to_bool( param ): - """ - Helper routine to convert human-readable representations of - boolean values to python bool types. - """ - _false_strings = ["off", "no", "false", "0", "none"] - _true_strings = ["on", "yes", "true", "1"] - if type(param) == str: - lparam = param.lower() - if lparam in _false_strings: - return False - if lparam in _true_strings: - return True - raise TypeError("unrecognized boolean string: '%s'" % param ) - else: - return bool(param) - - - -class SchemaClassId(_mapEncoder): - """ - Unique identifier for an instance of a SchemaClass. - - Map format: - map["package_name"] = str, name of associated package - map["class_name"] = str, name of associated class - map["type"] = str, "data"|"event", default: "data" - optional: - map["hash_str"] = str, hash value in standard format or None - if hash is unknown. - """ - KEY_PACKAGE="_package_name" - KEY_CLASS="_class_name" - KEY_TYPE="_type" - KEY_HASH="_hash_str" - - TYPE_DATA = "_data" - TYPE_EVENT = "_event" - - _valid_types=[TYPE_DATA, TYPE_EVENT] - _schemaHashStrFormat = "%08x-%08x-%08x-%08x" - _schemaHashStrDefault = "00000000-00000000-00000000-00000000" - - def __init__(self, pname=None, cname=None, stype=TYPE_DATA, hstr=None, - _map=None): - """ - @type pname: str - @param pname: the name of the class's package - @type cname: str - @param cname: name of the class - @type stype: str - @param stype: schema type [data | event] - @type hstr: str - @param hstr: the hash value in '%08x-%08x-%08x-%08x' format - """ - if _map is not None: - # construct from map - pname = _map.get(self.KEY_PACKAGE, pname) - cname = _map.get(self.KEY_CLASS, cname) - stype = _map.get(self.KEY_TYPE, stype) - hstr = _map.get(self.KEY_HASH, hstr) - - self._pname = pname - self._cname = cname - if stype not in SchemaClassId._valid_types: - raise TypeError("Invalid SchemaClassId type: '%s'" % stype) - self._type = stype - self._hstr = hstr - if self._hstr: - try: - # sanity check the format of the hash string - hexValues = hstr.split("-") - h0 = int(hexValues[0], 16) - h1 = int(hexValues[1], 16) - h2 = int(hexValues[2], 16) - h3 = int(hexValues[3], 16) - except: - raise Exception("Invalid SchemaClassId format: bad hash string: '%s':" - % hstr) - # constructor - def _create(cls, pname, cname, stype=TYPE_DATA, hstr=None): - return cls(pname=pname, cname=cname, stype=stype, hstr=hstr) - create = classmethod(_create) - - # map constructor - def _from_map(cls, map_): - return cls(_map=map_) - from_map = classmethod(_from_map) - - def get_package_name(self): - """ - Access the package name in the SchemaClassId. - - @rtype: str - """ - return self._pname - - - def get_class_name(self): - """ - Access the class name in the SchemaClassId - - @rtype: str - """ - return self._cname - - - def get_hash_string(self): - """ - Access the schema's hash as a string value - - @rtype: str - """ - return self._hstr - - - def get_type(self): - """ - Returns the type code associated with this Schema - - @rtype: str - """ - return self._type - - def map_encode(self): - _map = {} - _map[self.KEY_PACKAGE] = self._pname - _map[self.KEY_CLASS] = self._cname - _map[self.KEY_TYPE] = self._type - if self._hstr: _map[self.KEY_HASH] = self._hstr - return _map - - def __repr__(self): - hstr = self.get_hash_string() - if not hstr: - hstr = SchemaClassId._schemaHashStrDefault - return self._pname + ":" + self._cname + ":" + self._type + "(" + hstr + ")" - - - def __cmp__(self, other): - if isinstance(other, dict): - other = SchemaClassId.from_map(other) - if not isinstance(other, SchemaClassId): - raise TypeError("Invalid types for compare") - # return 1 - me = str(self) - them = str(other) - if me < them: - return -1 - if me > them: - return 1 - return 0 - - - def __hash__(self): - return (self._pname, self._cname, self._hstr).__hash__() - - - -class SchemaProperty(_mapEncoder): - """ - Describes the structure of a Property data object. - Map format: - map["amqp_type"] = int, AMQP type code indicating property's data type - - optional: - map["access"] = str, access allowed to this property, default "RO" - map["index"] = bool, True if this property is an index value, default False - map["optional"] = bool, True if this property is optional, default False - map["unit"] = str, describes units used - map["min"] = int, minimum allowed value - map["max"] = int, maximun allowed value - map["maxlen"] = int, if string type, this is the maximum length in bytes - required to represent the longest instance of this string. - map["desc"] = str, human-readable description of this argument - map["reference"] = str, ??? - map["parent_ref"] = bool, true if this property references an object in - which this object is in a child-parent relationship. Default False - """ - __hash__ = None - _access_strings = ["RO","RW","RC"] - _dir_strings = ["I", "O", "IO"] - def __init__(self, _type_code=None, _map=None, kwargs={}): - if _map is not None: - # construct from map - _type_code = _map.get("amqp_type", _type_code) - kwargs = _map - if not _type_code: - raise TypeError("SchemaProperty: amqp_type is a mandatory" - " parameter") - - self._type = _type_code - self._access = "RO" - self._isIndex = False - self._isOptional = False - self._unit = None - self._min = None - self._max = None - self._maxlen = None - self._desc = None - self._reference = None - self._isParentRef = False - self._dir = None - self._default = None - - for key, value in kwargs.items(): - if key == "access": - value = str(value).upper() - if value not in self._access_strings: - raise TypeError("invalid value for access parameter: '%s':" % value ) - self._access = value - elif key == "index" : self._isIndex = _to_bool(value) - elif key == "optional": self._isOptional = _to_bool(value) - elif key == "unit" : self._unit = value - elif key == "min" : self._min = value - elif key == "max" : self._max = value - elif key == "maxlen" : self._maxlen = value - elif key == "desc" : self._desc = value - elif key == "reference" : self._reference = value - elif key == "parent_ref" : self._isParentRef = _to_bool(value) - elif key == "dir": - value = str(value).upper() - if value not in self._dir_strings: - raise TypeError("invalid value for direction parameter: '%s'" % value) - self._dir = value - elif key == "default" : self._default = value - - # constructor - def _create(cls, type_code, kwargs={}): - return cls(_type_code=type_code, kwargs=kwargs) - create = classmethod(_create) - - # map constructor - def _from_map(cls, map_): - return cls(_map=map_) - from_map = classmethod(_from_map) - - def get_type(self): return self._type - - def get_access(self): return self._access - - def is_optional(self): return self._isOptional - - def is_index(self): return self._isIndex - - def get_unit(self): return self._unit - - def get_min(self): return self._min - - def get_max(self): return self._max - - def get_max_len(self): return self._maxlen - - def get_desc(self): return self._desc - - def get_reference(self): return self._reference - - def is_parent_ref(self): return self._isParentRef - - def get_direction(self): return self._dir - - def get_default(self): return self._default - - def map_encode(self): - """ - Return the map encoding of this schema. - """ - _map = {} - _map["amqp_type"] = self._type - _map["access"] = self._access - _map["index"] = self._isIndex - _map["optional"] = self._isOptional - if self._unit: _map["unit"] = self._unit - if self._min: _map["min"] = self._min - if self._max: _map["max"] = self._max - if self._maxlen: _map["maxlen"] = self._maxlen - if self._desc: _map["desc"] = self._desc - if self._reference: _map["reference"] = self._reference - _map["parent_ref"] = self._isParentRef - if self._dir: _map["dir"] = self._dir - if self._default: _map["default"] = self._default - return _map - - def __repr__(self): - return "SchemaProperty=<<" + str(self.map_encode()) + ">>" - - def _update_hash(self, hasher): - """ - Update the given hash object with a hash computed over this schema. - """ - hasher.update(str(self._type)) - hasher.update(str(self._isIndex)) - hasher.update(str(self._isOptional)) - if self._access: hasher.update(self._access) - if self._unit: hasher.update(self._unit) - if self._desc: hasher.update(self._desc) - if self._dir: hasher.update(self._dir) - if self._default: hasher.update(self._default) - - - -class SchemaMethod(_mapEncoder): - """ - The SchemaMethod class describes the method's structure, and contains a - SchemaProperty class for each argument declared by the method. - - Map format: - map["arguments"] = map of "name"=<SchemaProperty> pairs. - map["desc"] = str, description of the method - """ - KEY_NAME="_name" - KEY_ARGUMENTS="_arguments" - KEY_DESC="_desc" - KEY_ERROR="_error" - def __init__(self, _args={}, _desc=None, _map=None): - """ - Construct a SchemaMethod. - - @type args: map of "name"=<SchemaProperty> objects - @param args: describes the arguments accepted by the method - @type _desc: str - @param _desc: Human-readable description of the schema - """ - if _map is not None: - _desc = _map.get(self.KEY_DESC) - margs = _map.get(self.KEY_ARGUMENTS) - if margs: - # margs are in map format - covert to SchemaProperty - tmp_args = {} - for name,val in margs.iteritems(): - tmp_args[name] = SchemaProperty.from_map(val) - _args=tmp_args - - self._arguments = _args.copy() - self._desc = _desc - - # map constructor - def _from_map(cls, map_): - return cls(_map=map_) - from_map = classmethod(_from_map) - - def get_desc(self): return self._desc - - def get_arg_count(self): return len(self._arguments) - - def get_arguments(self): return self._arguments.copy() - - def get_argument(self, name): return self._arguments.get(name) - - def add_argument(self, name, schema): - """ - Add an argument to the list of arguments passed to this method. - Used by an agent for dynamically creating method schema. - - @type name: string - @param name: name of new argument - @type schema: SchemaProperty - @param schema: SchemaProperty to add to this method - """ - if not isinstance(schema, SchemaProperty): - raise TypeError("argument must be a SchemaProperty class") - # "Input" argument, by default - if schema._dir is None: - schema._dir = "I" - self._arguments[name] = schema - - def map_encode(self): - """ - Return the map encoding of this schema. - """ - _map = {} - _args = {} - for name,val in self._arguments.iteritems(): - _args[name] = val.map_encode() - _map[self.KEY_ARGUMENTS] = _args - if self._desc: _map[self.KEY_DESC] = self._desc - return _map - - def __repr__(self): - result = "SchemaMethod=<<args=(" - first = True - for name,arg in self._arguments.iteritems(): - if first: - first = False - else: - result += ", " - result += name - result += ")>>" - return result - - def _update_hash(self, hasher): - """ - Update the given hash object with a hash computed over this schema. - """ - for name,val in self._arguments.iteritems(): - hasher.update(name) - val._update_hash(hasher) - if self._desc: hasher.update(self._desc) - - - -class SchemaClass(QmfData): - """ - Base class for Data and Event Schema classes. - - Map format: - map(QmfData), plus: - map["_schema_id"] = map representation of a SchemaClassId instance - map["_primary_key_names"] = order list of primary key names - """ - KEY_PRIMARY_KEY_NAMES="_primary_key_names" - KEY_DESC = "_desc" - - SUBTYPE_PROPERTY="qmfProperty" - SUBTYPE_METHOD="qmfMethod" - - def __init__(self, _classId=None, _desc=None, _map=None): - """ - Schema Class constructor. - - @type classId: class SchemaClassId - @param classId: Identifier for this SchemaClass - @type _desc: str - @param _desc: Human-readable description of the schema - """ - if _map is not None: - super(SchemaClass, self).__init__(_map=_map) - - # decode each value based on its type - for name,value in self._values.iteritems(): - if self._subtypes.get(name) == self.SUBTYPE_METHOD: - self._values[name] = SchemaMethod.from_map(value) - else: - self._values[name] = SchemaProperty.from_map(value) - cid = _map.get(self.KEY_SCHEMA_ID) - if cid: - _classId = SchemaClassId.from_map(cid) - self._object_id_names = _map.get(self.KEY_PRIMARY_KEY_NAMES,[]) - _desc = _map.get(self.KEY_DESC) - else: - if _classId is None: - raise Exception("A class identifier must be supplied.") - super(SchemaClass, self).__init__(_object_id=str(_classId)) - self._object_id_names = [] - - self._classId = _classId - self._desc = _desc - - def get_class_id(self): - if not self._classId.get_hash_string(): - self.generate_hash() - return self._classId - - def get_desc(self): return self._desc - - def generate_hash(self): - """ - generate an md5 hash over the body of the schema, - and return a string representation of the hash - in format "%08x-%08x-%08x-%08x" - """ - md5Hash = _md5Obj() - md5Hash.update(self._classId.get_package_name()) - md5Hash.update(self._classId.get_class_name()) - md5Hash.update(self._classId.get_type()) - for name,x in self._values.iteritems(): - md5Hash.update(name) - x._update_hash( md5Hash ) - for name,value in self._subtypes.iteritems(): - md5Hash.update(name) - md5Hash.update(value) - idx = 0 - for name in self._object_id_names: - md5Hash.update(str(idx) + name) - idx += 1 - hstr = md5Hash.hexdigest()[0:8] + "-" +\ - md5Hash.hexdigest()[8:16] + "-" +\ - md5Hash.hexdigest()[16:24] + "-" +\ - md5Hash.hexdigest()[24:32] - # update classId with new hash value - self._classId._hstr = hstr - return hstr - - - def get_property_count(self): - count = 0 - for value in self._subtypes.itervalues(): - if value == self.SUBTYPE_PROPERTY: - count += 1 - return count - - def get_properties(self): - props = {} - for name,value in self._subtypes.iteritems(): - if value == self.SUBTYPE_PROPERTY: - props[name] = self._values.get(name) - return props - - def get_property(self, name): - if self._subtypes.get(name) == self.SUBTYPE_PROPERTY: - return self._values.get(name) - return None - - def add_property(self, name, prop): - self.set_value(name, prop, self.SUBTYPE_PROPERTY) - # need to re-generate schema hash - self._classId._hstr = None - - def get_value(self, name): - # check for meta-properties first - if name == SchemaClassId.KEY_PACKAGE: - return self._classId.get_package_name() - if name == SchemaClassId.KEY_CLASS: - return self._classId.get_class_name() - if name == SchemaClassId.KEY_TYPE: - return self._classId.get_type() - if name == SchemaClassId.KEY_HASH: - return self.get_class_id().get_hash_string() - if name == self.KEY_SCHEMA_ID: - return self.get_class_id() - if name == self.KEY_PRIMARY_KEY_NAMES: - return self._object_id_names[:] - return super(SchemaClass, self).get_value(name) - - def has_value(self, name): - if name in [SchemaClassId.KEY_PACKAGE, SchemaClassId.KEY_CLASS, SchemaClassId.KEY_TYPE, - SchemaClassId.KEY_HASH, self.KEY_SCHEMA_ID, self.KEY_PRIMARY_KEY_NAMES]: - return True - super(SchemaClass, self).has_value(name) - - def map_encode(self): - """ - Return the map encoding of this schema. - """ - _map = super(SchemaClass,self).map_encode() - _map[self.KEY_SCHEMA_ID] = self.get_class_id().map_encode() - if self._object_id_names: - _map[self.KEY_PRIMARY_KEY_NAMES] = self._object_id_names[:] - if self._desc: - _map[self.KEY_DESC] = self._desc - return _map - - def __repr__(self): - return str(self.get_class_id()) - - - -class SchemaObjectClass(SchemaClass): - """ - A schema class that describes a data object. The data object is composed - of zero or more properties and methods. An instance of the SchemaObjectClass - can be identified using a key generated by concantenating the values of - all properties named in the primary key list. - - Map format: - map(SchemaClass) - """ - def __init__(self, _classId=None, _desc=None, - _props={}, _methods={}, _object_id_names=[], - _map=None): - """ - @type pname: str - @param pname: name of package this schema belongs to - @type cname: str - @param cname: class name for this schema - @type desc: str - @param desc: Human-readable description of the schema - @type _hash: str - @param _methods: hash computed on the body of this schema, if known - @type _props: map of 'name':<SchemaProperty> objects - @param _props: all properties provided by this schema - @type _pkey: list of strings - @param _pkey: names of each property to be used for constructing the primary key - @type _methods: map of 'name':<SchemaMethod> objects - @param _methods: all methods provided by this schema - """ - if _map is not None: - super(SchemaObjectClass,self).__init__(_map=_map) - else: - super(SchemaObjectClass, self).__init__(_classId=_classId, _desc=_desc) - self._object_id_names = _object_id_names - for name,value in _props.iteritems(): - self.set_value(name, value, self.SUBTYPE_PROPERTY) - for name,value in _methods.iteritems(): - self.set_value(name, value, self.SUBTYPE_METHOD) - - if self._classId.get_type() != SchemaClassId.TYPE_DATA: - raise TypeError("Invalid ClassId type for data schema: %s" % self._classId) - - # map constructor - def __from_map(cls, map_): - return cls(_map=map_) - from_map = classmethod(__from_map) - - def get_id_names(self): - return self._object_id_names[:] - - def get_method_count(self): - count = 0 - for value in self._subtypes.itervalues(): - if value == self.SUBTYPE_METHOD: - count += 1 - return count - - def get_methods(self): - meths = {} - for name,value in self._subtypes.iteritems(): - if value == self.SUBTYPE_METHOD: - meths[name] = self._values.get(name) - return meths - - def get_method(self, name): - if self._subtypes.get(name) == self.SUBTYPE_METHOD: - return self._values.get(name) - return None - - def add_method(self, name, method): - self.set_value(name, method, self.SUBTYPE_METHOD) - # need to re-generate schema hash - self._classId._hstr = None - - - - -class SchemaEventClass(SchemaClass): - """ - A schema class that describes an event. The event is composed - of zero or more properties. - - Map format: - map["schema_id"] = map, SchemaClassId map for this object. - map["desc"] = string description of this schema - map["properties"] = map of "name":SchemaProperty values. - """ - def __init__(self, _classId=None, _desc=None, _props={}, - _map=None): - if _map is not None: - super(SchemaEventClass,self).__init__(_map=_map) - else: - super(SchemaEventClass, self).__init__(_classId=_classId, - _desc=_desc) - for name,value in _props.iteritems(): - self.set_value(name, value, self.SUBTYPE_PROPERTY) - - if self._classId.get_type() != SchemaClassId.TYPE_EVENT: - raise TypeError("Invalid ClassId type for event schema: %s" % - self._classId) - - # map constructor - def __from_map(cls, map_): - return cls(_map=map_) - from_map = classmethod(__from_map) - diff --git a/python/qmf2/console.py b/python/qmf2/console.py deleted file mode 100644 index c13cf70755..0000000000 --- a/python/qmf2/console.py +++ /dev/null @@ -1,2295 +0,0 @@ -# -# 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. -# -import sys -import os -import logging -import platform -import time -import datetime -import Queue -from threading import Thread, Event -from threading import Lock -from threading import currentThread -from threading import Condition - -from qpid.messaging import Connection, Message, Empty, SendError - -from common import (make_subject, parse_subject, OpCode, QmfQuery, Notifier, - MsgKey, QmfData, QmfAddress, SchemaClass, SchemaClassId, - SchemaEventClass, SchemaObjectClass, WorkItem, - SchemaMethod, QmfEvent, timedelta_to_secs) - - -# global flag that indicates which thread (if any) is -# running the console notifier callback -_callback_thread=None - - - - -##============================================================================== -## Console Transaction Management -## -## At any given time, a console application may have multiple outstanding -## message transactions with agents. The following objects allow the console -## to track these outstanding transactions. -##============================================================================== - - -class _Mailbox(object): - """ - Virtual base class for all Mailbox-like objects. - """ - def __init__(self, console): - self.console = console - self.cid = 0 - self.console._add_mailbox(self) - - def get_address(self): - return self.cid - - def deliver(self, data): - """ - Invoked by Console Management thread when a message arrives for - this mailbox. - """ - raise Exception("_Mailbox deliver() method must be provided") - - def destroy(self): - """ - Release the mailbox. Once called, the mailbox should no longer be - referenced. - """ - self.console._remove_mailbox(self.cid) - - -class _SyncMailbox(_Mailbox): - """ - A simple mailbox that allows a consumer to wait for delivery of data. - """ - def __init__(self, console): - """ - Invoked by application thread. - """ - super(_SyncMailbox, self).__init__(console) - self._cv = Condition() - self._data = [] - self._waiting = False - - def deliver(self, data): - """ - Drop data into the mailbox, waking any waiters if necessary. - Invoked by Console Management thread only. - """ - self._cv.acquire() - try: - self._data.append(data) - # if was empty, notify waiters - if len(self._data) == 1: - self._cv.notify() - finally: - self._cv.release() - - def fetch(self, timeout=None): - """ - Get one data item from a mailbox, with timeout. - Invoked by application thread. - """ - self._cv.acquire() - try: - if len(self._data) == 0: - self._cv.wait(timeout) - if len(self._data): - return self._data.pop(0) - return None - finally: - self._cv.release() - - -class _AsyncMailbox(_Mailbox): - """ - A Mailbox for asynchronous delivery, with a timeout value. - """ - def __init__(self, console, - _timeout=None): - """ - Invoked by application thread. - """ - super(_AsyncMailbox, self).__init__(console) - self.console = console - - if _timeout is None: - _timeout = console._reply_timeout - self.expiration_date = (datetime.datetime.utcnow() + - datetime.timedelta(seconds=_timeout)) - console._lock.acquire() - try: - console._async_mboxes[self.cid] = self - finally: - console._lock.release() - - # now that an async mbox has been created, wake the - # console mgmt thread so it will know about the mbox expiration - # date (and adjust its idle sleep period correctly) - - console._wake_thread() - - def deliver(self, msg): - """ - """ - raise Exception("deliver() method must be provided") - - def expire(self): - raise Exception("expire() method must be provided") - - - def destroy(self): - self.console._lock.acquire() - try: - if self.cid in self.console._async_mboxes: - del self.console._async_mboxes[self.cid] - finally: - self.console._lock.release() - super(_AsyncMailbox, self).destroy() - - - -class _QueryMailbox(_AsyncMailbox): - """ - A mailbox used for asynchronous query requests. - """ - def __init__(self, console, - agent_name, - context, - target, msgkey, - _timeout=None): - """ - Invoked by application thread. - """ - super(_QueryMailbox, self).__init__(console, - _timeout) - self.agent_name = agent_name - self.target = target - self.msgkey = msgkey - self.context = context - self.result = [] - - def deliver(self, reply): - """ - Process query response messages delivered to this mailbox. - Invoked by Console Management thread only. - """ - done = False - objects = reply.content.get(self.msgkey) - if not objects: - done = True - else: - # convert from map to native types if needed - if self.target == QmfQuery.TARGET_SCHEMA_ID: - for sid_map in objects: - self.result.append(SchemaClassId.from_map(sid_map)) - - elif self.target == QmfQuery.TARGET_SCHEMA: - for schema_map in objects: - # extract schema id, convert based on schema type - sid_map = schema_map.get(SchemaClass.KEY_SCHEMA_ID) - if sid_map: - sid = SchemaClassId.from_map(sid_map) - if sid: - if sid.get_type() == SchemaClassId.TYPE_DATA: - schema = SchemaObjectClass.from_map(schema_map) - else: - schema = SchemaEventClass.from_map(schema_map) - self.console._add_schema(schema) # add to schema cache - self.result.append(schema) - - elif self.target == QmfQuery.TARGET_OBJECT: - for obj_map in objects: - # @todo: need the agent name - ideally from the - # reply message iself. - agent = self.console.get_agent(self.agent_name) - if agent: - obj = QmfConsoleData(map_=obj_map, agent=agent) - # start fetch of schema if not known - sid = obj.get_schema_class_id() - if sid: - self.console._prefetch_schema(sid, agent) - self.result.append(obj) - - - else: - # no conversion needed. - self.result += objects - - if done: - # create workitem - # logging.error("QUERY COMPLETE for %s" % str(self.context)) - wi = WorkItem(WorkItem.QUERY_COMPLETE, self.context, self.result) - self.console._work_q.put(wi) - self.console._work_q_put = True - - self.destroy() - - - def expire(self): - logging.debug("ASYNC MAILBOX EXPIRED @ %s!!!" % - datetime.datetime.utcnow()) - # send along whatever (possibly none) has been received so far - wi = WorkItem(WorkItem.QUERY_COMPLETE, self.context, self.result) - self.console._work_q.put(wi) - self.console._work_q_put = True - - self.destroy() - - - -class _SchemaPrefetchMailbox(_AsyncMailbox): - """ - Handles responses to schema fetches made by the console. - """ - def __init__(self, console, - schema_id, - _timeout=None): - """ - Invoked by application thread. - """ - super(_SchemaPrefetchMailbox, self).__init__(console, - _timeout) - self.schema_id = schema_id - - def deliver(self, reply): - """ - Process schema response messages. - """ - done = False - schemas = reply.content.get(MsgKey.schema) - if schemas: - for schema_map in schemas: - # extract schema id, convert based on schema type - sid_map = schema_map.get(SchemaClass.KEY_SCHEMA_ID) - if sid_map: - sid = SchemaClassId.from_map(sid_map) - if sid: - if sid.get_type() == SchemaClassId.TYPE_DATA: - schema = SchemaObjectClass.from_map(schema_map) - else: - schema = SchemaEventClass.from_map(schema_map) - self.console._add_schema(schema) # add to schema cache - self.destroy() - - - def expire(self): - self.destroy() - - - -class _MethodMailbox(_AsyncMailbox): - """ - A mailbox used for asynchronous method requests. - """ - def __init__(self, console, - context, - _timeout=None): - """ - Invoked by application thread. - """ - super(_MethodMailbox, self).__init__(console, - _timeout) - self.context = context - - def deliver(self, reply): - """ - Process method response messages delivered to this mailbox. - Invoked by Console Management thread only. - """ - - _map = reply.content.get(MsgKey.method) - if not _map: - logging.error("Invalid method call reply message") - result = None - else: - error=_map.get(SchemaMethod.KEY_ERROR) - if error: - error = QmfData.from_map(error) - result = MethodResult(_error=error) - else: - result = MethodResult(_out_args=_map.get(SchemaMethod.KEY_ARGUMENTS)) - - # create workitem - wi = WorkItem(WorkItem.METHOD_RESPONSE, self.context, result) - self.console._work_q.put(wi) - self.console._work_q_put = True - - self.destroy() - - - def expire(self): - """ - The mailbox expired without receiving a reply. - Invoked by the Console Management thread only. - """ - logging.debug("ASYNC MAILBOX EXPIRED @ %s!!!" % - datetime.datetime.utcnow()) - # send along an empty response - wi = WorkItem(WorkItem.METHOD_RESPONSE, self.context, None) - self.console._work_q.put(wi) - self.console._work_q_put = True - - self.destroy() - - - -##============================================================================== -## DATA MODEL -##============================================================================== - - -class QmfConsoleData(QmfData): - """ - Console's representation of an managed QmfData instance. - """ - def __init__(self, map_, agent): - super(QmfConsoleData, self).__init__(_map=map_, - _const=True) - self._agent = agent - - def get_timestamps(self): - """ - Returns a list of timestamps describing the lifecycle of - the object. All timestamps are represented by the AMQP - timestamp type. [0] = time of last update from Agent, - [1] = creation timestamp - [2] = deletion timestamp, or zero if not - deleted. - """ - return [self._utime, self._ctime, self._dtime] - - def get_create_time(self): - """ - returns the creation timestamp - """ - return self._ctime - - def get_update_time(self): - """ - returns the update timestamp - """ - return self._utime - - def get_delete_time(self): - """ - returns the deletion timestamp, or zero if not yet deleted. - """ - return self._dtime - - def is_deleted(self): - """ - True if deletion timestamp not zero. - """ - return self._dtime != long(0) - - def refresh(self, _reply_handle=None, _timeout=None): - """ - request that the Agent update the value of this object's - contents. - """ - if _reply_handle is not None: - logging.error(" ASYNC REFRESH TBD!!!") - return None - - assert self._agent - assert self._agent._console - - if _timeout is None: - _timeout = self._agent._console._reply_timeout - - # create query to agent using this objects ID - query = QmfQuery.create_id_object(self.get_object_id(), - self.get_schema_class_id()) - obj_list = self._agent._console.do_query(self._agent, query, - _timeout=_timeout) - if obj_list is None or len(obj_list) != 1: - return None - - self._update(obj_list[0]) - return self - - - def invoke_method(self, name, _in_args={}, _reply_handle=None, - _timeout=None): - """ - Invoke the named method on this object. - """ - assert self._agent - assert self._agent._console - - oid = self.get_object_id() - if oid is None: - raise ValueError("Cannot invoke methods on unmanaged objects.") - - if _timeout is None: - _timeout = self._agent._console._reply_timeout - - if _reply_handle is not None: - mbox = _MethodMailbox(self._agent._console, - _reply_handle) - else: - mbox = _SyncMailbox(self._agent._console) - cid = mbox.get_address() - - _map = {self.KEY_OBJECT_ID:str(oid), - SchemaMethod.KEY_NAME:name} - - sid = self.get_schema_class_id() - if sid: - _map[self.KEY_SCHEMA_ID] = sid.map_encode() - if _in_args: - _map[SchemaMethod.KEY_ARGUMENTS] = _in_args - - logging.debug("Sending method req to Agent (%s)" % time.time()) - try: - self._agent._send_method_req(_map, cid) - except SendError, e: - logging.error(str(e)) - mbox.destroy() - return None - - if _reply_handle is not None: - return True - - logging.debug("Waiting for response to method req (%s)" % _timeout) - replyMsg = mbox.fetch(_timeout) - mbox.destroy() - - if not replyMsg: - logging.debug("Agent method req wait timed-out.") - return None - - _map = replyMsg.content.get(MsgKey.method) - if not _map: - logging.error("Invalid method call reply message") - return None - - error=_map.get(SchemaMethod.KEY_ERROR) - if error: - return MethodResult(_error=QmfData.from_map(error)) - else: - return MethodResult(_out_args=_map.get(SchemaMethod.KEY_ARGUMENTS)) - - def _update(self, newer): - super(QmfConsoleData,self).__init__(_values=newer._values, _subtypes=newer._subtypes, - _tag=newer._tag, _object_id=newer._object_id, - _ctime=newer._ctime, _utime=newer._utime, - _dtime=newer._dtime, - _schema_id=newer._schema_id, _const=True) - -class QmfLocalData(QmfData): - """ - Console's representation of an unmanaged QmfData instance. There - is no remote agent associated with this instance. The Console has - full control over this instance. - """ - def __init__(self, values, _subtypes={}, _tag=None, _object_id=None, - _schema=None): - # timestamp in millisec since epoch UTC - ctime = long(time.time() * 1000) - super(QmfLocalData, self).__init__(_values=values, - _subtypes=_subtypes, _tag=_tag, - _object_id=_object_id, - _schema=_schema, _ctime=ctime, - _utime=ctime, _const=False) - - -class Agent(object): - """ - A local representation of a remote agent managed by this console. - """ - def __init__(self, name, console): - """ - @type name: string - @param name: uniquely identifies this agent in the AMQP domain. - """ - - if not isinstance(console, Console): - raise TypeError("parameter must be an instance of class Console") - - self._name = name - self._address = QmfAddress.direct(name, console._domain) - self._console = console - self._sender = None - self._packages = {} # map of {package-name:[list of class-names], } for this agent - self._subscriptions = [] # list of active standing subscriptions for this agent - self._announce_timestamp = None # datetime when last announce received - logging.debug( "Created Agent with address: [%s]" % self._address ) - - - def get_name(self): - return self._name - - def is_active(self): - return self._announce_timestamp != None - - def _send_msg(self, msg, correlation_id=None): - """ - Low-level routine to asynchronously send a message to this agent. - """ - msg.reply_to = str(self._console._address) - if correlation_id: - msg.correlation_id = str(correlation_id) - # TRACE - #logging.error("!!! Console %s sending to agent %s (%s)" % - # (self._console._name, self._name, str(msg))) - self._sender.send(msg) - # return handle - - def get_packages(self): - """ - Return a list of the names of all packages known to this agent. - """ - return self._packages.keys() - - def get_classes(self): - """ - Return a dictionary [key:class] of classes known to this agent. - """ - return self._packages.copy() - - def get_objects(self, query, kwargs={}): - """ - Return a list of objects that satisfy the given query. - - @type query: dict, or common.Query - @param query: filter for requested objects - @type kwargs: dict - @param kwargs: ??? used to build match selector and query ??? - @rtype: list - @return: list of matching objects, or None. - """ - pass - - def get_object(self, query, kwargs={}): - """ - Get one object - query is expected to match only one object. - ??? Recommended: explicit timeout param, default None ??? - - @type query: dict, or common.Query - @param query: filter for requested objects - @type kwargs: dict - @param kwargs: ??? used to build match selector and query ??? - @rtype: qmfConsole.ObjectProxy - @return: one matching object, or none - """ - pass - - - def create_subscription(self, query): - """ - Factory for creating standing subscriptions based on a given query. - - @type query: common.Query object - @param query: determines the list of objects for which this subscription applies - @rtype: qmfConsole.Subscription - @returns: an object representing the standing subscription. - """ - pass - - - def invoke_method(self, name, _in_args={}, _reply_handle=None, - _timeout=None): - """ - Invoke the named method on this agent. - """ - assert self._console - - if _timeout is None: - _timeout = self._console._reply_timeout - - if _reply_handle is not None: - mbox = _MethodMailbox(self._console, - _reply_handle) - else: - mbox = _SyncMailbox(self._console) - cid = mbox.get_address() - - _map = {SchemaMethod.KEY_NAME:name} - if _in_args: - _map[SchemaMethod.KEY_ARGUMENTS] = _in_args.copy() - - logging.debug("Sending method req to Agent (%s)" % time.time()) - try: - self._send_method_req(_map, cid) - except SendError, e: - logging.error(str(e)) - mbox.destroy() - return None - - if _reply_handle is not None: - return True - - logging.debug("Waiting for response to method req (%s)" % _timeout) - replyMsg = mbox.fetch(_timeout) - mbox.destroy() - - if not replyMsg: - logging.debug("Agent method req wait timed-out.") - return None - - _map = replyMsg.content.get(MsgKey.method) - if not _map: - logging.error("Invalid method call reply message") - return None - - return MethodResult(_out_args=_map.get(SchemaMethod.KEY_ARGUMENTS), - _error=_map.get(SchemaMethod.KEY_ERROR)) - - def enable_events(self): - raise Exception("enable_events tbd") - - def disable_events(self): - raise Exception("disable_events tbd") - - def destroy(self): - raise Exception("destroy tbd") - - def __repr__(self): - return str(self._address) - - def __str__(self): - return self.__repr__() - - def _send_query(self, query, correlation_id=None): - """ - """ - msg = Message(properties={"method":"request", - "qmf.subject":make_subject(OpCode.get_query)}, - content={MsgKey.query: query.map_encode()}) - self._send_msg( msg, correlation_id ) - - - def _send_method_req(self, mr_map, correlation_id=None): - """ - """ - msg = Message(properties={"method":"request", - "qmf.subject":make_subject(OpCode.method_req)}, - content=mr_map) - self._send_msg( msg, correlation_id ) - - - ##============================================================================== - ## METHOD CALL - ##============================================================================== - -class MethodResult(object): - def __init__(self, _out_args=None, _error=None): - self._error = _error - self._out_args = _out_args - - def succeeded(self): - return self._error is None - - def get_exception(self): - return self._error - - def get_arguments(self): - return self._out_args - - def get_argument(self, name): - arg = None - if self._out_args: - arg = self._out_args.get(name) - return arg - - - ##============================================================================== - ## CONSOLE - ##============================================================================== - - - - - - -class Console(Thread): - """ - A Console manages communications to a collection of agents on behalf of an application. - """ - def __init__(self, name=None, _domain=None, notifier=None, - reply_timeout = 60, - # agent_timeout = 120, - agent_timeout = 60, - kwargs={}): - """ - @type name: str - @param name: identifier for this console. Must be unique. - @type notifier: qmfConsole.Notifier - @param notifier: invoked when events arrive for processing. - @type kwargs: dict - @param kwargs: ??? Unused - """ - Thread.__init__(self) - self._operational = False - self._ready = Event() - - if not name: - self._name = "qmfc-%s.%d" % (platform.node(), os.getpid()) - else: - self._name = str(name) - self._domain = _domain - self._address = QmfAddress.direct(self._name, self._domain) - self._notifier = notifier - self._lock = Lock() - self._conn = None - self._session = None - # dict of "agent-direct-address":class Agent entries - self._agent_map = {} - self._direct_recvr = None - self._announce_recvr = None - self._locate_sender = None - self._schema_cache = {} - self._pending_schema_req = [] - self._agent_discovery_filter = None - self._reply_timeout = reply_timeout - self._agent_timeout = agent_timeout - self._next_agent_expire = None - self._next_mbox_expire = None - # for passing WorkItems to the application - self._work_q = Queue.Queue() - self._work_q_put = False - # Correlation ID and mailbox storage - self._correlation_id = long(time.time()) # pseudo-randomize - self._post_office = {} # indexed by cid - self._async_mboxes = {} # indexed by cid, used to expire them - - ## Old stuff below??? - #self._broker_list = [] - #self.impl = qmfengine.Console() - #self._event = qmfengine.ConsoleEvent() - ##self._cv = Condition() - ##self._sync_count = 0 - ##self._sync_result = None - ##self._select = {} - ##self._cb_cond = Condition() - - - - def destroy(self, timeout=None): - """ - Must be called before the Console is deleted. - Frees up all resources and shuts down all background threads. - - @type timeout: float - @param timeout: maximum time in seconds to wait for all background threads to terminate. Default: forever. - """ - logging.debug("Destroying Console...") - if self._conn: - self.remove_connection(self._conn, timeout) - logging.debug("Console Destroyed") - - - - def add_connection(self, conn): - """ - Add a AMQP connection to the console. The console will setup a session over the - connection. The console will then broadcast an Agent Locate Indication over - the session in order to discover present agents. - - @type conn: qpid.messaging.Connection - @param conn: the connection to the AMQP messaging infrastructure. - """ - if self._conn: - raise Exception( "Multiple connections per Console not supported." ); - self._conn = conn - self._session = conn.session(name=self._name) - - # for messages directly addressed to me - self._direct_recvr = self._session.receiver(str(self._address) + - ";{create:always," - " node-properties:" - " {type:topic," - " x-properties:" - " {type:direct}}}", - capacity=1) - logging.debug("my direct addr=%s" % self._direct_recvr.source) - - self._direct_sender = self._session.sender(str(self._address.get_node()) + - ";{create:always," - " node-properties:" - " {type:topic," - " x-properties:" - " {type:direct}}}") - logging.debug("my direct sender=%s" % self._direct_sender.target) - - # for receiving "broadcast" messages from agents - default_addr = QmfAddress.topic(QmfAddress.SUBJECT_AGENT_IND + ".#", - self._domain) - self._topic_recvr = self._session.receiver(str(default_addr) + - ";{create:always," - " node-properties:{type:topic}}", - capacity=1) - logging.debug("default topic recv addr=%s" % self._topic_recvr.source) - - - # for sending to topic subscribers - topic_addr = QmfAddress.topic(QmfAddress.SUBJECT_CONSOLE_IND, self._domain) - self._topic_sender = self._session.sender(str(topic_addr) + - ";{create:always," - " node-properties:{type:topic}}") - logging.debug("default topic send addr=%s" % self._topic_sender.target) - - # - # Now that receivers are created, fire off the receive thread... - # - self._operational = True - self.start() - self._ready.wait(10) - if not self._ready.isSet(): - raise Exception("Console managment thread failed to start.") - - - - def remove_connection(self, conn, timeout=None): - """ - Remove an AMQP connection from the console. Un-does the add_connection() operation, - and releases any agents and sessions associated with the connection. - - @type conn: qpid.messaging.Connection - @param conn: connection previously added by add_connection() - """ - if self._conn and conn and conn != self._conn: - logging.error( "Attempt to delete unknown connection: %s" % str(conn)) - - # tell connection thread to shutdown - self._operational = False - if self.isAlive(): - # kick my thread to wake it up - self._wake_thread() - logging.debug("waiting for console receiver thread to exit") - self.join(timeout) - if self.isAlive(): - logging.error( "Console thread '%s' is hung..." % self.getName() ) - self._direct_recvr.close() - self._direct_sender.close() - self._topic_recvr.close() - self._topic_sender.close() - self._session.close() - self._session = None - self._conn = None - logging.debug("console connection removal complete") - - - def get_address(self): - """ - The AMQP address this Console is listening to. - """ - return self._address - - - def destroy_agent( self, agent ): - """ - Undoes create. - """ - if not isinstance(agent, Agent): - raise TypeError("agent must be an instance of class Agent") - - self._lock.acquire() - try: - if agent._name in self._agent_map: - del self._agent_map[agent._name] - finally: - self._lock.release() - - def find_agent(self, name, timeout=None ): - """ - Given the name of a particular agent, return an instance of class Agent - representing that agent. Return None if the agent does not exist. - """ - - self._lock.acquire() - try: - agent = self._agent_map.get(name) - if agent: - return agent - finally: - self._lock.release() - - # agent not present yet - ping it with an agent_locate - - mbox = _SyncMailbox(self) - cid = mbox.get_address() - - query = QmfQuery.create_id(QmfQuery.TARGET_AGENT, name) - msg = Message(subject="console.ind.locate." + name, - properties={"method":"request", - "qmf.subject":make_subject(OpCode.agent_locate)}, - content={MsgKey.query: query.map_encode()}) - msg.reply_to = str(self._address) - msg.correlation_id = str(cid) - logging.debug("Sending Agent Locate (%s)" % time.time()) - # TRACE - #logging.error("!!! Console %s sending agent locate (%s)" % - # (self._name, str(msg))) - try: - self._topic_sender.send(msg) - except SendError, e: - logging.error(str(e)) - mbox.destroy() - return None - - if timeout is None: - timeout = self._reply_timeout - - new_agent = None - logging.debug("Waiting for response to Agent Locate (%s)" % timeout) - mbox.fetch(timeout) - mbox.destroy() - logging.debug("Agent Locate wait ended (%s)" % time.time()) - self._lock.acquire() - try: - new_agent = self._agent_map.get(name) - finally: - self._lock.release() - - return new_agent - - - def get_agents(self): - """ - Return the list of known agents. - """ - self._lock.acquire() - try: - agents = self._agent_map.values() - finally: - self._lock.release() - return agents - - - def get_agent(self, name): - """ - Return the named agent, else None if not currently available. - """ - self._lock.acquire() - try: - agent = self._agent_map.get(name) - finally: - self._lock.release() - return agent - - - def do_query(self, agent, query, _reply_handle=None, _timeout=None ): - """ - """ - query_keymap={QmfQuery.TARGET_PACKAGES: MsgKey.package_info, - QmfQuery.TARGET_OBJECT_ID: MsgKey.object_id, - QmfQuery.TARGET_SCHEMA_ID: MsgKey.schema_id, - QmfQuery.TARGET_SCHEMA: MsgKey.schema, - QmfQuery.TARGET_OBJECT: MsgKey.data_obj, - QmfQuery.TARGET_AGENT: MsgKey.agent_info} - - target = query.get_target() - msgkey = query_keymap.get(target) - if not msgkey: - raise Exception("Invalid target for query: %s" % str(query)) - - if _reply_handle is not None: - mbox = _QueryMailbox(self, - agent.get_name(), - _reply_handle, - target, msgkey, - _timeout) - else: - mbox = _SyncMailbox(self) - - cid = mbox.get_address() - - try: - logging.debug("Sending Query to Agent (%s)" % time.time()) - agent._send_query(query, cid) - except SendError, e: - logging.error(str(e)) - mbox.destroy() - return None - - # return now if async reply expected - if _reply_handle is not None: - return True - - if not _timeout: - _timeout = self._reply_timeout - - logging.debug("Waiting for response to Query (%s)" % _timeout) - now = datetime.datetime.utcnow() - expire = now + datetime.timedelta(seconds=_timeout) - - response = [] - while (expire > now): - _timeout = timedelta_to_secs(expire - now) - reply = mbox.fetch(_timeout) - if not reply: - logging.debug("Query wait timed-out.") - break - - objects = reply.content.get(msgkey) - if not objects: - # last response is empty - break - - # convert from map to native types if needed - if target == QmfQuery.TARGET_SCHEMA_ID: - for sid_map in objects: - response.append(SchemaClassId.from_map(sid_map)) - - elif target == QmfQuery.TARGET_SCHEMA: - for schema_map in objects: - # extract schema id, convert based on schema type - sid_map = schema_map.get(SchemaClass.KEY_SCHEMA_ID) - if sid_map: - sid = SchemaClassId.from_map(sid_map) - if sid: - if sid.get_type() == SchemaClassId.TYPE_DATA: - schema = SchemaObjectClass.from_map(schema_map) - else: - schema = SchemaEventClass.from_map(schema_map) - self._add_schema(schema) # add to schema cache - response.append(schema) - - elif target == QmfQuery.TARGET_OBJECT: - for obj_map in objects: - obj = QmfConsoleData(map_=obj_map, agent=agent) - # start fetch of schema if not known - sid = obj.get_schema_class_id() - if sid: - self._prefetch_schema(sid, agent) - response.append(obj) - else: - # no conversion needed. - response += objects - - now = datetime.datetime.utcnow() - - mbox.destroy() - return response - - def _wake_thread(self): - """ - Make the console management thread loop wakeup from its next_receiver - sleep. - """ - logging.debug("Sending noop to wake up [%s]" % self._address) - msg = Message(properties={"method":"request", - "qmf.subject":make_subject(OpCode.noop)}, - subject=self._name, - content={"noop":"noop"}) - try: - self._direct_sender.send( msg, sync=True ) - except SendError, e: - logging.error(str(e)) - - - def run(self): - """ - Console Management Thread main loop. - Handles inbound messages, agent discovery, async mailbox timeouts. - """ - global _callback_thread - - self._ready.set() - - while self._operational: - - # qLen = self._work_q.qsize() - - while True: - try: - msg = self._topic_recvr.fetch(timeout=0) - except Empty: - break - # TRACE: - # logging.error("!!! Console %s: msg on %s [%s]" % - # (self._name, self._topic_recvr.source, msg)) - self._dispatch(msg, _direct=False) - - while True: - try: - msg = self._direct_recvr.fetch(timeout = 0) - except Empty: - break - # TRACE - #logging.error("!!! Console %s: msg on %s [%s]" % - # (self._name, self._direct_recvr.source, msg)) - self._dispatch(msg, _direct=True) - - self._expire_agents() # check for expired agents - self._expire_mboxes() # check for expired async mailbox requests - - #if qLen == 0 and self._work_q.qsize() and self._notifier: - if self._work_q_put and self._notifier: - # new stuff on work queue, kick the the application... - self._work_q_put = False - _callback_thread = currentThread() - logging.info("Calling console notifier.indication") - self._notifier.indication() - _callback_thread = None - - if self._operational: - # wait for a message to arrive, or an agent - # to expire, or a mailbox requrest to time out - now = datetime.datetime.utcnow() - next_expire = self._next_agent_expire - if (self._next_mbox_expire and - self._next_mbox_expire < next_expire): - next_expire = self._next_mbox_expire - if next_expire > now: - timeout = timedelta_to_secs(next_expire - now) - try: - logging.debug("waiting for next rcvr (timeout=%s)..." % timeout) - xxx = self._session.next_receiver(timeout = timeout) - except Empty: - pass - - - logging.debug("Shutting down Console thread") - - def get_objects(self, - _object_id=None, - _schema_id=None, - _pname=None, _cname=None, - _agents=None, - _timeout=None): - """ - Retrieve objects by id or schema. - - By object_id: must specify schema_id or pname & cname if object defined - by a schema. Undescribed objects: only object_id needed. - - By schema: must specify schema_id or pname & cname - all instances of - objects defined by that schema are returned. - """ - if _agents is None: - # use copy of current agent list - self._lock.acquire() - try: - agent_list = self._agent_map.values() - finally: - self._lock.release() - elif isinstance(_agents, Agent): - agent_list = [_agents] - else: - agent_list = _agents - # @todo validate this list! - - if _timeout is None: - _timeout = self._reply_timeout - - # @todo: fix when async do_query done - query all agents at once, then - # wait for replies, instead of per-agent querying.... - - obj_list = [] - expired = datetime.datetime.utcnow() + datetime.timedelta(seconds=_timeout) - for agent in agent_list: - if not agent.is_active(): - continue - now = datetime.datetime.utcnow() - if now >= expired: - break - - if _pname is None: - if _object_id: - query = QmfQuery.create_id_object(_object_id, - _schema_id) - else: - if _schema_id is not None: - t_params = {QmfData.KEY_SCHEMA_ID: _schema_id} - else: - t_params = None - query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT, - t_params) - timeout = timedelta_to_secs(expired - now) - reply = self.do_query(agent, query, _timeout=timeout) - if reply: - obj_list = obj_list + reply - else: - # looking up by package name (and maybe class name), need to - # find all schema_ids in that package, then lookup object by - # schema_id - if _cname is not None: - pred = [QmfQuery.AND, - [QmfQuery.EQ, - SchemaClassId.KEY_PACKAGE, - [QmfQuery.QUOTE, _pname]], - [QmfQuery.EQ, SchemaClassId.KEY_CLASS, - [QmfQuery.QUOTE, _cname]]] - else: - pred = [QmfQuery.EQ, - SchemaClassId.KEY_PACKAGE, - [QmfQuery.QUOTE, _pname]] - query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA_ID, pred) - timeout = timedelta_to_secs(expired - now) - sid_list = self.do_query(agent, query, _timeout=timeout) - if sid_list: - for sid in sid_list: - now = datetime.datetime.utcnow() - if now >= expired: - break - if _object_id is not None: - query = QmfQuery.create_id_object(_object_id, sid) - else: - t_params = {QmfData.KEY_SCHEMA_ID: sid} - query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT, t_params) - timeout = timedelta_to_secs(expired - now) - reply = self.do_query(agent, query, _timeout=timeout) - if reply: - obj_list = obj_list + reply - if obj_list: - return obj_list - return None - - - - # called by run() thread ONLY - # - def _dispatch(self, msg, _direct=True): - """ - PRIVATE: Process a message received from an Agent - """ - logging.debug( "Message received from Agent! [%s]" % msg ) - try: - version,opcode = parse_subject(msg.properties.get("qmf.subject")) - # @todo: deal with version mismatch!!! - except: - logging.error("Ignoring unrecognized message '%s'" % msg) - return - - cmap = {}; props = {} - if msg.content_type == "amqp/map": - cmap = msg.content - if msg.properties: - props = msg.properties - - if opcode == OpCode.agent_ind: - self._handle_agent_ind_msg( msg, cmap, version, _direct ) - elif opcode == OpCode.data_ind: - self._handle_data_ind_msg(msg, cmap, version, _direct) - elif opcode == OpCode.event_ind: - self._handle_event_ind_msg(msg, cmap, version, _direct) - elif opcode == OpCode.managed_object: - logging.warning("!!! managed_object TBD !!!") - elif opcode == OpCode.object_ind: - logging.warning("!!! object_ind TBD !!!") - elif opcode == OpCode.response: - self._handle_response_msg(msg, cmap, version, _direct) - elif opcode == OpCode.schema_ind: - logging.warning("!!! schema_ind TBD !!!") - elif opcode == OpCode.noop: - logging.debug("No-op msg received.") - else: - logging.warning("Ignoring message with unrecognized 'opcode' value: '%s'" % opcode) - - - def _handle_agent_ind_msg(self, msg, cmap, version, direct): - """ - Process a received agent-ind message. This message may be a response to a - agent-locate, or it can be an unsolicited agent announce. - """ - logging.debug("_handle_agent_ind_msg '%s' (%s)" % (msg, time.time())) - - ai_map = cmap.get(MsgKey.agent_info) - if not ai_map or not isinstance(ai_map, type({})): - logging.warning("Bad agent-ind message received: '%s'" % msg) - return - name = ai_map.get("_name") - if not name: - logging.warning("Bad agent-ind message received: agent name missing" - " '%s'" % msg) - return - - correlated = False - if msg.correlation_id: - mbox = self._get_mailbox(msg.correlation_id) - correlated = mbox is not None - - agent = None - self._lock.acquire() - try: - agent = self._agent_map.get(name) - if agent: - # agent already known, just update timestamp - agent._announce_timestamp = datetime.datetime.utcnow() - finally: - self._lock.release() - - if not agent: - # need to create and add a new agent? - matched = False - if self._agent_discovery_filter: - tmp = QmfData.create(values=ai_map, _object_id="agent-filter") - matched = self._agent_discovery_filter.evaluate(tmp) - - if (correlated or matched): - agent = self._create_agent(name) - if not agent: - return # failed to add agent - agent._announce_timestamp = datetime.datetime.utcnow() - - if matched: - # unsolicited, but newly discovered - logging.debug("AGENT_ADDED for %s (%s)" % (agent, time.time())) - wi = WorkItem(WorkItem.AGENT_ADDED, None, {"agent": agent}) - self._work_q.put(wi) - self._work_q_put = True - - if correlated: - # wake up all waiters - logging.debug("waking waiters for correlation id %s" % msg.correlation_id) - mbox.deliver(msg) - - def _handle_data_ind_msg(self, msg, cmap, version, direct): - """ - Process a received data-ind message. - """ - logging.debug("_handle_data_ind_msg '%s' (%s)" % (msg, time.time())) - - mbox = self._get_mailbox(msg.correlation_id) - if not mbox: - logging.debug("Data indicate received with unknown correlation_id" - " msg='%s'" % str(msg)) - return - - # wake up all waiters - logging.debug("waking waiters for correlation id %s" % - msg.correlation_id) - mbox.deliver(msg) - - - def _handle_response_msg(self, msg, cmap, version, direct): - """ - Process a received data-ind message. - """ - # @todo code replication - clean me. - logging.debug("_handle_response_msg '%s' (%s)" % (msg, time.time())) - - mbox = self._get_mailbox(msg.correlation_id) - if not mbox: - logging.debug("Response msg received with unknown correlation_id" - " msg='%s'" % str(msg)) - return - - # wake up all waiters - logging.debug("waking waiters for correlation id %s" % msg.correlation_id) - mbox.deliver(msg) - - def _handle_event_ind_msg(self, msg, cmap, version, _direct): - ei_map = cmap.get(MsgKey.event) - if not ei_map or not isinstance(ei_map, type({})): - logging.warning("Bad event indication message received: '%s'" % msg) - return - - aname = ei_map.get("_name") - emap = ei_map.get("_event") - if not aname: - logging.debug("No '_name' field in event indication message.") - return - if not emap: - logging.debug("No '_event' field in event indication message.") - return - - agent = None - self._lock.acquire() - try: - agent = self._agent_map.get(aname) - finally: - self._lock.release() - if not agent: - logging.debug("Agent '%s' not known." % aname) - return - try: - # @todo: schema??? - event = QmfEvent.from_map(emap) - except TypeError: - logging.debug("Invalid QmfEvent map received: %s" % str(emap)) - return - - # @todo: schema? Need to fetch it, but not from this thread! - # This thread can not pend on a request. - logging.debug("Publishing event received from agent %s" % aname) - wi = WorkItem(WorkItem.EVENT_RECEIVED, None, - {"agent":agent, - "event":event}) - self._work_q.put(wi) - self._work_q_put = True - - - def _expire_mboxes(self): - """ - Check all async mailboxes for outstanding requests that have expired. - """ - now = datetime.datetime.utcnow() - if self._next_mbox_expire and now < self._next_mbox_expire: - return - expired_mboxes = [] - self._next_mbox_expire = None - self._lock.acquire() - try: - for mbox in self._async_mboxes.itervalues(): - if now >= mbox.expiration_date: - expired_mboxes.append(mbox) - else: - if (self._next_mbox_expire is None or - mbox.expiration_date < self._next_mbox_expire): - self._next_mbox_expire = mbox.expiration_date - - for mbox in expired_mboxes: - del self._async_mboxes[mbox.cid] - finally: - self._lock.release() - - for mbox in expired_mboxes: - # note: expire() may deallocate the mbox, so don't touch - # it further. - mbox.expire() - - - def _expire_agents(self): - """ - Check for expired agents and issue notifications when they expire. - """ - now = datetime.datetime.utcnow() - if self._next_agent_expire and now < self._next_agent_expire: - return - lifetime_delta = datetime.timedelta(seconds = self._agent_timeout) - next_expire_delta = lifetime_delta - self._lock.acquire() - try: - logging.debug("!!! expiring agents '%s'" % now) - for agent in self._agent_map.itervalues(): - if agent._announce_timestamp: - agent_deathtime = agent._announce_timestamp + lifetime_delta - if agent_deathtime <= now: - logging.debug("AGENT_DELETED for %s" % agent) - agent._announce_timestamp = None - wi = WorkItem(WorkItem.AGENT_DELETED, None, - {"agent":agent}) - # @todo: remove agent from self._agent_map - self._work_q.put(wi) - self._work_q_put = True - else: - if (agent_deathtime - now) < next_expire_delta: - next_expire_delta = agent_deathtime - now - - self._next_agent_expire = now + next_expire_delta - logging.debug("!!! next expire cycle = '%s'" % self._next_agent_expire) - finally: - self._lock.release() - - - - def _create_agent( self, name ): - """ - Factory to create/retrieve an agent for this console - """ - logging.debug("creating agent %s" % name) - self._lock.acquire() - try: - agent = self._agent_map.get(name) - if agent: - return agent - - agent = Agent(name, self) - try: - agent._sender = self._session.sender(str(agent._address) + - ";{create:always," - " node-properties:" - " {type:topic," - " x-properties:" - " {type:direct}}}") - except: - logging.warning("Unable to create sender for %s" % name) - return None - logging.debug("created agent sender %s" % agent._sender.target) - - self._agent_map[name] = agent - finally: - self._lock.release() - - # new agent - query for its schema database for - # seeding the schema cache (@todo) - # query = QmfQuery({QmfQuery.TARGET_SCHEMA_ID:None}) - # agent._sendQuery( query ) - - return agent - - - - def enable_agent_discovery(self, _query=None): - """ - Called to enable the asynchronous Agent Discovery process. - Once enabled, AGENT_ADD work items can arrive on the WorkQueue. - """ - # @todo: fix - take predicate only, not entire query! - if _query is not None: - if (not isinstance(_query, QmfQuery) or - _query.get_target() != QmfQuery.TARGET_AGENT): - raise TypeError("Type QmfQuery with target == TARGET_AGENT expected") - self._agent_discovery_filter = _query - else: - # create a match-all agent query (no predicate) - self._agent_discovery_filter = QmfQuery.create_wildcard(QmfQuery.TARGET_AGENT) - - def disable_agent_discovery(self): - """ - Called to disable the async Agent Discovery process enabled by - calling enableAgentDiscovery() - """ - self._agent_discovery_filter = None - - - - def get_workitem_count(self): - """ - Returns the count of pending WorkItems that can be retrieved. - """ - return self._work_q.qsize() - - - - def get_next_workitem(self, timeout=None): - """ - Returns the next pending work item, or None if none available. - @todo: subclass and return an Empty event instead. - """ - try: - wi = self._work_q.get(True, timeout) - except Queue.Empty: - return None - return wi - - - def release_workitem(self, wi): - """ - Return a WorkItem to the Console when it is no longer needed. - @todo: call Queue.task_done() - only 2.5+ - - @type wi: class qmfConsole.WorkItem - @param wi: work item object to return. - """ - pass - - def _add_schema(self, schema): - """ - @todo - """ - if not isinstance(schema, SchemaClass): - raise TypeError("SchemaClass type expected") - - self._lock.acquire() - try: - sid = schema.get_class_id() - if not self._schema_cache.has_key(sid): - self._schema_cache[sid] = schema - if sid in self._pending_schema_req: - self._pending_schema_req.remove(sid) - finally: - self._lock.release() - - def _prefetch_schema(self, schema_id, agent): - """ - Send an async request for the schema identified by schema_id if the - schema is not available in the cache. - """ - need_fetch = False - self._lock.acquire() - try: - if ((not self._schema_cache.has_key(schema_id)) and - schema_id not in self._pending_schema_req): - self._pending_schema_req.append(schema_id) - need_fetch = True - finally: - self._lock.release() - - if need_fetch: - mbox = _SchemaPrefetchMailbox(self, schema_id) - query = QmfQuery.create_id(QmfQuery.TARGET_SCHEMA, schema_id) - logging.debug("Sending Schema Query to Agent (%s)" % time.time()) - try: - agent._send_query(query, mbox.get_address()) - except SendError, e: - logging.error(str(e)) - mbox.destroy() - self._lock.acquire() - try: - self._pending_schema_req.remove(schema_id) - finally: - self._lock.release() - - - def _fetch_schema(self, schema_id, _agent=None, _timeout=None): - """ - Find the schema identified by schema_id. If not in the cache, ask the - agent for it. - """ - if not isinstance(schema_id, SchemaClassId): - raise TypeError("SchemaClassId type expected") - - self._lock.acquire() - try: - schema = self._schema_cache.get(schema_id) - if schema: - return schema - finally: - self._lock.release() - - if _agent is None: - return None - - # note: do_query will add the new schema to the cache automatically. - slist = self.do_query(_agent, - QmfQuery.create_id(QmfQuery.TARGET_SCHEMA, schema_id), - _timeout=_timeout) - if slist: - return slist[0] - else: - return None - - def _add_mailbox(self, mbox): - """ - Add a mailbox to the post office, and assign it a unique address. - """ - self._lock.acquire() - try: - mbox.cid = self._correlation_id - self._correlation_id += 1 - self._post_office[mbox.cid] = mbox - finally: - self._lock.release() - - def _get_mailbox(self, mid): - try: - mid = long(mid) - except TypeError: - logging.error("Invalid mailbox id: %s" % str(mid)) - return None - - self._lock.acquire() - try: - return self._post_office.get(mid) - finally: - self._lock.release() - - - def _remove_mailbox(self, mid): - """ Remove a mailbox and its address from the post office """ - try: - mid = long(mid) - except TypeError: - logging.error("Invalid mailbox id: %s" % str(mid)) - return None - - self._lock.acquire() - try: - if mid in self._post_office: - del self._post_office[mid] - finally: - self._lock.release() - - def __repr__(self): - return str(self._address) - - # def get_packages(self): - # plist = [] - # for i in range(self.impl.packageCount()): - # plist.append(self.impl.getPackageName(i)) - # return plist - - - # def get_classes(self, package, kind=CLASS_OBJECT): - # clist = [] - # for i in range(self.impl.classCount(package)): - # key = self.impl.getClass(package, i) - # class_kind = self.impl.getClassKind(key) - # if class_kind == kind: - # if kind == CLASS_OBJECT: - # clist.append(SchemaObjectClass(None, None, {"impl":self.impl.getObjectClass(key)})) - # elif kind == CLASS_EVENT: - # clist.append(SchemaEventClass(None, None, {"impl":self.impl.getEventClass(key)})) - # return clist - - - # def bind_package(self, package): - # return self.impl.bindPackage(package) - - - # def bind_class(self, kwargs = {}): - # if "key" in kwargs: - # self.impl.bindClass(kwargs["key"]) - # elif "package" in kwargs: - # package = kwargs["package"] - # if "class" in kwargs: - # self.impl.bindClass(package, kwargs["class"]) - # else: - # self.impl.bindClass(package) - # else: - # raise Exception("Argument error: invalid arguments, use 'key' or 'package'[,'class']") - - - # def get_agents(self, broker=None): - # blist = [] - # if broker: - # blist.append(broker) - # else: - # self._cv.acquire() - # try: - # # copy while holding lock - # blist = self._broker_list[:] - # finally: - # self._cv.release() - - # agents = [] - # for b in blist: - # for idx in range(b.impl.agentCount()): - # agents.append(AgentProxy(b.impl.getAgent(idx), b)) - - # return agents - - - # def get_objects(self, query, kwargs = {}): - # timeout = 30 - # agent = None - # temp_args = kwargs.copy() - # if type(query) == type({}): - # temp_args.update(query) - - # if "_timeout" in temp_args: - # timeout = temp_args["_timeout"] - # temp_args.pop("_timeout") - - # if "_agent" in temp_args: - # agent = temp_args["_agent"] - # temp_args.pop("_agent") - - # if type(query) == type({}): - # query = Query(temp_args) - - # self._select = {} - # for k in temp_args.iterkeys(): - # if type(k) == str: - # self._select[k] = temp_args[k] - - # self._cv.acquire() - # try: - # self._sync_count = 1 - # self._sync_result = [] - # broker = self._broker_list[0] - # broker.send_query(query.impl, None, agent) - # self._cv.wait(timeout) - # if self._sync_count == 1: - # raise Exception("Timed out: waiting for query response") - # finally: - # self._cv.release() - - # return self._sync_result - - - # def get_object(self, query, kwargs = {}): - # ''' - # Return one and only one object or None. - # ''' - # objs = objects(query, kwargs) - # if len(objs) == 1: - # return objs[0] - # else: - # return None - - - # def first_object(self, query, kwargs = {}): - # ''' - # Return the first of potentially many objects. - # ''' - # objs = objects(query, kwargs) - # if objs: - # return objs[0] - # else: - # return None - - - # # Check the object against select to check for a match - # def _select_match(self, object): - # schema_props = object.properties() - # for key in self._select.iterkeys(): - # for prop in schema_props: - # if key == p[0].name() and self._select[key] != p[1]: - # return False - # return True - - - # def _get_result(self, list, context): - # ''' - # Called by Broker proxy to return the result of a query. - # ''' - # self._cv.acquire() - # try: - # for item in list: - # if self._select_match(item): - # self._sync_result.append(item) - # self._sync_count -= 1 - # self._cv.notify() - # finally: - # self._cv.release() - - - # def start_sync(self, query): pass - - - # def touch_sync(self, sync): pass - - - # def end_sync(self, sync): pass - - - - -# def start_console_events(self): -# self._cb_cond.acquire() -# try: -# self._cb_cond.notify() -# finally: -# self._cb_cond.release() - - -# def _do_console_events(self): -# ''' -# Called by the Console thread to poll for events. Passes the events -# onto the ConsoleHandler associated with this Console. Is called -# periodically, but can also be kicked by Console.start_console_events(). -# ''' -# count = 0 -# valid = self.impl.getEvent(self._event) -# while valid: -# count += 1 -# try: -# if self._event.kind == qmfengine.ConsoleEvent.AGENT_ADDED: -# logging.debug("Console Event AGENT_ADDED received") -# if self._handler: -# self._handler.agent_added(AgentProxy(self._event.agent, None)) -# elif self._event.kind == qmfengine.ConsoleEvent.AGENT_DELETED: -# logging.debug("Console Event AGENT_DELETED received") -# if self._handler: -# self._handler.agent_deleted(AgentProxy(self._event.agent, None)) -# elif self._event.kind == qmfengine.ConsoleEvent.NEW_PACKAGE: -# logging.debug("Console Event NEW_PACKAGE received") -# if self._handler: -# self._handler.new_package(self._event.name) -# elif self._event.kind == qmfengine.ConsoleEvent.NEW_CLASS: -# logging.debug("Console Event NEW_CLASS received") -# if self._handler: -# self._handler.new_class(SchemaClassKey(self._event.classKey)) -# elif self._event.kind == qmfengine.ConsoleEvent.OBJECT_UPDATE: -# logging.debug("Console Event OBJECT_UPDATE received") -# if self._handler: -# self._handler.object_update(ConsoleObject(None, {"impl":self._event.object}), -# self._event.hasProps, self._event.hasStats) -# elif self._event.kind == qmfengine.ConsoleEvent.EVENT_RECEIVED: -# logging.debug("Console Event EVENT_RECEIVED received") -# elif self._event.kind == qmfengine.ConsoleEvent.AGENT_HEARTBEAT: -# logging.debug("Console Event AGENT_HEARTBEAT received") -# if self._handler: -# self._handler.agent_heartbeat(AgentProxy(self._event.agent, None), self._event.timestamp) -# elif self._event.kind == qmfengine.ConsoleEvent.METHOD_RESPONSE: -# logging.debug("Console Event METHOD_RESPONSE received") -# else: -# logging.debug("Console thread received unknown event: '%s'" % str(self._event.kind)) -# except e: -# print "Exception caught in callback thread:", e -# self.impl.popEvent() -# valid = self.impl.getEvent(self._event) -# return count - - - - - -# class Broker(ConnectionHandler): -# # attr_reader :impl :conn, :console, :broker_bank -# def __init__(self, console, conn): -# self.broker_bank = 1 -# self.console = console -# self.conn = conn -# self._session = None -# self._cv = Condition() -# self._stable = None -# self._event = qmfengine.BrokerEvent() -# self._xmtMessage = qmfengine.Message() -# self.impl = qmfengine.BrokerProxy(self.console.impl) -# self.console.impl.addConnection(self.impl, self) -# self.conn.add_conn_handler(self) -# self._operational = True - - -# def shutdown(self): -# logging.debug("broker.shutdown() called.") -# self.console.impl.delConnection(self.impl) -# self.conn.del_conn_handler(self) -# if self._session: -# self.impl.sessionClosed() -# logging.debug("broker.shutdown() sessionClosed done.") -# self._session.destroy() -# logging.debug("broker.shutdown() session destroy done.") -# self._session = None -# self._operational = False -# logging.debug("broker.shutdown() done.") - - -# def wait_for_stable(self, timeout = None): -# self._cv.acquire() -# try: -# if self._stable: -# return -# if timeout: -# self._cv.wait(timeout) -# if not self._stable: -# raise Exception("Timed out: waiting for broker connection to become stable") -# else: -# while not self._stable: -# self._cv.wait() -# finally: -# self._cv.release() - - -# def send_query(self, query, ctx, agent): -# agent_impl = None -# if agent: -# agent_impl = agent.impl -# self.impl.sendQuery(query, ctx, agent_impl) -# self.conn.kick() - - -# def _do_broker_events(self): -# count = 0 -# valid = self.impl.getEvent(self._event) -# while valid: -# count += 1 -# if self._event.kind == qmfengine.BrokerEvent.BROKER_INFO: -# logging.debug("Broker Event BROKER_INFO received"); -# elif self._event.kind == qmfengine.BrokerEvent.DECLARE_QUEUE: -# logging.debug("Broker Event DECLARE_QUEUE received"); -# self.conn.impl.declareQueue(self._session.handle, self._event.name) -# elif self._event.kind == qmfengine.BrokerEvent.DELETE_QUEUE: -# logging.debug("Broker Event DELETE_QUEUE received"); -# self.conn.impl.deleteQueue(self._session.handle, self._event.name) -# elif self._event.kind == qmfengine.BrokerEvent.BIND: -# logging.debug("Broker Event BIND received"); -# self.conn.impl.bind(self._session.handle, self._event.exchange, self._event.name, self._event.bindingKey) -# elif self._event.kind == qmfengine.BrokerEvent.UNBIND: -# logging.debug("Broker Event UNBIND received"); -# self.conn.impl.unbind(self._session.handle, self._event.exchange, self._event.name, self._event.bindingKey) -# elif self._event.kind == qmfengine.BrokerEvent.SETUP_COMPLETE: -# logging.debug("Broker Event SETUP_COMPLETE received"); -# self.impl.startProtocol() -# elif self._event.kind == qmfengine.BrokerEvent.STABLE: -# logging.debug("Broker Event STABLE received"); -# self._cv.acquire() -# try: -# self._stable = True -# self._cv.notify() -# finally: -# self._cv.release() -# elif self._event.kind == qmfengine.BrokerEvent.QUERY_COMPLETE: -# result = [] -# for idx in range(self._event.queryResponse.getObjectCount()): -# result.append(ConsoleObject(None, {"impl":self._event.queryResponse.getObject(idx), "broker":self})) -# self.console._get_result(result, self._event.context) -# elif self._event.kind == qmfengine.BrokerEvent.METHOD_RESPONSE: -# obj = self._event.context -# obj._method_result(MethodResponse(self._event.methodResponse())) - -# self.impl.popEvent() -# valid = self.impl.getEvent(self._event) - -# return count - - -# def _do_broker_messages(self): -# count = 0 -# valid = self.impl.getXmtMessage(self._xmtMessage) -# while valid: -# count += 1 -# logging.debug("Broker: sending msg on connection") -# self.conn.impl.sendMessage(self._session.handle, self._xmtMessage) -# self.impl.popXmt() -# valid = self.impl.getXmtMessage(self._xmtMessage) - -# return count - - -# def _do_events(self): -# while True: -# self.console.start_console_events() -# bcnt = self._do_broker_events() -# mcnt = self._do_broker_messages() -# if bcnt == 0 and mcnt == 0: -# break; - - -# def conn_event_connected(self): -# logging.debug("Broker: Connection event CONNECTED") -# self._session = Session(self.conn, "qmfc-%s.%d" % (socket.gethostname(), os.getpid()), self) -# self.impl.sessionOpened(self._session.handle) -# self._do_events() - - -# def conn_event_disconnected(self, error): -# logging.debug("Broker: Connection event DISCONNECTED") -# pass - - -# def conn_event_visit(self): -# self._do_events() - - -# def sess_event_session_closed(self, context, error): -# logging.debug("Broker: Session event CLOSED") -# self.impl.sessionClosed() - - -# def sess_event_recv(self, context, message): -# logging.debug("Broker: Session event MSG_RECV") -# if not self._operational: -# logging.warning("Unexpected session event message received by Broker proxy: context='%s'" % str(context)) -# self.impl.handleRcvMessage(message) -# self._do_events() - - - -################################################################################ -################################################################################ -################################################################################ -################################################################################ -# TEMPORARY TEST CODE - TO BE DELETED -################################################################################ -################################################################################ -################################################################################ -################################################################################ - -if __name__ == '__main__': - # temp test code - from common import (qmfTypes, SchemaProperty) - - logging.getLogger().setLevel(logging.INFO) - - logging.info( "************* Creating Async Console **************" ) - - class MyNotifier(Notifier): - def __init__(self, context): - self._myContext = context - self.WorkAvailable = False - - def indication(self): - print("Indication received! context=%d" % self._myContext) - self.WorkAvailable = True - - _noteMe = MyNotifier( 666 ) - - _myConsole = Console(notifier=_noteMe) - - _myConsole.enable_agent_discovery() - logging.info("Waiting...") - - - logging.info( "Destroying console:" ) - _myConsole.destroy( 10 ) - - logging.info( "******** Messing around with Schema ********" ) - - _sec = SchemaEventClass( _classId=SchemaClassId("myPackage", "myClass", - stype=SchemaClassId.TYPE_EVENT), - _desc="A typical event schema", - _props={"Argument-1": SchemaProperty(_type_code=qmfTypes.TYPE_UINT8, - kwargs = {"min":0, - "max":100, - "unit":"seconds", - "desc":"sleep value"}), - "Argument-2": SchemaProperty(_type_code=qmfTypes.TYPE_LSTR, - kwargs={"maxlen":100, - "desc":"a string argument"})}) - print("_sec=%s" % _sec.get_class_id()) - print("_sec.gePropertyCount()=%d" % _sec.get_property_count() ) - print("_sec.getProperty('Argument-1`)=%s" % _sec.get_property('Argument-1') ) - print("_sec.getProperty('Argument-2`)=%s" % _sec.get_property('Argument-2') ) - try: - print("_sec.getProperty('not-found')=%s" % _sec.get_property('not-found') ) - except: - pass - print("_sec.getProperties()='%s'" % _sec.get_properties()) - - print("Adding another argument") - _arg3 = SchemaProperty( _type_code=qmfTypes.TYPE_BOOL, - kwargs={"dir":"IO", - "desc":"a boolean argument"}) - _sec.add_property('Argument-3', _arg3) - print("_sec=%s" % _sec.get_class_id()) - print("_sec.getPropertyCount()=%d" % _sec.get_property_count() ) - print("_sec.getProperty('Argument-1')=%s" % _sec.get_property('Argument-1') ) - print("_sec.getProperty('Argument-2')=%s" % _sec.get_property('Argument-2') ) - print("_sec.getProperty('Argument-3')=%s" % _sec.get_property('Argument-3') ) - - print("_arg3.mapEncode()='%s'" % _arg3.map_encode() ) - - _secmap = _sec.map_encode() - print("_sec.mapEncode()='%s'" % _secmap ) - - _sec2 = SchemaEventClass( _map=_secmap ) - - print("_sec=%s" % _sec.get_class_id()) - print("_sec2=%s" % _sec2.get_class_id()) - - _soc = SchemaObjectClass( _map = {"_schema_id": {"_package_name": "myOtherPackage", - "_class_name": "myOtherClass", - "_type": "_data"}, - "_desc": "A test data object", - "_values": - {"prop1": {"amqp_type": qmfTypes.TYPE_UINT8, - "access": "RO", - "index": True, - "unit": "degrees"}, - "prop2": {"amqp_type": qmfTypes.TYPE_UINT8, - "access": "RW", - "index": True, - "desc": "The Second Property(tm)", - "unit": "radians"}, - "statistics": { "amqp_type": qmfTypes.TYPE_DELTATIME, - "unit": "seconds", - "desc": "time until I retire"}, - "meth1": {"_desc": "A test method", - "_arguments": - {"arg1": {"amqp_type": qmfTypes.TYPE_UINT32, - "desc": "an argument 1", - "dir": "I"}, - "arg2": {"amqp_type": qmfTypes.TYPE_BOOL, - "dir": "IO", - "desc": "some weird boolean"}}}, - "meth2": {"_desc": "A test method", - "_arguments": - {"m2arg1": {"amqp_type": qmfTypes.TYPE_UINT32, - "desc": "an 'nuther argument", - "dir": - "I"}}}}, - "_subtypes": - {"prop1":"qmfProperty", - "prop2":"qmfProperty", - "statistics":"qmfProperty", - "meth1":"qmfMethod", - "meth2":"qmfMethod"}, - "_primary_key_names": ["prop2", "prop1"]}) - - print("_soc='%s'" % _soc) - - print("_soc.getPrimaryKeyList='%s'" % _soc.get_id_names()) - - print("_soc.getPropertyCount='%d'" % _soc.get_property_count()) - print("_soc.getProperties='%s'" % _soc.get_properties()) - print("_soc.getProperty('prop2')='%s'" % _soc.get_property('prop2')) - - print("_soc.getMethodCount='%d'" % _soc.get_method_count()) - print("_soc.getMethods='%s'" % _soc.get_methods()) - print("_soc.getMethod('meth2')='%s'" % _soc.get_method('meth2')) - - _socmap = _soc.map_encode() - print("_socmap='%s'" % _socmap) - _soc2 = SchemaObjectClass( _map=_socmap ) - print("_soc='%s'" % _soc) - print("_soc2='%s'" % _soc2) - - if _soc2.get_class_id() == _soc.get_class_id(): - print("soc and soc2 are the same schema") - - - logging.info( "******** Messing around with ObjectIds ********" ) - - - qd = QmfData( _values={"prop1":1, "prop2":True, "prop3": {"a":"map"}, "prop4": "astring"} ) - print("qd='%s':" % qd) - - print("prop1=%d prop2=%s prop3=%s prop4=%s" % (qd.prop1, qd.prop2, qd.prop3, qd.prop4)) - - print("qd map='%s'" % qd.map_encode()) - print("qd getProperty('prop4')='%s'" % qd.get_value("prop4")) - qd.set_value("prop4", 4, "A test property called 4") - print("qd setProperty('prop4', 4)='%s'" % qd.get_value("prop4")) - qd.prop4 = 9 - print("qd.prop4 = 9 ='%s'" % qd.prop4) - qd["prop4"] = 11 - print("qd[prop4] = 11 ='%s'" % qd["prop4"]) - - print("qd.mapEncode()='%s'" % qd.map_encode()) - _qd2 = QmfData( _map = qd.map_encode() ) - print("_qd2.mapEncode()='%s'" % _qd2.map_encode()) - - _qmfDesc1 = QmfConsoleData( {"_values" : {"prop1": 1, "statistics": 666, - "prop2": 0}}, - agent="some agent name?", - _schema = _soc) - - print("_qmfDesc1 map='%s'" % _qmfDesc1.map_encode()) - - _qmfDesc1._set_schema( _soc ) - - print("_qmfDesc1 prop2 = '%s'" % _qmfDesc1.get_value("prop2")) - print("_qmfDesc1 primarykey = '%s'" % _qmfDesc1.get_object_id()) - print("_qmfDesc1 classid = '%s'" % _qmfDesc1.get_schema_class_id()) - - - _qmfDescMap = _qmfDesc1.map_encode() - print("_qmfDescMap='%s'" % _qmfDescMap) - - _qmfDesc2 = QmfData( _map=_qmfDescMap, _schema=_soc ) - - print("_qmfDesc2 map='%s'" % _qmfDesc2.map_encode()) - print("_qmfDesc2 prop2 = '%s'" % _qmfDesc2.get_value("prop2")) - print("_qmfDesc2 primary key = '%s'" % _qmfDesc2.get_object_id()) - - - logging.info( "******** Messing around with QmfEvents ********" ) - - - _qmfevent1 = QmfEvent( _timestamp = 1111, - _schema = _sec, - _values = {"Argument-1": 77, - "Argument-3": True, - "Argument-2": "a string"}) - print("_qmfevent1.mapEncode()='%s'" % _qmfevent1.map_encode()) - print("_qmfevent1.getTimestamp()='%s'" % _qmfevent1.get_timestamp()) - - _qmfevent1Map = _qmfevent1.map_encode() - - _qmfevent2 = QmfEvent(_map=_qmfevent1Map, _schema=_sec) - print("_qmfevent2.mapEncode()='%s'" % _qmfevent2.map_encode()) - - - logging.info( "******** Messing around with Queries ********" ) - - _q1 = QmfQuery.create_predicate(QmfQuery.TARGET_AGENT, - [QmfQuery.AND, - [QmfQuery.EQ, "vendor", [QmfQuery.QUOTE, "AVendor"]], - [QmfQuery.EQ, [QmfQuery.QUOTE, "SomeProduct"], "product"], - [QmfQuery.EQ, [QmfQuery.UNQUOTE, "name"], [QmfQuery.QUOTE, "Thingy"]], - [QmfQuery.OR, - [QmfQuery.LE, "temperature", -10], - [QmfQuery.FALSE], - [QmfQuery.EXISTS, "namey"]]]) - - print("_q1.mapEncode() = [%s]" % _q1.map_encode()) diff --git a/python/qmf2/tests/__init__.py b/python/qmf2/tests/__init__.py deleted file mode 100644 index 186f09349e..0000000000 --- a/python/qmf2/tests/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -# Do not delete - marks this directory as a python package. - -# -# 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. -# - -import agent_discovery -import basic_query -import basic_method -import obj_gets -import events -import multi_response -import async_query -import async_method diff --git a/python/qmf2/tests/agent_discovery.py b/python/qmf2/tests/agent_discovery.py deleted file mode 100644 index 59b65221e0..0000000000 --- a/python/qmf2/tests/agent_discovery.py +++ /dev/null @@ -1,484 +0,0 @@ -# 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. -# -import unittest -import logging -import time -from threading import Thread, Event - -import qpid.messaging -import qmf2.common -import qmf2.console -import qmf2.agent - - -class _testNotifier(qmf2.common.Notifier): - def __init__(self): - self._event = Event() - - def indication(self): - # note: called by qmf daemon thread - self._event.set() - - def wait_for_work(self, timeout): - # note: called by application thread to wait - # for qmf to generate work - self._event.wait(timeout) - timed_out = self._event.isSet() == False - if not timed_out: - self._event.clear() - return True - return False - - -class _agentApp(Thread): - def __init__(self, name, broker_url, heartbeat): - Thread.__init__(self) - self.timeout = 3 - self.broker_url = broker_url - self.notifier = _testNotifier() - self.agent = qmf2.agent.Agent(name, - _notifier=self.notifier, - _heartbeat_interval=heartbeat) - # No database needed for this test - self.running = False - self.ready = Event() - - def start_app(self): - self.running = True - self.start() - self.ready.wait(10) - if not self.ready.is_set(): - raise Exception("Agent failed to connect to broker.") - - def stop_app(self): - self.running = False - # wake main thread - self.notifier.indication() # hmmm... collide with daemon??? - self.join(10) - if self.isAlive(): - raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!") - - def run(self): - # Connect the agent to the broker, - # broker_url = "user/passwd@hostname:port" - conn = qpid.messaging.Connection(self.broker_url.host, - self.broker_url.port, - self.broker_url.user, - self.broker_url.password) - conn.connect() - self.agent.set_connection(conn) - self.ready.set() - - while self.running: - self.notifier.wait_for_work(None) - wi = self.agent.get_next_workitem(timeout=0) - while wi is not None: - logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type()) - self.agent.release_workitem(wi) - wi = self.agent.get_next_workitem(timeout=0) - - # done, cleanup agent - self.agent.remove_connection(self.timeout) - self.agent.destroy(self.timeout) - - -class BaseTest(unittest.TestCase): - def configure(self, config): - self.config = config - self.broker = config.broker - self.defines = self.config.defines - - def setUp(self): - # one second agent indication interval - self.agent_heartbeat = 1 - self.agent1 = _agentApp("agent1", self.broker, self.agent_heartbeat) - self.agent1.start_app() - self.agent2 = _agentApp("agent2", self.broker, self.agent_heartbeat) - self.agent2.start_app() - - def tearDown(self): - if self.agent1: - self.agent1.stop_app() - self.agent1 = None - if self.agent2: - self.agent2.stop_app() - self.agent2 = None - - def test_discover_all(self): - """ - create console - enable agent discovery - wait - expect agent add for agent1 and agent2 - """ - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - self.console.enable_agent_discovery() - - agent1_found = agent2_found = False - wi = self.console.get_next_workitem(timeout=3) - while wi and not (agent1_found and agent2_found): - if wi.get_type() == wi.AGENT_ADDED: - agent = wi.get_params().get("agent") - if not agent or not isinstance(agent, qmf2.console.Agent): - self.fail("Unexpected workitem from agent") - else: - if agent.get_name() == "agent1": - agent1_found = True - elif agent.get_name() == "agent2": - agent2_found = True - else: - self.fail("Unexpected agent name received: %s" % - agent.get_name()) - if agent1_found and agent2_found: - break; - - wi = self.console.get_next_workitem(timeout=3) - - self.assertTrue(agent1_found and agent2_found, "All agents not discovered") - - self.console.destroy(10) - - - def test_discover_one(self): - """ - create console - enable agent discovery, filter for agent1 only - wait until timeout - expect agent add for agent1 only - """ - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - query = qmf2.common.QmfQuery.create_predicate( - qmf2.common.QmfQuery.TARGET_AGENT, - [qmf2.common.QmfQuery.EQ, qmf2.common.QmfQuery.KEY_AGENT_NAME, - [qmf2.common.QmfQuery.QUOTE, "agent1"]]) - self.console.enable_agent_discovery(query) - - agent1_found = agent2_found = False - wi = self.console.get_next_workitem(timeout=3) - while wi: - if wi.get_type() == wi.AGENT_ADDED: - agent = wi.get_params().get("agent") - if not agent or not isinstance(agent, qmf2.console.Agent): - self.fail("Unexpected workitem from agent") - else: - if agent.get_name() == "agent1": - agent1_found = True - elif agent.get_name() == "agent2": - agent2_found = True - else: - self.fail("Unexpected agent name received: %s" % - agent.get_name()) - - wi = self.console.get_next_workitem(timeout=2) - - self.assertTrue(agent1_found and not agent2_found, "Unexpected agent discovered") - - self.console.destroy(10) - - - def test_heartbeat(self): - """ - create console with 2 sec agent timeout - enable agent discovery, find all agents - stop agent1, expect timeout notification - stop agent2, expect timeout notification - """ - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=2) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - self.console.enable_agent_discovery() - - agent1_found = agent2_found = False - wi = self.console.get_next_workitem(timeout=4) - while wi and not (agent1_found and agent2_found): - if wi.get_type() == wi.AGENT_ADDED: - agent = wi.get_params().get("agent") - if not agent or not isinstance(agent, qmf2.console.Agent): - self.fail("Unexpected workitem from agent") - else: - if agent.get_name() == "agent1": - agent1_found = True - elif agent.get_name() == "agent2": - agent2_found = True - else: - self.fail("Unexpected agent name received: %s" % - agent.get_name()) - if agent1_found and agent2_found: - break; - - wi = self.console.get_next_workitem(timeout=4) - - self.assertTrue(agent1_found and agent2_found, "All agents not discovered") - - # now kill agent1 and wait for expiration - - agent1 = self.agent1 - self.agent1 = None - agent1.stop_app() - - wi = self.console.get_next_workitem(timeout=4) - while wi is not None: - if wi.get_type() == wi.AGENT_DELETED: - agent = wi.get_params().get("agent") - if not agent or not isinstance(agent, qmf2.console.Agent): - self.fail("Unexpected workitem from agent") - else: - if agent.get_name() == "agent1": - agent1_found = False - else: - self.fail("Unexpected agent_deleted received: %s" % - agent.get_name()) - if not agent1_found: - break; - - wi = self.console.get_next_workitem(timeout=4) - - self.assertFalse(agent1_found, "agent1 did not delete!") - - # now kill agent2 and wait for expiration - - agent2 = self.agent2 - self.agent2 = None - agent2.stop_app() - - wi = self.console.get_next_workitem(timeout=4) - while wi is not None: - if wi.get_type() == wi.AGENT_DELETED: - agent = wi.get_params().get("agent") - if not agent or not isinstance(agent, qmf2.console.Agent): - self.fail("Unexpected workitem from agent") - else: - if agent.get_name() == "agent2": - agent2_found = False - else: - self.fail("Unexpected agent_deleted received: %s" % - agent.get_name()) - if not agent2_found: - break; - - wi = self.console.get_next_workitem(timeout=4) - - self.assertFalse(agent2_found, "agent2 did not delete!") - - self.console.destroy(10) - - - def test_find_agent(self): - """ - create console - do not enable agent discovery - find agent1, expect success - find agent-none, expect failure - find agent2, expect success - """ - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - agent1 = self.console.find_agent("agent1", timeout=3) - self.assertTrue(agent1 and agent1.get_name() == "agent1") - - no_agent = self.console.find_agent("agent-none", timeout=3) - self.assertTrue(no_agent == None) - - agent2 = self.console.find_agent("agent2", timeout=3) - self.assertTrue(agent2 and agent2.get_name() == "agent2") - - self.console.remove_connection(self.conn, 10) - self.console.destroy(10) - - - def test_heartbeat_x2(self): - """ - create 2 consoles with 2 sec agent timeout - enable agent discovery, find all agents - stop agent1, expect timeout notification on both consoles - stop agent2, expect timeout notification on both consoles - """ - console_count = 2 - self.consoles = [] - for i in range(console_count): - console = qmf2.console.Console("test-console-" + str(i), - notifier=_testNotifier(), - agent_timeout=2) - conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - conn.connect() - console.add_connection(conn) - console.enable_agent_discovery() - self.consoles.append(console) - - # now wait for all consoles to discover all agents, - # agents send a heartbeat once a second - for console in self.consoles: - agent1_found = agent2_found = False - wi = console.get_next_workitem(timeout=2) - while wi and not (agent1_found and agent2_found): - if wi.get_type() == wi.AGENT_ADDED: - agent = wi.get_params().get("agent") - if not agent or not isinstance(agent, qmf2.console.Agent): - self.fail("Unexpected workitem from agent") - else: - if agent.get_name() == "agent1": - agent1_found = True - elif agent.get_name() == "agent2": - agent2_found = True - else: - self.fail("Unexpected agent name received: %s" % - agent.get_name()) - if agent1_found and agent2_found: - break; - wi = console.get_next_workitem(timeout=2) - - self.assertTrue(agent1_found and agent2_found, "All agents not discovered") - - # now kill agent1 and wait for expiration - - agent1 = self.agent1 - self.agent1 = None - agent1.stop_app() - - for console in self.consoles: - agent1_found = True - wi = console.get_next_workitem(timeout=4) - while wi is not None: - if wi.get_type() == wi.AGENT_DELETED: - agent = wi.get_params().get("agent") - if not agent or not isinstance(agent, qmf2.console.Agent): - self.fail("Unexpected workitem from agent") - else: - if agent.get_name() == "agent1": - agent1_found = False - break - else: - self.fail("Unexpected agent_deleted received: %s" % - agent.get_name()) - - wi = console.get_next_workitem(timeout=4) - - self.assertFalse(agent1_found, "agent1 did not delete!") - - # now kill agent2 and wait for expiration - - agent2 = self.agent2 - self.agent2 = None - agent2.stop_app() - - for console in self.consoles: - agent2_found = True - wi = console.get_next_workitem(timeout=4) - while wi is not None: - if wi.get_type() == wi.AGENT_DELETED: - agent = wi.get_params().get("agent") - if not agent or not isinstance(agent, qmf2.console.Agent): - self.fail("Unexpected workitem from agent") - else: - if agent.get_name() == "agent2": - agent2_found = False - break - else: - self.fail("Unexpected agent_deleted received: %s" % - agent.get_name()) - - wi = console.get_next_workitem(timeout=4) - - self.assertFalse(agent2_found, "agent2 did not delete!") - - - for console in self.consoles: - console.destroy(10) - - - def test_find_agent_x2(self): - """ - create 2 consoles, do not enable agent discovery - console-1: find agent1, expect success - console-2: find agent2, expect success - Verify console-1 does -not- know agent2 - Verify console-2 does -not- know agent1 - """ - console_count = 2 - self.consoles = [] - for i in range(console_count): - console = qmf2.console.Console("test-console-" + str(i), - notifier=_testNotifier(), - agent_timeout=2) - conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - conn.connect() - console.add_connection(conn) - self.consoles.append(console) - - agent1 = self.consoles[0].find_agent("agent1", timeout=3) - self.assertTrue(agent1 and agent1.get_name() == "agent1") - - agent2 = self.consoles[1].find_agent("agent2", timeout=3) - self.assertTrue(agent2 and agent2.get_name() == "agent2") - - # wait long enough for agent heartbeats to be sent... - - time.sleep(self.agent_heartbeat * 2) - - agents = self.consoles[0].get_agents() - self.assertTrue(len(agents) == 1 and agents[0].get_name() == "agent1") - agent1 = self.consoles[0].get_agent("agent1") - self.assertTrue(agent1 and agent1.get_name() == "agent1") - - - agents = self.consoles[1].get_agents() - self.assertTrue(len(agents) == 1 and agents[0].get_name() == "agent2") - agent2 = self.consoles[1].get_agent("agent2") - self.assertTrue(agent2 and agent2.get_name() == "agent2") - - # verify no new agents were learned - - for console in self.consoles: - console.destroy(10) - diff --git a/python/qmf2/tests/agent_test.py b/python/qmf2/tests/agent_test.py deleted file mode 100644 index 14d8ada197..0000000000 --- a/python/qmf2/tests/agent_test.py +++ /dev/null @@ -1,167 +0,0 @@ -# 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. -# -import logging -import time -import unittest -from threading import Semaphore - - -from qpid.messaging import * -from qmf2.common import (qmfTypes, SchemaProperty, SchemaObjectClass, QmfData, - QmfEvent, SchemaMethod, Notifier, SchemaClassId, - WorkItem) -from qmf2.agent import (Agent, QmfAgentData) - - - -class ExampleNotifier(Notifier): - def __init__(self): - self._sema4 = Semaphore(0) # locked - - def indication(self): - self._sema4.release() - - def waitForWork(self): - print("Waiting for event...") - self._sema4.acquire() - print("...event present") - - - - -class QmfTest(unittest.TestCase): - def test_begin(self): - print("!!! being test") - - def test_end(self): - print("!!! end test") - - -# -# An example agent application -# - - -if __name__ == '__main__': - _notifier = ExampleNotifier() - _agent = Agent( "qmf.testAgent", _notifier=_notifier ) - - # Dynamically construct a class schema - - _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage", "MyClass"), - _desc="A test data schema", - _object_id_names=["index1", "index2"] ) - # add properties - _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8)) - _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR)) - - # these two properties are statistics - _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # These two properties can be set via the method call - _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR)) - _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32)) - - - # add method - _meth = SchemaMethod( _desc="Method to set string and int in object." ) - _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) ) - _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) ) - _schema.add_method( "set_meth", _meth ) - - # Add schema to Agent - - _agent.register_object_class(_schema) - - # instantiate managed data objects matching the schema - - _obj1 = QmfAgentData( _agent, _schema=_schema ) - _obj1.set_value("index1", 100) - _obj1.set_value("index2", "a name" ) - _obj1.set_value("set_string", "UNSET") - _obj1.set_value("set_int", 0) - _obj1.set_value("query_count", 0) - _obj1.set_value("method_call_count", 0) - _agent.add_object( _obj1 ) - - _agent.add_object( QmfAgentData( _agent, _schema=_schema, - _values={"index1":99, - "index2": "another name", - "set_string": "UNSET", - "set_int": 0, - "query_count": 0, - "method_call_count": 0} )) - - # add an "unstructured" object to the Agent - _obj2 = QmfAgentData(_agent, _object_id="01545") - _obj2.set_value("field1", "a value") - _obj2.set_value("field2", 2) - _obj2.set_value("field3", {"a":1, "map":2, "value":3}) - _obj2.set_value("field4", ["a", "list", "value"]) - _agent.add_object(_obj2) - - - ## Now connect to the broker - - _c = Connection("localhost") - _c.connect() - _agent.setConnection(_c) - - _error_data = QmfData.create({"code": -1, "description": "You made a boo-boo."}) - - _done = False - while not _done: - # try: - _notifier.waitForWork() - - _wi = _agent.get_next_workitem(timeout=0) - while _wi: - - if _wi.get_type() == WorkItem.METHOD_CALL: - mc = _wi.get_params() - - if mc.get_name() == "set_meth": - print("!!! Calling 'set_meth' on Object_id = %s" % mc.get_object_id()) - print("!!! args='%s'" % str(mc.get_args())) - print("!!! userid=%s" % str(mc.get_user_id())) - print("!!! handle=%s" % _wi.get_handle()) - _agent.method_response(_wi.get_handle(), - {"rc1": 100, "rc2": "Success"}) - else: - print("!!! Unknown Method name = %s" % mc.get_name()) - _agent.method_response(_wi.get_handle(), _error=_error_data) - else: - print("TBD: work item %d:%s" % (_wi.get_type(), str(_wi.get_params()))) - - _agent.release_workitem(_wi) - _wi = _agent.get_next_workitem(timeout=0) - # except: - # print( "shutting down...") - # _done = True - - print( "Removing connection... TBD!!!" ) - #_myConsole.remove_connection( _c, 10 ) - - print( "Destroying agent... TBD!!!" ) - #_myConsole.destroy( 10 ) - - print( "******** agent test done ********" ) - - - diff --git a/python/qmf2/tests/async_method.py b/python/qmf2/tests/async_method.py deleted file mode 100644 index 556b62756f..0000000000 --- a/python/qmf2/tests/async_method.py +++ /dev/null @@ -1,362 +0,0 @@ -# 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. -# -import unittest -import logging -from threading import Thread, Event - -import qpid.messaging -from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId, - SchemaProperty, qmfTypes, SchemaMethod, QmfQuery, - QmfData, WorkItem) -import qmf2.console -from qmf2.agent import(QmfAgentData, Agent, MethodCallParams) - - -class _testNotifier(Notifier): - def __init__(self): - self._event = Event() - - def indication(self): - # note: called by qmf daemon thread - self._event.set() - - def wait_for_work(self, timeout): - # note: called by application thread to wait - # for qmf to generate work - self._event.wait(timeout) - timed_out = self._event.isSet() == False - if not timed_out: - self._event.clear() - return True - return False - - -class _agentApp(Thread): - def __init__(self, name, broker_url, heartbeat): - Thread.__init__(self) - self.notifier = _testNotifier() - self.broker_url = broker_url - self.agent = Agent(name, - _notifier=self.notifier, - _heartbeat_interval=heartbeat) - - # Dynamically construct a management database - - _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage", "MyClass"), - _desc="A test data schema", - _object_id_names=["index1", "index2"] ) - # add properties - _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8)) - _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR)) - - # these two properties are statistics - _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # These two properties can be set via the method call - _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR)) - _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # add method - _meth = SchemaMethod( _desc="Method to set string and int in object." ) - _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) ) - _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) ) - # the input value of cookie is returned in the response - _meth.add_argument( "cookie", SchemaProperty(qmfTypes.TYPE_LSTR, - kwargs={"dir":"IO"})) - _schema.add_method( "set_meth", _meth ) - - # Add schema to Agent - - self.agent.register_object_class(_schema) - - # instantiate managed data objects matching the schema - - _obj1 = QmfAgentData( self.agent, _schema=_schema, - _values={"index1":100, "index2":"a name"}) - _obj1.set_value("set_string", "UNSET") - _obj1.set_value("set_int", 0) - _obj1.set_value("query_count", 0) - _obj1.set_value("method_call_count", 0) - self.agent.add_object( _obj1 ) - - self.agent.add_object( QmfAgentData( self.agent, _schema=_schema, - _values={"index1":99, - "index2": "another name", - "set_string": "UNSET", - "set_int": 0, - "query_count": 0, - "method_call_count": 0} )) - - # add an "unstructured" object to the Agent - _obj2 = QmfAgentData(self.agent, _object_id="01545") - _obj2.set_value("field1", "a value") - _obj2.set_value("field2", 2) - _obj2.set_value("field3", {"a":1, "map":2, "value":3}) - _obj2.set_value("field4", ["a", "list", "value"]) - self.agent.add_object(_obj2) - - self.running = False - self.ready = Event() - - def start_app(self): - self.running = True - self.start() - self.ready.wait(10) - if not self.ready.is_set(): - raise Exception("Agent failed to connect to broker.") - - def stop_app(self): - self.running = False - # wake main thread - self.notifier.indication() # hmmm... collide with daemon??? - self.join(10) - if self.isAlive(): - raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!") - - def run(self): - # broker_url = "user/passwd@hostname:port" - self.conn = qpid.messaging.Connection(self.broker_url.host, - self.broker_url.port, - self.broker_url.user, - self.broker_url.password) - self.conn.connect() - self.agent.set_connection(self.conn) - self.ready.set() - - # Agent application main processing loop - while self.running: - self.notifier.wait_for_work(None) - wi = self.agent.get_next_workitem(timeout=0) - while wi is not None: - if wi.get_type() == WorkItem.METHOD_CALL: - mc = wi.get_params() - if not isinstance(mc, MethodCallParams): - raise Exception("Unexpected method call parameters") - - if mc.get_name() == "set_meth": - obj = self.agent.get_object(mc.get_object_id(), - mc.get_schema_id()) - if obj is None: - error_info = QmfData.create({"code": -2, - "description": - "Bad Object Id."}, - _object_id="_error") - self.agent.method_response(wi.get_handle(), - _error=error_info) - else: - obj.inc_value("method_call_count") - out_args = {"code" : 0} - if "cookie" in mc.get_args(): - out_args["cookie"] = mc.get_args()["cookie"] - if "arg_int" in mc.get_args(): - obj.set_value("set_int", mc.get_args()["arg_int"]) - if "arg_str" in mc.get_args(): - obj.set_value("set_string", mc.get_args()["arg_str"]) - self.agent.method_response(wi.get_handle(), - out_args) - elif mc.get_name() == "a_method": - obj = self.agent.get_object(mc.get_object_id(), - mc.get_schema_id()) - if obj is None: - error_info = QmfData.create({"code": -3, - "description": - "Unknown object id."}, - _object_id="_error") - self.agent.method_response(wi.get_handle(), - _error=error_info) - elif obj.get_object_id() != "01545": - error_info = QmfData.create( {"code": -4, - "description": - "Unexpected id."}, - _object_id="_error") - self.agent.method_response(wi.get_handle(), - _error=error_info) - else: - args = mc.get_args() - if ("arg1" in args and args["arg1"] == 1 and - "arg2" in args and args["arg2"] == "Now set!" - and "arg3" in args and args["arg3"] == 1966): - out_args = {"code" : 0} - if "cookie" in mc.get_args(): - out_args["cookie"] = mc.get_args()["cookie"] - self.agent.method_response(wi.get_handle(), - out_args) - else: - error_info = QmfData.create( - {"code": -5, - "description": - "Bad Args."}, - _object_id="_error") - self.agent.method_response(wi.get_handle(), - _error=error_info) - else: - error_info = QmfData.create( {"code": -1, - "description": - "Unknown method call."}, - _object_id="_error") - self.agent.method_response(wi.get_handle(), _error=error_info) - - self.agent.release_workitem(wi) - wi = self.agent.get_next_workitem(timeout=0) - - if self.conn: - self.agent.remove_connection(10) - self.agent.destroy(10) - - - -class BaseTest(unittest.TestCase): - def configure(self, config): - self.config = config - self.broker = config.broker - self.defines = self.config.defines - - def setUp(self): - # one second agent heartbeat interval - self.agent_heartbeat = 1 - self.agent1 = _agentApp("agent1", self.broker, self.agent_heartbeat) - self.agent1.start_app() - self.agent2 = _agentApp("agent2", self.broker, self.agent_heartbeat) - self.agent2.start_app() - - def tearDown(self): - if self.agent1: - self.agent1.stop_app() - self.agent1 = None - if self.agent2: - self.agent2.stop_app() - self.agent2 = None - - def test_described_obj(self): - # create console - # find agents - # synchronous query for all objects in schema - # method call on each object - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - i_count = 0 - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID) - - sid_list = self.console.do_query(agent, query) - self.assertTrue(sid_list and len(sid_list) == 1) - for sid in sid_list: - t_params = {QmfData.KEY_SCHEMA_ID: sid} - query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT, - _target_params=t_params) - obj_list = self.console.do_query(agent, query) - self.assertTrue(len(obj_list) == 2) - for obj in obj_list: - cookie = "cookie-" + str(i_count) - i_count += 1 - mr = obj.invoke_method( "set_meth", - {"arg_int": -99, - "arg_str": "Now set!", - "cookie": cookie}, - _reply_handle=cookie, - _timeout=3) - self.assertTrue(mr) - - # done, now wait for async responses - - r_count = 0 - while self.notifier.wait_for_work(3): - wi = self.console.get_next_workitem(timeout=0) - while wi is not None: - r_count += 1 - self.assertTrue(wi.get_type() == WorkItem.METHOD_RESPONSE) - reply = wi.get_params() - self.assertTrue(isinstance(reply, qmf2.console.MethodResult)) - self.assertTrue(reply.succeeded()) - self.assertTrue(reply.get_argument("cookie") == wi.get_handle()) - - wi = self.console.get_next_workitem(timeout=0) - - self.assertTrue(r_count == i_count) - - self.console.destroy(10) - - - def test_managed_obj(self): - # create console - # find agents - # synchronous query for a managed object - # method call on each object - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - i_count = 0 - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - query = QmfQuery.create_id(QmfQuery.TARGET_OBJECT, "01545") - obj_list = self.console.do_query(agent, query) - - self.assertTrue(isinstance(obj_list, type([]))) - self.assertTrue(len(obj_list) == 1) - obj = obj_list[0] - - cookie = "cookie-" + str(i_count) - i_count += 1 - mr = obj.invoke_method("a_method", - {"arg1": 1, - "arg2": "Now set!", - "arg3": 1966, - "cookie": cookie}, - _reply_handle=cookie, - _timeout=3) - self.assertTrue(mr) - - # done, now wait for async responses - - r_count = 0 - while self.notifier.wait_for_work(3): - wi = self.console.get_next_workitem(timeout=0) - while wi is not None: - r_count += 1 - self.assertTrue(wi.get_type() == WorkItem.METHOD_RESPONSE) - reply = wi.get_params() - self.assertTrue(isinstance(reply, qmf2.console.MethodResult)) - self.assertTrue(reply.succeeded()) - self.assertTrue(reply.get_argument("cookie") == wi.get_handle()) - - wi = self.console.get_next_workitem(timeout=0) - - self.assertTrue(r_count == i_count) - - self.console.destroy(10) diff --git a/python/qmf2/tests/async_query.py b/python/qmf2/tests/async_query.py deleted file mode 100644 index 3a9a767bf0..0000000000 --- a/python/qmf2/tests/async_query.py +++ /dev/null @@ -1,462 +0,0 @@ -# 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. -# -import unittest -import logging -from threading import Thread, Event - -import qpid.messaging -from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId, - SchemaProperty, qmfTypes, SchemaMethod, QmfQuery, - QmfData, WorkItem) -import qmf2.console -from qmf2.agent import(QmfAgentData, Agent) - - -class _testNotifier(Notifier): - def __init__(self): - self._event = Event() - - def indication(self): - # note: called by qmf daemon thread - self._event.set() - - def wait_for_work(self, timeout): - # note: called by application thread to wait - # for qmf to generate work - self._event.wait(timeout) - timed_out = self._event.isSet() == False - if not timed_out: - self._event.clear() - return True - return False - - -class _agentApp(Thread): - def __init__(self, name, broker_url, heartbeat): - Thread.__init__(self) - self.notifier = _testNotifier() - self.broker_url = broker_url - self.agent = Agent(name, - _notifier=self.notifier, - _heartbeat_interval=heartbeat) - - # Dynamically construct a management database - - _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage", "MyClass"), - _desc="A test data schema", - _object_id_names=["index1", "index2"] ) - # add properties - _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8)) - _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR)) - - # these two properties are statistics - _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # These two properties can be set via the method call - _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR)) - _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # add method - _meth = SchemaMethod( _desc="Method to set string and int in object." ) - _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) ) - _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) ) - _schema.add_method( "set_meth", _meth ) - - # Add schema to Agent - - self.agent.register_object_class(_schema) - - # instantiate managed data objects matching the schema - - _obj1 = QmfAgentData( self.agent, _schema=_schema, - _values={"index1":100, "index2":"a name"}) - _obj1.set_value("set_string", "UNSET") - _obj1.set_value("set_int", 0) - _obj1.set_value("query_count", 0) - _obj1.set_value("method_call_count", 0) - self.agent.add_object( _obj1 ) - - self.agent.add_object( QmfAgentData( self.agent, _schema=_schema, - _values={"index1":99, - "index2": "another name", - "set_string": "UNSET", - "set_int": 0, - "query_count": 0, - "method_call_count": 0} )) - - self.agent.add_object( QmfAgentData( self.agent, _schema=_schema, - _values={"index1":50, - "index2": "my name", - "set_string": "SET", - "set_int": 0, - "query_count": 0, - "method_call_count": 0} )) - - - # add an "unstructured" object to the Agent - _obj2 = QmfAgentData(self.agent, _object_id="01545") - _obj2.set_value("field1", "a value") - _obj2.set_value("field2", 2) - _obj2.set_value("field3", {"a":1, "map":2, "value":3}) - _obj2.set_value("field4", ["a", "list", "value"]) - _obj2.set_value("index1", 50) - self.agent.add_object(_obj2) - - _obj2 = QmfAgentData(self.agent, _object_id="01546") - _obj2.set_value("field1", "a value") - _obj2.set_value("field2", 3) - _obj2.set_value("field3", {"a":1, "map":2, "value":3}) - _obj2.set_value("field4", ["a", "list", "value"]) - _obj2.set_value("index1", 51) - self.agent.add_object(_obj2) - - _obj2 = QmfAgentData(self.agent, _object_id="01544") - _obj2.set_value("field1", "a value") - _obj2.set_value("field2", 4) - _obj2.set_value("field3", {"a":1, "map":2, "value":3}) - _obj2.set_value("field4", ["a", "list", "value"]) - _obj2.set_value("index1", 49) - self.agent.add_object(_obj2) - - _obj2 = QmfAgentData(self.agent, _object_id="01543") - _obj2.set_value("field1", "a value") - _obj2.set_value("field2", 4) - _obj2.set_value("field3", {"a":1, "map":2, "value":3}) - _obj2.set_value("field4", ["a", "list", "value"]) - _obj2.set_value("index1", 48) - self.agent.add_object(_obj2) - - self.running = False - self.ready = Event() - - def start_app(self): - self.running = True - self.start() - self.ready.wait(10) - if not self.ready.is_set(): - raise Exception("Agent failed to connect to broker.") - - def stop_app(self): - self.running = False - # wake main thread - self.notifier.indication() # hmmm... collide with daemon??? - self.join(10) - if self.isAlive(): - raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!") - - def run(self): - # broker_url = "user/passwd@hostname:port" - self.conn = qpid.messaging.Connection(self.broker_url.host, - self.broker_url.port, - self.broker_url.user, - self.broker_url.password) - self.conn.connect() - self.agent.set_connection(self.conn) - self.ready.set() - - while self.running: - self.notifier.wait_for_work(None) - wi = self.agent.get_next_workitem(timeout=0) - while wi is not None: - logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type()) - self.agent.release_workitem(wi) - wi = self.agent.get_next_workitem(timeout=0) - - if self.conn: - self.agent.remove_connection(10) - self.agent.destroy(10) - - - - -class BaseTest(unittest.TestCase): - def configure(self, config): - self.config = config - self.broker = config.broker - self.defines = self.config.defines - - def setUp(self): - # one second agent indication interval - self.agent_heartbeat = 1 - self.agent1 = _agentApp("agent1", self.broker, self.agent_heartbeat) - self.agent1.start_app() - self.agent2 = _agentApp("agent2", self.broker, self.agent_heartbeat) - self.agent2.start_app() - - def tearDown(self): - if self.agent1: - self.agent1.stop_app() - self.agent1 = None - if self.agent2: - self.agent2.stop_app() - self.agent2 = None - - def test_all_schema_ids(self): - # create console - # find agents - # asynchronous query for all schema ids - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - # send queries - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID) - rc = self.console.do_query(agent, query, - _reply_handle=aname) - self.assertTrue(rc) - - # done. Now wait for async responses - - count = 0 - while self.notifier.wait_for_work(3): - wi = self.console.get_next_workitem(timeout=0) - while wi is not None: - count += 1 - self.assertTrue(wi.get_type() == WorkItem.QUERY_COMPLETE) - self.assertTrue(wi.get_handle() == "agent1" or - wi.get_handle() == "agent2") - reply = wi.get_params() - self.assertTrue(len(reply) == 1) - self.assertTrue(isinstance(reply[0], SchemaClassId)) - self.assertTrue(reply[0].get_package_name() == "MyPackage") - self.assertTrue(reply[0].get_class_name() == "MyClass") - self.console.release_workitem(wi) - wi = self.console.get_next_workitem(timeout=0) - - self.assertTrue(count == 2) - self.console.destroy(10) - - - - def test_undescribed_objs(self): - # create console - # find agents - # asynchronous query for all non-schema objects - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - # send queries - query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT) - rc = self.console.do_query(agent, query, _reply_handle=aname) - self.assertTrue(rc) - - # done. Now wait for async responses - - count = 0 - while self.notifier.wait_for_work(3): - wi = self.console.get_next_workitem(timeout=0) - while wi is not None: - count += 1 - self.assertTrue(wi.get_type() == WorkItem.QUERY_COMPLETE) - self.assertTrue(wi.get_handle() == "agent1" or - wi.get_handle() == "agent2") - reply = wi.get_params() - self.assertTrue(len(reply) == 4) - self.assertTrue(isinstance(reply[0], qmf2.console.QmfConsoleData)) - self.assertFalse(reply[0].is_described()) # no schema - self.console.release_workitem(wi) - wi = self.console.get_next_workitem(timeout=0) - - self.assertTrue(count == 2) - self.console.destroy(10) - - - - def test_described_objs(self): - # create console - # find agents - # asynchronous query for all schema-based objects - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - # - t_params = {QmfData.KEY_SCHEMA_ID: SchemaClassId("MyPackage", "MyClass")} - query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT, t_params) - # - rc = self.console.do_query(agent, query, _reply_handle=aname) - self.assertTrue(rc) - - # done. Now wait for async responses - - count = 0 - while self.notifier.wait_for_work(3): - wi = self.console.get_next_workitem(timeout=0) - while wi is not None: - count += 1 - self.assertTrue(wi.get_type() == WorkItem.QUERY_COMPLETE) - self.assertTrue(wi.get_handle() == "agent1" or - wi.get_handle() == "agent2") - reply = wi.get_params() - self.assertTrue(len(reply) == 3) - self.assertTrue(isinstance(reply[0], qmf2.console.QmfConsoleData)) - self.assertTrue(reply[0].is_described()) # has schema - self.console.release_workitem(wi) - wi = self.console.get_next_workitem(timeout=0) - - self.assertTrue(count == 2) - # @todo test if the console has learned the corresponding schemas.... - self.console.destroy(10) - - - - def test_all_schemas(self): - # create console - # find agents - # asynchronous query for all schemas - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - # test internal state using non-api calls: - # no schemas present yet - self.assertTrue(len(self.console._schema_cache) == 0) - # end test - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - # send queries - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA) - rc = self.console.do_query(agent, query, _reply_handle=aname) - self.assertTrue(rc) - - # done. Now wait for async responses - - count = 0 - while self.notifier.wait_for_work(3): - wi = self.console.get_next_workitem(timeout=0) - while wi is not None: - count += 1 - self.assertTrue(wi.get_type() == WorkItem.QUERY_COMPLETE) - self.assertTrue(wi.get_handle() == "agent1" or - wi.get_handle() == "agent2") - reply = wi.get_params() - self.assertTrue(len(reply) == 1) - self.assertTrue(isinstance(reply[0], qmf2.common.SchemaObjectClass)) - self.assertTrue(reply[0].get_class_id().get_package_name() == "MyPackage") - self.assertTrue(reply[0].get_class_id().get_class_name() == "MyClass") - self.console.release_workitem(wi) - wi = self.console.get_next_workitem(timeout=0) - - self.assertTrue(count == 2) - - # test internal state using non-api calls: - # schema has been learned - self.assertTrue(len(self.console._schema_cache) == 1) - # end test - - self.console.destroy(10) - - - - def test_query_expiration(self): - # create console - # find agents - # kill the agents - # send async query - # wait for & verify expiration - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=30) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - # find the agents - agents = [] - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - agents.append(agent) - - # now nuke the agents from orbit. It's the only way to be sure. - - self.agent1.stop_app() - self.agent1 = None - self.agent2.stop_app() - self.agent2 = None - - # now send queries to agents that no longer exist - for agent in agents: - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA) - rc = self.console.do_query(agent, query, - _reply_handle=agent.get_name(), - _timeout=2) - self.assertTrue(rc) - - # done. Now wait for async responses due to timeouts - - count = 0 - while self.notifier.wait_for_work(3): - wi = self.console.get_next_workitem(timeout=0) - while wi is not None: - count += 1 - self.assertTrue(wi.get_type() == WorkItem.QUERY_COMPLETE) - self.assertTrue(wi.get_handle() == "agent1" or - wi.get_handle() == "agent2") - reply = wi.get_params() - self.assertTrue(len(reply) == 0) # empty - - self.console.release_workitem(wi) - wi = self.console.get_next_workitem(timeout=0) - - self.assertTrue(count == 2) - self.console.destroy(10) diff --git a/python/qmf2/tests/basic_method.py b/python/qmf2/tests/basic_method.py deleted file mode 100644 index be2bdff9ab..0000000000 --- a/python/qmf2/tests/basic_method.py +++ /dev/null @@ -1,406 +0,0 @@ -# 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. -# -import unittest -import logging -from threading import Thread, Event - -import qpid.messaging -from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId, - SchemaProperty, qmfTypes, SchemaMethod, QmfQuery, - QmfData, WorkItem) -import qmf2.console -from qmf2.agent import(QmfAgentData, Agent, MethodCallParams) - - -class _testNotifier(Notifier): - def __init__(self): - self._event = Event() - - def indication(self): - # note: called by qmf daemon thread - self._event.set() - - def wait_for_work(self, timeout): - # note: called by application thread to wait - # for qmf to generate work - self._event.wait(timeout) - timed_out = self._event.isSet() == False - if not timed_out: - self._event.clear() - return True - return False - - -class _agentApp(Thread): - def __init__(self, name, broker_url, heartbeat): - Thread.__init__(self) - self.notifier = _testNotifier() - self.broker_url = broker_url - self.agent = Agent(name, - _notifier=self.notifier, - _heartbeat_interval=heartbeat) - - # Dynamically construct a management database - - _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage", "MyClass"), - _desc="A test data schema", - _object_id_names=["index1", "index2"] ) - # add properties - _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8)) - _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR)) - - # these two properties are statistics - _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # These two properties can be set via the method call - _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR)) - _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # add method - _meth = SchemaMethod( _desc="Method to set string and int in object." ) - _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) ) - _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) ) - _schema.add_method( "set_meth", _meth ) - - # Add schema to Agent - - self.agent.register_object_class(_schema) - - # instantiate managed data objects matching the schema - - _obj1 = QmfAgentData( self.agent, _schema=_schema, - _values={"index1":100, "index2":"a name"}) - _obj1.set_value("set_string", "UNSET") - _obj1.set_value("set_int", 0) - _obj1.set_value("query_count", 0) - _obj1.set_value("method_call_count", 0) - self.agent.add_object( _obj1 ) - - self.agent.add_object( QmfAgentData( self.agent, _schema=_schema, - _values={"index1":99, - "index2": "another name", - "set_string": "UNSET", - "set_int": 0, - "query_count": 0, - "method_call_count": 0} )) - - # add an "unstructured" object to the Agent - _obj2 = QmfAgentData(self.agent, _object_id="01545") - _obj2.set_value("field1", "a value") - _obj2.set_value("field2", 2) - _obj2.set_value("field3", {"a":1, "map":2, "value":3}) - _obj2.set_value("field4", ["a", "list", "value"]) - self.agent.add_object(_obj2) - - self.running = False - self.ready = Event() - - def start_app(self): - self.running = True - self.start() - self.ready.wait(10) - if not self.ready.is_set(): - raise Exception("Agent failed to connect to broker.") - - def stop_app(self): - self.running = False - # wake main thread - self.notifier.indication() # hmmm... collide with daemon??? - self.join(10) - if self.isAlive(): - raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!") - - def run(self): - # broker_url = "user/passwd@hostname:port" - self.conn = qpid.messaging.Connection(self.broker_url.host, - self.broker_url.port, - self.broker_url.user, - self.broker_url.password) - self.conn.connect() - self.agent.set_connection(self.conn) - self.ready.set() - - # Agent application main processing loop - while self.running: - self.notifier.wait_for_work(None) - wi = self.agent.get_next_workitem(timeout=0) - while wi is not None: - if wi.get_type() == WorkItem.METHOD_CALL: - mc = wi.get_params() - if not isinstance(mc, MethodCallParams): - raise Exception("Unexpected method call parameters") - - if mc.get_name() == "set_meth": - obj = self.agent.get_object(mc.get_object_id(), - mc.get_schema_id()) - if obj is None: - error_info = QmfData.create({"code": -2, - "description": - "Bad Object Id."}, - _object_id="_error") - self.agent.method_response(wi.get_handle(), - _error=error_info) - else: - obj.inc_value("method_call_count") - if "arg_int" in mc.get_args(): - obj.set_value("set_int", mc.get_args()["arg_int"]) - if "arg_str" in mc.get_args(): - obj.set_value("set_string", mc.get_args()["arg_str"]) - self.agent.method_response(wi.get_handle(), - {"code" : 0}) - elif mc.get_name() == "a_method": - obj = self.agent.get_object(mc.get_object_id(), - mc.get_schema_id()) - if obj is None: - error_info = QmfData.create({"code": -3, - "description": - "Unknown object id."}, - _object_id="_error") - self.agent.method_response(wi.get_handle(), - _error=error_info) - elif obj.get_object_id() != "01545": - error_info = QmfData.create( {"code": -4, - "description": - "Unexpected id."}, - _object_id="_error") - self.agent.method_response(wi.get_handle(), - _error=error_info) - else: - args = mc.get_args() - if ("arg1" in args and args["arg1"] == 1 and - "arg2" in args and args["arg2"] == "Now set!" - and "arg3" in args and args["arg3"] == 1966): - self.agent.method_response(wi.get_handle(), - {"code" : 0}) - else: - error_info = QmfData.create( - {"code": -5, - "description": - "Bad Args."}, - _object_id="_error") - self.agent.method_response(wi.get_handle(), - _error=error_info) - else: - error_info = QmfData.create( {"code": -1, - "description": - "Unknown method call."}, - _object_id="_error") - self.agent.method_response(wi.get_handle(), _error=error_info) - - self.agent.release_workitem(wi) - wi = self.agent.get_next_workitem(timeout=0) - - if self.conn: - self.agent.remove_connection(10) - self.agent.destroy(10) - - - -class BaseTest(unittest.TestCase): - def configure(self, config): - self.config = config - self.broker = config.broker - self.defines = self.config.defines - - def setUp(self): - # one second agent heartbeat interval - self.agent_heartbeat = 1 - self.agent1 = _agentApp("agent1", self.broker, self.agent_heartbeat) - self.agent1.start_app() - self.agent2 = _agentApp("agent2", self.broker, self.agent_heartbeat) - self.agent2.start_app() - - def tearDown(self): - if self.agent1: - self.agent1.stop_app() - self.agent1 = None - if self.agent2: - self.agent2.stop_app() - self.agent2 = None - - def test_described_obj(self): - # create console - # find agents - # synchronous query for all objects in schema - # method call on each object - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID) - - sid_list = self.console.do_query(agent, query) - self.assertTrue(sid_list and len(sid_list) == 1) - for sid in sid_list: - t_params = {QmfData.KEY_SCHEMA_ID: sid} - query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT, - _target_params=t_params) - obj_list = self.console.do_query(agent, query) - self.assertTrue(len(obj_list) == 2) - for obj in obj_list: - mr = obj.invoke_method( "set_meth", {"arg_int": -99, - "arg_str": "Now set!"}, - _timeout=3) - self.assertTrue(isinstance(mr, qmf2.console.MethodResult)) - self.assertTrue(mr.succeeded()) - self.assertTrue(mr.get_argument("code") == 0) - - self.assertTrue(obj.get_value("method_call_count") == 0) - self.assertTrue(obj.get_value("set_string") == "UNSET") - self.assertTrue(obj.get_value("set_int") == 0) - - obj.refresh() - - self.assertTrue(obj.get_value("method_call_count") == 1) - self.assertTrue(obj.get_value("set_string") == "Now set!") - self.assertTrue(obj.get_value("set_int") == -99) - - self.console.destroy(10) - - - def test_bad_method_schema(self): - # create console - # find agents - # synchronous query for all objects with schema - # invalid method call on each object - # - should throw a ValueError - NOT YET. - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID) - - sid_list = self.console.do_query(agent, query) - self.assertTrue(sid_list and len(sid_list) == 1) - for sid in sid_list: - - t_params = {QmfData.KEY_SCHEMA_ID: sid} - query = QmfQuery.create_predicate(QmfQuery.TARGET_OBJECT, - [QmfQuery.TRUE], - _target_params=t_params) - - obj_list = self.console.do_query(agent, query) - self.assertTrue(len(obj_list) == 2) - for obj in obj_list: - mr = obj.invoke_method("unknown_method", - {"arg1": -99, "arg2": "Now set!"}, - _timeout=3) - # self.failUnlessRaises(ValueError, - # obj.invoke_method, - # "unknown_meth", - # {"arg1": -99, "arg2": "Now set!"}, - # _timeout=3) - self.assertTrue(isinstance(mr, qmf2.console.MethodResult)) - self.assertFalse(mr.succeeded()) - self.assertTrue(isinstance(mr.get_exception(), QmfData)) - - self.console.destroy(10) - - def test_bad_method_no_schema(self): - # create console - # find agents - # synchronous query for all objects with no schema - # invalid method call on each object - # - should throw a ValueError - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT) - - obj_list = self.console.do_query(agent, query) - self.assertTrue(len(obj_list) == 1) - for obj in obj_list: - self.assertTrue(obj.get_schema_class_id() == None) - mr = obj.invoke_method("unknown_meth", - {"arg1": -99, "arg2": "Now set!"}, - _timeout=3) - self.assertTrue(isinstance(mr, qmf2.console.MethodResult)) - self.assertFalse(mr.succeeded()) - self.assertTrue(isinstance(mr.get_exception(), QmfData)) - - self.console.destroy(10) - - def test_managed_obj(self): - # create console - # find agents - # synchronous query for a managed object - # method call on each object - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - query = QmfQuery.create_id(QmfQuery.TARGET_OBJECT, "01545") - obj_list = self.console.do_query(agent, query) - - self.assertTrue(isinstance(obj_list, type([]))) - self.assertTrue(len(obj_list) == 1) - obj = obj_list[0] - - mr = obj.invoke_method("a_method", - {"arg1": 1, - "arg2": "Now set!", - "arg3": 1966}, - _timeout=3) - self.assertTrue(isinstance(mr, qmf2.console.MethodResult)) - self.assertTrue(mr.succeeded()) - self.assertTrue(mr.get_argument("code") == 0) - # @todo refresh and verify changes - - self.console.destroy(10) diff --git a/python/qmf2/tests/basic_query.py b/python/qmf2/tests/basic_query.py deleted file mode 100644 index dd321cb4bb..0000000000 --- a/python/qmf2/tests/basic_query.py +++ /dev/null @@ -1,516 +0,0 @@ -# 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. -# -import unittest -import logging -from threading import Thread, Event - -import qpid.messaging -from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId, - SchemaProperty, qmfTypes, SchemaMethod, QmfQuery, - QmfData) -import qmf2.console -from qmf2.agent import(QmfAgentData, Agent) - - -class _testNotifier(Notifier): - def __init__(self): - self._event = Event() - - def indication(self): - # note: called by qmf daemon thread - self._event.set() - - def wait_for_work(self, timeout): - # note: called by application thread to wait - # for qmf to generate work - self._event.wait(timeout) - timed_out = self._event.isSet() == False - if not timed_out: - self._event.clear() - return True - return False - - -class _agentApp(Thread): - def __init__(self, name, broker_url, heartbeat): - Thread.__init__(self) - self.notifier = _testNotifier() - self.broker_url = broker_url - self.agent = Agent(name, - _notifier=self.notifier, - _heartbeat_interval=heartbeat) - - # Dynamically construct a management database - - _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage", "MyClass"), - _desc="A test data schema", - _object_id_names=["index1", "index2"] ) - # add properties - _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8)) - _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR)) - - # these two properties are statistics - _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # These two properties can be set via the method call - _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR)) - _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # add method - _meth = SchemaMethod( _desc="Method to set string and int in object." ) - _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) ) - _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) ) - _schema.add_method( "set_meth", _meth ) - - # Add schema to Agent - - self.agent.register_object_class(_schema) - - # instantiate managed data objects matching the schema - - _obj1 = QmfAgentData( self.agent, _schema=_schema, - _values={"index1":100, "index2":"a name"}) - _obj1.set_value("set_string", "UNSET") - _obj1.set_value("set_int", 0) - _obj1.set_value("query_count", 0) - _obj1.set_value("method_call_count", 0) - self.agent.add_object( _obj1 ) - - self.agent.add_object( QmfAgentData( self.agent, _schema=_schema, - _values={"index1":99, - "index2": "another name", - "set_string": "UNSET", - "set_int": 0, - "query_count": 0, - "method_call_count": 0} )) - - self.agent.add_object( QmfAgentData( self.agent, _schema=_schema, - _values={"index1":50, - "index2": "my name", - "set_string": "SET", - "set_int": 0, - "query_count": 0, - "method_call_count": 0} )) - - - # add an "unstructured" object to the Agent - _obj2 = QmfAgentData(self.agent, _object_id="01545") - _obj2.set_value("field1", "a value") - _obj2.set_value("field2", 2) - _obj2.set_value("field3", {"a":1, "map":2, "value":3}) - _obj2.set_value("field4", ["a", "list", "value"]) - _obj2.set_value("index1", 50) - self.agent.add_object(_obj2) - - _obj2 = QmfAgentData(self.agent, _object_id="01546") - _obj2.set_value("field1", "a value") - _obj2.set_value("field2", 3) - _obj2.set_value("field3", {"a":1, "map":2, "value":3}) - _obj2.set_value("field4", ["a", "list", "value"]) - _obj2.set_value("index1", 51) - self.agent.add_object(_obj2) - - _obj2 = QmfAgentData(self.agent, _object_id="01544") - _obj2.set_value("field1", "a value") - _obj2.set_value("field2", 4) - _obj2.set_value("field3", {"a":1, "map":2, "value":3}) - _obj2.set_value("field4", ["a", "list", "value"]) - _obj2.set_value("index1", 49) - self.agent.add_object(_obj2) - - _obj2 = QmfAgentData(self.agent, _object_id="01543") - _obj2.set_value("field1", "a value") - _obj2.set_value("field2", 4) - _obj2.set_value("field3", {"a":1, "map":2, "value":3}) - _obj2.set_value("field4", ["a", "list", "value"]) - _obj2.set_value("index1", 48) - self.agent.add_object(_obj2) - - self.running = False - self.ready = Event() - - def start_app(self): - self.running = True - self.start() - self.ready.wait(10) - if not self.ready.is_set(): - raise Exception("Agent failed to connect to broker.") - - def stop_app(self): - self.running = False - # wake main thread - self.notifier.indication() # hmmm... collide with daemon??? - self.join(10) - if self.isAlive(): - raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!") - - def run(self): - # broker_url = "user/passwd@hostname:port" - self.conn = qpid.messaging.Connection(self.broker_url.host, - self.broker_url.port, - self.broker_url.user, - self.broker_url.password) - self.conn.connect() - self.agent.set_connection(self.conn) - self.ready.set() - - while self.running: - self.notifier.wait_for_work(None) - wi = self.agent.get_next_workitem(timeout=0) - while wi is not None: - logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type()) - self.agent.release_workitem(wi) - wi = self.agent.get_next_workitem(timeout=0) - - if self.conn: - self.agent.remove_connection(10) - self.agent.destroy(10) - - - - -class BaseTest(unittest.TestCase): - def configure(self, config): - self.config = config - self.broker = config.broker - self.defines = self.config.defines - - def setUp(self): - # one second agent indication interval - self.agent_heartbeat = 1 - self.agent1 = _agentApp("agent1", self.broker, self.agent_heartbeat) - self.agent1.start_app() - self.agent2 = _agentApp("agent2", self.broker, self.agent_heartbeat) - self.agent2.start_app() - - def tearDown(self): - if self.agent1: - self.agent1.stop_app() - self.agent1 = None - if self.agent2: - self.agent2.stop_app() - self.agent2 = None - - def test_all_oids(self): - # create console - # find agents - # synchronous query for all schemas - # synchronous query for all objects per schema - # verify known object ids are returned - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - # first, find objects per schema - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID) - sid_list = self.console.do_query(agent, query) - self.assertTrue(sid_list and len(sid_list) == 1) - for sid in sid_list: - t_params = {QmfData.KEY_SCHEMA_ID: sid} - query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT_ID, - _target_params=t_params) - - oid_list = self.console.do_query(agent, query) - - self.assertTrue(isinstance(oid_list, type([])), - "Unexpected return type") - self.assertTrue(len(oid_list) == 3, "Wrong count") - self.assertTrue('100a name' in oid_list) - self.assertTrue('99another name' in oid_list) - self.assertTrue('50my name' in oid_list) - self.assertTrue('01545' not in oid_list) - - - # now, find all unmanaged objects (no schema) - query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT_ID) - oid_list = self.console.do_query(agent, query) - - self.assertTrue(isinstance(oid_list, type([])), - "Unexpected return type") - self.assertTrue(len(oid_list) == 4, "Wrong count") - self.assertTrue('100a name' not in oid_list) - self.assertTrue('99another name' not in oid_list) - self.assertTrue('01545' in oid_list) - self.assertTrue('01544' in oid_list) - self.assertTrue('01543' in oid_list) - self.assertTrue('01546' in oid_list) - - self.console.destroy(10) - - - def test_direct_oids(self): - # create console - # find agents - # synchronous query for each objects - # verify objects and schemas are correct - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - # first, find objects per schema - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID) - sid_list = self.console.do_query(agent, query) - self.assertTrue(sid_list and len(sid_list) == 1) - - for oid in ['100a name', '99another name']: - query = QmfQuery.create_id_object(oid, sid_list[0]) - obj_list = self.console.do_query(agent, query) - - self.assertTrue(isinstance(obj_list, type([])), - "Unexpected return type") - self.assertTrue(len(obj_list) == 1) - obj = obj_list[0] - self.assertTrue(isinstance(obj, QmfData)) - self.assertTrue(obj.get_object_id() == oid) - self.assertTrue(obj.get_schema_class_id() == sid_list[0]) - schema_id = obj.get_schema_class_id() - self.assertTrue(isinstance(schema_id, SchemaClassId)) - self.assertTrue(obj.is_described()) - - # now find schema-less objects - for oid in ['01545']: - query = QmfQuery.create_id_object(oid) - obj_list = self.console.do_query(agent, query) - - self.assertTrue(isinstance(obj_list, type([])), - "Unexpected return type") - self.assertTrue(len(obj_list) == 1) - obj = obj_list[0] - self.assertTrue(isinstance(obj, QmfData)) - self.assertTrue(obj.get_object_id() == oid) - self.assertFalse(obj.is_described()) - - self.console.destroy(10) - - - - def test_packages(self): - # create console - # find agents - # synchronous query all package names - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - query = QmfQuery.create_wildcard(QmfQuery.TARGET_PACKAGES) - package_list = self.console.do_query(agent, query) - self.assertTrue(len(package_list) == 1) - self.assertTrue('MyPackage' in package_list) - - - self.console.destroy(10) - - - - def test_predicate_schema_id(self): - # create console - # find agents - # synchronous query for all schema by package name - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA, - [QmfQuery.EQ, - SchemaClassId.KEY_PACKAGE, - [QmfQuery.QUOTE, "MyPackage"]]) - - schema_list = self.console.do_query(agent, query) - self.assertTrue(len(schema_list)) - for schema in schema_list: - self.assertTrue(schema.get_class_id().get_package_name() == - "MyPackage") - - - self.console.destroy(10) - - - - def test_predicate_no_match(self): - # create console - # find agents - # synchronous query for all schema by package name - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA, - [QmfQuery.EQ, - [QmfQuery.UNQUOTE, SchemaClassId.KEY_PACKAGE], - [QmfQuery.QUOTE, "No-Such-Package"]]) - - schema_list = self.console.do_query(agent, query) - self.assertTrue(len(schema_list) == 0) - - self.console.destroy(10) - - - def test_predicate_match_string(self): - # create console - # find agents - # synchronous query for all objects with a value named - # set_string which is < or equal to "UNSET" - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - # get the schema id for MyPackage:MyClass schema - query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA_ID, - [QmfQuery.AND, - [QmfQuery.EQ, SchemaClassId.KEY_PACKAGE, - [QmfQuery.QUOTE, "MyPackage"]], - [QmfQuery.EQ, SchemaClassId.KEY_CLASS, - [QmfQuery.QUOTE, "MyClass"]]]) - sid_list = self.console.do_query(agent, query) - self.assertTrue(len(sid_list) == 1) - - query = QmfQuery.create_predicate(QmfQuery.TARGET_OBJECT, - [QmfQuery.AND, - [QmfQuery.EXISTS, [QmfQuery.QUOTE, "set_string"]], - [QmfQuery.EQ, "set_string", [QmfQuery.QUOTE, "UNSET"]]], - _target_params={QmfData.KEY_SCHEMA_ID: sid_list[0]}) - obj_list = self.console.do_query(agent, query) - self.assertTrue(len(obj_list) == 2) - for obj in obj_list: - self.assertTrue(obj.has_value("set_string")) - self.assertTrue(obj.get_value("set_string") == "UNSET") - - self.console.destroy(10) - - - - def test_predicate_match_integer(self): - # create console - # find agents - # synchronous query for all objects with a value named - # "index1" which is < or equal to various values - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - # Query the unmanaged (no schema) objects - - # == 50 - query = QmfQuery.create_predicate(QmfQuery.TARGET_OBJECT, - [QmfQuery.AND, - [QmfQuery.EXISTS, [QmfQuery.QUOTE, "index1"]], - [QmfQuery.EQ, "index1", 50]]) - - obj_list = self.console.do_query(agent, query) - self.assertTrue(len(obj_list) == 1) - self.assertTrue(obj_list[0].has_value("index1")) - self.assertTrue(obj_list[0].get_value("index1") == 50) - - # <= 50 - query = QmfQuery.create_predicate(QmfQuery.TARGET_OBJECT, - [QmfQuery.AND, - [QmfQuery.EXISTS, [QmfQuery.QUOTE, "index1"]], - [QmfQuery.LE, "index1", 50]]) - - obj_list = self.console.do_query(agent, query) - self.assertTrue(len(obj_list) == 3) - for obj in obj_list: - self.assertTrue(obj.has_value("index1")) - self.assertTrue(obj.get_value("index1") <= 50) - - - # > 50 - query = QmfQuery.create_predicate(QmfQuery.TARGET_OBJECT, - [QmfQuery.AND, - [QmfQuery.EXISTS, [QmfQuery.QUOTE, "index1"]], - [QmfQuery.GT, "index1", 50]]) - - obj_list = self.console.do_query(agent, query) - self.assertTrue(len(obj_list) == 1) - for obj in obj_list: - self.assertTrue(obj.has_value("index1")) - self.assertTrue(obj.get_value("index1") > 50) - - self.console.destroy(10) - diff --git a/python/qmf2/tests/console_test.py b/python/qmf2/tests/console_test.py deleted file mode 100644 index ac0e064f20..0000000000 --- a/python/qmf2/tests/console_test.py +++ /dev/null @@ -1,175 +0,0 @@ -# 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. -# -import logging -import time -from threading import Semaphore - - -from qpid.messaging import * -from qmf2.common import (Notifier, QmfQuery, QmfQueryPredicate, MsgKey, - SchemaClassId, SchemaClass, QmfData) -from qmf2.console import Console - - -class ExampleNotifier(Notifier): - def __init__(self): - self._sema4 = Semaphore(0) # locked - - def indication(self): - self._sema4.release() - - def waitForWork(self): - print("Waiting for event...") - self._sema4.acquire() - print("...event present") - - -logging.getLogger().setLevel(logging.INFO) - -print( "Starting Connection" ) -_c = Connection("localhost") -_c.connect() - -print( "Starting Console" ) - -_notifier = ExampleNotifier() -_myConsole = Console(notifier=_notifier) -_myConsole.addConnection( _c ) - -# Allow discovery only for the agent named "qmf.testAgent" -# @todo: replace "manual" query construction with -# a formal class-based Query API -_query = QmfQuery.create_predicate(QmfQuery.TARGET_AGENT, - QmfQueryPredicate({QmfQuery.CMP_EQ: - [QmfQuery.KEY_AGENT_NAME, - "qmf.testAgent"]})) -_myConsole.enable_agent_discovery(_query) - -_done = False -while not _done: -# try: - _notifier.waitForWork() - - _wi = _myConsole.get_next_workitem(timeout=0) - while _wi: - print("!!! work item received %d:%s" % (_wi.get_type(), - str(_wi.get_params()))) - - - if _wi.get_type() == _wi.AGENT_ADDED: - _agent = _wi.get_params().get("agent") - if not _agent: - print("!!!! AGENT IN REPLY IS NULL !!! ") - - _query = QmfQuery.create_wildcard(QmfQuery.TARGET_OBJECT_ID) - oid_list = _myConsole.doQuery(_agent, _query) - - print("!!!************************** REPLY=%s" % oid_list) - - for oid in oid_list: - _query = QmfQuery.create_id(QmfQuery.TARGET_OBJECT, - oid) - obj_list = _myConsole.doQuery(_agent, _query) - - print("!!!************************** REPLY=%s" % obj_list) - - if obj_list is None: - obj_list={} - - for obj in obj_list: - resp = obj.invoke_method( "set_meth", - {"arg_int": -11, - "arg_str": "are we not goons?"}, - None, - 3) - if resp is None: - print("!!!*** NO RESPONSE FROM METHOD????") - else: - print("!!! method succeeded()=%s" % resp.succeeded()) - print("!!! method exception()=%s" % resp.get_exception()) - print("!!! method get args() = %s" % resp.get_arguments()) - - if not obj.is_described(): - resp = obj.invoke_method( "bad method", - {"arg_int": -11, - "arg_str": "are we not goons?"}, - None, - 3) - if resp is None: - print("!!!*** NO RESPONSE FROM METHOD????") - else: - print("!!! method succeeded()=%s" % resp.succeeded()) - print("!!! method exception()=%s" % resp.get_exception()) - print("!!! method get args() = %s" % resp.get_arguments()) - - - #--------------------------------- - #_query = QmfQuery.create_id(QmfQuery.TARGET_OBJECT, "99another name") - - #obj_list = _myConsole.doQuery(_agent, _query) - - #--------------------------------- - - # _query = QmfQuery.create_wildcard(QmfQuery.TARGET_PACKAGES) - - # package_list = _myConsole.doQuery(_agent, _query) - - # for pname in package_list: - # print("!!! Querying for schema from package: %s" % pname) - # _query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA_ID, - # QmfQueryPredicate( - # {QmfQuery.CMP_EQ: [SchemaClassId.KEY_PACKAGE, pname]})) - - # schema_id_list = _myConsole.doQuery(_agent, _query) - # for sid in schema_id_list: - # _query = QmfQuery.create_predicate(QmfQuery.TARGET_SCHEMA, - # QmfQueryPredicate( - # {QmfQuery.CMP_EQ: [SchemaClass.KEY_SCHEMA_ID, - # sid.map_encode()]})) - - # schema_list = _myConsole.doQuery(_agent, _query) - # for schema in schema_list: - # sid = schema.get_class_id() - # _query = QmfQuery.create_predicate( - # QmfQuery.TARGET_OBJECT_ID, - # QmfQueryPredicate({QmfQuery.CMP_EQ: - # [QmfData.KEY_SCHEMA_ID, - # sid.map_encode()]})) - - # oid_list = _myConsole.doQuery(_agent, _query) - # for oid in oid_list: - # _query = QmfQuery.create_id( - # QmfQuery.TARGET_OBJECT, oid) - # _reply = _myConsole.doQuery(_agent, _query) - - # print("!!!************************** REPLY=%s" % _reply) - - - _myConsole.release_workitem(_wi) - _wi = _myConsole.get_next_workitem(timeout=0) -# except: -# logging.info( "shutting down..." ) -# _done = True - -print( "Removing connection" ) -_myConsole.removeConnection( _c, 10 ) - -print( "Destroying console:" ) -_myConsole.destroy( 10 ) - -print( "******** console test done ********" ) diff --git a/python/qmf2/tests/events.py b/python/qmf2/tests/events.py deleted file mode 100644 index e55dc8572e..0000000000 --- a/python/qmf2/tests/events.py +++ /dev/null @@ -1,208 +0,0 @@ -# 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. -# -import unittest -import time -import datetime -import logging -from threading import Thread, Event - -import qpid.messaging -from qpid.harness import Skipped -from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId, - SchemaProperty, qmfTypes, SchemaMethod, QmfQuery, - QmfData, SchemaEventClass, - QmfEvent) -import qmf2.console -from qmf2.agent import(QmfAgentData, Agent) - - -class _testNotifier(Notifier): - def __init__(self): - self._event = Event() - - def indication(self): - # note: called by qmf daemon thread - self._event.set() - - def wait_for_work(self, timeout): - # note: called by application thread to wait - # for qmf to generate work - self._event.wait(timeout) - timed_out = self._event.isSet() == False - if not timed_out: - self._event.clear() - return True - return False - - -class _agentApp(Thread): - def __init__(self, name, broker_url, heartbeat): - Thread.__init__(self) - self.timeout = 3 - self.broker_url = broker_url - self.notifier = _testNotifier() - self.agent = Agent(name, - _notifier=self.notifier, - _heartbeat_interval=heartbeat) - - # Dynamically construct a management database - - _schema = SchemaEventClass(_classId=SchemaClassId("MyPackage", - "MyClass", - stype=SchemaClassId.TYPE_EVENT), - _desc="A test event schema") - # add properties - _schema.add_property( "prop-1", SchemaProperty(qmfTypes.TYPE_UINT8)) - _schema.add_property( "prop-2", SchemaProperty(qmfTypes.TYPE_LSTR)) - - # Add schema to Agent - self.schema = _schema - self.agent.register_object_class(_schema) - - self.running = False - self.ready = Event() - - def start_app(self): - self.running = True - self.start() - self.ready.wait(10) - if not self.ready.is_set(): - raise Exception("Agent failed to connect to broker.") - # time.sleep(1) - - def stop_app(self): - self.running = False - # wake main thread - self.notifier.indication() # hmmm... collide with daemon??? - self.join(self.timeout) - if self.isAlive(): - raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!") - - def run(self): - # broker_url = "user/passwd@hostname:port" - conn = qpid.messaging.Connection(self.broker_url.host, - self.broker_url.port, - self.broker_url.user, - self.broker_url.password) - try: - conn.connect() - except qpid.messaging.ConnectError, e: - raise Skipped(e) - - self.agent.set_connection(conn) - self.ready.set() - - counter = 1 - while self.running: - # post an event every second - event = QmfEvent.create(long(time.time() * 1000), - QmfEvent.SEV_WARNING, - {"prop-1": counter, - "prop-2": str(datetime.datetime.utcnow())}, - _schema_id=self.schema.get_class_id()) - counter += 1 - self.agent.raise_event(event) - wi = self.agent.get_next_workitem(timeout=0) - while wi is not None: - logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type()) - self.agent.release_workitem(wi) - wi = self.agent.get_next_workitem(timeout=0) - self.notifier.wait_for_work(1) - - self.agent.remove_connection(self.timeout) - self.agent.destroy(self.timeout) - - - -class BaseTest(unittest.TestCase): - def configure(self, config): - self.config = config - self.broker = config.broker - self.defines = self.config.defines - - def setUp(self): - # one second agent indication interval - self.agent1 = _agentApp("agent1", self.broker, 1) - self.agent1.start_app() - self.agent2 = _agentApp("agent2", self.broker, 1) - self.agent2.start_app() - - def tearDown(self): - if self.agent1: - self.agent1.stop_app() - self.agent1 = None - if self.agent2: - self.agent2.stop_app() - self.agent2 = None - - def test_get_events(self): - # create console - # find agents - - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - try: - self.conn.connect() - except qpid.messaging.ConnectError, e: - raise Skipped(e) - - self.console.add_connection(self.conn) - - # find the agents - for aname in ["agent1", "agent2"]: - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - # now wait for events - agent1_events = agent2_events = 0 - wi = self.console.get_next_workitem(timeout=4) - while wi: - if wi.get_type() == wi.EVENT_RECEIVED: - event = wi.get_params().get("event") - self.assertTrue(isinstance(event, QmfEvent)) - self.assertTrue(event.get_severity() == QmfEvent.SEV_WARNING) - self.assertTrue(event.get_value("prop-1") > 0) - - agent = wi.get_params().get("agent") - if not agent or not isinstance(agent, qmf2.console.Agent): - self.fail("Unexpected workitem from agent") - else: - if agent.get_name() == "agent1": - agent1_events += 1 - elif agent.get_name() == "agent2": - agent2_events += 1 - else: - self.fail("Unexpected agent name received: %s" % - agent.get_name()) - if agent1_events and agent2_events: - break; - - wi = self.console.get_next_workitem(timeout=4) - - self.assertTrue(agent1_events > 0 and agent2_events > 0) - - self.console.destroy(10) - - - - diff --git a/python/qmf2/tests/multi_response.py b/python/qmf2/tests/multi_response.py deleted file mode 100644 index d3d00a70c5..0000000000 --- a/python/qmf2/tests/multi_response.py +++ /dev/null @@ -1,295 +0,0 @@ -# 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. -# -import unittest -import logging -from threading import Thread, Event - -import qpid.messaging -from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId, - SchemaProperty, qmfTypes, SchemaMethod, QmfQuery, - QmfData) -import qmf2.console -from qmf2.agent import(QmfAgentData, Agent) - -# note: objects, schema per agent must each be > max objs -_SCHEMAS_PER_AGENT=7 -_OBJS_PER_AGENT=19 -_MAX_OBJS_PER_MSG=3 - - -class _testNotifier(Notifier): - def __init__(self): - self._event = Event() - - def indication(self): - # note: called by qmf daemon thread - self._event.set() - - def wait_for_work(self, timeout): - # note: called by application thread to wait - # for qmf to generate work - self._event.wait(timeout) - timed_out = self._event.isSet() == False - if not timed_out: - self._event.clear() - return True - return False - - -class _agentApp(Thread): - def __init__(self, name, broker_url, heartbeat): - Thread.__init__(self) - self.schema_count = _SCHEMAS_PER_AGENT - self.obj_count = _OBJS_PER_AGENT - self.notifier = _testNotifier() - self.broker_url = broker_url - self.agent = Agent(name, - _notifier=self.notifier, - _heartbeat_interval=heartbeat, - _max_msg_size=_MAX_OBJS_PER_MSG) - - # Dynamically construct a management database - for i in range(self.schema_count): - _schema = SchemaObjectClass( _classId=SchemaClassId("MyPackage", - "MyClass-" + str(i)), - _desc="A test data schema", - _object_id_names=["index1", "index2"] ) - # add properties - _schema.add_property( "index1", SchemaProperty(qmfTypes.TYPE_UINT8)) - _schema.add_property( "index2", SchemaProperty(qmfTypes.TYPE_LSTR)) - - # these two properties are statistics - _schema.add_property( "query_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - _schema.add_property( "method_call_count", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # These two properties can be set via the method call - _schema.add_property( "set_string", SchemaProperty(qmfTypes.TYPE_LSTR)) - _schema.add_property( "set_int", SchemaProperty(qmfTypes.TYPE_UINT32)) - - # add method - _meth = SchemaMethod( _desc="Method to set string and int in object." ) - _meth.add_argument( "arg_int", SchemaProperty(qmfTypes.TYPE_UINT32) ) - _meth.add_argument( "arg_str", SchemaProperty(qmfTypes.TYPE_LSTR) ) - _schema.add_method( "set_meth", _meth ) - - # Add schema to Agent - - self.agent.register_object_class(_schema) - - # instantiate managed data objects matching the schema - - for j in range(self.obj_count): - - self.agent.add_object( QmfAgentData( self.agent, _schema=_schema, - _values={"index1":j, - "index2": "name-" + str(j), - "set_string": "UNSET", - "set_int": 0, - "query_count": 0, - "method_call_count": 0} )) - - self.running = False - self.ready = Event() - - def start_app(self): - self.running = True - self.start() - self.ready.wait(10) - if not self.ready.is_set(): - raise Exception("Agent failed to connect to broker.") - - def stop_app(self): - self.running = False - # wake main thread - self.notifier.indication() # hmmm... collide with daemon??? - self.join(10) - if self.isAlive(): - raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!") - - def run(self): - # broker_url = "user/passwd@hostname:port" - self.conn = qpid.messaging.Connection(self.broker_url.host, - self.broker_url.port, - self.broker_url.user, - self.broker_url.password) - self.conn.connect() - self.agent.set_connection(self.conn) - self.ready.set() - - while self.running: - self.notifier.wait_for_work(None) - wi = self.agent.get_next_workitem(timeout=0) - while wi is not None: - logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type()) - self.agent.release_workitem(wi) - wi = self.agent.get_next_workitem(timeout=0) - - if self.conn: - self.agent.remove_connection(10) - self.agent.destroy(10) - - - - -class BaseTest(unittest.TestCase): - def configure(self, config): - self.agent_count = 2 - self.config = config - self.broker = config.broker - self.defines = self.config.defines - - def setUp(self): - # one second agent indication interval - self.agent_heartbeat = 1 - self.agents = [] - for a in range(self.agent_count): - agent = _agentApp("agent-" + str(a), - self.broker, - self.agent_heartbeat) - agent.start_app() - self.agents.append(agent) - - def tearDown(self): - for agent in self.agents: - if agent is not None: - agent.stop_app() - - def test_all_schema_id(self): - # create console - # find agents - # synchronous query for all schemas_ids - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for agent_app in self.agents: - agent = self.console.find_agent(agent_app.agent.get_name(), timeout=3) - self.assertTrue(agent and agent.get_name() == agent_app.agent.get_name()) - - # get a list of all schema_ids - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID) - sid_list = self.console.do_query(agent, query) - self.assertTrue(sid_list and len(sid_list) == _SCHEMAS_PER_AGENT) - for sid in sid_list: - self.assertTrue(isinstance(sid, SchemaClassId)) - self.assertTrue(sid.get_package_name() == "MyPackage") - self.assertTrue(sid.get_class_name().split('-')[0] == "MyClass") - - self.console.destroy(10) - - - def test_all_schema(self): - # create console - # find agents - # synchronous query for all schemas - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for agent_app in self.agents: - agent = self.console.find_agent(agent_app.agent.get_name(), timeout=3) - self.assertTrue(agent and agent.get_name() == agent_app.agent.get_name()) - - # get a list of all schema_ids - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA) - schema_list = self.console.do_query(agent, query) - self.assertTrue(schema_list and - len(schema_list) == _SCHEMAS_PER_AGENT) - for schema in schema_list: - self.assertTrue(isinstance(schema, SchemaObjectClass)) - - self.console.destroy(10) - - - def test_all_object_id(self): - # create console - # find agents - # synchronous query for all object_ids by schema_id - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for agent_app in self.agents: - agent = self.console.find_agent(agent_app.agent.get_name(), timeout=3) - self.assertTrue(agent and agent.get_name() == agent_app.agent.get_name()) - - # get a list of all schema_ids - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID) - sid_list = self.console.do_query(agent, query) - self.assertTrue(sid_list and len(sid_list) == _SCHEMAS_PER_AGENT) - for sid in sid_list: - query = QmfQuery.create_wildcard_object_id(sid) - oid_list = self.console.do_query(agent, query) - self.assertTrue(oid_list and - len(oid_list) == _OBJS_PER_AGENT) - for oid in oid_list: - self.assertTrue(isinstance(oid, basestring)) - - self.console.destroy(10) - - - def test_all_objects(self): - # create console - # find agents - # synchronous query for all objects by schema_id - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for agent_app in self.agents: - agent = self.console.find_agent(agent_app.agent.get_name(), timeout=3) - self.assertTrue(agent and agent.get_name() == agent_app.agent.get_name()) - - # get a list of all schema_ids - query = QmfQuery.create_wildcard(QmfQuery.TARGET_SCHEMA_ID) - sid_list = self.console.do_query(agent, query) - self.assertTrue(sid_list and len(sid_list) == _SCHEMAS_PER_AGENT) - for sid in sid_list: - query = QmfQuery.create_wildcard_object(sid) - obj_list = self.console.do_query(agent, query) - self.assertTrue(obj_list and - len(obj_list) == _OBJS_PER_AGENT) - for obj in obj_list: - self.assertTrue(isinstance(obj, - qmf2.console.QmfConsoleData)) - - self.console.destroy(10) diff --git a/python/qmf2/tests/obj_gets.py b/python/qmf2/tests/obj_gets.py deleted file mode 100644 index 5b1446bb3a..0000000000 --- a/python/qmf2/tests/obj_gets.py +++ /dev/null @@ -1,599 +0,0 @@ -# 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. -# -import unittest -import logging -import datetime -from threading import Thread, Event - -import qpid.messaging -from qmf2.common import (Notifier, SchemaObjectClass, SchemaClassId, - SchemaProperty, qmfTypes, SchemaMethod, QmfQuery, - QmfData) -import qmf2.console -from qmf2.agent import(QmfAgentData, Agent) - - -class _testNotifier(Notifier): - def __init__(self): - self._event = Event() - - def indication(self): - # note: called by qmf daemon thread - self._event.set() - - def wait_for_work(self, timeout): - # note: called by application thread to wait - # for qmf to generate work - self._event.wait(timeout) - timed_out = self._event.isSet() == False - if not timed_out: - self._event.clear() - return True - return False - - -class _agentApp(Thread): - def __init__(self, name, broker_url, heartbeat): - Thread.__init__(self) - self.notifier = _testNotifier() - self.broker_url = broker_url - self.agent = Agent(name, - _notifier=self.notifier, - _heartbeat_interval=heartbeat) - - # Management Database - # - two different schema packages, - # - two classes within one schema package - # - multiple objects per schema package+class - # - two "undescribed" objects - - # "package1/class1" - - _schema = SchemaObjectClass( _classId=SchemaClassId("package1", "class1"), - _desc="A test data schema - one", - _object_id_names=["key"] ) - - _schema.add_property( "key", SchemaProperty(qmfTypes.TYPE_LSTR)) - _schema.add_property( "count1", SchemaProperty(qmfTypes.TYPE_UINT32)) - _schema.add_property( "count2", SchemaProperty(qmfTypes.TYPE_UINT32)) - - self.agent.register_object_class(_schema) - - _obj = QmfAgentData( self.agent, - _values={"key":"p1c1_key1"}, - _schema=_schema) - _obj.set_value("count1", 0) - _obj.set_value("count2", 0) - self.agent.add_object( _obj ) - - _obj = QmfAgentData( self.agent, - _values={"key":"p1c1_key2"}, - _schema=_schema ) - _obj.set_value("count1", 9) - _obj.set_value("count2", 10) - self.agent.add_object( _obj ) - - # "package1/class2" - - _schema = SchemaObjectClass( _classId=SchemaClassId("package1", "class2"), - _desc="A test data schema - two", - _object_id_names=["name"] ) - # add properties - _schema.add_property( "name", SchemaProperty(qmfTypes.TYPE_LSTR)) - _schema.add_property( "string1", SchemaProperty(qmfTypes.TYPE_LSTR)) - - self.agent.register_object_class(_schema) - - _obj = QmfAgentData( self.agent, - _values={"name":"p1c2_name1"}, - _schema=_schema ) - _obj.set_value("string1", "a data string") - self.agent.add_object( _obj ) - - - # "package2/class1" - - _schema = SchemaObjectClass( _classId=SchemaClassId("package2", "class1"), - _desc="A test data schema - second package", - _object_id_names=["key"] ) - - _schema.add_property( "key", SchemaProperty(qmfTypes.TYPE_LSTR)) - _schema.add_property( "counter", SchemaProperty(qmfTypes.TYPE_UINT32)) - - self.agent.register_object_class(_schema) - - _obj = QmfAgentData( self.agent, - _values={"key":"p2c1_key1"}, - _schema=_schema ) - _obj.set_value("counter", 0) - self.agent.add_object( _obj ) - - _obj = QmfAgentData( self.agent, - _values={"key":"p2c1_key2"}, - _schema=_schema ) - _obj.set_value("counter", 2112) - self.agent.add_object( _obj ) - - - # add two "unstructured" objects to the Agent - - _obj = QmfAgentData(self.agent, _object_id="undesc-1") - _obj.set_value("field1", "a value") - _obj.set_value("field2", 2) - _obj.set_value("field3", {"a":1, "map":2, "value":3}) - _obj.set_value("field4", ["a", "list", "value"]) - self.agent.add_object(_obj) - - - _obj = QmfAgentData(self.agent, _object_id="undesc-2") - _obj.set_value("key-1", "a value") - _obj.set_value("key-2", 2) - self.agent.add_object(_obj) - - self.running = False - self.ready = Event() - - def start_app(self): - self.running = True - self.start() - self.ready.wait(10) - if not self.ready.is_set(): - raise Exception("Agent failed to connect to broker.") - - def stop_app(self): - self.running = False - self.notifier.indication() # hmmm... collide with daemon??? - self.join(10) - if self.isAlive(): - raise Exception("AGENT DID NOT TERMINATE AS EXPECTED!!!") - - def run(self): - # broker_url = "user/passwd@hostname:port" - self.conn = qpid.messaging.Connection(self.broker_url.host, - self.broker_url.port, - self.broker_url.user, - self.broker_url.password) - self.conn.connect() - self.agent.set_connection(self.conn) - self.ready.set() - - while self.running: - self.notifier.wait_for_work(None) - wi = self.agent.get_next_workitem(timeout=0) - while wi is not None: - logging.error("UNEXPECTED AGENT WORKITEM RECEIVED=%s" % wi.get_type()) - self.agent.release_workitem(wi) - wi = self.agent.get_next_workitem(timeout=0) - - if self.conn: - self.agent.remove_connection(10) - self.agent.destroy(10) - - -class BaseTest(unittest.TestCase): - agent_count = 5 - - def configure(self, config): - self.config = config - self.broker = config.broker - self.defines = self.config.defines - - def setUp(self): - self.agents = [] - for i in range(self.agent_count): - agent = _agentApp("agent-" + str(i), self.broker, 1) - agent.start_app() - self.agents.append(agent) - #print("!!!! STARTING TEST: %s" % datetime.datetime.utcnow()) - - def tearDown(self): - #print("!!!! STOPPING TEST: %s" % datetime.datetime.utcnow()) - for agent in self.agents: - if agent is not None: - agent.stop_app() - - - def test_all_agents(self): - # create console - # find all agents - # synchronous query for all objects by id - # verify known object ids are returned - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for agent_app in self.agents: - aname = agent_app.agent.get_name() - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - # console has discovered all agents, now query all undesc-2 objects - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_object_id="undesc-2", _timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(len(objs) == self.agent_count) - for obj in objs: - self.assertTrue(obj.get_object_id() == "undesc-2") - - # now query all objects from schema "package1" - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_pname="package1", _timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(len(objs) == (self.agent_count * 3)) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - - # now query all objects from schema "package2" - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_pname="package2", _timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(len(objs) == (self.agent_count * 2)) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2") - - # now query all objects from schema "package1/class2" - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_pname="package1", _cname="class2", - _timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(len(objs) == self.agent_count) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class2") - - # given the schema identifier from the last query, repeat using the - # specific schema id - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - schema_id = objs[0].get_schema_class_id() - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_schema_id=schema_id, _timeout=5) - self.assertTrue(len(objs) == self.agent_count) - for obj in objs: - self.assertTrue(obj.get_schema_class_id() == schema_id) - - - self.console.destroy(10) - - - - def test_agent_subset(self): - # create console - # find all agents - # synchronous query for all objects by id - # verify known object ids are returned - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - agent_list = [] - for agent_app in self.agents: - aname = agent_app.agent.get_name() - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - agent_list.append(agent) - - # Only use a subset of the agents: - agent_list = agent_list[:len(agent_list)/2] - - # console has discovered all agents, now query all undesc-2 objects - objs = self.console.get_objects(_object_id="undesc-2", - _agents=agent_list, _timeout=5) - self.assertTrue(len(objs) == len(agent_list)) - for obj in objs: - self.assertTrue(obj.get_object_id() == "undesc-2") - - # now query all objects from schema "package1" - objs = self.console.get_objects(_pname="package1", - _agents=agent_list, - _timeout=5) - self.assertTrue(len(objs) == (len(agent_list) * 3)) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - - # now query all objects from schema "package2" - objs = self.console.get_objects(_pname="package2", - _agents=agent_list, - _timeout=5) - self.assertTrue(len(objs) == (len(agent_list) * 2)) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2") - - # now query all objects from schema "package1/class2" - objs = self.console.get_objects(_pname="package1", _cname="class2", - _agents=agent_list, - _timeout=5) - self.assertTrue(len(objs) == len(agent_list)) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class2") - - # given the schema identifier from the last query, repeat using the - # specific schema id - schema_id = objs[0].get_schema_class_id() - objs = self.console.get_objects(_schema_id=schema_id, - _agents=agent_list, - _timeout=5) - self.assertTrue(len(objs) == len(agent_list)) - for obj in objs: - self.assertTrue(obj.get_schema_class_id() == schema_id) - - - self.console.destroy(10) - - - - def test_single_agent(self): - # create console - # find all agents - # synchronous query for all objects by id - # verify known object ids are returned - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - agent_list = [] - for agent_app in self.agents: - aname = agent_app.agent.get_name() - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - agent_list.append(agent) - - # Only use one agent - agent = agent_list[0] - - # console has discovered all agents, now query all undesc-2 objects - objs = self.console.get_objects(_object_id="undesc-2", - _agents=agent, _timeout=5) - self.assertTrue(len(objs) == 1) - for obj in objs: - self.assertTrue(obj.get_object_id() == "undesc-2") - - # now query all objects from schema "package1" - objs = self.console.get_objects(_pname="package1", - _agents=agent, - _timeout=5) - self.assertTrue(len(objs) == 3) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - - # now query all objects from schema "package2" - objs = self.console.get_objects(_pname="package2", - _agents=agent, - _timeout=5) - self.assertTrue(len(objs) == 2) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2") - - # now query all objects from schema "package1/class2" - objs = self.console.get_objects(_pname="package1", _cname="class2", - _agents=agent, - _timeout=5) - self.assertTrue(len(objs) == 1) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class2") - - # given the schema identifier from the last query, repeat using the - # specific schema id - schema_id = objs[0].get_schema_class_id() - objs = self.console.get_objects(_schema_id=schema_id, - _agents=agent, - _timeout=5) - self.assertTrue(len(objs) == 1) - for obj in objs: - self.assertTrue(obj.get_schema_class_id() == schema_id) - - - self.console.destroy(10) - - - - def test_all_objs_by_oid(self): - # create console - # find all agents - # synchronous query for all described objects by: - # oid & schema_id - # oid & package name - # oid & package and class name - # verify known object ids are returned - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for agent_app in self.agents: - aname = agent_app.agent.get_name() - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - # now query all objects from schema "package1" - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_pname="package1", - _object_id="p1c1_key1", _timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(len(objs) == self.agent_count) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1") - self.assertTrue(obj.get_object_id() == "p1c1_key1") - # mooch the schema for a later test - schema_id_p1c1 = objs[0].get_schema_class_id() - - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_pname="package1", - _object_id="p1c2_name1", _timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(len(objs) == self.agent_count) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class2") - self.assertTrue(obj.get_object_id() == "p1c2_name1") - - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_pname="package2", _cname="class1", - _object_id="p2c1_key1", _timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(len(objs) == self.agent_count) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1") - self.assertTrue(obj.get_object_id() == "p2c1_key1") - - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_schema_id=schema_id_p1c1, - _object_id="p1c1_key2", _timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(len(objs) == self.agent_count) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1") - self.assertTrue(obj.get_object_id() == "p1c1_key2") - - # this should return all "undescribed" objects - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(len(objs) == (self.agent_count * 2)) - for obj in objs: - self.assertTrue(obj.get_object_id() == "undesc-1" or - obj.get_object_id() == "undesc-2") - - # these should fail - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_schema_id=schema_id_p1c1, - _object_id="does not exist", - _timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(objs == None) - - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_pname="package2", - _object_id="does not exist", - _timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(objs == None) - - #print("!!!! STARTING GET: %s" % datetime.datetime.utcnow()) - objs = self.console.get_objects(_pname="package3", - _object_id="does not exist", - _timeout=5) - #print("!!!! STOPPING GET: %s" % datetime.datetime.utcnow()) - self.assertTrue(objs == None) - - self.console.destroy(10) - - - def test_wildcard_schema_id(self): - # create console - # find all agents - # synchronous query for all described objects by: - # oid & wildcard schema_id - # wildcard schema_id - # verify known object ids are returned - self.notifier = _testNotifier() - self.console = qmf2.console.Console(notifier=self.notifier, - agent_timeout=3) - self.conn = qpid.messaging.Connection(self.broker.host, - self.broker.port, - self.broker.user, - self.broker.password) - self.conn.connect() - self.console.add_connection(self.conn) - - for agent_app in self.agents: - aname = agent_app.agent.get_name() - agent = self.console.find_agent(aname, timeout=3) - self.assertTrue(agent and agent.get_name() == aname) - - wild_schema_id = SchemaClassId("package1", "class1") - objs = self.console.get_objects(_schema_id=wild_schema_id, _timeout=5) - self.assertTrue(len(objs) == (self.agent_count * 2)) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1") - - wild_schema_id = SchemaClassId("package1", "class2") - objs = self.console.get_objects(_schema_id=wild_schema_id, _timeout=5) - self.assertTrue(len(objs) == self.agent_count) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class2") - self.assertTrue(obj.get_object_id() == "p1c2_name1") - - wild_schema_id = SchemaClassId("package2", "class1") - objs = self.console.get_objects(_schema_id=wild_schema_id, _timeout=5) - self.assertTrue(len(objs) == (self.agent_count * 2)) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1") - - wild_schema_id = SchemaClassId("package1", "class1") - objs = self.console.get_objects(_schema_id=wild_schema_id, - _object_id="p1c1_key2", _timeout=5) - self.assertTrue(len(objs) == self.agent_count) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package1") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1") - self.assertTrue(obj.get_object_id() == "p1c1_key2") - - # should fail - objs = self.console.get_objects(_schema_id=wild_schema_id, - _object_id="does not exist", - _timeout=5) - self.assertTrue(objs == None) - - wild_schema_id = SchemaClassId("package2", "class1") - objs = self.console.get_objects(_schema_id=wild_schema_id, - _object_id="p2c1_key2", _timeout=5) - self.assertTrue(len(objs) == self.agent_count) - for obj in objs: - self.assertTrue(obj.get_schema_class_id().get_package_name() == "package2") - self.assertTrue(obj.get_schema_class_id().get_class_name() == "class1") - self.assertTrue(obj.get_object_id() == "p2c1_key2") - - # should fail - wild_schema_id = SchemaClassId("package1", "bad-class") - objs = self.console.get_objects(_schema_id=wild_schema_id, - _object_id="p1c1_key2", _timeout=5) - self.assertTrue(objs == None) - - self.console.destroy(10) - diff --git a/python/setup.py b/python/setup.py index 5178bad0ed..2bd6e7fe0d 100644 --- a/python/setup.py +++ b/python/setup.py @@ -21,15 +21,8 @@ from distutils.core import setup setup(name="qpid", version="0.7", - packages=["mllib", "qpid", "qpid.tests", "qmf", "qmf2", "qmf2.tests"], - scripts=["qpid-python-test", - "commands/qpid-cluster", - "commands/qpid-config", - "commands/qpid-printevents", - "commands/qpid-queue-stats", - "commands/qpid-route", - "commands/qpid-stat", - "commands/qpid-tool"], + packages=["mllib", "qpid", "qpid.tests"], + scripts=["qpid-python-test"], url="http://qpid.apache.org/", license="Apache Software License", description="Python language client implementation for Apache Qpid") |