kitchen-terraform 3.3.1 → 4.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 (36) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +45 -28
  5. data/lib/kitchen/driver/terraform.rb +87 -66
  6. data/lib/kitchen/provisioner/terraform.rb +1 -1
  7. data/lib/kitchen/terraform/client_version_verifier.rb +3 -3
  8. data/lib/kitchen/terraform/command/output.rb +43 -40
  9. data/lib/kitchen/{verifier/terraform/configure_inspec_runner_host.rb → terraform/config_attribute/systems.rb} +18 -11
  10. data/lib/kitchen/terraform/config_attribute/variable_files.rb +1 -1
  11. data/lib/kitchen/terraform/config_schemas/system.rb +555 -0
  12. data/lib/kitchen/terraform/{breaking/kitchen_instance.rb → config_schemas/systems.rb} +16 -5
  13. data/lib/kitchen/terraform/configurable.rb +2 -6
  14. data/lib/kitchen/terraform/inspec.rb +74 -0
  15. data/lib/kitchen/terraform/inspec_options_mapper.rb +49 -0
  16. data/lib/kitchen/terraform/inspec_with_hosts.rb +49 -0
  17. data/lib/kitchen/terraform/inspec_without_hosts.rb +44 -0
  18. data/lib/kitchen/terraform/shell_out.rb +13 -10
  19. data/lib/kitchen/terraform/system.rb +120 -0
  20. data/lib/kitchen/terraform/system_attrs_resolver.rb +57 -0
  21. data/lib/kitchen/terraform/system_hosts_resolver.rb +45 -0
  22. data/lib/kitchen/terraform/version.rb +60 -17
  23. data/lib/kitchen/verifier/terraform.rb +162 -156
  24. metadata +45 -41
  25. metadata.gz.sig +0 -0
  26. data/lib/kitchen/terraform/config_attribute/groups.rb +0 -148
  27. data/lib/kitchen/terraform/config_schemas/groups.rb +0 -52
  28. data/lib/kitchen/terraform/deprecating/kitchen_instance.rb +0 -61
  29. data/lib/kitchen/terraform/kitchen_instance.rb +0 -49
  30. data/lib/kitchen/verifier/terraform/configure_inspec_runner_attributes.rb +0 -98
  31. data/lib/kitchen/verifier/terraform/configure_inspec_runner_backend.rb +0 -32
  32. data/lib/kitchen/verifier/terraform/configure_inspec_runner_controls.rb +0 -41
  33. data/lib/kitchen/verifier/terraform/configure_inspec_runner_port.rb +0 -40
  34. data/lib/kitchen/verifier/terraform/configure_inspec_runner_ssh_key.rb +0 -41
  35. data/lib/kitchen/verifier/terraform/configure_inspec_runner_user.rb +0 -40
  36. data/lib/kitchen/verifier/terraform/enumerate_groups_and_hostnames.rb +0 -82
@@ -14,10 +14,21 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require "delegate"
18
- require "kitchen"
19
- require "kitchen/terraform/breaking"
17
+ require "dry/validation"
18
+ require "kitchen/terraform/config_schemas"
19
+ require "kitchen/terraform/config_schemas/system"
20
20
 
21
- # This class provides the breaking change to the KitchenInstance.
22
- class ::Kitchen::Terraform::Breaking::KitchenInstance < DelegateClass ::Kitchen::Instance
21
+ module Kitchen
22
+ module Terraform
23
+ module ConfigSchemas
24
+ # The value of the +systems+ key must be a sequence of systems.
25
+ #
26
+ # {include:Kitchen::Terraform::ConfigSchemas::System}
27
+ Systems = ::Dry::Validation.Schema do
28
+ required(:value).each do
29
+ schema ::Kitchen::Terraform::ConfigSchemas::System
30
+ end
31
+ end
32
+ end
33
+ end
23
34
  end
@@ -16,7 +16,6 @@
16
16
 
17
17
  require "kitchen"
18
18
  require "kitchen/terraform"
19
- require "kitchen/terraform/kitchen_instance"
20
19
  require "kitchen/terraform/version"
21
20
 
22
21
  # Refinements to Kitchen::Configurable.
@@ -27,10 +26,7 @@ module ::Kitchen::Terraform::Configurable
27
26
  #
