Module: MCollective::Util

### Home Classes Methods

### In Files

- lib/mcollective/util.rb

### Methods

- ::color
- ::colorize
- ::config_file_for_user
- ::default_options
- ::empty_filter
- ::empty_filter?
- ::get_fact
- ::has_agent?
- ::has_cf_class?
- ::has_fact?
- ::has_identity?
- ::loadclass
- ::make_subscriptions
- ::parse_fact_string
- ::ruby_version
- ::setup_windows_sleeper
- ::shellescape
- ::subscribe
- ::unsubscribe
- ::windows?

### Files

- COPYING
- README
- Rakefile
- PLACEHOLDER
- PLACEHOLDER

### Class/Module Index

Quicksearch

- MCollective
- MCollective::Agent
- MCollective::Agents
- MCollective::Aggregate
- MCollective::Aggregate::Base
- MCollective::Aggregate::Result
- MCollective::Aggregate::Result::Base
- MCollective::Aggregate::Result::CollectionResult
- MCollective::Aggregate::Result::NumericResult
- MCollective::Application
- MCollective::Applications
- MCollective::Client
- MCollective::Config
- MCollective::Connector
- MCollective::Connector::Base
- MCollective::DDL
- MCollective::DDLValidationError
- MCollective::Data
- MCollective::Data::Base
- MCollective::Data::Result
- MCollective::Discovery
- MCollective::Facts
- MCollective::Facts::Base
- MCollective::Generators
- MCollective::Generators::AgentGenerator
- MCollective::Generators::Base
- MCollective::Generators::DataGenerator
- MCollective::InvalidRPCData
- MCollective::Log
- MCollective::Logger
- MCollective::Logger::Base
- MCollective::Logger::Console_logger
- MCollective::Logger::File_logger
- MCollective::Logger::Syslog_logger
- MCollective::Matcher
- MCollective::Matcher::Parser
- MCollective::Matcher::Scanner
- MCollective::Message
- MCollective::MissingRPCData
- MCollective::MsgDoesNotMatchRequestID
- MCollective::MsgTTLExpired
- MCollective::NotTargettedAtUs
- MCollective::Optionparser
- MCollective::PluginManager
- MCollective::PluginPackager
- MCollective::PluginPackager::AgentDefinition
- MCollective::PluginPackager::StandardDefinition
- MCollective::RPC
- MCollective::RPC::ActionRunner
- MCollective::RPC::Agent
- MCollective::RPC::Audit
- MCollective::RPC::Client
- MCollective::RPC::Helpers
- MCollective::RPC::Progress
- MCollective::RPC::Reply
- MCollective::RPC::Request
- MCollective::RPC::Result
- MCollective::RPC::Stats
- MCollective::RPCAborted
- MCollective::RPCError
- MCollective::Registration
- MCollective::Registration::Base
- MCollective::Runner
- MCollective::RunnerStats
- MCollective::SSL
- MCollective::Security
- MCollective::Security::Base
- MCollective::SecurityValidationFailed
- MCollective::Shell
- MCollective::UnixDaemon
- MCollective::UnknownRPCAction
- MCollective::UnknownRPCError
- MCollective::Util
- MCollective::WindowsDaemon
- Array
- Dir
- Object
- String
- Symbol

No matching classes.

# MCollective::Util

Some basic utility helper methods useful to clients, agents, runner etc.

### Public Class Methods

color(code) click to toggle source

Return color codes, if the config color= option is false just return a empty string

    # File lib/mcollective/util.rb, line 254
    def self.color(code)
      colorize = Config.instance.color

      colors = {:red => "[31m",
                :green => "[32m",
                :yellow => "[33m",
                :cyan => "[36m",
                :bold => "[1m",
                :reset => "[0m"}

      if colorize
        return colors[code] || ""
      else
        return ""
      end
    end

colorize(code, msg) click to toggle source

Helper to return a string in specific color

    # File lib/mcollective/util.rb, line 272
    def self.colorize(code, msg)
      "%s%s%s" % [ color(code), msg, color(:reset) ]
    end

config_file_for_user() click to toggle source

Picks a config file defaults to ~/.mcollective else /etc/mcollective/client.cfg

    # File lib/mcollective/util.rb, line 140
    def self.config_file_for_user
      # expand_path is pretty lame, it relies on HOME environment
      # which isnt't always there so just handling all exceptions
      # here as cant find reverting to default
      begin
        config = File.expand_path("~/.mcollective")

        unless File.readable?(config) && File.file?(config)
          config = "/etc/mcollective/client.cfg"
        end
      rescue Exception => e
        config = "/etc/mcollective/client.cfg"
      end

      return config
    end

