Class MCollective::Connector::Stomp
In: spec/unit/util_spec.rb
plugins/mcollective/connector/stomp.rb
Parent: MCollective::Connector::Base

Handles sending and receiving messages over the Stomp protocol

This plugin supports version 1.1 or 1.1.6 and newer of the Stomp rubygem the versions between those had multi threading issues.

For all versions you can configure it as follows:

   connector = stomp
   plugin.stomp.host = stomp.your.net
   plugin.stomp.port = 6163
   plugin.stomp.user = you
   plugin.stomp.password = secret

All of these can be overriden per user using environment variables:

   STOMP_SERVER, STOMP_PORT, STOMP_USER, STOMP_PASSWORD

Version 1.1.6 onward support supplying multiple connections and it will do failover between these servers, you can configure it as follows:

    connector = stomp
    plugin.stomp.pool.size = 2

    plugin.stomp.pool.host1 = stomp1.your.net
    plugin.stomp.pool.port1 = 6163
    plugin.stomp.pool.user1 = you
    plugin.stomp.pool.password1 = secret
    plugin.stomp.pool.ssl1 = true

    plugin.stomp.pool.host2 = stomp2.your.net
    plugin.stomp.pool.port2 = 6163
    plugin.stomp.pool.user2 = you
    plugin.stomp.pool.password2 = secret
    plugin.stomp.pool.ssl2 = false

Using this method you can supply just STOMP_USER and STOMP_PASSWORD you have to supply the hostname for each pool member in the config. The port will default to 6163 if not specified.

In addition you can set the following options but only when using pooled configuration:

    plugin.stomp.pool.initial_reconnect_delay = 0.01
    plugin.stomp.pool.max_reconnect_delay = 30.0
    plugin.stomp.pool.use_exponential_back_off = true
    plugin.stomp.pool.back_off_multiplier = 2
    plugin.stomp.pool.max_reconnect_attempts = 0
    plugin.stomp.pool.randomize = false
    plugin.stomp.pool.timeout = -1

For versions of ActiveMQ that supports message priorities you can set a priority, this will cause a "priority" header to be emitted if present:

    plugin.stomp.priority = 4

Methods

Attributes

connection  [R] 

Public Class methods

[Source]

    # File plugins/mcollective/connector/stomp.rb, line 64
64:             def initialize
65:                 @config = Config.instance
66:                 @subscriptions = []
67:             end

Public Instance methods

Connects to the Stomp middleware

[Source]

     # File plugins/mcollective/connector/stomp.rb, line 70
 70:             def connect(connector = ::Stomp::Connection)
 71:                 if @connection
 72:                     Log.debug("Already connection, not re-initializing connection")
 73:                     return
 74:                 end
 75: 
 76:                 begin
 77:                     host = nil
 78:                     port = nil
 79:                     user = nil
 80:                     password = nil
 81:                     @base64 = get_bool_option("stomp.base64", false)
 82:                     @msgpriority = get_option("stomp.priority", 0).to_i
 83: 
 84:                     # Maintain backward compat for older stomps
 85:                     unless @config.pluginconf.include?("stomp.pool.size")
 86:                         host = get_env_or_option("STOMP_SERVER", "stomp.host")
 87:                         port = get_env_or_option("STOMP_PORT", "stomp.port", 6163).to_i
 88:                         user = get_env_or_option("STOMP_USER", "stomp.user")
 89:                         password = get_env_or_option("STOMP_PASSWORD", "stomp.password")
 90: 
 91:                         Log.debug("Connecting to #{host}:#{port}")
 92:                         @connection = connector.new(user, password, host, port, true)
 93:                     else
 94:                         pools = @config.pluginconf["stomp.pool.size"].to_i
 95:                         hosts = []
 96: 
 97:                         1.upto(pools) do |poolnum|
 98:                             host = {}
 99: 
100:                             host[:host] = get_option("stomp.pool.host#{poolnum}")
101:                             host[:port] = get_option("stomp.pool.port#{poolnum}", 6163).to_i
102:                             host[:login] = get_env_or_option("STOMP_USER", "stomp.pool.user#{poolnum}")
103:                             host[:passcode] = get_env_or_option("STOMP_PASSWORD", "stomp.pool.password#{poolnum}")
104:                             host[:ssl] = get_bool_option("stomp.pool.ssl#{poolnum}", false)
105: 
106:                             Log.debug("Adding #{host[:host]}:#{host[:port]} to the connection pool")
107:                             hosts << host
108:                         end
109: 
110:                         raise "No hosts found for the STOMP connection pool" if hosts.size == 0
111: 
112:                         connection = {:hosts => hosts}
113: 
114:                         # Various STOMP gem options, defaults here matches defaults for 1.1.6 the meaning of
115:                         # these can be guessed, the documentation isn't clear
116:                         connection[:initial_reconnect_delay] = get_option("stomp.pool.initial_reconnect_delay", 0.01).to_f
117:                         connection[:max_reconnect_delay] = get_option("stomp.pool.max_reconnect_delay", 30.0).to_f
118:                         connection[:use_exponential_back_off] = get_bool_option("stomp.pool.use_exponential_back_off", true)
119:                         connection[:back_off_multiplier] = get_bool_option("stomp.pool.back_off_multiplier", 2).to_i
120:                         connection[:max_reconnect_attempts] = get_option("stomp.pool.max_reconnect_attempts", 0).to_i
121:                         connection[:randomize] = get_bool_option("stomp.pool.randomize", false)
122:                         connection[:backup] = get_bool_option("stomp.pool.backup", false)
123:                         connection[:timeout] = get_option("stomp.pool.timeout", -1).to_i
124: 
125:                         @connection = connector.new(connection)
126:                     end
127:                 rescue Exception => e
128:                     raise("Could not connect to Stomp Server: #{e}")
129:                 end
130:             end