28
27
  # @return [self]
29
28
  def self.included(configurable_class)
30
- ::Kitchen::Terraform::Version
31
- .new
32
- .assign_plugin_version configurable_class: configurable_class
33
-
29
+ ::Kitchen::Terraform::Version.assign_plugin_version configurable_class: configurable_class
34
30
  self
35
31
  end
36
32
 
@@ -51,7 +47,7 @@ module ::Kitchen::Terraform::Configurable
51
47
  "Instance must be provided to #{self}"
52
48
  )
53
49
 
54
- @instance = ::Kitchen::Terraform::KitchenInstance.new kitchen_instance: kitchen_instance
50
+ @instance = kitchen_instance
55
51
  validate_config!
56
52
  expand_paths!
57
53
  load_needed_dependencies!
@@ -0,0 +1,74 @@
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 "inspec"
18
+ require "kitchen/terraform/error"
19
+ require "train"
20
+
21
+ module Kitchen
22
+ module Terraform
23
+ # InSpec is the class of objects which act as interfaces to InSpec.
24
+ class InSpec
25
+ class << self
26
+ # .logger= sets the logger for all InSpec processes.
27
+ #
28
+ # The logdev of the logger is extended to conform to interface expected by InSpec.
29
+ #
30
+ # @param logger [::Kitchen::Logger] the logger to use.
31
+ # @return [void]
32
+ def logger=(logger)
33
+ logger.logdev.define_singleton_method :filename do
34
+ false
35
+ end
36
+
37
+ ::Inspec::Log.logger = logger
38
+ end
39
+ end
40
+
41
+ # #exec executes InSpec.
42
+ #
43
+ # @return [self]
44
+ def exec
45
+ @runner.run.tap do |exit_code|
46
+ if 0 != exit_code
47
+ raise ::Kitchen::Terraform::Error, "InSpec Runner exited with #{exit_code}"
48
+ end
49
+ end
50
+
51
+ self
52
+ rescue ::ArgumentError, ::RuntimeError, ::Train::UserError => error
53
+ raise ::Kitchen::Terraform::Error, "Executing InSpec failed\n#{error.message}"
54
+ end
55
+
56
+ # #info logs an information message using the InSpec logger.
57
+ #
58
+ # @param message [::String] the message to be logged.
59
+ # @return [self]
60
+ def info(message:)
61
+ ::Inspec::Log.info ::String.new message
62
+
63
+ self
64
+ end
65
+
66
+ private
67
+
68
+ def initialize(options:, profile_path:)
69
+ @runner = ::Inspec::Runner.new options.merge logger: ::Inspec::Log.logger
70
+ @runner.add_target path: profile_path
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,49 @@
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"
18
+
19
+ # Kitchen::Terraform::InSpecOptionsMapper maps system configuration attributes to an InSpec options hash.
20
+ class ::Kitchen::Terraform::InSpecOptionsMapper
21
+ # map populates an InSpec options hash based on the intersection between the system keys and the supported options
22
+ # keys, converting keys from symbols to strings as required by InSpec.
23
+ #
24
+ # @param options [::Hash] the InSpec options hash to be populated.
25
+ # @return [void]
26
+ def map(options:)
27
+ system_keys.&(options_keys).each do |key|
28
+ options.store system_to_options.dig(key), system.fetch(key)
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ attr_accessor :system, :system_keys, :system_to_options, :options_keys
35
+
36
+ # @api private
37
+ def initialize(system:)
38
+ self.system = system
39
+ self.system_keys = system.keys
40
+ self.system_to_options = ::Hash.new do |hash, key|
41
+ hash.store key, key
42
+ end
43
+ system_to_options.store :reporter, "reporter"
44
+ self.options_keys = [:attrs, :backend, :backend_cache, :bastion_host, :bastion_port, :bastion_user, :controls,
45
+ :enable_password, :key_files, :password, :path, :port, :proxy_command, :reporter, :self_signed,
46
+ :shell, :shell_command, :shell_options, :show_progress, :ssl, :sudo, :sudo_command,
47
+ :sudo_options, :sudo_password, :user, :vendor_cache]
48
+ end
49
+ end
@@ -0,0 +1,49 @@
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"
18
+ require "kitchen/terraform/error"
19
+ require "kitchen/terraform/inspec"
20
+
21
+ module Kitchen
22
+ module Terraform
23
+ # InSpec instances act as interfaces to the InSpec gem.
24
+ class InSpecWithHosts
25
+ # exec executes the InSpec controls of an InSpec profile.
26
+ #
27
+ # @raise [::Kitchen::Terraform::Error] if the execution of the InSpec controls fails.
28
+ # @return [void]
29
+ def exec(system:)
30
+ system.each_host do |host:|
31
+ ::Kitchen::Terraform::InSpec
32
+ .new(options: options.merge(host: host), profile_path: profile_path)
33
+ .info(message: "Verifying host #{host} of #{system}").exec
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ attr_accessor :options, :profile_path
40
+
41
+ # @param options [::Hash] options for execution.
42
+ # @param profile_path [::String] the path to the InSpec profile which contains the controls to be executed.
43
+ def initialize(options:, profile_path:)
44
+ self.options = options
45
+ self.profile_path = profile_path
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,44 @@
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/inspec"
18
+
19
+ module Kitchen
20
+ module Terraform
21
+ # InSpec instances act as interfaces to the InSpec gem.
22
+ class InSpecWithoutHosts
23
+ # exec executes the InSpec controls of an InSpec profile.
24
+ #
25
+ # @raise [::Kitchen::Terraform::Error] if the execution of the InSpec controls fails.
26
+ # @return [void]
27
+ def exec(system:)
28
+ ::Kitchen::Terraform::InSpec
29
+ .new(options: options, profile_path: profile_path).info(message: "Verifying #{system}").exec
30
+ end
31
+
32
+ private
33
+
34
+ attr_accessor :options, :profile_path
35
+
36
+ # @param options [::Hash] options for execution.
37
+ # @param profile_path [::String] the path to the InSpec profile which contains the controls to be executed.
38
+ def initialize(options:, profile_path:)
39
+ self.options = options
40
+ self.profile_path = profile_path
41
+ end
42
+ end
43
+ end
44
+ end
@@ -26,14 +26,17 @@ require "mixlib/shellout"
26
26
  module ::Kitchen::Terraform::ShellOut
