Class MCollective::Client
In: lib/mcollective/client.rb
Parent: Object

Helpers for writing clients that can talk to agents, do discovery and so forth

Methods

Attributes

options  [RW] 
stats  [RW] 

Public Class methods

[Source]

    # File lib/mcollective/client.rb, line 8
 8:         def initialize(configfile)
 9:             @config = Config.instance
10:             @config.loadconfig(configfile) unless @config.configured
11:             @log = Log.instance
12:             @connection = PluginManager["connector_plugin"]
13: 
14:             @security = PluginManager["security_plugin"]
15:             @security.initiated_by = :client
16: 
17:             @options = nil
18: 
19:             @subscriptions = {}
20: 
21:             @connection.connect
22:         end

Public Instance methods

Performs a discovery of nodes matching the filter passed returns an array of nodes

[Source]

    # File lib/mcollective/client.rb, line 75
75:         def discover(filter, timeout)
76:             begin
77:                 reqid = sendreq("ping", "discovery", filter)
78:                 @log.debug("Waiting #{timeout} seconds for discovery replies to request #{reqid}")
79: 
80:                 hosts = []
81:                 Timeout.timeout(timeout) do
82:                     loop do
83:                         msg = receive(reqid)
84:                         @log.debug("Got discovery reply from #{msg[:senderid]}")
85:                         hosts << msg[:senderid]
86:                     end
87:                 end
88:             rescue Timeout::Error => e
89:                 hosts.sort
90:             rescue Exception => e
91:                 raise
92:             end
93:         end

Performs a discovery and then send a request, performs the passed block for each response

   times = discovered_req("status", "mcollectived", options, client) {|resp|
      pp resp
   }

It returns a hash of times and timeouts for discovery and total run is taken from the options hash which in turn is generally built using MCollective::Optionparser

[Source]

     # File lib/mcollective/client.rb, line 147
147:         def discovered_req(body, agent, options=false)
148:             stat = {:starttime => Time.now.to_f, :discoverytime => 0, :blocktime => 0, :totaltime => 0}
149: 
150:             options = @options unless options
151: 
152:             STDOUT.sync = true
153: 
154:             print("Determining the amount of hosts matching filter for #{options[:disctimeout]} seconds .... ")
155: 
156:             begin
157:                 discovered_hosts = discover(options[:filter], options[:disctimeout])
158:                 discovered = discovered_hosts.size
159:                 hosts_responded = []
160:                 hosts_not_responded = discovered_hosts
161: 
162:                 stat[:discoverytime] = Time.now.to_f - stat[:starttime]
163: 
164:                 puts("#{discovered}\n\n")
165:             rescue Interrupt
166:                 puts("Discovery interrupted.")
167:                 exit!
168:             end
169: 
170:             raise("No matching clients found") if discovered == 0
171: 
172:             reqid = sendreq(body, agent, options[:filter])
173: 
174:             begin
175:                 Timeout.timeout(options[:timeout]) do
176:                     (1..discovered).each do |c|
177:                         resp = receive(reqid)
178:     
179:                         hosts_responded << resp[:senderid]
180:                         hosts_not_responded.delete(resp[:senderid]) if hosts_not_responded.include?(resp[:senderid])
181: 
182:                         yield(resp)
183:                     end
184:                 end
185:             rescue Interrupt => e
186:             rescue Timeout::Error => e
187:             end
188: 
189:             stat[:totaltime] = Time.now.to_f - stat[:starttime]
190:             stat[:blocktime] = stat[:totaltime] - stat[:discoverytime]
191:             stat[:responses] = hosts_responded.size
192:             stat[:responsesfrom] = hosts_responded
193:             stat[:noresponsefrom] = hosts_not_responded
194:             stat[:discovered] = discovered
195: 
196:             @stats = stat
197:             return stat
198:         end

Prints out the stats returns from req and discovered_req in a nice way

[Source]

     # File lib/mcollective/client.rb, line 201
