diff options
author | Darryl L. Pierce <mcpierce@apache.org> | 2013-03-20 17:20:34 +0000 |
---|---|---|
committer | Darryl L. Pierce <mcpierce@apache.org> | 2013-03-20 17:20:34 +0000 |
commit | bef7da03ea1cacc98ae33e28f09b48fa9335204b (patch) | |
tree | 02feae405afe9ed2f1f11b1025649e04f517c042 | |
parent | ca84abd2a227eb09d483c66b8a3dcf7211484ee7 (diff) | |
download | qpid-python-bef7da03ea1cacc98ae33e28f09b48fa9335204b.tar.gz |
QPID-4644: Provides a Ruby version of qpidtoollibs
Contributed by: Andrew Goldstein <agoldste@redhat.com>
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1458961 13f79535-47bb-0310-9956-ffa450edef68
26 files changed, 1769 insertions, 0 deletions
diff --git a/qpid/tools/src/ruby/qpid_management/.gitignore b/qpid/tools/src/ruby/qpid_management/.gitignore new file mode 100644 index 0000000000..6a65a36504 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/.gitignore @@ -0,0 +1,3 @@ +*.gem +.bundle +pkg/* diff --git a/qpid/tools/src/ruby/qpid_management/.rspec b/qpid/tools/src/ruby/qpid_management/.rspec new file mode 100644 index 0000000000..4e1e0d2f72 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/.rspec @@ -0,0 +1 @@ +--color diff --git a/qpid/tools/src/ruby/qpid_management/Gemfile b/qpid/tools/src/ruby/qpid_management/Gemfile new file mode 100644 index 0000000000..1bd80c10c1 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/Gemfile @@ -0,0 +1,30 @@ +# +# 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. +# + +source "http://rubygems.org" + +# Specify your gem's dependencies in qpid_config.gemspec +gemspec + +# development deps +gem 'rspec' +gem 'pry' +gem 'pry-stack_explorer' +gem 'pry-debugger' +gem 'yard' diff --git a/qpid/tools/src/ruby/qpid_management/Gemfile.lock b/qpid/tools/src/ruby/qpid_management/Gemfile.lock new file mode 100644 index 0000000000..bf35564e90 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/Gemfile.lock @@ -0,0 +1,55 @@ +PATH + remote: . + specs: + qpid_management (1.0) + qpid_messaging + +GEM + remote: http://rubygems.org/ + specs: + binding_of_caller (0.7.1) + debug_inspector (>= 0.0.1) + coderay (1.0.9) + columnize (0.3.6) + debug_inspector (0.0.2) + debugger (1.4.0) + columnize (>= 0.3.1) + debugger-linecache (~> 1.1.1) + debugger-ruby_core_source (~> 1.2.0) + debugger-linecache (1.1.2) + debugger-ruby_core_source (>= 1.1.1) + debugger-ruby_core_source (1.2.0) + diff-lcs (1.2.1) + method_source (0.8.1) + pry (0.9.12) + coderay (~> 1.0.5) + method_source (~> 0.8) + slop (~> 3.4) + pry-debugger (0.2.2) + debugger (~> 1.3) + pry (~> 0.9.10) + pry-stack_explorer (0.4.9) + binding_of_caller (>= 0.7) + pry (~> 0.9.11) + qpid_messaging (0.20.2) + rspec (2.13.0) + rspec-core (~> 2.13.0) + rspec-expectations (~> 2.13.0) + rspec-mocks (~> 2.13.0) + rspec-core (2.13.0) + rspec-expectations (2.13.0) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.13.0) + slop (3.4.3) + yard (0.8.5.2) + +PLATFORMS + ruby + +DEPENDENCIES + pry + pry-debugger + pry-stack_explorer + qpid_management! + rspec + yard diff --git a/qpid/tools/src/ruby/qpid_management/Rakefile b/qpid/tools/src/ruby/qpid_management/Rakefile new file mode 100644 index 0000000000..7f295eda5c --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/Rakefile @@ -0,0 +1,27 @@ +# +# 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. +# + +require "bundler/gem_tasks" +require 'rspec/core/rake_task' + +require 'rake/clean' +CLOBBER.include('pkg') + +RSpec::Core::RakeTask.new('spec') + diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management.rb new file mode 100644 index 0000000000..0529710693 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management.rb @@ -0,0 +1,81 @@ +# +# 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. +# + +require 'qpid_management/broker_agent' +require 'qpid_management/broker_object' +require 'qpid_management/acl' +require 'qpid_management/binding' +require 'qpid_management/bridge' +require 'qpid_management/broker' +require 'qpid_management/cluster' +require 'qpid_management/connection' +require 'qpid_management/errors' +require 'qpid_management/exchange' +require 'qpid_management/ha_broker' +require 'qpid_management/link' +require 'qpid_management/memory' +require 'qpid_management/queue' +require 'qpid_management/session' +require 'qpid_management/subscription' + +module Qpid + # The Qpid Management framework is a management framework for Qpid brokers + # that uses QMF2. + # + # ==== Example Usage + # + # Here is a simple example. It TODO. + # + # require 'rubygems' + # require 'qpid_messaging' + # require 'qpid_management' + # + # # create a connection and open it + # conn = Qpid::Messaging::Connection.new(:url => "broker.myqpiddomain.com") + # conn.open() + # + # # create a broker agent + # agent = Qpid::Management::BrokerAgent.new(conn) + # + # # get a reference to the broker + # broker = agent.broker + # + # # print out all exchange names + # puts broker.exchanges.map(&:name) + # + # # print out info about a single exchange + # amq_direct = broker.exchange('amq.direct') + # puts amq_direct + # puts amq_direct.msgDrops + # + # # create an exchange + # broker.add_exchange('topic', 'myexchange') + # + # # print out all queue names + # puts broker.queues.map(&:name) + # + # # create a queue + # broker.add_queue('myqueue') + # + # # print out info about a single queue + # myqueue = broker.queue('myqueue') + # puts myqueue.msgDepth + module Management + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/acl.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/acl.rb new file mode 100644 index 0000000000..589b11fa59 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/acl.rb @@ -0,0 +1,38 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of the access control list (ACL) for the broker. Properties + # include: + # - aclDenyCount + # - brokerRef + # - connectionDenyCount + # - enforcingAcl + # - lastAclLoad + # - maxConnectionsPerIp + # - maxConnectionsPerUser + # - maxQueuesPerUser + # - policyFile + # - queueQuotaDenyCount + # - transferAcl + class Acl < BrokerObject + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/binding.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/binding.rb new file mode 100644 index 0000000000..cc46d84eeb --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/binding.rb @@ -0,0 +1,31 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of a binding in the broker. Properties include: + # - arguments + # - bindingKey + # - exchangeRef + # - msgMatched + # - queueRef + class Binding < BrokerObject + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/bridge.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/bridge.rb new file mode 100644 index 0000000000..cece0ba2ed --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/bridge.rb @@ -0,0 +1,39 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of a bridge to another broker. Properties include: + # - channelId + # - dest + # - durable + # - dynamic + # - excludes + # - key + # - linkRef + # - name + # - src + # - srcIsLocal + # - srcIsQueue + # - sync + # - tag + class Bridge < BrokerObject + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker.rb new file mode 100644 index 0000000000..31171bdf35 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker.rb @@ -0,0 +1,278 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of the broker. Properties include: + # - abandoned + # - abandonedViaAlt + # - acquires + # - byteDepth + # - byteFtdDepth + # - byteFtdDequeues + # - byteFtdEnqueues + # - bytePersistDequeues + # - bytePersistEnqueues + # - byteTotalDequeues + # - byteTotalEnqueues + # - byteTxnDequeues + # - byteTxnEnqueues + # - connBacklog + # - dataDir + # - discardsLvq + # - discardsNoRoute + # - discardsOverflow + # - discardsPurge + # - discardsRing + # - discardsSubscriber + # - discardsTtl + # - maxConns + # - mgmtPubInterval + # - mgmtPublish + # - msgDepth + # - msgFtdDepth + # - msgFtdDequeues + # - msgFtdEnqueues + # - msgPersistDequeues + # - msgPersistEnqueues + # - msgTotalDequeues + # - msgTotalEnqueues + # - msgTxnDequeues + # - msgTxnEnqueues + # - name + # - port + # - queueCount + # - releases + # - reroutes + # - stagingThreshold + # - systemRef + # - uptime + # - version + # - workerThreads + class Broker < BrokerObject + # Adds methods for the specified collections to be able to access all instances + # of a given collection, as well as a single instance by oid. + # + # == Example + # <tt>has_many :queues</tt> which will add: + # * <tt>#queues</tt> to retrieve all queues + # * <tt>#queue(oid)</tt> to retrieve a queue by oid (note, this is the short form of the object id, e.g. "myqueue" for a queue instead of "org.apache.qpid.broker:queue:myqueue" + # + # @param collections one or more symbols for the collections of objects a broker manages + def self.has_many(*collections) + [*collections].each do |collection| + singular_form = collection.to_s[0..-2] + capitalized_type = singular_form.gsub(/^\w/) { $&.upcase } + + define_method(collection) do + @agent.find_all_by_class(Qpid::Management::const_get(capitalized_type)) + end + + define_method(singular_form) do |oid| + @agent.find_by_object_id(Qpid::Management::const_get(capitalized_type), "org.apache.qpid.broker:#{singular_form}:#{oid}") + end + end + end + + # Adds method for the specified types to be able to access the singular + # instance of a given type. + # + # == Example + # <tt>has_one :acl</tt> which will add: + # * <tt>#acl</tt> to retrieve the Acl data for the Broker + # + # @param types one or more symbols for the singular objects a broker manages + def self.has_one(*types) + [*types].each do |type| + capitalized_type = type.to_s.gsub(/^\w/) { $&.upcase } + + define_method("#{type}") do + @agent.find_first_by_class(Qpid::Management::const_get(capitalized_type)) + end + end + end + + has_many :connections, :sessions, :subscriptions, :exchanges, :queues, :bindings, :links, :bridges + has_one :acl, :memory + + # Adds an exchange to the broker + # @param [String] type exchange type (fanout, direct, topic, headers, xml) + # @param [String] name exchange name + # @param [Hash] options exchange creation options + def add_exchange(type, name, options={}) + create_broker_object('exchange', name, options.merge!({'exchange-type' => type})) + end + + # Deletes an exchange from the broekr + # @param [String] name exchange name + def delete_exchange(name) + invoke_method('delete', {'type' => 'exchange', 'name' => name}) + end + + # Adds a queue to the broker + # @param [String] name queue name + # @param [Hash] options queue creation options + def add_queue(name, options={}) + create_broker_object('queue', name, options) + end + + # Deletes a queue from the broker + # @param [String] name queue name + def delete_queue(name) + invoke_method('delete', {'type' => 'queue', 'name' => name}) + end + + # Adds a binding from an exchange to a queue + # @param [String] exchange exchange name + # @param [String] queue queue name + # @param [String] key binding key + # @param [Hash] options binding creation options + def add_binding(exchange, queue, key="", options={}) + create_broker_object('binding', "#{exchange}/#{queue}/#{key}", options) + end + + # Deletes a binding from an exchange to a queue + # @param [String] exchange exchange name + # @param [String] queue queue name + # @param [String] key binding key + def delete_binding(exchange, queue, key="") + invoke_method('delete', {'type' => 'binding', 'name' => "#{exchange}/#{queue}/#{key}"}) + end + + # Adds a link to a remote broker + # @param [String] name link name + # @param [String] host remote broker host name or IP address + # @param [Fixnum] port remote broker port + # @param [String] transport transport mechanism used to connect to the remote broker + # @param [Boolean] durable should this link be persistent + # @param [String] auth_mechanism authentication mechanism to use + # @param [String] username user name to authenticate with the remote broker + # @param [String] password password for the user name + def add_link(name, host, port, transport='tcp', durable=false, auth_mechanism="", username="", password="") + options = { + 'host' => host, + 'port' => port, + 'transport' => transport, + 'durable' => durable, + 'authMechanism' => auth_mechanism, + 'username' => username, + 'password' => password + } + + create_broker_object('link', name, options) + end + + # Deletes a link to a remote broker + # @param [String] name link name + def delete_link(name) + invoke_method('delete', {'type' => 'link', 'name' => name}) + end + + # Adds a queue route + # @param [String] name the name of the bridge to create + # @param [Hash] options options for the queue route + # @option options [String] :link the name of the link to use (required) + # @option options [String] :queue the name of the source queue from which messages are pulled (required) + # @option options [String] :exchange the name of the destination exchange to which messages are sent (required) + # @option options [Fixnum] :sync the number of messages to send before issuing an explicit session sync (required) + def add_queue_route(name, options={}) + validate_options(options, [:link, :queue, :exchange, :sync]) + + properties = { + 'link' => options[:link], + 'src' => options[:queue], + 'dest' => options[:exchange], + 'srcIsQueue' => true, + 'sync' => options[:sync] + } + + create_broker_object('bridge', name, properties) + end + + # Adds an exchange route + # @param [String] name the name of the bridge to create + # @param [Hash] options options for the exchange route + # @option options [String] :link the name of the link to use (required) + # @option options [String] :exchange the name of the exchange to use (required) + # @option options [String] :key routing key to federate (required) + # @option options [Fixnum] :sync the number of messages to send before issuing an explicit session sync (required) + # @option options [String] :bridge_queue name of the queue to use as a bridge queue (optional) + def add_exchange_route(name, options={}) + validate_options(options, [:link, :exchange, :key, :sync]) + + properties = { + 'link' => options[:link], + 'src' => options[:exchange], + 'dest' => options[:exchange], + 'key' => options[:key], + 'sync' => options[:sync] + } + + properties['queue'] = options[:bridge_queue] if options.has_key?(:bridge_queue) + + create_broker_object('bridge', name, properties) + end + + # Adds a dynamic route + # @param [String] name the name of the bridge to create + # @param [Hash] options options for the dynamic route + # @option options [String] :link the name of the link to use (required) + # @option options [String] :exchange the name of the exchange to use (required) + # @option options [Fixnum] :sync the number of messages to send before issuing an explicit session sync (required) + # @option options [String] :bridge_queue name of the queue to use as a bridge queue (optional) + def add_dynamic_route(name, options={}) + validate_options(options, [:link, :exchange, :sync]) + + properties = { + 'link' => options[:link], + 'src' => options[:exchange], + 'dest' => options[:exchange], + 'dynamic' => true, + 'sync' => options[:sync] + } + + properties['queue'] = options[:bridge_queue] if options.has_key?(:bridge_queue) + + create_broker_object('bridge', name, properties) + end + + # Deletes a bridge (route) + # @param [String] name bridge name + def delete_bridge(name) + invoke_method('delete', {'type' => 'bridge', 'name' => name}) + end + + private + + def create_broker_object(type, name, options) + invoke_method('create', {'type' => type, + 'name' => name, + 'properties' => options, + 'strict' => true}) + end + + def validate_options(options, required) + required.each do |req| + raise "Option :#{req.to_s} is required" unless options.has_key?(req) + end + end + + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_agent.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_agent.rb new file mode 100644 index 0000000000..800dcf26dc --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_agent.rb @@ -0,0 +1,173 @@ +# +# 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. +# + +# for simplistic UUID - may want to consider something better in the future +require 'securerandom' + +# Ruby 1.8 doesn't include SecureRandom#uuid, so let's add it if it's missing +unless SecureRandom.respond_to? :uuid + module SecureRandom + def self.uuid + ary = self.random_bytes(16).unpack("NnnnnN") + ary[2] = (ary[2] & 0x0fff) | 0x4000 + ary[3] = (ary[3] & 0x3fff) | 0x8000 + "%08x-%04x-%04x-%04x-%04x%08x" % ary + end + end +end + +module Qpid + module Management + # This is the primary class that interacts with a Qpid messaging broker for + # querying information from the broker and for configuring it. + class BrokerAgent + # Creates a new BrokerAgent instance. A new Qpid::Messaging::Session, + # Qpid::Messaging::Receiver, and Qpid::Messaging::Sender will be created + # so this instance of the BrokerAgent may send requests to the broker + # and receive replies back. + # @param [Qpid::Messaging::Connection] connection a valid, opened connection + def initialize(connection) + @connection = connection + @session = @connection.create_session() + @reply_to = "qmf.default.topic/direct.#{SecureRandom.uuid}; {node: {type:topic}, link:{x-declare:{auto-delete:True,exclusive:True}}}" + @reply_rx = @session.create_receiver(@reply_to) + @reply_rx.capacity = 10 + @tx = @session.create_sender("qmf.default.direct/broker") + end + + # Closes the Qpid::Messaging::Session for this BrokerAgent. + def close() + @session.close() + end + + # Queries the broker for the Broker QMF object. + # @return [Broker] the broker QMF object + def broker() + find_first_by_class(Broker) + end + + # Queries the broker for the Cluster QMF object. + # @return [Cluster] the cluster QMF object + def cluster + find_first_by_class(Cluster) + end + + # Queries the broker for the HaBroker QMF object. + # @return [HaBroker] the HA broker QMF object + def ha_broker + find_first_by_class(HaBroker) + end + + # Invokes a method on a target object. + # @param [String] method the name of the method to invoke + # @param [Hash] args the arguments to pass to the method + # @param [String] addr the full id of the target object + # @param [Fixnum] timeout the amount of time to wait for the broker to respond to the method invocation + def invoke_method(method, args, addr="org.apache.qpid.broker:broker:amqp-broker", timeout=10) + content = {'_object_id' => {'_object_name' => addr}, + '_method_name' => method, + '_arguments' => args} + + message = Qpid::Messaging::Message.new() + message.content = content + message.reply_to = @reply_to + message['method'] = 'request' + message['qmf.opcode'] = '_method_request' + message['x-amqp-0-10.app-id'] = 'qmf2' + message.subject = 'broker' + + @tx.send(message) + + response = @reply_rx.fetch(Qpid::Messaging::Duration.new(timeout * 1000)) + @session.acknowledge() + + raise "Exception from Agent: #{response.content['_values']}" if response.properties['qmf.opcode'] == '_exception' + raise "Bad response: #{response.properties}" if response.properties['qmf.opcode'] != '_method_response' + + return response.content['_arguments'] + end + + def send_query(query) + message = Qpid::Messaging::Message.new() + message.content = query + message.reply_to = @reply_to + message['method'] = 'request' + message['qmf.opcode'] = '_query_request' + message['x-amqp-0-10.app-id'] = 'qmf2' + message.subject = 'broker' + + @tx.send(message) + + response = @reply_rx.fetch(Qpid::Messaging::Duration.new(10*1000)) + @session.acknowledge() + + raise 'Bad response' if response.properties['qmf.opcode'] != '_query_response' + + items = response.content + + while response.properties.has_key?('partial') + response = @reply_rx.fetch(Qpid::Messaging::Duration.new(10*1000)) + items += response.content + @session.acknowledge() + end + + return items + end + + def find_all_by_class(clazz) + query = { + '_what' => 'OBJECT', + '_schema_id' => { + '_class_name' => BrokerObject.qmf_class(clazz) + } + } + + items = send_query(query) + + [].tap do |objs| + for item in items + objs << clazz.new(self, item) + end + end + end + + def find_first_by_class(clazz) + objects = find_all_by_class(clazz) + return objects[0] if objects.size > 0 + return nil + end + + def find_by_object_id(clazz, oid) + query = { + '_what' => 'OBJECT', + '_object_id' => { + '_object_name' => oid + } + } + + results = send_query(query) + + return clazz.new(self, results[0]) if results.count == 1 and not results[0].nil? + + # return nil if not found + return nil + end + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_object.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_object.rb new file mode 100644 index 0000000000..fbbe5ff6e2 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/broker_object.rb @@ -0,0 +1,126 @@ +# 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. +# + +module Qpid + module Management + # Representation of an object in the broker retrieved via QMF + class BrokerObject + attr_reader :content + + # Creates a new BrokerObject + # @param [BrokerAgent] agent the agent used to query the data from the broker + # @param [Hash] content the raw QMF response data from the broker + def initialize(agent, content) + @agent = agent + @content = content + @values = content['_values'] + end + + # Refreshes the information associated with this instance by requerying the broker + # @raise [ObjectDeletedError] if the object has been deleted + def refresh! + refreshed = @agent.named_object(self.class, id) + if refreshed + @content = refreshed.content + @values = @content['_values'] + else + raise ObjectDeletedError + end + end + + # Returns the full object id + # @return [String] the full object id + def id + @content['_object_id']['_object_name'] + end + + # Helper method to convert a Class to its QMF name counterpart. For + # example, QpidConfig::Connection will be converted to connection. + # @param [Class] clazz the Class to convert + # @return [String] the converted QMF name counterpart for this Class + def self.qmf_class(clazz) + clazz.name.split(/::/).last.downcase + end + + # Returns the short object id, i.e. without the leading org.apache.qpid.broker:<class name>: + # @return [String] the short object id + def short_id + clazz = BrokerObject.qmf_class(self.class) + if id =~ /org.apache.qpid.broker:#{clazz}:(.*)/ + return $1; + end + return nil + end + + # Returns the time at which this object was created + # @return [Time] the time at which this object was created + def created_at + Time.at(content['_create_ts'] / 1000000000.0) + end + + # Returns the time at which this object was deleted. Only ever applies to + # BrokerObject instances created from a QMF event. + # @return [Time] the time at which this object was deleted + def deleted_at + Time.at(content['_delete_ts'] / 1000000000.0) + end + + # Returns the time at which this object was last updated + # @return [Time] the time at which this object was last updated + def updated_at + Time.at(content['_update_ts'] / 1000000000.0) + end + + # Exposes data from the QMF response + # @param [String] key the key to look up a value, e.g. msgDepth for a queue + # @return the value associated with the key, or nil if not found + def [](key) + return nil unless @values.has_key?(key) + value = @values[key] + if value.is_a?(Hash) and value.has_key?('_object_name') + full_name = value['_object_name'] + colon = full_name.index(':') + unless colon.nil? + full_name = full_name[colon+1..-1] + colon = full_name.index(':') + return full_name[colon+1..-1] unless colon.nil? + end + end + + return value + end + + # Exposes data from the QMF response via methods, e.g. queue.msgDepth + def method_missing(method, *args, &block) + key = method.to_s + return self[key] if args.empty? and not self[key].nil? + super + end + + def to_s + @values.to_s + end + + # Invokes a QMF method + # @see BrokerAgent#invoke_method + def invoke_method(*args) + @agent.invoke_method(*args) + end + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/cluster.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/cluster.rb new file mode 100644 index 0000000000..4fa7f146a7 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/cluster.rb @@ -0,0 +1,26 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of a cluster + class Cluster < BrokerObject + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/connection.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/connection.rb new file mode 100644 index 0000000000..153ccee684 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/connection.rb @@ -0,0 +1,51 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of a client connection. Properties include: + # - SystemConnection + # - address + # - authIdentity + # - bytesFromClient + # - bytesToClient + # - closing + # - federationLink + # - framesFromClient + # - framesToClient + # - incoming + # - msgsFromClient + # - msgsToClient + # - remoteParentPid + # - remotePid + # - remoteProcessName + # - remoteProperties + # - saslMechanism + # - saslSsf + # - shadow + # - userProxyAuth + # - vhostRef + class Connection < BrokerObject + # Closes this connection to the broker + def close + invoke_method('close', {}, "org.apache.qpid.broker:connection:#{address}") + end + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/errors.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/errors.rb new file mode 100644 index 0000000000..b922cda680 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/errors.rb @@ -0,0 +1,28 @@ +# +# 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. +# + +module Qpid + module Management + class ObjectNotFoundError < RuntimeError + end + + class ObjectDeletedError < RuntimeError + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/exchange.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/exchange.rb new file mode 100644 index 0000000000..5a3223aba6 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/exchange.rb @@ -0,0 +1,44 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of an exchange. Properties include: + # - arguments + # - autoDelete + # - bindingCount + # - bindingCountHigh + # - bindingCountLow + # - byteDrops + # - byteReceives + # - byteRoutes + # - durable + # - msgDrops + # - msgReceives + # - msgRoutes + # - name + # - producerCount + # - producerCountHigh + # - producerCountLow + # - type + # - vhostRef + class Exchange < BrokerObject + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/ha_broker.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/ha_broker.rb new file mode 100644 index 0000000000..1ac9ea7a17 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/ha_broker.rb @@ -0,0 +1,26 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of an HA broker + class HaBroker < BrokerObject + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/link.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/link.rb new file mode 100644 index 0000000000..455b26a440 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/link.rb @@ -0,0 +1,35 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of a link to a remote broker. Properties include: + # - connectionRef + # - durable + # - host + # - lastError + # - name + # - port + # - state + # - transport + # - vhostRef + class Link < BrokerObject + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/memory.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/memory.rb new file mode 100644 index 0000000000..39dd803c9a --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/memory.rb @@ -0,0 +1,34 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of the broker's memory. Properties include: + # - malloc_arena + # - malloc_fordblks + # - malloc_hblkhd + # - malloc_hblks + # - malloc_keepcost + # - malloc_ordblks + # - malloc_uordblks + # - name + class Memory < BrokerObject + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/queue.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/queue.rb new file mode 100644 index 0000000000..c4fae3a53e --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/queue.rb @@ -0,0 +1,97 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of a queue. Properties include: + # - acquires + # - arguments + # - autoDelete + # - bindingCount + # - bindingCountHigh + # - bindingCountLow + # - byteDepth + # - byteFtdDepth + # - byteFtdDequeues + # - byteFtdEnqueues + # - bytePersistDequeues + # - bytePersistEnqueues + # - byteTotalDequeues + # - byteTotalEnqueues + # - byteTxnDequeues + # - byteTxnEnqueues + # - consumerCount + # - consumerCountHigh + # - consumerCountLow + # - discardsLvq + # - discardsOverflow + # - discardsPurge + # - discardsRing + # - discardsSubscriber + # - discardsTtl + # - durable + # - exclusive + # - flowStopped + # - flowStoppedCount + # - messageLatencyAvg + # - messageLatencyCount + # - messageLatencyMax + # - messageLatencyMin + # - msgDepth + # - msgFtdDepth + # - msgFtdDequeues + # - msgFtdEnqueues + # - msgPersistDequeues + # - msgPersistEnqueues + # - msgTotalDequeues + # - msgTotalEnqueues + # - msgTxnDequeues + # - msgTxnEnqueues + # - name + # - releases + # - reroutes + # - unackedMessages + # - unackedMessagesHigh + # - unackedMessagesLow + # - vhostRef + class Queue < BrokerObject + # Purges (removes) messages from this queue + # @param [Fixnum] message_count number of messages to remove from the queue, or 0 for all messages + # @param [Hash] filter an optional filter to use when removing messages + def purge(message_count, filter={}) + invoke_method('purge', {'request' => message_count, 'filter' => filter}, "org.apache.qpid.broker:queue:#{name}") + end + + # Reroutes messages from this queue to an exchange, either the queue's + # alternate exchange, or the specified exchange + # @param [Fixnum] message_count number of messages to reroute from the queue, or 0 for all messages + # @param [Boolean] use_alternate_exchange whether to use the queue's alternate exchange as the destination + # @param [String] exchange name of destination exchange + # @param [Hash] filter an optional filter to use when rerouting messages + def reroute(message_count, use_alternate_exchange, exchange, filter) + args = {'request' => message_count, + 'useAltExchange' => use_alternate_exchange, + 'exchange' => exchange, + 'filter' => filter} + + invoke_method('reroute', args, "org.apache.qpid.broker:queue:#{name}") + end + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/session.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/session.rb new file mode 100644 index 0000000000..b4fcc7da59 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/session.rb @@ -0,0 +1,38 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of a session to the broker. Properties include: + # - TxnCommits + # - TxnCount + # - TxnRejects + # - TxnStarts + # - attached + # - channelId + # - clientCredit + # - connectionRef + # - detachedLifespan + # - name + # - unackedMessages + # - vhostRef + class Session < BrokerObject + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/lib/qpid_management/subscription.rb b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/subscription.rb new file mode 100644 index 0000000000..fcff2831c0 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/lib/qpid_management/subscription.rb @@ -0,0 +1,35 @@ +# +# 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. +# + +module Qpid + module Management + # Representation of a subscription. Properties include: + # - acknowledged + # - arguments + # - browsing + # - creditMode + # - delivered + # - exclusive + # - name + # - queueRef + # - sessionRef + class Subscription < BrokerObject + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/qpid_management.gemspec b/qpid/tools/src/ruby/qpid_management/qpid_management.gemspec new file mode 100644 index 0000000000..a6cc1b828e --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/qpid_management.gemspec @@ -0,0 +1,36 @@ +# +# 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. +# + +# -*- encoding: utf-8 -*- +$:.push File.expand_path("../lib", __FILE__) + +Gem::Specification.new do |s| + s.name = "qpid_management" + s.version = "1.0" + s.authors = ["Apache Qpid Project"] + s.email = ["dev@qpid.apache.org"] + s.homepage = "http://qpid.apache.org" + s.summary = %q{Qpid management library} + s.description = %q{Qpid management library} + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } + s.require_paths = ["lib"] + s.add_runtime_dependency 'qpid_messaging' +end diff --git a/qpid/tools/src/ruby/qpid_management/spec/broker_agent_spec.rb b/qpid/tools/src/ruby/qpid_management/spec/broker_agent_spec.rb new file mode 100644 index 0000000000..7ffbf842e2 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/spec/broker_agent_spec.rb @@ -0,0 +1,43 @@ +# +# 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. +# + +require 'spec_helper' + +describe Qpid::Management::BrokerAgent do + before(:each) do + @broker_port = `qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop + @connection = Qpid::Messaging::Connection.new(url:"localhost:#{@broker_port}") + @connection.open() + @agent = Qpid::Management::BrokerAgent.new(@connection) + end + + after(:each) do + @agent.close() + @connection.close() + `qpidd -q --port #{@broker_port}` + end + + describe '#broker' do + let(:broker) { @agent.broker } + + it 'returns the broker' do + broker.class.should == Qpid::Management::Broker + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/spec/broker_spec.rb b/qpid/tools/src/ruby/qpid_management/spec/broker_spec.rb new file mode 100644 index 0000000000..6d6e1106a4 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/spec/broker_spec.rb @@ -0,0 +1,373 @@ +# +# 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. +# + +require 'spec_helper' + +describe Qpid::Management::Broker do + before(:each) do + @broker_port = `qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop + @connection = Qpid::Messaging::Connection.new(url:"localhost:#{@broker_port}") + @connection.open() + @agent = Qpid::Management::BrokerAgent.new(@connection) + @broker = @agent.broker + end + + after(:each) do + @agent.close() + @connection.close() + `qpidd --quit --port #{@broker_port}` + end + + def setup_queue_route + @other_port = `qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop + @broker.add_link('link1', 'localhost', @other_port) + @broker.add_queue('queue') + @broker.add_queue_route('qr1', + link: 'link1', + queue: 'queue', + exchange: 'amq.direct', + sync: 2) + end + + %w(connection session subscription exchange queue binding link bridge).each do |type| + describe "##{type}s" do + before(:each) do + setup_queue_route if %w(link bridge).include?(type) + end + + after(:each) do + if %w(link bridge).include?(type) + `qpidd --quit --port #{@other_port}` + end + end + + let(:collection) { @broker.send("#{type}s") } + + it "returns at least 1 #{type}" do + if type == 'subscription' + session = @connection.create_session + receiver = session.create_receiver("amq.direct/temp") + end + collection.count.should be > 0 + end + end + + describe "##{type}" do + before(:each) do + setup_queue_route if %w(link bridge).include?(type) + end + + after(:each) do + if %w(link bridge).include?(type) + `qpidd --quit --port #{@other_port}` + end + end + + let(:object) { @broker.send("#{type}s")[0] } + + it "returns a #{type} by oid" do + if type == 'subscription' + session = @connection.create_session + receiver = session.create_receiver("amq.direct/temp") + end + @broker.send(type, object.short_id).id.should == object.id + end + end + end + + describe '#add_exchange' do + %w(fanout direct topic headers).each do |type| + context "when adding a #{type} exchange" do + let(:exchange_name) { "#{type}1" } + before(:each) do + @before_creation = Time.now + @broker.add_exchange(type, exchange_name, {'qpid.replicate' => 'none'}) + end + + subject { @broker.exchange(exchange_name) } + its(:short_id) { should == exchange_name } + its(:type) { should == type } + its(:created_at) { should be > @before_creation } + it 'has the correct arguments' do + subject.arguments.should == {'qpid.replicate' => 'none'} + end + end + end + end + + describe "#delete_exchange" do + before(:each) do + @before_creation = Time.now + @broker.add_exchange('fanout', 'fanout_to_delete') + end + + let(:exchange) { @broker.exchange('fanout_to_delete') } + + context "with a valid exchange name" do + it "deletes the exchange" do + @broker.delete_exchange(exchange.short_id) + expect { exchange.refresh! }.to raise_error + end + end + + context "with an invalid exchange name" do + it "raises a not-found exception" do + expect { @broker.delete_exchange("badname") }.to raise_error(/not-found.*badname/) + end + end + end + + describe "#add_queue" do + before(:each) do + @before_creation = Time.now + @queue_name = 'myqueue' + @broker.add_queue(@queue_name, {'qpid.replicate' => 'none'}) + end + + subject { @broker.queue(@queue_name) } + its(:short_id) { should == @queue_name } + its(:created_at) { should be > @before_creation } + it 'has the correct arguments' do + subject.arguments.should == {'qpid.replicate' => 'none'} + end + end + + describe "#delete_queue" do + before(:each) do + @before_creation = Time.now + @broker.add_queue('queue_to_delete') + end + + let(:queue) { @broker.queue('queue_to_delete') } + + context "with a valid queue name" do + it "deletes the queue" do + @broker.delete_queue(queue.short_id) + expect { queue.refresh! }.to raise_error + end + end + + context "with an invalid name" do + it "raises a not-found exception" do + expect { @broker.delete_queue("badname") }.to raise_error(/not-found.*badname/) + end + end + end + + describe "#add_binding" do + before(:each) do + @broker.add_queue('queue') + end + + it "creates a binding for a fanout exchange" do + @broker.add_exchange('fanout', 'fanout') + @broker.add_binding('fanout', 'queue') + expect { @broker.binding('org.apache.qpid.broker:exchange:fanout,org.apache.qpid.broker:queue:queue,') }.to_not raise_error + end + + it "creates a binding for a direct exchange" do + @broker.add_exchange('direct', 'direct') + @broker.add_binding('direct', 'queue', 'mykey') + expect { @broker.binding('org.apache.qpid.broker:exchange:direct,org.apache.qpid.broker:queue:queue,mykey') }.to_not raise_error + end + + it "creates a binding for a topic exchange" do + @broker.add_exchange('topic', 'topic') + @broker.add_binding('topic', 'queue', 'us.#') + expect { @broker.binding('org.apache.qpid.broker:exchange:topic,org.apache.qpid.broker:queue:queue,us.#') }.to_not raise_error + end + end + + describe "#delete_binding" do + it "deletes an existing binding" do + @broker.add_queue('queue') + @broker.add_exchange('fanout', 'fanout') + @broker.add_binding('fanout', 'queue') + expect { @broker.delete_binding('fanout', 'queue') }.to_not raise_error + end + end + + describe "#add_link" do + before(:each) do + @other_port = `/usr/sbin/qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop + end + + after(:each) do + `/usr/sbin/qpidd -q --port #{@other_port}` + end + + it "adds a link" do + @broker.add_link('link1', 'localhost', @other_port) + @broker.links.count.should == 1 + end + end + + describe "#delete_link" do + before(:each) do + @other_port = `/usr/sbin/qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop + @broker.add_link('link1', 'localhost', @other_port) + end + + after(:each) do + `/usr/sbin/qpidd -q --port #{@other_port}` + end + + it "deletes a link" do + @broker.delete_link('link1') + @broker.links.count.should == 0 + end + end + + describe "#add_queue_route" do + context "with missing options" do + [:link, :queue, :exchange, :sync].each do |opt| + opts = {link: 'l', queue: 'q', exchange: 'e', sync:2} + opts.delete(opt) + it "raises an error when :#{opt} is missing" do + expect { @broker.add_queue_route('name', opts) }.to raise_error(/Option :#{opt} is required/) + end + end + end + + context "with all required options" do + before(:each) do + @other_port = `/usr/sbin/qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop + @broker.add_link('link1', 'localhost', @other_port) + @broker.add_queue('queue') + @broker.add_queue_route('qr1', + link: 'link1', + queue: 'queue', + exchange: 'amq.direct', + sync: 2) + end + + after(:each) do + `/usr/sbin/qpidd -q --port #{@other_port}` + end + + it "adds a queue route" do + @broker.bridges.count.should == 1 + end + + subject { @broker.bridges[0] } + its(:dest) { should == 'amq.direct' } + its(:durable) { should == false } + its(:dynamic) { should == false } + its(:excludes) { should == "" } + its(:key) { should == "" } + its(:name) { should == "qr1" } + its(:src) { should == "queue" } + its(:srcIsLocal) { should == false } + its(:srcIsQueue) { should == true } + its(:sync) { should == 2 } + its(:tag) { should == "" } + end + end + + describe "#add_exchange_route" do + context "with missing options" do + [:link, :exchange, :key, :sync].each do |opt| + opts = {link: 'l', exchange: 'e', key:'rk', sync:2} + opts.delete(opt) + it "raises an error when :#{opt} is missing" do + expect { @broker.add_exchange_route('name', opts) }.to raise_error(/Option :#{opt} is required/) + end + end + end + + context "with all required options" do + before(:each) do + @other_port = `/usr/sbin/qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop + @broker.add_link('link1', 'localhost', @other_port) + @broker.add_queue('queue') + @broker.add_exchange_route('er1', + link: 'link1', + exchange: 'amq.direct', + key: 'foo', + sync: 2) + end + + after(:each) do + `/usr/sbin/qpidd -q --port #{@other_port}` + end + + it "adds an exchange route" do + @broker.bridges.count.should == 1 + end + + subject { @broker.bridges[0] } + its(:dest) { should == 'amq.direct' } + its(:durable) { should == false } + its(:dynamic) { should == false } + its(:excludes) { should == "" } + its(:key) { should == "foo" } + its(:name) { should == "er1" } + its(:src) { should == "amq.direct" } + its(:srcIsLocal) { should == false } + its(:srcIsQueue) { should == false } + its(:sync) { should == 2 } + its(:tag) { should == "" } + end + end + + describe "#add_dynamic_route" do + context "with missing options" do + [:link, :exchange, :sync].each do |opt| + opts = {link: 'l', exchange: 'e', sync:2} + opts.delete(opt) + it "raises an error when :#{opt} is missing" do + expect { @broker.add_dynamic_route('name', opts) }.to raise_error(/Option :#{opt} is required/) + end + end + end + + context "with all required options" do + before(:each) do + @other_port = `/usr/sbin/qpidd --no-data-dir --auth=no --no-module-dir --daemon --port 0`.chop + @broker.add_link('link1', 'localhost', @other_port) + @broker.add_queue('queue') + @broker.add_dynamic_route('dr1', + link: 'link1', + exchange: 'amq.direct', + sync: 2) + end + + after(:each) do + `/usr/sbin/qpidd -q --port #{@other_port}` + end + + it "adds an exchange route" do + @broker.bridges.count.should == 1 + end + + subject { @broker.bridges[0] } + its(:dest) { should == 'amq.direct' } + its(:durable) { should == false } + its(:dynamic) { should == true } + its(:excludes) { should == "" } + its(:key) { should == "" } + its(:name) { should == "dr1" } + its(:src) { should == "amq.direct" } + its(:srcIsLocal) { should == false } + its(:srcIsQueue) { should == false } + its(:sync) { should == 2 } + its(:tag) { should == "" } + end + end +end diff --git a/qpid/tools/src/ruby/qpid_management/spec/spec_helper.rb b/qpid/tools/src/ruby/qpid_management/spec/spec_helper.rb new file mode 100644 index 0000000000..f552c55888 --- /dev/null +++ b/qpid/tools/src/ruby/qpid_management/spec/spec_helper.rb @@ -0,0 +1,21 @@ +# +# 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. +# + +require 'qpid_messaging' +require 'qpid_management' |