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

Disconnects cleanly from the middleware

[Source]

    # File lib/mcollective/client.rb, line 25
25:         def disconnect
26:             @log.debug("Disconnecting from the middleware")
27:             @connection.disconnect
28:         end

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

[Source]

    # File lib/mcollective/client.rb, line 81
81:         def discover(filter, timeout)
82:             begin
83:                 reqid = sendreq("ping", "discovery", filter)
84:                 @log.debug("Waiting #{timeout} seconds for discovery replies to request #{reqid}")
85: 
86:                 hosts = []
87:                 Timeout.timeout(timeout) do
88:                     loop do
89:                         msg = receive(reqid)
90:                         @log.debug("Got discovery reply from #{msg[:senderid]}")
91:                         hosts << msg[:senderid]
92:                     end
93:                 end
94:             rescue Timeout::Error => e
95:                 hosts.sort
96:             rescue Exception => e
97:                 raise
98:             end
99:         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 153
153:         def discovered_req(body, agent, options=false)
154:             stat = {:starttime => Time.now.to_f, :discoverytime => 0, :blocktime => 0, :totaltime => 0}
155: 
156:             options = @options unless options
157: 
158:             STDOUT.sync = true
159: 
160:             print("Determining the amount of hosts matching filter for #{options[:disctimeout]} seconds .... ")
161: 
162:             begin
163:                 discovered_hosts = discover(options[:filter], options[:disctimeout])
164:                 discovered = discovered_hosts.size
165:                 hosts_responded = []
166:                 hosts_not_responded = discovered_hosts
167: 
168:                 stat[:discoverytime] = Time.now.to_f - stat[:starttime]
169: 
170:                 puts("#{discovered}\n\n")
171:             rescue Interrupt
172:                 puts("Discovery interrupted.")
173:                 exit!
174:             end
175: 
176:             raise("No matching clients found") if discovered == 0
177: 
178:             reqid = sendreq(body, agent, options[:filter])
179: 
180:             begin
181:                 Timeout.timeout(options[:timeout]) do
182:                     (1..discovered).each do |c|
183:                         resp = receive(reqid)
184: 
185:                         hosts_responded << resp[:senderid]
186:                         hosts_not_responded.delete(resp[:senderid]) if hosts_not_responded.include?(resp[:senderid])
187: 
188:                         yield(resp)
189:                     end
190:                 end
191:             rescue Interrupt => e
192:             rescue Timeout::Error => e
193:             end
194: 
195:             stat[:totaltime] = Time.now.to_f - stat[:starttime]
196:             stat[:blocktime] = stat[:totaltime] - stat[:discoverytime]
197:             stat[:responses] = hosts_responded.size
198:             stat[:responsesfrom] = hosts_responded
199:             stat[:noresponsefrom] = hosts_not_responded
200:             stat[:discovered] = discovered
201: 
202:             @stats = stat
203:             return stat
204:         end

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

[Source]

     # File lib/mcollective/client.rb, line 207
207:         def display_stats(stats, options=false, caption="stomp call summary")
208:             options = @options unless options
209: 
210:             if options[:verbose]
211:                 puts("\n---- #{caption} ----")
212: 
213:                 if stats[:discovered]
214:                     puts("           Nodes: #{stats[:discovered]} / #{stats[:responses]}")
215:                 else
216:                     puts("           Nodes: #{stats[:responses]}")
217:                 end
218: 
219:                 printf("      Start Time: %s\n", Time.at(stats[:starttime]))
220:                 printf("  Discovery Time: %.2fms\n", stats[:discoverytime] * 1000)
221:                 printf("      Agent Time: %.2fms\n", stats[:blocktime] * 1000)
222:                 printf("      Total Time: %.2fms\n", stats[:totaltime] * 1000)
223: 
224:             else
225:                 if stats[:discovered]
226:                     printf("\nFinished processing %d / %d hosts in %.2f ms\n\n", stats[:responses], stats[:discovered], stats[:blocktime] * 1000)
227:                 else
228:                     printf("\nFinished processing %d hosts in %.2f ms\n\n", stats[:responses], stats[:blocktime] * 1000)
229:                 end
230:             end
231: 
232:             if stats[:noresponsefrom].size > 0
233:                 puts("\nNo response from:\n")
234: 
235:                 stats[:noresponsefrom].each do |c|
236:                     puts if c % 4 == 1
237:                     printf("%30s", c)
238:                 end
239: 
240:                 puts
241:             end
242:         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 60
60:         def receive(requestid = nil)
61:             msg = nil
62: 
63:             begin
64:                 msg = @connection.receive
65: 
66:                 msg = @security.decodemsg(msg)
67: 
68:                 msg[:senderid] = Digest::MD5.hexdigest(msg[:senderid]) if ENV.include?("MCOLLECTIVE_ANON")
69: 
70:                 raise(MsgDoesNotMatchRequestID, "Message reqid #{requestid} does not match our reqid #{msg[:requestid]}") if msg[:requestid] != requestid
71:             rescue MsgDoesNotMatchRequestID => e
72:                 @log.debug("Ignoring a message for some other client")
73:                 retry
74:             end
75: 
76:             msg
77:         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 109
109:         def req(body, agent, options=false, waitfor=0)
110:             stat = {:starttime => Time.now.to_f, :discoverytime => 0, :blocktime => 0, :totaltime => 0}
111: 
112:             options = @options unless options
113: 
114:             STDOUT.sync = true
115: 
116:             reqid = sendreq(body, agent, options[:filter])
117: 
118:             hosts_responded = 0
119: 
120:             begin
121:                 Timeout.timeout(options[:timeout]) do
122:                     loop do
123:                         resp = receive(reqid)
124: 
125:                         hosts_responded += 1
126: 
127:                         yield(resp)
128: 
129:                         break if (waitfor != 0 && hosts_responded >= waitfor)
130:                     end
131:                 end
132:             rescue Interrupt => e
133:             rescue Timeout::Error => e
134:             end
135: 
136:             stat[:totaltime] = Time.now.to_f - stat[:starttime]
137:             stat[:blocktime] = stat[:totaltime] - stat[:discoverytime]
138:             stat[:responses] = hosts_responded
139:             stat[:noresponsefrom] = []
140: 
141:             @stats = stat
142:             return stat
143:         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 32
32:         def sendreq(msg, agent, filter = {})
33:             target = Util.make_target(agent, :command)
34: 
35:             reqid = Digest::MD5.hexdigest("#{@config.identity}-#{Time.now.to_f.to_s}-#{target}")
36: 
37:             req = @security.encoderequest(@config.identity, target, msg, reqid, filter)
38: 
39:             @log.debug("Sending request #{reqid} to #{target}")
40: 
41:             unless @subscriptions.include?(agent)
42:                 topic = Util.make_target(agent, :reply)
43:                 @log.debug("Subscribing to #{topic}")
44: 
45:                 @connection.subscribe(topic)
46:                 @subscriptions[agent] = 1
47:             end
48: 
49:             @connection.send(target, req)
50: 
51:             reqid
52:         end

[Validate]