kitchen-terraform 0.7.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +3 -1
  4. data/README.md +33 -359
  5. data/lib/kitchen/driver/terraform.rb +273 -57
  6. data/lib/kitchen/driver/terraform/verify_client_version.rb +44 -0
  7. data/lib/kitchen/driver/terraform/workflow.rb +90 -0
  8. data/lib/kitchen/provisioner/terraform.rb +31 -37
  9. data/lib/{terraform/get_command.rb → kitchen/terraform.rb} +3 -5
  10. data/lib/{terraform/deprecated_version.rb → kitchen/terraform/client.rb} +5 -12
  11. data/lib/kitchen/terraform/client/apply.rb +38 -0
  12. data/lib/kitchen/terraform/client/execute_command.rb +56 -0
  13. data/lib/kitchen/terraform/client/get.rb +35 -0
  14. data/lib/kitchen/terraform/client/output.rb +50 -0
  15. data/lib/kitchen/terraform/client/plan.rb +42 -0
  16. data/lib/kitchen/terraform/client/process_options.rb +87 -0
  17. data/lib/kitchen/terraform/client/validate.rb +35 -0
  18. data/lib/kitchen/terraform/client/version.rb +48 -0
  19. data/lib/{terraform/apply_timeout_config.rb → kitchen/terraform/create_directories.rb} +18 -11
  20. data/lib/kitchen/terraform/define_config_attribute.rb +39 -0
  21. data/lib/kitchen/terraform/define_integer_config_attribute.rb +43 -0
  22. data/lib/kitchen/terraform/define_string_config_attribute.rb +43 -0
  23. data/lib/kitchen/verifier/terraform.rb +186 -38
  24. data/lib/kitchen/verifier/terraform/configure_inspec_runner_attributes.rb +93 -0
  25. data/lib/kitchen/verifier/terraform/configure_inspec_runner_backend.rb +32 -0
  26. data/lib/kitchen/verifier/terraform/configure_inspec_runner_controls.rb +39 -0
  27. data/lib/{terraform/apply_command.rb → kitchen/verifier/terraform/configure_inspec_runner_host.rb} +11 -15
  28. data/lib/{terraform/deprecated_output_parser.rb → kitchen/verifier/terraform/configure_inspec_runner_port.rb} +16 -20
  29. data/lib/{terraform/deprecated_variables_coercer.rb → kitchen/verifier/terraform/configure_inspec_runner_user.rb} +16 -14
  30. data/lib/kitchen/verifier/terraform/enumerate_groups_and_hostnames.rb +67 -0
  31. data/lib/{terraform/version_command.rb → terraform.rb} +1 -5
  32. data/lib/terraform/configurable.rb +18 -61
  33. data/lib/terraform/debug_logger.rb +12 -12
  34. data/lib/terraform/project_version.rb +1 -1
  35. metadata +72 -135
  36. metadata.gz.sig +0 -0
  37. data/lib/terraform/cli_config.rb +0 -29
  38. data/lib/terraform/client.rb +0 -96
  39. data/lib/terraform/color_coercer.rb +0 -35
  40. data/lib/terraform/color_config.rb +0 -32
  41. data/lib/terraform/command.rb +0 -53
  42. data/lib/terraform/command_factory.rb +0 -111
  43. data/lib/terraform/command_option.rb +0 -65
  44. data/lib/terraform/command_options.rb +0 -103
  45. data/lib/terraform/destructive_plan_command.rb +0 -35
  46. data/lib/terraform/directory_config.rb +0 -32
  47. data/lib/terraform/file_configs.rb +0 -36
  48. data/lib/terraform/group.rb +0 -61
  49. data/lib/terraform/group_attributes.rb +0 -42
  50. data/lib/terraform/group_hostnames.rb +0 -38
  51. data/lib/terraform/groups_coercer.rb +0 -43
  52. data/lib/terraform/groups_config.rb +0 -32
  53. data/lib/terraform/integer_coercer.rb +0 -37
  54. data/lib/terraform/no_output_parser.rb +0 -28
  55. data/lib/terraform/output_command.rb +0 -23
  56. data/lib/terraform/output_parser.rb +0 -55
  57. data/lib/terraform/parallelism_config.rb +0 -32
  58. data/lib/terraform/pathname_coercer.rb +0 -40
  59. data/lib/terraform/plan_command.rb +0 -30
  60. data/lib/terraform/prepare_input_file.rb +0 -34
  61. data/lib/terraform/prepare_output_file.rb +0 -36
  62. data/lib/terraform/shell_out.rb +0 -59
  63. data/lib/terraform/show_command.rb +0 -30
  64. data/lib/terraform/simple_coercer.rb +0 -36
  65. data/lib/terraform/simple_config.rb +0 -28
  66. data/lib/terraform/unsupported_version.rb +0 -26
  67. data/lib/terraform/validate_command.rb +0 -23
  68. data/lib/terraform/variable_files_coercer.rb +0 -40
  69. data/lib/terraform/variable_files_config.rb +0 -32
  70. data/lib/terraform/variables_coercer.rb +0 -49
  71. data/lib/terraform/variables_config.rb +0 -32
  72. data/lib/terraform/version.rb +0 -73
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2016 New Context Services, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "dry/monads"
18
+ require "kitchen/terraform/client"
19
+
20
+ # Processes Terraform Client function options in to Terraform Command-Line Interface (CLI) flags.
21
+ #
22
+ # @see https://www.terraform.io/docs/commands/index.html Terraform commands
23
+ module ::Kitchen::Terraform::Client::ProcessOptions
24
+ extend ::Dry::Monads::Either::Mixin
25
+ extend ::Dry::Monads::Maybe::Mixin
26
+ extend ::Dry::Monads::List::Mixin
27
+ extend ::Dry::Monads::Try::Mixin
28
+
29
+ OPTIONS_FLAGS = {
30
+ color: lambda do |value:|
31
+ "-no-color" if not value
32
+ end,
33
+ destroy: lambda do |value:|
34
+ "-destroy" if value
35
+ end,
36
+ input: lambda do |value:|
37
+ "-input=#{value}"
38
+ end,
39
+ json: lambda do |value:|
40
+ "-json" if value
41
+ end,
42
+ out: lambda do |value:|
43
+ "-out=#{value}"
44
+ end,
45
+ parallelism: lambda do |value:|
46
+ "-parallelism=#{value}"
47
+ end,
48
+ state: lambda do |value:|
49
+ "-state=#{value}"
50
+ end,
51
+ state_out: lambda do |value:|
52
+ "-state-out=#{value}"
53
+ end,
54
+ update: lambda do |value:|
55
+ "-update" if value
56
+ end,
57
+ var: lambda do |value:|
58
+ value.map do |variable_name, variable_value|
59
+ "-var='#{variable_name}=#{variable_value}'"
60
+ end
61
+ end,
62
+ var_file: lambda do |value:|
63
+ value.map do |file|
64
+ "-var-file=#{file}"
65
+ end
66
+ end
67
+ }.freeze
68
+
69
+ # Invokes the function.
70
+ #
71
+ # @param unprocessed_options [::Hash{::Symbol => TrueClass, FalseClass, #to_s, #map}] underscore delimited option keys
72
+ # associated with their values.
73
+ # @return [::Dry::Monads::Either] the result of the function.
74
+ def self.call(unprocessed_options:)
75
+ List(unprocessed_options.to_a).fmap(&method(:Right)).typed(::Dry::Monads::Either).traverse do |member|
76
+ member.bind do |key, value|
77
+ Maybe(::Kitchen::Terraform::Client::ProcessOptions::OPTIONS_FLAGS[key]).bind do |processor|
78
+ Right processor.call value: value
79
+ end.or do
80
+ Left ":#{key} is not a supported Terraform Client option"
81
+ end
82
+ end
83
+ end.fmap do |options|
84
+ options.value.flatten.compact.sort
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2016 New Context Services, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "kitchen/terraform/client"
18
+ require "kitchen/terraform/client/execute_command"
19
+
20
+ # Validates the syntax of Terraform configuration files.
21
+ #
22
+ # @see https://www.terraform.io/docs/commands/validate.html Terraform validate command
23
+ module ::Kitchen::Terraform::Client::Validate
24
+ # Invokes the function.
25
+ #
26
+ # @param cli [::String] the path of the Terraform CLI to use to execute the validate command.
27
+ # @param directory [::String] the directory containing files to validate.
28
+ # @param logger [#<<] a logger to receive the stdout and stderr of the validate command.
29
+ # @param timeout [::Integer] the maximum execution time in seconds for the validate command.
30
+ # @return [::Dry::Monads::Either] the result of the function.
31
+ def self.call(cli:, directory:, logger:, timeout:)
32
+ ::Kitchen::Terraform::Client::ExecuteCommand.call cli: cli, command: "validate", logger: logger, target: directory,
33
+ timeout: timeout
34
+ end
35
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2016 New Context Services, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "dry/monads"
18
+ require "kitchen/terraform/client"
19
+ require "kitchen/terraform/client/execute_command"
20
+
21
+ # Retrieves the version of the Terraform Command-Line Interface (CLI).
22
+ #
23
+ # @see https://www.terraform.io/docs/commands/index.html Terraform commands
24
+ module ::Kitchen::Terraform::Client::Version
25
+ extend ::Dry::Monads::Either::Mixin
26
+
27
+ extend ::Dry::Monads::Maybe::Mixin
28
+
29
+ # Invokes the function.
30
+ #
31
+ # @param cli [::String] the path of the Terraform CLI to use to execute the version command.
32
+ # @param logger [#<<] a logger to receive the stdout and stderr of the version command.
33
+ # @param timeout [::Integer] the time in seconds to wait for the version command to finish.
34
+ # @return [::Dry::Monads::Either] the result of the function.
35
+ def self.call(cli:, logger:, timeout:)
36
+ ::Kitchen::Terraform::Client::ExecuteCommand
37
+ .call(cli: cli, command: "version", logger: logger, timeout: timeout)
38
+ .bind do |output|
39
+ Maybe output.slice /v(\d+\.\d+)/, 1
40
+ end.bind do |major_minor_versions|
41
+ Right Float major_minor_versions
42
+ end.or do |error|
43
+ error.nil? and Left "Terraform client version output did not match 'vX.Y'" or Left error
44
+ end.or do |error|
45
+ Left "Unable to parse Terraform client version output\n#{error}"
46
+ end
47
+ end
48
+ end
@@ -14,19 +14,26 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require 'terraform/integer_coercer'
18
- require 'terraform/simple_config'
17
+ require "dry/monads"
18
+ require "fileutils"
19
+ require "kitchen/terraform"
19
20
 