default_options() click to toggle source

Creates a standard options hash

    # File lib/mcollective/util.rb, line 158
    def self.default_options
      {:verbose           => false,
       :disctimeout       => nil,
       :timeout           => 5,
       :config            => config_file_for_user,
       :collective        => nil,
       :discovery_method  => nil,
       :discovery_options => Config.instance.default_discovery_options,
       :filter            => empty_filter}
    end

empty_filter() click to toggle source

Creates an empty filter

    # File lib/mcollective/util.rb, line 130
    def self.empty_filter
      {"fact"     => [],
       "cf_class" => [],
       "agent"    => [],
       "identity" => [],
       "compound" => []}
    end

empty_filter?(filter) click to toggle source

Checks if the passed in filter is an empty one

    # File lib/mcollective/util.rb, line 125
    def self.empty_filter?(filter)
      filter == empty_filter || filter == {}
    end

get_fact(fact) click to toggle source

Gets the value of a specific fact, mostly just a duplicate of MCollective::Facts.get_fact but it kind of goes with the other classes here

    # File lib/mcollective/util.rb, line 61
    def self.get_fact(fact)
      Facts.get_fact(fact)
    end

has_agent?(agent) click to toggle source

Finds out if this MCollective has an agent by the name passed

If the passed name starts with a / it’s assumed to be regex and will use regex to match

    # File lib/mcollective/util.rb, line 8
    def self.has_agent?(agent)
      agent = Regexp.new(agent.gsub("\/", "")) if agent.match("^/")

      if agent.is_a?(Regexp)
        if Agents.agentlist.grep(agent).size > 0
          return true
        else
          return false
        end
      else
        return Agents.agentlist.include?(agent)
      end

      false
    end

has_cf_class?(klass) click to toggle source

Checks if this node has a configuration management class by parsing the a text file with just a list of classes, recipes, roles etc. This is ala the classes.txt from puppet.

If the passed name starts with a / it’s assumed to be regex and will use regex to match

    # File lib/mcollective/util.rb, line 38
    def self.has_cf_class?(klass)
      klass = Regexp.new(klass.gsub("\/", "")) if klass.match("^/")
      cfile = Config.instance.classesfile

      Log.debug("Looking for configuration management classes in #{cfile}")

      begin
        File.readlines(cfile).each do |k|
          if klass.is_a?(Regexp)
            return true if k.chomp.match(klass)
          else
            return true if k.chomp == klass
          end
        end
      rescue Exception => e
        Log.warn("Parsing classes file '#{cfile}' failed: #{e.class}: #{e}")
      end

      false
    end

has_fact?(fact, value, operator) click to toggle source

Compares fact == value,

If the passed value starts with a / it’s assumed to be regex and will use regex to match

    # File lib/mcollective/util.rb, line 69
    def self.has_fact?(fact, value, operator)

      Log.debug("Comparing #{fact} #{operator} #{value}")
      Log.debug("where :fact = '#{fact}', :operator = '#{operator}', :value = '#{value}'")

      fact = Facts[fact]
      return false if fact.nil?

      fact = fact.clone

      if operator == '=~'
        # to maintain backward compat we send the value
        # as /.../ which is what 1.0.x needed.  this strips
        # off the /'s wich is what we need here
        if value =~ /^\/(.+)\/$/
          value = $1
        end

        return true if fact.match(Regexp.new(value))

      elsif operator == "=="
        return true if fact == value

      elsif ['<=', '>=', '<', '>', '!='].include?(operator)
        # Yuk - need to type cast, but to_i and to_f are overzealous
        if value =~ /^[0-9]+$/ && fact =~ /^[0-9]+$/
          fact = Integer(fact)
          value = Integer(value)
        elsif value =~ /^[0-9]+.[0-9]+$/ && fact =~ /^[0-9]+.[0-9]+$/
          fact = Float(fact)
          value = Float(value)
        end

        return true if eval("fact #{operator} value")
      end

      false
    end

has_identity?(identity) click to toggle source

Checks if the configured identity matches the one supplied

