inspec 4.56.17 → 5.10.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/inspec.gemspec +4 -1
  3. data/lib/plugins/inspec-artifact/inspec-artifact.gemspec +9 -0
  4. data/lib/plugins/inspec-compliance/inspec-compliance.gemspec +9 -0
  5. data/lib/plugins/inspec-habitat/inspec-habitat.gemspec +9 -0
  6. data/lib/plugins/inspec-init/inspec-init.gemspec +9 -0
  7. data/lib/plugins/inspec-init/templates/profiles/aws/inspec.yml +1 -1
  8. data/lib/plugins/inspec-plugin-manager-cli/inspec-plugin-manager-cli.gemspec +10 -0
  9. data/lib/plugins/inspec-reporter-html2/inspec-reporter-html2.gemspec +9 -0
  10. data/lib/plugins/inspec-reporter-json-min/inspec-reporter-json-min.gemspec +9 -0
  11. data/lib/plugins/inspec-reporter-junit/inspec-reporter-junit.gemspec +9 -0
  12. data/lib/plugins/inspec-streaming-reporter-progress-bar/inspec-streaming-reporter-progress-bar.gemspec +9 -0
  13. metadata +28 -62
  14. data/lib/resource_support/aws/aws_backend_base.rb +0 -12
  15. data/lib/resource_support/aws/aws_backend_factory_mixin.rb +0 -12
  16. data/lib/resource_support/aws/aws_plural_resource_mixin.rb +0 -24
  17. data/lib/resource_support/aws/aws_resource_mixin.rb +0 -69
  18. data/lib/resource_support/aws/aws_singular_resource_mixin.rb +0 -27
  19. data/lib/resource_support/aws.rb +0 -76
  20. data/lib/resources/aws/aws_billing_report.rb +0 -105
  21. data/lib/resources/aws/aws_billing_reports.rb +0 -74
  22. data/lib/resources/aws/aws_cloudtrail_trail.rb +0 -97
  23. data/lib/resources/aws/aws_cloudtrail_trails.rb +0 -51
  24. data/lib/resources/aws/aws_cloudwatch_alarm.rb +0 -67
  25. data/lib/resources/aws/aws_cloudwatch_log_metric_filter.rb +0 -105
  26. data/lib/resources/aws/aws_config_delivery_channel.rb +0 -74
  27. data/lib/resources/aws/aws_config_recorder.rb +0 -99
  28. data/lib/resources/aws/aws_ebs_volume.rb +0 -127
  29. data/lib/resources/aws/aws_ebs_volumes.rb +0 -69
  30. data/lib/resources/aws/aws_ec2_instance.rb +0 -162
  31. data/lib/resources/aws/aws_ec2_instances.rb +0 -69
  32. data/lib/resources/aws/aws_ecs_cluster.rb +0 -87
  33. data/lib/resources/aws/aws_eks_cluster.rb +0 -105
  34. data/lib/resources/aws/aws_elb.rb +0 -85
  35. data/lib/resources/aws/aws_elbs.rb +0 -84
  36. data/lib/resources/aws/aws_flow_log.rb +0 -106
  37. data/lib/resources/aws/aws_iam_access_key.rb +0 -112
  38. data/lib/resources/aws/aws_iam_access_keys.rb +0 -153
  39. data/lib/resources/aws/aws_iam_group.rb +0 -62
  40. data/lib/resources/aws/aws_iam_groups.rb +0 -56
  41. data/lib/resources/aws/aws_iam_password_policy.rb +0 -121
  42. data/lib/resources/aws/aws_iam_policies.rb +0 -57
  43. data/lib/resources/aws/aws_iam_policy.rb +0 -311
  44. data/lib/resources/aws/aws_iam_role.rb +0 -60
  45. data/lib/resources/aws/aws_iam_root_user.rb +0 -82
  46. data/lib/resources/aws/aws_iam_user.rb +0 -145
  47. data/lib/resources/aws/aws_iam_users.rb +0 -160
  48. data/lib/resources/aws/aws_kms_key.rb +0 -100
  49. data/lib/resources/aws/aws_kms_keys.rb +0 -58
  50. data/lib/resources/aws/aws_rds_instance.rb +0 -74
  51. data/lib/resources/aws/aws_route_table.rb +0 -67
  52. data/lib/resources/aws/aws_route_tables.rb +0 -64
  53. data/lib/resources/aws/aws_s3_bucket.rb +0 -141
  54. data/lib/resources/aws/aws_s3_bucket_object.rb +0 -87
  55. data/lib/resources/aws/aws_s3_buckets.rb +0 -52
  56. data/lib/resources/aws/aws_security_group.rb +0 -314
  57. data/lib/resources/aws/aws_security_groups.rb +0 -71
  58. data/lib/resources/aws/aws_sns_subscription.rb +0 -82
  59. data/lib/resources/aws/aws_sns_topic.rb +0 -57
  60. data/lib/resources/aws/aws_sns_topics.rb +0 -60
  61. data/lib/resources/aws/aws_sqs_queue.rb +0 -66
  62. data/lib/resources/aws/aws_subnet.rb +0 -92
  63. data/lib/resources/aws/aws_subnets.rb +0 -56
  64. data/lib/resources/aws/aws_vpc.rb +0 -77
  65. data/lib/resources/aws/aws_vpcs.rb +0 -55
  66. data/lib/resources/azure/azure_backend.rb +0 -379
  67. data/lib/resources/azure/azure_generic_resource.rb +0 -55
  68. data/lib/resources/azure/azure_resource_group.rb +0 -151
  69. data/lib/resources/azure/azure_virtual_machine.rb +0 -262
  70. data/lib/resources/azure/azure_virtual_machine_data_disk.rb +0 -131