20
- module Terraform
21
- # Behaviour for the [:apply_timeout] config option
22
- module ApplyTimeoutConfig
23
- include ::Terraform::SimpleConfig
21
+ # Creates directories on the filesystem.
22
+ module ::Kitchen::Terraform::CreateDirectories
23
+ extend ::Dry::Monads::Either::Mixin
24
+ extend ::Dry::Monads::Try::Mixin
24
25
 
25
- def self.extended(configurable_class)
26
- configurable_class
27
- .configure_required attr: :apply_timeout,
28
- coercer_class: ::Terraform::IntegerCoercer,
29
- default_value: 600
26
+ # Invokes the function.
27
+ #
28
+ # @param directories [::Array<::String>, ::String] the list of directories to create.
29
+ # @return [::Dry::Monads::Either] the result of the function.
30
+ def self.call(directories:)
31
+ Try ::SystemCallError do
32
+ ::FileUtils.makedirs directories
33
+ end.to_either.bind do
34
+ Right "Created directories #{directories}"
35
+ end.or do |error|
36
+ Left error.to_s
30
37
  end
31
38
  end
32
39
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2016 New Context Services, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "dry-validation"
18
+ require "kitchen"
19
+ require "kitchen/terraform"
20
+
21
+ # Defines a configuration attribute for a plugin class.
22
+ #
23
+ # @see http://dry-rb.org/gems/dry-validation/ DRY Validation
24
+ module ::Kitchen::Terraform::DefineConfigAttribute
25
+ # Invokes the function.
26
+ #
27
+ # @param attribute [::Symbol] the name of the attribute.
28
+ # @param initialize_default_value [::Proc] a proc to lazily provide a default value.
29
+ # @param plugin_class [::Class] the plugin class on which the attribute will be defined.
30
+ # @param schema [::Proc] a proc to define the validation schema of the attribute.
31
+ def self.call(attribute:, initialize_default_value:, plugin_class:, schema:)
32
+ plugin_class.required_config attribute do |_attribute, value, plugin|
33
+ ::Dry::Validation.Schema(&schema).call(value: value).messages.tap do |messages|
34
+ raise ::Kitchen::UserError, "#{plugin.class} configuration: #{attribute} #{messages}" if not messages.empty?
35
+ end
36
+ end
37
+ plugin_class.default_config attribute, &initialize_default_value
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2016 New Context Services, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "dry-validation"
18
+ require "kitchen"
19
+ require "kitchen/terraform"
20
+ require "kitchen/terraform/define_config_attribute"
21
+
22
+ # Defines an integer configuration attribute for a plugin class.
23
+ #
24
+ # @see http://dry-rb.org/gems/dry-validation/ DRY Validation
25
+ module ::Kitchen::Terraform::DefineIntegerConfigAttribute
26
+ # Invokes the function.
27
+ #
28
+ # @param attribute [::Symbol] the name of the attribute.
29
+ # @param plugin_class [::Class] the plugin class on which the attribute will be defined.
30
+ # @yieldparam plugin [::Kitchen::Driver::Terraform, ::Kitchen::Provisioner::Terraform, ::Kitchen::Verifier::Terraform]
31
+ # an instance of the plugin class.
32
+ # @yieldreturn [::Object] the default value of the attribute.
33
+ def self.call(attribute:, plugin_class:, &initialize_default_value)
34
+ ::Kitchen::Terraform::DefineConfigAttribute.call(
35
+ attribute: attribute,
36
+ initialize_default_value: initialize_default_value,
37
+ plugin_class: plugin_class,
38
+ schema: lambda do
39
+ required(:value).filled :int?
40
+ end
41
+ )
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2016 New Context Services, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require "dry-validation"
18
+ require "kitchen"
19
+ require "kitchen/terraform"
20
+ require "kitchen/terraform/define_config_attribute"
21
+
22
+ # Defines a string configuration attribute for a plugin class.
23
+ #
24
+ # @see http://dry-rb.org/gems/dry-validation/ DRY Validation
25
+ module ::Kitchen::Terraform::DefineStringConfigAttribute
26
+ # Invokes the function.
27
+ #
28
+ # @param attribute [::Symbol] the name of the attribute.
29
+ # @param plugin_class [::Class] the plugin class on which the attribute will be defined.
30
+ # @yieldparam plugin [::Kitchen::Driver::Terraform, ::Kitchen::Provisioner::Terraform, ::Kitchen::Verifier::Terraform]
31
+ # an instance of the plugin class.
32
+ # @yieldreturn [::Object] the default value of the attribute.
33
+ def self.call(attribute:, plugin_class:, &initialize_default_value)
34
+ ::Kitchen::Terraform::DefineConfigAttribute.call(
35
+ attribute: attribute,
36
+ initialize_default_value: initialize_default_value,
37
+ plugin_class: plugin_class,
38
+ schema: lambda do
39
+ required(:value).filled :str?
40
+ end
41
+ )
42
+ end
43
+ end
@@ -14,56 +14,204 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require 'kitchen/verifier/inspec'
18
- require 'terraform/configurable'
19
- require 'terraform/groups_config'
17
+ require "dry/monads"
18
+ require "kitchen"
19
+ require "kitchen/terraform/define_config_attribute"
20
+ require "kitchen/verifier/inspec"
21
+ require "terraform/configurable"
20
22
 
