class Inspec::Resource

Attributes

resource_exception_message[R]

Public Class Methods

__register(name, resource_klass) click to toggle source

Infrastructure / Bookkeeping

# File lib/inspec/resource.rb, line 110
def self.__register(name, resource_klass)
  # This has bitten us and should be a great candidate to remove in InSpec5
  cl = Class.new(resource_klass) do # TODO: remove
    # As best I can figure out, this anonymous class only exists
    # because we're trying to avoid having resources with
    # initialize methods from having to call super, which is,
    # quite frankly, dumb. Avoidable even with some simple
    # documentation.
    def initialize(backend, name, *args)
      supersuper_initialize(backend, name) do
        @resource_params = args
        super(*args)
      end
    end
  end

  reg = __resource_registry rescue nil
  reg = self.__resource_registry = Inspec::Resource.registry unless reg

  # Warn if a resource pack is overwriting a core resource.
  # Suppress warning if the resource is an AWS resource, see #3822

  if reg.key?(name) && !name.start_with?("aws_")
    Inspec::Log.warn("Overwriting resource #{name}. To reference a specific version of #{name} use the resource() method")
  end

  reg[name] = cl
end
__resource_registry() click to toggle source
# File lib/inspec/resource.rb, line 139
def self.__resource_registry
  # rubocop:disable Style/AndOr
  find_class_instance_variable(:@__resource_registry) or
    raise("__resource_registry not set!")
end
__resource_registry=(o) click to toggle source
# File lib/inspec/resource.rb, line 145
def self.__resource_registry=(o)
  @__resource_registry = o
end
backfill_supports!() click to toggle source
# File lib/inspec/resource.rb, line 167
def self.backfill_supports!
  reg = registry.keys.map(&:to_sym).sort
  sup = supports.keys.map(&:to_sym).sort

  missings = reg - sup

  supports[:platform] = [{ platform: "os" }] # patch the circular dep

  missings.each do |missing|
    klass = registry[missing.to_s].superclass
    sklas = klass.superclass.name&.to_sym # might be resource = no name

    klass = klass.name.to_sym

    case
    when klass != missing # an alias
      supports[missing] = supports[klass]
    when sklas
      supports[klass]   = supports[sklas]
    end
  end
end
default_registry() click to toggle source
# File lib/inspec/resource.rb, line 149
def self.default_registry
  @default_registry ||= {}
end
desc(value = nil) click to toggle source
# File lib/inspec/resource.rb, line 15
def self.desc(value = nil)
  return find_class_instance_variable(:@description) unless value

  @description = value
end
example(value = nil) click to toggle source
# File lib/inspec/resource.rb, line 21
def self.example(value = nil)
  return find_class_instance_variable(:@example) unless value

  @example = value
end
method_missing(method_name, *arguments, &block) click to toggle source

Support for Resource DSL plugins. This is called when an unknown method is encountered within a resource class definition. Even tho this is defined as an instance method, it gets added to the class via `extend`, so this is actually a class defintion.

Calls superclass method
# File lib/inspec/resource.rb, line 84
def self.method_missing(method_name, *arguments, &block)
  require "inspec/plugin/v2"
  # Check to see if there is a resource_dsl plugin activator hook with the method name
  registry = Inspec::Plugin::V2::Registry.instance
  hook = registry.find_activators(plugin_type: :resource_dsl, activator_name: method_name).first
  if hook
    # OK, load the hook if it hasn't been already.  We'll then know a module,
    # which we can then inject into the resource
    hook.activate
    # Inject the module's methods into the resource as class methods.
    # implementation_class is the field name, but this is actually a module.
    extend(hook.implementation_class)
    # Now that the module is loaded, it defined one or more methods
    # (presumably the one we were looking for.)
    # We still haven't called it, so do so now.
    send(method_name, *arguments, &block)
  else
    # If we couldn't find a plugin to match, maybe something up above has it,
    # or maybe it is just a unknown method error.
    super
  end
end
name(value = nil) click to toggle source
# File lib/inspec/resource.rb, line 7
def self.name(value = nil)
  return @name unless value

  @name = value

  __register(value, self)
end
new(backend, name, *args) click to toggle source

