Class | MCollective::Client |
In: |
lib/mcollective/client.rb
|
Parent: | Object |
Helpers for writing clients that can talk to agents, do discovery and so forth
options | [RW] | |
stats | [RW] |
# 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
Performs a discovery of nodes matching the filter passed returns an array of nodes
# 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
# 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
# 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.
# 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
# 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
# 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