21
- module Kitchen
22
- module Verifier
23
- # Runs tests post-converge to confirm that instances in the Terraform state
24
- # are in an expected state
25
- class Terraform < ::Kitchen::Verifier::Inspec
26
- extend ::Terraform::GroupsConfig
23
+ # The verifier utilizes the InSpec infrastructure testing framework to verify the behaviour and state of resources in
24
+ # the Terraform state.
25
+ #
26
+ # InSpec profiles are assumed to be located in `test/integration/<suite-name>/`.
27
+ #
28
+ # === Configuration
29
+ #
30
+ # ==== Example .kitchen.yml snippet
31
+ #
32
+ # verifier:
33
+ # name: terraform
34
+ # groups:
35
+ # - name: group_one
36
+ # attributes:
37
+ # foo: bar
38
+ # controls:
39
+ # - biz
40
+ # hostnames: hostnames_output
41
+ # port: 123
42
+ # username: test-user
43
+ # - name: group_two
44
+ #
45
+ # ==== Attributes
46
+ #
47
+ # ===== groups
48
+ #
49
+ # Description:: A collection of maps that configure which InSpec profile will be run against different resources in the
50
+ # Terraform state.
51
+ #
52
+ # Type:: Array
53
+ #
54
+ # Status:: Optional
55
+ #
56
+ # Default:: +[]+
57
+ #
58
+ # ====== name
59
+ #
60
+ # Description:: A label that is used to identify the group.
61
+ #
62
+ # Type:: String
63
+ #
64
+ # Status:: Required
65
+ #
66
+ # ====== attributes
67
+ #
68
+ # Description:: A map that associates InSpec profile attribute names to Terraform output variable names.
69
+ #
70
+ # Type:: Hash
71
+ #
72
+ # Status:: Optional
73
+ #
74
+ # Default:: +{}+
75
+ #
76
+ # ====== controls
77
+ #
78
+ # Description:: A collection of controls to selectively include from the suite's InSpec profile.
79
+ #
80
+ # Type:: Array
81
+ #
82
+ # Status:: Optional
83
+ #
84
+ # Default:: +[]+
85
+ #
86
+ # ====== hostnames
87
+ #
88
+ # Description:: The name of a Terraform output variable of type String or Array which contains one or more hostnames
89
+ # from the Terraform state that will be targeted with the suite's InSpec profile.
90
+ #
91
+ # Type:: String
92
+ #
93
+ # Status:: Optional
94
+ #
95
+ # ====== port
96
+ #
97
+ # Description:: The port to use when connecting to the group's hosts with Secure Shell (SSH).
98
+ #
99
+ # Type:: Integer
100
+ #
101
+ # Status:: Optional
102
+ #
103
+ # ====== username
104
+ #
105
+ # Description:: The username to use when connecting to the group's hosts with SSH.
106
+ #
107
+ # Type:: String
108
+ #
109
+ # Status:: Optional
110
+ #
111
+ # @see https://en.wikipedia.org/wiki/Secure_Shell Secure Shell
112
+ # @see https://www.inspec.io/ InSpec
113
+ # @see https://www.inspec.io/docs/reference/dsl_inspec/ InSpec Controls
114
+ # @see https://www.inspec.io/docs/reference/profiles/ InSpec Profiles
115
+ # @see https://www.terraform.io/docs/configuration/outputs.html Terraform Output Variables
116
+ # @see https://www.terraform.io/docs/state/index.html Terraform State
117
+ # @version 2
118
+ class ::Kitchen::Verifier::Terraform < ::Kitchen::Verifier::Inspec
119
+ kitchen_verifier_api_version 2
27
120
 