Disconnects from the Stomp connection

[Source]

     # File plugins/mcollective/connector/stomp.rb, line 182
182:             def disconnect
183:                 Log.debug("Disconnecting from Stomp")
184:                 @connection.disconnect
185:             end

gets a boolean option from the config, supports y/n/true/false/1/0

[Source]

     # File plugins/mcollective/connector/stomp.rb, line 217
217:             def get_bool_option(opt, default)
218:                 return default unless @config.pluginconf.include?(opt)
219: 
220:                 val = @config.pluginconf[opt]
221: 
222:                 if val =~ /^1|yes|true/
223:                     return true
224:                 elsif val =~ /^0|no|false/
225:                     return false
226:                 else
227:                     return default
228:                 end
229:             end

looks in the environment first then in the config file for a specific option, accepts an optional default.

raises an exception when it cant find a value anywhere

[Source]

     # File plugins/mcollective/connector/stomp.rb, line 198
198:             def get_env_or_option(env, opt, default=nil)
199:                 return ENV[env] if ENV.include?(env)
200:                 return @config.pluginconf[opt] if @config.pluginconf.include?(opt)
201:                 return default if default
202: 
203:                 raise("No #{env} environment or plugin.#{opt} configuration option given")
204:             end

looks for a config option, accepts an optional default

raises an exception when it cant find a value anywhere

[Source]

     # File plugins/mcollective/connector/stomp.rb, line 209
209:             def get_option(opt, default=nil)
210:                 return @config.pluginconf[opt] if @config.pluginconf.include?(opt)
211:                 return default if default
212: 
213:                 raise("No plugin.#{opt} configuration option given")
214:             end

[Source]

     # File plugins/mcollective/connector/stomp.rb, line 231
231:             def make_target(agent, type, collective)
232:                 raise("Unknown target type #{type}") unless [:broadcast, :directed, :reply].include?(type)
233:                 raise("Unknown collective '#{collective}' known collectives are '#{@config.collectives.join ', '}'") unless @config.collectives.include?(collective)
234: 
235:                 type = :command unless type == :reply
236: 
237:                 ["#{@config.topicprefix}#{collective}", agent, type].join(@config.topicsep)
238:             end

[Source]

     # File plugins/mcollective/connector/stomp.rb, line 187
187:             def msgheaders
188:                 headers = {}
189:                 headers = {"priority" => @msgpriority} if @msgpriority > 0
190: 
191:                 return headers
192:             end

Sends a message to the Stomp connection

[Source]

     # File plugins/mcollective/connector/stomp.rb, line 148
148:             def publish(target, msg)
149:                 Log.debug("Sending a message to Stomp target '#{target}'")
150: 
151:                 msg = SSL.base64_encode(msg) if @base64
152: 
153:                 # deal with deprecation warnings in newer stomp gems
154:                 if @connection.respond_to?("publish")
155:                     @connection.publish(target, msg, msgheaders)
156:                 else
157:                     @connection.send(target, msg, msgheaders)
158:                 end
159:             end

Receives a message from the Stomp connection

[Source]

     # File plugins/mcollective/connector/stomp.rb, line 133
133:             def receive
134:                 Log.debug("Waiting for a message from Stomp")
135:                 msg = @connection.receive
136: 
137:                 # STOMP puts the payload in the body variable, pass that
138:                 # into the payload of MCollective::Request and discard all the
139:                 # other headers etc that stomp provides
140:                 if @base64
141:                     Request.new(SSL.base64_decode(msg.body))
142:                 else
143:                     Request.new(msg.body)
144:                 end
145:             end

Subscribe to a topic or queue

[Source]

     # File plugins/mcollective/connector/stomp.rb, line 162
162:             def subscribe(agent, type, collective)
163:                 source = make_target(agent, type, collective)
164: 
165:                 unless @subscriptions.include?(source)
166:                     Log.debug("Subscribing to #{source}")
167:                     @connection.subscribe(source)
168:                     @subscriptions << source
169:                 end
170:             end

Subscribe to a topic or queue

[Source]

     # File plugins/mcollective/connector/stomp.rb, line 173
173:             def unsubscribe(agent, type, collective)
174:                 source = make_target(agent, type, collective)
175: 
176:                 Log.debug("Unsubscribing from #{source}")
177:                 @connection.unsubscribe(source)
178:                 @subscriptions.delete(source)
179:             end

[Validate]