27
27
  # Runs a Terraform command.
28
28
  #
29
+ # @option options [::String] :cwd the directory in which to run the command.
30
+ # @option options [::Kitchen::Logger] :live_stream a Test Kitchen logger to capture the output from running the
31
+ # command.
32
+ # @option options [::Integer] :timeout the maximum duration in seconds to run the command.
29
33
  # @param command [::String] the command to run.
30
- # @param duration [::Integer] the maximum duration in seconds to run the command.
31
- # @param logger [::Kitchen::Logger] a Test Kitchen logger to capture the output from running the command.
34
+ # @param options [::Hash] options which adjust the execution of the command.
32
35
  # @raise [::Kitchen::Terraform::Error] if running the command fails.
33
36
  # @return [::String] the standard output from running the command.
34
37
  # @see https://rubygems.org/gems/mixlib-shellout mixlib-shellout
35
38
  # @yieldparam standard_output [::String] the standard output from running the command.
36
- def self.run(command:, duration: ::Mixlib::ShellOut::DEFAULT_READ_TIMEOUT, logger:, &block)
39
+ def self.run(command:, options:, &block)
37
40
  block ||=
38
41
  lambda do |standard_output:|
39
42
  standard_output
@@ -41,8 +44,7 @@ module ::Kitchen::Terraform::ShellOut
41
44
 
42
45
  run_shell_out(
43
46
  command: command,
44
- duration: duration,
45
- logger: logger,
47
+ options: options,
46
48
  &block
47
49
  )
48
50
  rescue ::Errno::EACCES,
@@ -64,18 +66,19 @@ module ::Kitchen::Terraform::ShellOut
64
66
  end
65
67
 
66
68
  # @api private