If the passed name starts with a / it’s assumed to be regex and will use regex to match

    # File lib/mcollective/util.rb, line 112
    def self.has_identity?(identity)
      identity = Regexp.new(identity.gsub("\/", "")) if identity.match("^/")

      if identity.is_a?(Regexp)
        return Config.instance.identity.match(identity)
      else
        return true if Config.instance.identity == identity
      end

      false
    end

loadclass(klass) click to toggle source

Wrapper around PluginManager.loadclass

    # File lib/mcollective/util.rb, line 208
    def self.loadclass(klass)
      PluginManager.loadclass(klass)
    end

make_subscriptions(agent, type, collective=nil) click to toggle source

    # File lib/mcollective/util.rb, line 169
    def self.make_subscriptions(agent, type, collective=nil)
      config = Config.instance

      raise("Unknown target type #{type}") unless [:broadcast, :directed, :reply].include?(type)

      if collective.nil?
        config.collectives.map do |c|
          {:agent => agent, :type => type, :collective => c}
        end
      else
        raise("Unknown collective '#{collective}' known collectives are '#{config.collectives.join ', '}'") unless config.collectives.include?(collective)

        [{:agent => agent, :type => type, :collective => collective}]
      end
    end

parse_fact_string(fact) click to toggle source

Parse a fact filter string like foo=bar into the tuple hash thats needed

    # File lib/mcollective/util.rb, line 213
    def self.parse_fact_string(fact)
      if fact =~ /^([^ ]+?)[ ]*=>[ ]*(.+)/
        return {:fact => $1, :value => $2, :operator => '>=' }
      elsif fact =~ /^([^ ]+?)[ ]*=<[ ]*(.+)/
        return {:fact => $1, :value => $2, :operator => '<=' }
      elsif fact =~ /^([^ ]+?)[ ]*(<=|>=|<|>|!=|==|=~)[ ]*(.+)/
        return {:fact => $1, :value => $3, :operator => $2 }
      elsif fact =~ /^(.+?)[ ]*=[ ]*\/(.+)\/$/
        return {:fact => $1, :value => "/#{$2}/", :operator => '=~' }
      elsif fact =~ /^([^= ]+?)[ ]*=[ ]*(.+)/
        return {:fact => $1, :value => $2, :operator => '==' }
      else
        raise "Could not parse fact #{fact} it does not appear to be in a valid format"
      end
    end

ruby_version() click to toggle source

Returns the current ruby version as per RUBY_VERSION, mostly doing this here to aid testing

    # File lib/mcollective/util.rb, line 278
    def self.ruby_version
      RUBY_VERSION
    end

setup_windows_sleeper() click to toggle source

On windows ^c can’t interrupt the VM if its blocking on IO, so this sets up a dummy thread that sleeps and this will have the end result of being interruptable at least once a second. This is a common pattern found in Rails etc

    # File lib/mcollective/util.rb, line 28
    def self.setup_windows_sleeper
      Thread.new { loop { sleep 1 } } if Util.windows?
    end

shellescape(str) click to toggle source

Escapes a string so it’s safe to use in system() or backticks

Taken from Shellwords#shellescape since it’s only in a few ruby versions

    # File lib/mcollective/util.rb, line 232
    def self.shellescape(str)
      return "''" if str.empty?

      str = str.dup

      # Process as a single byte sequence because not all shell
      # implementations are multibyte aware.
      str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/, "\\\\\\1")

      # A LF cannot be escaped with a backslash because a backslash + LF
      # combo is regarded as line continuation and simply ignored.
      str.gsub!(/\n/, "'\n'")

      return str
    end

subscribe(targets) click to toggle source

Helper to subscribe to a topic on multiple collectives or just one

    # File lib/mcollective/util.rb, line 186
    def self.subscribe(targets)
      connection = PluginManager["connector_plugin"]

      targets = [targets].flatten

      targets.each do |target|
        connection.subscribe(target[:agent], target[:type], target[:collective])
      end
    end

unsubscribe(targets) click to toggle source

Helper to unsubscribe to a topic on multiple collectives or just one

    # File lib/mcollective/util.rb, line 197
    def self.unsubscribe(targets)
      connection = PluginManager["connector_plugin"]

      targets = [targets].flatten

      targets.each do |target|
        connection.unsubscribe(target[:agent], target[:type], target[:collective])
      end
    end

windows?() click to toggle source

    # File lib/mcollective/util.rb, line 248
    def self.windows?
      !!(RbConfig::CONFIG['host_os'] =~ /mswin|win32|dos|mingw|cygwin/)
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.