28
- include ::Terraform::Configurable
121
+ ::Kitchen::Terraform::DefineConfigAttribute.call(
122
+ attribute: :groups,
123
+ initialize_default_value: lambda do |_plugin|
124
+ []
125
+ end,
126
+ plugin_class: self,
127
+ schema: lambda do
128
+ configure do
129
+ def self.messages
130
+ super.merge en: {
131
+ errors: {
132
+ keys_are_strings_or_symbols?: "keys must be strings or symbols",
133
+ values_are_strings?: "values must be strings"
134
+ }
135
+ }
136
+ end
29
137
 
30
- kitchen_verifier_api_version 2
138
+ def keys_are_strings_or_symbols?(hash)
139
+ hash.keys.all? do |key|
140
+ key.is_a?(::String) | key.is_a?(::Symbol)
141
+ end
142
+ end
31
143
 
32
- def call(state)
33
- resolve_groups do |group|
34
- self.group = group
35
- config[:attributes] = {
36
- 'terraform_state' => provisioner[:state].to_path
37
- }.merge group.attributes
38
- info "Verifying #{group.description}"
39
- super
144
+ def values_are_strings?(hash)
145
+ hash.values.all? do |value|
146
+ value.is_a? ::String
147
+ end
148
+ end
149
+ end
150
+ required(:value).each do
151
+ schema do
152
+ required(:name).filled :str?
153
+ optional(:attributes).value :hash?, :keys_are_strings_or_symbols?, :values_are_strings?
154
+ optional(:controls).each :filled?, :str?
155
+ optional(:hostnames).value :str?
156
+ optional(:port).value :int?
157
+ optional(:username).value :str?
40
158
  end
41
- rescue ::Kitchen::StandardError, ::SystemCallError => error
42
- raise ::Kitchen::ActionFailed, error.message
43
159
  end
160
+ end
161
+ )
44
162
 