67
- def self.run_shell_out(command:, duration:, logger:)
69
+ def self.run_shell_out(command:, options:)
68
70
  yield(
69
71
  standard_output:
70
72
  ::Mixlib::ShellOut
71
73
  .new(
72
74
  "terraform #{command}",
73
- environment: {"TF_IN_AUTOMATION" => "true"},
74
- live_stream: logger,
75
- timeout: duration
75
+ options.merge(environment: {"TF_IN_AUTOMATION" => "true", "TF_WARN_OUTPUT_ERRORS" => "1"})
76
76
  )
77
77
  .tap do |shell_out|
78
- logger.warn "Running command `#{shell_out.command}`"
78
+ shell_out
79
+ .live_stream
80
+ .warn "Running command `#{shell_out.command}` in directory #{shell_out.cwd}"
81
+
79
82
  shell_out.run_command
80
83
  shell_out.error!
81
84
  end
@@ -0,0 +1,120 @@
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/inspec_with_hosts"
18
+ require "kitchen/terraform/inspec_without_hosts"
19
+
20
+ module Kitchen
21
+ module Terraform
22
+ # System is the class of objects which are verified by the Terraform Verifier.
23
+ class System
24
+ # #add_attrs adds attributes to the system.
25
+ #
26
+ # @param attrs [#to_hash] the attributes to be added.
27
+ # @return [self]
28
+ def add_attrs(attrs:)
29
+ @attributes = @attributes.merge Hash attrs
30
+
31
+ self
32
+ end
33
+
34
+ # #add_hosts adds hosts to the system.
35
+ #
36
+ # @param hosts [#to_arr,#to_a] the hosts to be added.
37
+ # @return [self]
38
+ def add_hosts(hosts:)
39
+ @hosts = @hosts.+ Array hosts
40
+
41
+ self
42
+ end
43
+
44
+ # #each_host enumerates each host of the system.
45
+ #
46
+ # @yieldparam host [::String] the next host.
47
+ # @return [self]
48
+ def each_host
49
+ @hosts.each do |host|
50
+ yield host: host
51
+ end
52
+
53
+ self
54
+ end
55
+
56
+ # #resolve_attrs resolves the attributes of the system which are contained in Terraform outputs.
57
+ #
58
+ # @param system_attrs_resolver [::Kitchen::Terraform::SystemAttrsResolver] the resolver.
59
+ # @return [self]
60
+ def resolve_attrs(system_attrs_resolver:)
61
+ system_attrs_resolver.resolve attrs_outputs_keys: @attrs_outputs.keys,
62
+ attrs_outputs_values: @attrs_outputs.values, system: self
63
+
64
+ self
65
+ end
66
+
67
+ # #resolve_hosts resolves the hosts of the system which are contained a Terraform output.
68
+ #
69
+ # @param system_hosts_resolver [::Kitchen::Terraform::SystemHostsResolver] the resolver.
70
+ # @return [self]
71
+ def resolve_hosts(system_hosts_resolver:)
72
+ system_hosts_resolver.resolve(
73
+ hosts_output: @mapping.fetch(:hosts_output) do
74
+ return self
75
+ end,
76
+ system: self,
77
+ )
78
+
79
+ self
80
+ end
81
+
82
+ # #to_s returns a string representation of the system.
83
+ #
84
+ # @return [::String] the name of the system.
85
+ def to_s
86
+ @mapping.fetch :name
87
+ end
88
+
89
+ # #verify verifies the system by executing InSpec.
90
+ #
91
+ # @param inspec_options [::Hash] the options to be passed to InSpec.
92
+ # @param inspec_profile_path [::String] the path to the profile which InSpec will execute.
93
+ # @return [self]
94
+ def verify(inspec_options:, inspec_profile_path:)
95
+ if @hosts.empty?
96
+ ::Kitchen::Terraform::InSpecWithoutHosts
97
+ else
98
+ ::Kitchen::Terraform::InSpecWithHosts
99
+ end
100
+ .new(options: inspec_options.merge(attributes: @attributes), profile_path: inspec_profile_path)
101
+ .exec(system: self)
102
+
103
+ self
104
+ end
105
+
106
+ private
107
+
108
+ def initialize(mapping:)
109
+ @attributes = {}
110
+ @attrs_outputs = mapping.fetch :attrs_outputs do
111
+ {}
112
+ end
113
+ @hosts = mapping.fetch :hosts do
114
+ []
115
+ end
116
+ @mapping = mapping
117
+ end
118
+ end
119
+ end
120
+ end