@@ -1,379 +0,0 @@
1
- # Base class for Azure Resources. This allows the generic class to work
2
- # as well as the specific target resources for Azure Resources
3
- #
4
- # @author Russell Seymour
5
- module Inspec::Resources
6
- class AzureResourceBase < Inspec.resource(1)
7
- attr_reader :opts, :client, :azure
8
-
9
- # Constructor that retrieves the specified resource
10
- #
11
- # The opts hash should contain the following
12
- # :group_name - name of the resource group in which to look for items
13
- # :type - the type of Azure resource to look for
14
- # :apiversion - API version to use when looking for a specific resource
15
- # :name - name of the resource to find
16
- #
17
- # @author Russell Seymour
18
- #
19
- # @param [Hash] opts Hashtable of options as highlighted above
20
- # rubocop:disable Metrics/AbcSize
21
- def initialize(opts)
22
- # declare the hashtable of counts
23
- @counts = {}
24
- @total = 0
25
- @opts = opts
26
-
27
- # Determine if the environment variables for the options have been set
28
- option_var_names = {
29
- group_name: "AZURE_RESOURCE_GROUP_NAME",
30
- name: "AZURE_RESOURCE_NAME",
31
- type: "AZURE_RESOURCE_TYPE",
32
- apiversion: "AZURE_RESOURCE_API_VERSION",
33
- }
34
- option_var_names.each do |option_name, env_var_name|
35
- opts[option_name] = ENV[env_var_name] unless ENV[env_var_name].nil?
36
- end
37
-
38
- @azure = inspec.backend
39
- @client = azure.azure_client
40
- @failed_resource = false
41
- end
42
-
43
- def failed_resource?
44
- @failed_resource
45
- end
46
-
47
- def catch_azure_errors
48
- yield
49
- rescue MsRestAzure::AzureOperationError => e
50
- # e.message is actually a massive stringified JSON, which might be useful in the future.
51
- # You want error_message here.
52
- fail_resource e.error_message
53
- @failed_resource = true
54
- nil
55
- end
56
-
57
- # Return information about the resource group
58
- def resource_group
59
- catch_azure_errors do
60
- resource_group = client.resource_groups.get(opts[:group_name])
61
-
62
- # create the methods for the resource group object
63
- dm = AzureResourceDynamicMethods.new
64
- dm.create_methods(self, resource_group)
65
- end
66
- end
67
-
68
- def resources
69
- resources = nil
70
- catch_azure_errors do
71
- resources = client.resources.list_by_resource_group(opts[:group_name])
72
- end
73
- return if failed_resource?
74
-
75
- # filter the resources based on the type, and the name if they been specified
76
- resources = filter_resources(resources, opts)
77
-
78
- # if there is one resource then define methods on this class
79
- if resources.count == 1
80
- @total = 1
81
-
82
- resource = nil
83
- catch_azure_errors do
84
- # get the apiversion for the resource, if one has not been specified
85
- apiversion = azure.get_api_version(resources[0].type, opts)
86
-
87
- # get the resource by id so it can be interrogated
88
- resource = client.resources.get_by_id(resources[0].id, apiversion)
89
- end
90
- return if failed_resource?
91
-
92
- dm = AzureResourceDynamicMethods.new
93
-
94
- dm.create_methods(self, resource)
95
- else
96
-
97
- # As there are many resources, parse each one so that it can be
98
- # interrogated by the FilterTable
99
- # @probes = parse_resources(resources, azure)
100
- @probes = resources.each.map do |item|
101
- # update the total
102
- @total += 1
103
-
104
- # determine the counts for each type
105
- namespace, type_name = item.type.split(/\./)
106
- counts.key?(namespace) ? false : counts[namespace] = {}
107
- counts[namespace].key?(type_name) ? counts[namespace][type_name] += 1 : counts[namespace][type_name] = 1
108
-
109
- # get the detail about the resource
110
- apiversion = azure.get_api_version(item.type, opts)
111
- resource = client.resources.get_by_id(item.id, apiversion)
112
-
113
- # parse the resource
114
- parse_resource(resource)
115
- end.compact
116
-
117
- # Iterate around the counts and create the necessary classes
118
- counts.each do |namespace, ns_counts|
119
- define_singleton_method namespace do
120
- AzureResourceTypeCounts.new(ns_counts)
121
- end
122
- end
123
- end
124
- end
125
-
126
- # Does the resource have any tags?
127
- #
128
- # If it is a Hashtable then it does not, because there was nothing to parse so there is not
129
- # a nested object to work with
130
- #
131
- # @author Russell Seymour
132
- def has_tags?
133
- tags.is_a?(Hash) ? false : true
134
- end
135
-
136
- # Returns how many tags have been set on the resource
137
- #
138
- # @author Russell Seymour
139
- def tag_count
140
- tags.count
141
- end
142
-
143
- # It is necessary to be able to test the tags of a resource. It is possible to say of the
144
- # resource has tags or not, and it is possible to check that the tags include a specific tag
145
- # However the value is not accessible, this function creates methods for all the tags that
146
- # are available.
147
- #
148
- # The format of the method name is '<TAG_NAME>_tag' and will return the value of that tag
149
- #
150
- # Disabling rubopcop check. If this is set as a normal if..then..end statement there is a
151
- # violation stating it should use a guard. When using a guard it throws this error
152
- #
153
- # @author Russell Seymour
154
- def create_tag_methods
155
- # Iterate around the items of the tags and create the necessary access methods
156
- if defined?(tags.item)
157
- tags.item.each do |name, value|
158
- method_name = format("%s_tag", name)
159
- define_singleton_method method_name do
160
- value
161
- end
162
- end
163
- end
164
- end
165
-
166
- private
167
-
168
- # Filter the resources that are returned by the options that have been specified
169
- #
170
- def filter_resources(resources, opts)
171
- if opts[:type] && opts[:name]
172
- resources.select { |r| r.type == opts[:type] && r.name == opts[:name] }
173
- elsif opts[:type]
174
- resources.select { |r| r.type == opts[:type] }
175
- elsif opts[:name]
176
- resources.select { |r| r.name == opts[:name] }
177
- else
178
- resources
179
- end
180
- end
181
- end
182
- end
183
-
184
- # Class to create methods on the calling object at run time.
185
- # Each of the Azure Resources have different attributes and properties, and they all need
186
- # to be testable. To do this no methods are hardcoded, each on is craeted based on the
187
- # information returned from Azure.
188
- #
189
- # The class is a helper class essentially as it creates the methods on the calling class
190
- # rather than itself. This means that there is less duplication of code and it can be
191
- # reused easily.
192
- #
193
- # @author Russell Seymour
194
- # @since 0.2.0
195
- class AzureResourceDynamicMethods
196
- # Given the calling object and its data, create the methods on the object according
197
- # to the data that has been retrieved. Various types of data can be returned so the method
198
- # checks the type to ensure that the necessary methods are configured correctly
199
- #
200
- # @param AzureResourceProbe|AzureResource object The object on which the methods should be craeted
201
- # @param variant data The data from which the methods should be created
202
- def create_methods(object, data)
203
- # Check the type of data as this affects the setup of the methods
204
- # If it is an Azure Generic Resource then setup methods for each of
205
- # the instance variables
206
- case data.class.to_s
207
- when /^Azure::Resources::Mgmt::.*::Models::GenericResource$/,
208
- /^Azure::Resources::Mgmt::.*::Models::ResourceGroup$/
209
- # iterate around the instance variables
210
- data.instance_variables.each do |var|
211
- create_method(object, var.to_s.delete("@"), data.instance_variable_get(var))
212
- end
213
- # When the data is a Hash object iterate around each of the key value pairs and
214
- # craete a method for each one.
215
- when "Hash"
216
- data.each do |key, value|
217
- create_method(object, key, value)
218
- end
219
- end
220
- end
221
-
222
- private
223
-
224
- # Method that is responsible for creating the method on the calling object. This is
225
- # because some nesting maybe required. For example of the value is a Hash then it will
226
- # need to have an AzureResourceProbe create for each key, whereas if it is a simple
227
- # string then the value just needs to be returned
228
- #
229
- # @private
230
- #
231
- # @param AzureResourceProbe|AzureResource object Object on which the methods need to be created
232
- # @param string name The name of the method
233
- # @param variant value The value that needs to be returned by the method
234
- def create_method(object, name, value)
235
- # Create the necessary method based on the var that has been passed
236
- # Test the value for its type so that the method can be setup correctly
237
- case value.class.to_s
238
- when "String", "Integer", "TrueClass", "FalseClass", "Fixnum"
239
- object.define_singleton_method name do
240
- value
241
- end
242
- when "Hash"
243
- value.count == 0 ? return_value = value : return_value = AzureResourceProbe.new(value)
244
- object.define_singleton_method name do
245
- return_value
246
- end
247
- when /^Azure::Resources::Mgmt::.*::Models::ResourceGroupProperties$/
248
- # This is a special case where the properties of the resource group is not a simple JSON model
249
- # This is because the plugin is using the Azure SDK to get this information so it is an SDK object
250
- # that has to be interrogated in a different way. This is the only object type that behaves like this
251
- value.instance_variables.each do |var|
252
- create_method(object, var.to_s.delete("@"), value.instance_variable_get(var))
253
- end
254
- when "Array"
255
- # Some things are just string or integer arrays
256
- # Check this by seeing if the first element is a string / integer / boolean or
257
- # a hashtable
258
- # This may not be the best methid, but short of testing all elements in the array, this is
259
- # the quickest test
260
- case value[0].class.to_s
261
- when "String", "Integer", "TrueClass", "FalseClass", "Fixnum"
262
- probes = value
263
- else
264
- probes = []
265
- value.each do |value_item|
266
- probes << AzureResourceProbe.new(value_item)
267
- end
268
- end
269
- object.define_singleton_method name do
270
- probes
271
- end
272
- end
273
- end
274
- end
275
-
276
- # Class object to maintain a count of the Azure Resource types that are found
277
- # when a less specific test is carried out. For example if all the resoures of a resource
278
- # group are called for, there will be various types and number of those types.
279
- #
280
- # Each type is namespaced, so for example a virtual machine has the type 'Microsoft.Compute/virtualMachines'
281
- # This is broken down into the 'Microsoft' class with the type 'Compute/virtualMachines'
282
- # This has been done for two reasons:
283
- # 1. Enable the dotted notation to work in the test
284
- # 2. Allow third party resource types ot be catered for if they are ever enabled by Microsoft
285
- #
286
- # @author Russell Seymour
287
- # @since 0.2.0
288
- class AzureResourceTypeCounts
289
- # Constructor to setup a new class for a specific Azure Resource type.
290
- # It should be passed a hashtable with information such as:
291
- # {
292
- # "Compute/virtualMachines" => 2,
293
- # "Network/networkInterfaces" => 3
294
- # }
295
- # This will result in two methods being created on the class:
296
- # - Compute/virtualNetworks
297
- # - Network/networkInterfaces
298
- # Each of which will return the corresponding count value
299
- #
300
- # @param Hash counts Hash table of types and the count of each one
301
- #
302
- # @return AzureResourceTypeCounts
303
- def initialize(counts)
304
- counts.each do |type, count|
305
- define_singleton_method type do
306
- count
307
- end
308
- end
309
- end
310
- end
311
-
312
- # Class object that is created for each element that is returned by Azure.
313
- # This is what is interrogated by InSpec. If they are nested hashes, then this results
314
- # in nested AzureResourceProbe objects.
315
- #
316
- # For example, if the following was seen in an Azure Resource
317
- # properties -> storageProfile -> imageReference
318
- # Would result in the following nestec classes
319
- # AzureResource -> AzureResourceProbe -> AzureResourceProbe
320
- #
321
- # The methods for each of the classes are dynamically defined at run time and will
322
- # match the items that are retrieved from Azure. See the 'test/integration/verify/controls' for
323
- # examples
324
- #
325
- # This class will not be called externally
326
- #
327
- # @author Russell Seymour
328
- # @since 0.2.0
329
- # @attr_reader string name Name of the Azure resource
330
- # @attr_reader string type Type of the Azure Resource
331
- # @attr_reader string location Location in Azure of the resource
332
- class AzureResourceProbe
333
- attr_reader :name, :type, :location, :item, :count
334
-
335
- # Initialize method for the class. Accepts an item, be it a scalar value, hash or Azure object
336
- # It will then create the necessary dynamic methods so that they can be called in the tests
337
- # This is accomplished by call the AzureResourceDynamicMethods
338
- #
339
- # @param varaint The item from which the class will be initialized
340
- #
341
- # @return AzureResourceProbe
342
- def initialize(item)
343
- dm = AzureResourceDynamicMethods.new
344
- dm.create_methods(self, item)
345
-
346
- # Set the item as a property on the class
347
- # This is so that it is possible to interrogate what has been added to the class and isolate them from
348
- # the standard methods that a Ruby class has.
349
- # This used for checking Tags on a resource for example
350
- # It also allows direct access if so required
351
- @item = item
352
-
353
- # Set how many items have been set
354
- @count = item.length
355
- end
356
-
357
- # Allows resources to respond to the include test
358
- # This means that things like tags can be checked for and then their value tested
359
- #
360
- # @author Russell Seymour
361
- #
362
- # @param [String] key Name of the item to look for in the @item property
363
- def include?(key)
364
- @item.key?(key)
365
- end
366
-
367
- # Give a sting like `computer_name` return the camelCase version, e.g.
368
- # computerName
369
- #
370
- # @param string data Data that needs to be converted from snake_case to camelCase
371
- #
372
- # @return string
373
- def camel_case(data)
374
- camel_case_data = data.split("_").inject([]) { |buffer, e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
375
-
376
- # Ensure that gb (as in gigabytes) is uppercased
377
- camel_case_data.gsub(/[gb]/, &:upcase)
378
- end
379
- end
@@ -1,55 +0,0 @@
1
- require "resources/azure/azure_backend"
2
- require "inspec/utils/filter"
3
-
4
- module Inspec::Resources
5
- class AzureGenericResource < AzureResourceBase
6
- name "azure_generic_resource"
7
-
8
- desc '
9
- InSpec Resource to interrogate any Resource type in Azure
10
- '
11
-
12
- supports platform: "azure"
13
-
14
- attr_accessor :filter, :total, :counts, :name, :type, :location, :probes
15
-
16
- def initialize(opts = {})
17
- Inspec.deprecate(:resource_azure_generic_resource)
18
-
19
- # Call the parent class constructor
20
- super(opts)
21
-
22
- # Get the resource group
23
- resource_group
24
-
25
- # Get the resources
26
- resources
27
-
28
- # Create the tag methods
29
- create_tag_methods
30
- end
31
-
32
- # Define the filter table so that it can be interrogated
33
- @filter = FilterTable.create
34
- @filter.register_filter_method(:contains)
35
- .register_column(:type, field: "type")
36
- .register_column(:name, field: "name")
37
- .register_column(:location, field: "location")
38
- .register_column(:properties, field: "properties")
39
-
40
- @filter.install_filter_methods_on_resource(self, :probes)
41
-
42
- def parse_resource(resource)
43
- # return a hash of information
44
- parsed = {
45
- "location" => resource.location,
46
- "name" => resource.name,
47
- "type" => resource.type,
48
- "exist?" => true,
49
- "properties" => AzureResourceProbe.new(resource.properties),
50
- }
51
-
52
- parsed
53
- end
54
- end
55
- end
@@ -1,151 +0,0 @@
1
- require "resources/azure/azure_backend"
2
-
3
- module Inspec::Resources
4
- class AzureResourceGroup < AzureResourceBase
5
- name "azure_resource_group"
6
-
7
- desc '
8
- InSpec Resource to get metadata about a specific Resource Group
9
- '
10
-
11
- supports platform: "azure"
12
-
13
- attr_reader :name, :location, :id, :total, :counts, :mapping
14
-
15
- # Constructor to get the resource group itself and perform some analysis on the
16
- # resources that in the resource group.
17
- #
18
- # This analysis is defined by the the mapping hashtable which is used to define
19
- # the 'has_xxx?' methods (see AzureResourceGroup#create_has_methods) and return
20
- # the counts for each type
21
- #
22
- # @author Russell Seymour
23
- def initialize(opts)
24
- opts.key?(:name) ? opts[:group_name] = opts[:name] : false
25
- # Ensure that the opts only have the name of the resource group set
26
- opts.select! { |k, _v| k == :group_name }
27
- super(opts)
28
-
29
- # set the mapping for the Azure Resources
30
- @mapping = {
31
- nic: "Microsoft.Network/networkInterfaces",
32
- vm: "Microsoft.Compute/virtualMachines",
33
- extension: "Microsoft.Compute/virtualMachines/extensions",
34
- nsg: "Microsoft.Network/networkSecurityGroups",
35
- vnet: "Microsoft.Network/virtualNetworks",
36
- managed_disk: "Microsoft.Compute/disks",
37
- managed_disk_image: "Microsoft.Compute/images",
38
- sa: "Microsoft.Storage/storageAccounts",
39
- public_ip: "Microsoft.Network/publicIPAddresses",
40
- }
41
-
42
- # Get information about the resource group itself
43
- resource_group
44
-
45
- # Get information about the resources in the resource group
46
- resources
47
-
48
- # Call method to create the has_xxxx? methods
49
- create_has_methods
50
-
51
- # Call method to allow access to the tag values
52
- create_tag_methods
53
- end
54
-
55
- # Return the provisioning state of the resource group
56
- #
57
- # @author Russell Seymour
58
- def provisioning_state
59
- properties.provisioningState
60
- end
61
-
62
- # Analyze the fully qualified id of the resource group to return the subscription id
63
- # that this resource group is part of
64
- #
65
- # The format of the id is
66
- # /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP_NAME>
67
- #
68
- # @author Russell Seymour
69
- def subscription_id
70
- id.split(%r{\/}).reject(&:empty?)[1]
71
- end
72
-
73
- # Method to parse the resources that have been returned
74
- # This allows the calculations of the amount of resources to be determined
75
- #
76
- # @author Russell Seymour
77
- #
78
- # @param [Hash] resource A hashtable representing the resource group
79
- def parse_resource(resource)
80
- # return a hash of information
81
- parsed = {
82
- "name" => resource.name,
83
- "type" => resource.type,
84
- }
85
-
86
- parsed
87
- end
88
-
89
- # This method catches the xxx_count calls that are made on the resource.
90
- #
91
- # The method that is called is stripped of '_count' and then compared with the
92
- # mappings table. If that type exists then the number of those items is returned.
93
- # However if that type is not in the Resource Group then the method will return
94
- # a NoMethodError exception
95
- #
96
- # @author Russell Seymour
97
- #
98
- # @param [Symbol] method_id The name of the method that was called
99
- def method_missing(method_id)
100
- # Determine the mapping_key based on the method_id
101
- mapping_key = method_id.to_s.chomp("_count").to_sym
102
-
103
- if mapping.key?(mapping_key)
104
- # based on the method id get the
105
- namespace, type_name = mapping[mapping_key].split(/\./)
106
-
107
- # check that the type_name is defined, if not return 0
108
- if send(namespace).methods.include?(type_name.to_sym)
109
- # return the count for the method id
110
- send(namespace).send(type_name)
111
- else
112
- 0
113
- end
114
- else
115
- msg = format("undefined method `%s` for %s", method_id, self.class)
116
- raise NoMethodError, msg
117
- end
118
- end
119
-
120
- private
121
-
122
- # For each of the mappings this method creates the has_xxx? method. This allows the use
123
- # of the following type of test
124
- #
125
- # it { should have_nics }
126
- #
127
- # For example, it will create a has_nics? method that returns a boolean to state of the
128
- # resource group has any nics at all.
129
- #
130
- # @author Russell Seymour
131
- # @private
132
- def create_has_methods
133
- return if failed_resource?
134
-
135
- # Create the has methods for each of the mappings
136
- # This is a quick test to show that the resource group has at least one of these things
137
- mapping.each do |name, type|
138
- # Determine the name of the method name
139
- method_name = format("has_%ss?", name)
140
- namespace, type_name = type.split(/\./)
141
-
142
- # use the namespace and the type_name to determine if the resource group has this type or not
143
- result = send(namespace).methods.include?(type_name.to_sym) ? true : false
144
-
145
- define_singleton_method method_name do
146
- result
147
- end
148
- end
149
- end
150
- end
151
- end