201:         def display_stats(stats, options=false, caption="stomp call summary")
202:             options = @options unless options
203: 
204:             if options[:verbose]
205:                 puts("\n---- #{caption} ----")
206: 
207:                 if stats[:discovered]
208:                     puts("           Nodes: #{stats[:discovered]} / #{stats[:responses]}")
209:                 else
210:                     puts("           Nodes: #{stats[:responses]}")
211:                 end
212: 
213:                 printf("      Start Time: %s\n", Time.at(stats[:starttime]))
214:                 printf("  Discovery Time: %.2fms\n", stats[:discoverytime] * 1000)
215:                 printf("      Agent Time: %.2fms\n", stats[:blocktime] * 1000)
216:                 printf("      Total Time: %.2fms\n", stats[:totaltime] * 1000)
217:     
218:             else
219:                 if stats[:discovered]
220:                     printf("\nFinished processing %d / %d hosts in %.2f ms\n\n", stats[:responses], stats[:discovered], stats[:blocktime] * 1000)
221:                 else
222:                     printf("\nFinished processing %d hosts in %.2f ms\n\n", stats[:responses], stats[:blocktime] * 1000)
223:                 end
224:             end
225: 
226:             if stats[:noresponsefrom].size > 0
227:                 puts("\nNo response from:\n")
228:     
229:                 stats[:noresponsefrom].each do |c|
230:                     puts if c % 4 == 1
231:                     printf("%30s", c)
232:                 end
233: 
234:                 puts
235:             end
236:         end

Blocking call that waits for ever for a message to arrive.

If you give it a requestid this means you‘ve previously send a request with that ID and now you just want replies that matches that id, in that case the current connection will just ignore all messages not directed at it and keep waiting for more till it finds a matching message.

[Source]

    # File lib/mcollective/client.rb, line 54
54:         def receive(requestid = nil)
55:             msg = nil
56: 
57:             begin
58:                 msg = @connection.receive
59: 
60:                 msg = @security.decodemsg(msg)
61: 
62:                 msg[:senderid] = Digest::MD5.hexdigest(msg[:senderid]) if ENV.include?("MCOLLECTIVE_ANON")
63: 
64:                 raise(MsgDoesNotMatchRequestID, "Message reqid #{requestid} does not match our reqid #{msg[:requestid]}") if msg[:requestid] != requestid
65:             rescue MsgDoesNotMatchRequestID => e
66:                 @log.debug("Ignoring a message for some other client")
67:                 retry
68:             end
69: 
70:             msg
71:         end

Send a request, performs the passed block for each response

times = req("status", "mcollectived", options, client) {|resp|

  pp resp

}

It returns a hash of times and timeouts for discovery and total run is taken from the options hash which in turn is generally built using MCollective::Optionparser

[Source]

     # File lib/mcollective/client.rb, line 103
103:         def req(body, agent, options=false, waitfor=0)
104:             stat = {:starttime => Time.now.to_f, :discoverytime => 0, :blocktime => 0, :totaltime => 0}
105: 
106:             options = @options unless options
107: 
108:             STDOUT.sync = true
109: 
110:             reqid = sendreq(body, agent, options[:filter])
111: 
112:             hosts_responded = 0
113: 
114:             begin
115:                 Timeout.timeout(options[:timeout]) do
116:                     loop do
117:                         resp = receive(reqid)
118:     
119:                         hosts_responded += 1
120: 
121:                         yield(resp)
122: 
123:                         break if (waitfor != 0 && hosts_responded >= waitfor)
124:                     end
125:                 end
126:             rescue Interrupt => e
127:             rescue Timeout::Error => e
128:             end
129: 
130:             stat[:totaltime] = Time.now.to_f - stat[:starttime]
131:             stat[:blocktime] = stat[:totaltime] - stat[:discoverytime]
132:             stat[:responses] = hosts_responded
133:             stat[:noresponsefrom] = []
134: 
135:             @stats = stat
136:             return stat
137:         end

Sends a request and returns the generated request id, doesn‘t wait for responses and doesn‘t execute any passed in code blocks for responses

[Source]

    # File lib/mcollective/client.rb, line 26
26:         def sendreq(msg, agent, filter = {})
27:             target = Util.make_target(agent, :command)
28: 
29:             reqid = Digest::MD5.hexdigest("#{@config.identity}-#{Time.now.to_f.to_s}-#{target}")
30: 
31:             req = @security.encoderequest(@config.identity, target, msg, reqid, filter)
32:     
33:             @log.debug("Sending request #{reqid} to #{target}")
34: 
35:             unless @subscriptions.include?(agent)
36:                 topic = Util.make_target(agent, :reply)
37:                 @log.debug("Subscribing to #{topic}")
38: 
39:                 @connection.subscribe(topic)
40:                 @subscriptions[agent] = 1
41:             end
42: 
43:             @connection.send(target, req)
44: 
45:             reqid
46:         end

[Validate]