45
- private
163
+ include ::Dry::Monads::Either::Mixin
46
164
 
47
- attr_accessor :group
165
+ include ::Terraform::Configurable
48
166
 
49
- def configure_backend(options:)
50
- /(local)host/.match group.hostname do |match|
51
- options.merge! 'backend' => match[1]
52
- end
53
- end
167
+ # The verifier enumerates through each hostname of each group and verifies the associated InSpec controls.
168
+ #
169
+ # @example
170
+ # `kitchen verify suite-name`
171
+ # @param state [::Hash] the mutable instance and verifier state.
172
+ # @raise [::Kitchen::ActionFailed] if the result of the action is a failure.
173
+ # @return [::Dry::Monads::Either] the result of the action.
174
+ def call(state)
175
+ self.class::EnumerateGroupsAndHostnames.call driver: driver, groups: config.fetch(:groups) do |group:, hostname:|
176
+ state.store :group, group
177
+ state.store :hostname, hostname
178
+ info "Verifying host '#{hostname}' of group '#{group.fetch :name}'"
179
+ super state
180
+ end.fmap do |success|
181
+ logger.debug success
182
+ end.or do |failure|
183
+ raise ::Kitchen::ActionFailed, failure
184
+ end
185
+ end
54
186
 
55
- def resolve_groups(&block)
56
- config[:groups]
57
- .each { |group| group.resolve client: silent_client, &block }
58
- end
187
+ private
59
188
 