As best I can figure out, this anonymous class only exists because we're trying to avoid having resources with initialize methods from having to call super, which is, quite frankly, dumb. Avoidable even with some simple documentation.

Calls superclass method
# File lib/inspec/resource.rb, line 118
def initialize(backend, name, *args)
  supersuper_initialize(backend, name) do
    @resource_params = args
    super(*args)
  end
end
new_registry() click to toggle source
# File lib/inspec/resource.rb, line 163
def self.new_registry
  default_registry.dup
end
registry() click to toggle source

TODO: these are keyed off of strings

# File lib/inspec/resource.rb, line 154
def self.registry
  @registry ||= default_registry
end
support_registry() click to toggle source

TODO: these are keyed off of symbols

# File lib/inspec/resource.rb, line 159
def self.support_registry
  @support_registry ||= {}
end
supports(criteria = nil) click to toggle source
# File lib/inspec/resource.rb, line 27
def self.supports(criteria = nil)
  return if criteria.nil?

  key = @name.to_sym

  # HACK: this is broken!!! this is global where the rest are localized to registry
  Inspec::Resource.support_registry[key] ||= []
  Inspec::Resource.support_registry[key].push(criteria)
end
toggle_inspect() click to toggle source
# File lib/inspec/resource.rb, line 194
def self.toggle_inspect
  has_inspect = instance_method(:inspect).source_location
  unless has_inspect
    define_method :inspect do
      to_s
    end
  else
    undef_method :inspect
  end
end

Public Instance Methods

check_supported!() click to toggle source
# File lib/inspec/resource.rb, line 65
def check_supported!
  backend = @__backend_runner__
  name = @__resource_name__

  supported = @supports ? check_supports : true # check_supports has side effects!
  test_backend = defined?(Train::Transports::Mock::Connection) && backend.backend.class == Train::Transports::Mock::Connection
  # raise unless we are supported or in test
  unless supported || test_backend
    msg = "Unsupported resource/backend combination: %s / %s. Exiting." %
      [name, backend.platform.name]
    raise ArgumentError, msg
  end
end
check_supports() click to toggle source
# File lib/inspec/resource.rb, line 225
def check_supports
  require "inspec/resources/platform"
  status = inspec.platform.supported?(@supports)
  fail_msg = "Resource `#{@__resource_name__}` is not supported on platform #{inspec.platform.name}/#{inspec.platform.release}."
  fail_resource(fail_msg) unless status
  status
end
fail_resource(message) click to toggle source
# File lib/inspec/resource.rb, line 216
def fail_resource(message)
  @resource_failed = true
  @resource_exception_message = message
end
inspec() click to toggle source
# File lib/inspec/resource.rb, line 233
def inspec
  @__backend_runner__
end
resource_failed?() click to toggle source
# File lib/inspec/resource.rb, line 221
def resource_failed?
  @resource_failed
end
resource_skipped?() click to toggle source
# File lib/inspec/resource.rb, line 212
def resource_skipped?
  @resource_skipped
end
skip_resource(message) click to toggle source
# File lib/inspec/resource.rb, line 207
def skip_resource(message)
  @resource_skipped = true
  @resource_exception_message = message
end
supersuper_initialize(backend, name) { || ... } click to toggle source

TODO: this is pretty terrible and is only here to work around the idea that we've trained resource authors to make initialize methods w/o calling super.

# File lib/inspec/resource.rb, line 41
def supersuper_initialize(backend, name)
  @resource_skipped = false
  @resource_failed = false
  # TODO remove this (or the support_registry) (again?)
  @supports = Inspec::Resource.support_registry[name.to_sym]
  @resource_exception_message = nil

  # attach the backend to this instance
  @__backend_runner__ = backend
  @__resource_name__ = name

  check_supported!

  yield
rescue Inspec::Exceptions::ResourceSkipped => e
  skip_resource(e.message)
rescue Inspec::Exceptions::ResourceFailed => e
  fail_resource(e.message)
rescue NotImplementedError => e
  fail_resource(e.message) unless @resource_failed
rescue NoMethodError => e
  skip_resource(e.message) unless @resource_failed
end
to_s() click to toggle source
# File lib/inspec/resource.rb, line 190
def to_s
  @__resource_name__
end