Parent

Class/Module Index [+]

Quicksearch

MCollective::Client

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

Attributes

discoverer[RW]
options[RW]
stats[RW]

Public Instance Methods

collective() click to toggle source

Returns the configured main collective if no specific collective is specified as options

# File lib/mcollective/client.rb, line 23
def collective
  if @options[:collective].nil?
    @config.main_collective
  else
    @options[:collective]
  end
end
disconnect() click to toggle source

Disconnects cleanly from the middleware

# File lib/mcollective/client.rb, line 32
def disconnect
  Log.debug("Disconnecting from the middleware")
  @connection.disconnect
end
discover(filter, timeout, limit=0) click to toggle source

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

An integer limit can be supplied this will have the effect of the discovery being cancelled soon as it reached the requested limit of hosts

# File lib/mcollective/client.rb, line 115
def discover(filter, timeout, limit=0)
  raise "Limit has to be an integer" unless limit.is_a?(Fixnum)

  compount_timeout = timeout_for_compound_filter(@options[:filter]["compound"])
  timeout = timeout + compount_timeout

  discovered = @discoverer.discover(filter, timeout, limit)
end
discovered_req(body, agent, options=false) click to toggle source
# File lib/mcollective/client.rb, line 181
def discovered_req(body, agent, options=false)
  raise "Client#discovered_req has been removed, please port your agent and client to the SimpleRPC framework"
end
display_stats(stats, options=false, caption="stomp call summary") click to toggle source

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

# File lib/mcollective/client.rb, line 207
def display_stats(stats, options=false, caption="stomp call summary")
  options = @options unless options

  if options[:verbose]
    puts("\n---- #{caption} ----")

    if stats[:discovered]
      puts("           Nodes: #{stats[:discovered]} / #{stats[:responses]}")
    else
      puts("           Nodes: #{stats[:responses]}")
    end

    printf("      Start Time: %s\n", Time.at(stats[:starttime]))
    printf("  Discovery Time: %.2fms\n", stats[:discoverytime] * 1000)
    printf("      Agent Time: %.2fms\n", stats[:blocktime] * 1000)
    printf("      Total Time: %.2fms\n", stats[:totaltime] * 1000)

  else
    if stats[:discovered]
      printf("\nFinished processing %d / %d hosts in %.2f ms\n\n", stats[:responses], stats[:discovered], stats[:blocktime] * 1000)
    else
      printf("\nFinished processing %d hosts in %.2f ms\n\n", stats[:responses], stats[:blocktime] * 1000)
    end
  end

  if stats[:noresponsefrom].size > 0
    puts("\nNo response from:\n")

    stats[:noresponsefrom].each do |c|
      puts if c % 4 == 1
      printf("%30s", c)
    end

    puts
  end
end
receive(requestid = nil) click to toggle source

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 85
def receive(requestid = nil)
  reply = nil

  begin
    reply = @connection.receive
    reply.type = :reply
    reply.expected_msgid = requestid

    reply.decode!

    reply.payload[:senderid] = Digest::MD5.hexdigest(reply.payload[:senderid]) if ENV.include?("MCOLLECTIVE_ANON")

    raise(MsgDoesNotMatchRequestID, "Message reqid #{requestid} does not match our reqid #{reply.requestid}") unless reply.requestid == requestid
  rescue SecurityValidationFailed => e
    Log.warn("Ignoring a message that did not pass security validations")
    retry
  rescue MsgDoesNotMatchRequestID => e
    Log.debug("Ignoring a message for some other client")
    retry
  end

  reply
end
req(body, agent=nil, options=false, waitfor=0) click to toggle source

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 132
def req(body, agent=nil, options=false, waitfor=0)
  if body.is_a?(Message)
    agent = body.agent
    options = body.options
    waitfor = body.discovered_hosts.size || 0
  end

  stat = {:starttime => Time.now.to_f, :discoverytime => 0, :blocktime => 0, :totaltime => 0}

  options = @options unless options

  compount_timeout = timeout_for_compound_filter(options[:filter]["compound"])
  timeout = options[:timeout] + compount_timeout

  STDOUT.sync = true

  hosts_responded = 0
  reqid = nil

  begin
    Timeout.timeout(timeout) do
      reqid = sendreq(body, agent, options[:filter])

      loop do
        resp = receive(reqid)

        hosts_responded += 1

        yield(resp.payload)

        break if (waitfor != 0 && hosts_responded >= waitfor)
      end
    end
  rescue Interrupt => e
  rescue Timeout::Error => e
  ensure
    unsubscribe(agent, :reply)
  end

  stat[:totaltime] = Time.now.to_f - stat[:starttime]
  stat[:blocktime] = stat[:totaltime] - stat[:discoverytime]
  stat[:responses] = hosts_responded
  stat[:noresponsefrom] = []
  stat[:requestid] = reqid

  @stats = stat
  return stat
end
sendreq(msg, agent, filter = {}) click to toggle source

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 39
def sendreq(msg, agent, filter = {})
  if msg.is_a?(Message)
    request = msg
    agent = request.agent
  else
    ttl = @options[:ttl] || @config.ttl
    request = Message.new(msg, nil, {:agent => agent, :type => :request, :collective => collective, :filter => filter, :ttl => ttl})
    request.reply_to = @options[:reply_to] if @options[:reply_to]
  end

  request.encode!

  Log.debug("Sending request #{request.requestid} to the #{request.agent} agent with ttl #{request.ttl} in collective #{request.collective}")

  subscribe(agent, :reply) unless request.reply_to

  request.publish

  request.requestid
end
subscribe(agent, type) click to toggle source
# File lib/mcollective/client.rb, line 60
def subscribe(agent, type)
  unless @subscriptions.include?(agent)
    subscription = Util.make_subscriptions(agent, type, collective)
    Log.debug("Subscribing to #{type} target for agent #{agent}")

    Util.subscribe(subscription)
    @subscriptions[agent] = 1
  end
end
timeout_for_compound_filter(compound_filter) click to toggle source

if a compound filter is specified and it has any function then we read the DDL for each of those plugins and sum up the timeout declared in the DDL

# File lib/mcollective/client.rb, line 188
def timeout_for_compound_filter(compound_filter)
  return 0 if compound_filter.nil? || compound_filter.empty?

  timeout = 0

  compound_filter.each do |filter|
    filter.each do |statement|
      if statement["fstatement"]
        pluginname = Data.pluginname(statement["fstatement"]["name"])
        ddl = DDL.new(pluginname, :data)
        timeout += ddl.meta[:timeout]
      end
    end
  end

  timeout
end
unsubscribe(agent, type) click to toggle source
# File lib/mcollective/client.rb, line 70
def unsubscribe(agent, type)
  if @subscriptions.include?(agent)
    subscription = Util.make_subscriptions(agent, type, collective)
    Log.debug("Unsubscribing #{type} target for #{agent}")

    Util.unsubscribe(subscription)
    @subscriptions.delete(agent)
  end
end

Public Class Methods

new(configfile) click to toggle source
# File lib/mcollective/client.rb, line 6
def initialize(configfile)
  @config = Config.instance
  @config.loadconfig(configfile) unless @config.configured

  @connection = PluginManager["connector_plugin"]
  @security = PluginManager["security_plugin"]

  @security.initiated_by = :client
  @options = nil
  @subscriptions = {}

  @discoverer = Discovery.new(self)
  @connection.connect
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.