60
- def runner_options(transport, state = {}, platform = nil, suite = nil)
61
- super.tap do |options|
62
- options.merge! controls: group.controls, 'host' => group.hostname,
63
- 'port' => group.port, 'user' => group.username
64
- configure_backend options: options
189
+ # Modifies the Inspec Runner options generated by the kitchen-inspec verifier to support the verification of each
190
+ # group's hosts.
191
+ #
192
+ # @api private
193
+ # @return [::Hash] Inspec Runner options.
194
+ # @see https://github.com/chef/inspec/blob/master/lib/inspec/runner.rb ::Inspec::Runner
195
+ # @see https://github.com/chef/kitchen-inspec/blob/master/lib/kitchen/verifier.rb kitchen-inspec verifier
196
+ def runner_options(transport, state = {}, platform = nil, suite = nil)
197
+ super(transport, state, platform, suite).tap do |options|
198
+ self.class::ConfigureInspecRunnerBackend.call hostname: state.fetch(:hostname), options: options
199
+ self.class::ConfigureInspecRunnerHost.call hostname: state.fetch(:hostname), options: options
200
+ self.class::ConfigureInspecRunnerPort.call group: state.fetch(:group), options: options
201
+ self.class::ConfigureInspecRunnerUser.call group: state.fetch(:group), options: options
202
+ self.class::ConfigureInspecRunnerAttributes
203
+ .call(driver: driver, group: state.fetch(:group), terraform_state: driver[:state]).bind do |attributes|
204
+ config.store :attributes, attributes
65
205
  end
66
- end
206
+ self.class::ConfigureInspecRunnerControls.call group: state.fetch(:group), options: options
67
207
  end
68
208
  end
69
209
  end
210
+
211
+ require "kitchen/verifier/terraform/configure_inspec_runner_attributes"
212
+ require "kitchen/verifier/terraform/configure_inspec_runner_backend"
213
+ require "kitchen/verifier/terraform/configure_inspec_runner_controls"
214
+ require "kitchen/verifier/terraform/configure_inspec_runner_host"
215
+ require "kitchen/verifier/terraform/configure_inspec_runner_port"
216
+ require "kitchen/verifier/terraform/configure_inspec_runner_user"
217
+ require "kitchen/verifier/terraform/enumerate_groups_and_hostnames"