Class: Inspec::Resource

Inherits:
Object
  • Object
show all
Defined in:
lib/inspec/resource.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#resource_exception_messageObject (readonly)

Returns the value of attribute resource_exception_message.



211
212
213
# File 'lib/inspec/resource.rb', line 211

def resource_exception_message
  @resource_exception_message
end

Class Method Details

.__register(name, resource_klass) ⇒ Object

Infrastructure / Bookkeeping



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/inspec/resource.rb', line 116

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_registryObject

__register



145
146
147
148
149
# File 'lib/inspec/resource.rb', line 145

def self.__resource_registry
  # rubocop:disable Style/AndOr
  find_class_instance_variable(:@__resource_registry) or
    raise("__resource_registry not set!")
end

.__resource_registry=(o) ⇒ Object



151
152
153
# File 'lib/inspec/resource.rb', line 151

def self.__resource_registry=(o)
  @__resource_registry = o
end

.backfill_supports!Object



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/inspec/resource.rb', line 173

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_registryObject



155
156
157
# File 'lib/inspec/resource.rb', line 155

def self.default_registry
  @default_registry ||= {}
end

.desc(value = nil) ⇒ Object



15
16
17
18
19
# 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) ⇒ Object



21
22
23
24
25
# 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) ⇒ Object

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.



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/inspec/resource.rb', line 90

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) ⇒ Object



7
8
9
10
11
12
13
# File 'lib/inspec/resource.rb', line 7

def self.name(value = nil)
  return @name unless value

  @name = value

  __register(value, self)
end

.new_registryObject



169
170
171
# File 'lib/inspec/resource.rb', line 169

def self.new_registry
  default_registry.dup
end

.registryObject

TODO: these are keyed off of strings



160
161
162
# File 'lib/inspec/resource.rb', line 160

def self.registry
  @registry ||= default_registry
end

.support_registryObject

TODO: these are keyed off of symbols



165
166
167
# File 'lib/inspec/resource.rb', line 165

def self.support_registry
  @support_registry ||= {}
end

.supports(criteria = nil) ⇒ Object



27
28
29
30
31
32
33
34
35
# 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_inspectObject



200
201
202
203
204
205
206
207
208
209
# File 'lib/inspec/resource.rb', line 200

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

Instance Method Details

#check_supported!Object



71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/inspec/resource.rb', line 71

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_supportsObject



231
232
233
234
235
236
237
# File 'lib/inspec/resource.rb', line 231

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) ⇒ Object



222
223
224
225
# File 'lib/inspec/resource.rb', line 222

def fail_resource(message)
  @resource_failed = true
  @resource_exception_message = message
end

#inspecObject



239
240
241
# File 'lib/inspec/resource.rb', line 239

def inspec
  @__backend_runner__
end

#resource_failed?Boolean

Returns:

  • (Boolean)


227
228
229
# File 'lib/inspec/resource.rb', line 227

def resource_failed?
  @resource_failed
end

#resource_id(value = nil) ⇒ Object



37
38
39
40
41
# File 'lib/inspec/resource.rb', line 37

def resource_id(value = nil)
  @resource_id = value if value
  @resource_id = ""    if @resource_id.nil?
  @resource_id
end

#resource_skipped?Boolean

Returns:

  • (Boolean)


218
219
220
# File 'lib/inspec/resource.rb', line 218

def resource_skipped?
  @resource_skipped
end

#skip_resource(message) ⇒ Object



213
214
215
216
# File 'lib/inspec/resource.rb', line 213

def skip_resource(message)
  @resource_skipped = true
  @resource_exception_message = message
end

#supersuper_initialize(backend, name) ⇒ Object

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.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/inspec/resource.rb', line 47

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_sObject



196
197
198
# File 'lib/inspec/resource.rb', line 196

def to_s
  @__resource_name__
end