kitchen-terraform 3.0.0 → 3.1.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.
@@ -16,6 +16,7 @@
16
16
 
17
17
  require "kitchen/provisioner"
18
18
  require "kitchen/terraform/configurable"
19
+ require "kitchen/terraform/error"
19
20
 
20
21
  # The provisioner utilizes the driver to apply changes to the Terraform state in order to reach the desired
21
22
  # configuration of the root module.
@@ -88,19 +89,17 @@ class ::Kitchen::Provisioner::Terraform < ::Kitchen::Provisioner::Base
88
89
  def call(state)
89
90
  instance
90
91
  .driver
91
- .apply
92
- .fmap do |output|
92
+ .apply do |output:|
93
93
  state
94
94
  .store(
95
95
  :kitchen_terraform_output,
96
96
  output
97
97
  )
98
98
  end
99
- .or do |failure|
100
- raise(
101
- ::Kitchen::ActionFailed,
102
- failure
103
- )
104
- end
99
+ rescue ::Kitchen::Terraform::Error => error
100
+ raise(
101
+ ::Kitchen::ActionFailed,
102
+ error.message
103
+ )
105
104
  end
106
105
  end
@@ -14,43 +14,45 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require "dry/monads"
18
17
  require "kitchen/terraform"
18
+ require "kitchen/terraform/error"
19
19
  require "rubygems"
20
20
 
21
- # Verifies that the output of the Terraform Client version subcommand indicates a supported version of Terraform.
21
+ # Verifies that the output of the Terraform version command indicates a supported version of Terraform.
22
+ #
23
+ # Supported:: Terraform version >= 0.10.2, < 0.12.0.
22
24
  class ::Kitchen::Terraform::ClientVersionVerifier
23
- include ::Dry::Monads::Either::Mixin
24
-
25
- # Verifies output from the Terraform Client version subcommand against the support version.
26
- #
27
- # Supported:: Terraform version ~> 0.10.2.
25
+ # Verifies output from the Terraform version command against the support version.
28
26
  #
29
27
  # @param version_output [::String] the Terraform Client version subcommand output.
30
- # @return [::Dry::Monads::Either] the result of the function.
28
+ # @raise [::Kitchen::Terraform::Error] if the version is not supported.
29
+ # @return [::String] a confirmation that the version is supported.
31
30
  def verify(version_output:)
32
- Right(
33
- ::Gem::Version
34
- .new(
35
- version_output
36
- .slice(
37
- /v(\d+\.\d+\.\d+)/,
38
- 1
39
- )
40
- )
41
- ).bind do |version|
42
- if requirement.satisfied_by? version
43
- Right "Terraform v#{version} is supported"
44
- else
45
- Left "Terraform v#{version} is not supported; install Terraform ~> v0.11.0"
31
+ ::Gem::Version
32
+ .new(
33
+ version_output
34
+ .slice(
35
+ /v(\d+\.\d+\.\d+)/,
36
+ 1
37
+ )
38
+ )
39
+ .tap do |version|
40
+ requirement
41
+ .satisfied_by? version or
42
+ raise(
43
+ ::Kitchen::Terraform::Error,
44
+ "Terraform v#{version} is not supported; install Terraform ~> v0.11.0"
45
+ )
46
+
47
+ return "Terraform v#{version} is supported"
46
48
  end
47
- end
48
49
  end
49
50
 
50
51
  private
51
52
 
52
53
  attr_reader :requirement
53
54
 
55
+ # @api private
54
56
  def initialize
55
57
  @requirement =
56
58
  ::Gem::Requirement
@@ -0,0 +1,21 @@
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
+ # The namespace for Terraform commands.
20
+ module ::Kitchen::Terraform::Command
21
+ end
@@ -0,0 +1,71 @@
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 "json"
18
+ require "kitchen/terraform/command"
19
+ require "kitchen/terraform/error"
20
+ require "kitchen/terraform/shell_out"
21
+
22
+ # Behaviour to run the `terraform output` command.
23
+ module ::Kitchen::Terraform::Command::Output
24
+ # Runs the command with JSON foramtting.
25
+ #
26
+ # @param duration [::Integer] the maximum duration in seconds to run the command.
27
+ # @param logger [::Kitchen::Logger] a Test Kitchen logger to capture the output from running the command.
28
+ # @yieldparam output [::String] the standard output of the command parsed as JSON.
29
+ def self.run(duration:, logger:, &block)
30
+ run_shell_out(
31
+ duration: duration,
32
+ logger: logger,
33
+ &block
34
+ )
35
+ rescue ::JSON::ParserError => error
36
+ handle_json_parser error: error
37
+ rescue ::Kitchen::Terraform::Error => error
38
+ handle_kitchen_terraform(
39
+ error: error,
40
+ &block
41
+ )
42
+ end
43
+
44
+ private_class_method
45
+
46
+ # @api private
47
+ def self.handle_json_parser(error:)
48
+ raise(
49
+ ::Kitchen::Terraform::Error,
50
+ "Parsing Terraform output as JSON failed: #{error.message}"
51
+ )
52
+ end
53
+
54
+ # @api private
55
+ def self.handle_kitchen_terraform(error:)
56
+ /no\\ outputs\\ defined/.match ::Regexp.escape error.to_s or raise error
57
+ yield output: {}
58
+ end
59
+
60
+ # @api private
61
+ def self.run_shell_out(duration:, logger:)
62
+ ::Kitchen::Terraform::ShellOut
63
+ .run(
64
+ command: "output -json",
65
+ duration: duration,
66
+ logger: logger
67
+ ) do |standard_output:|
68
+ yield output: ::JSON.parse(standard_output)
69
+ end
70
+ end
71
+ end
@@ -62,7 +62,7 @@ module ::Kitchen::Terraform::ConfigAttribute::BackendConfigurations
62
62
  def config_backend_configurations_flags
63
63
  config_backend_configurations
64
64
  .map do |key, value|
65
- "-backend-config='#{key}=#{value}'"
65
+ "-backend-config=\"#{key}=#{value}\""
66
66
  end
67
67
  .join " "
68
68
  end
@@ -19,30 +19,25 @@ require "kitchen/terraform/config_attribute_cacher"
19
19
  require "kitchen/terraform/config_attribute_definer"
20
20
  require "kitchen/terraform/config_schemas/groups"
21
21
 
22
- # This attribute is an optional array including hashes comprising properties to manage the execution of
23
- # {https://www.inspec.io/docs/reference/profiles/ InSpec profiles} against different resources in the Terraform state.
22
+ # This attribute configures the execution of {https://www.inspec.io/docs/reference/profiles/ InSpec profiles} against
23
+ # different groups of resources in the Terraform state. Each group may be configured by using the proceeding attributes.
24
24
  #
25
25
  # Type:: {http://www.yaml.org/spec/1.2/spec.html#id2760193 Sequence of mappings}
26
26
  # Required:: False
27
- # Example::
28
- # _
29
- # groups:
30
- # -
31
- # name: a_group
32
27
  #
33
- # === Mapping Keys
34
- #
35
- # These keys must be declared in each of the mappings in the sequence.
36
- #
37
- # ==== name
28
+ # ===== name
38
29
  #
39
30
  # This key contains the name of the group to be used for logging purposes.
40
31
  #
41
32
  # Type:: {http://www.yaml.org/spec/1.2/spec.html#id2760844 Scalar}
42
33
  # Required:: True
43
- # Example:: <code>name: a_group</code>
34
+ # Example::
35
+ # _
36
+ # groups:
37
+ # -
38
+ # name: a_group
44
39
  #
45
- # ==== attributes
40
+ # ===== attributes
46
41
  #
47
42
  # This key comprises associations of the names of
48
43
  # {https://www.inspec.io/docs/reference/profiles/#profile-attributes InSpec profile attributes} with the names of
@@ -53,61 +48,93 @@ require "kitchen/terraform/config_schemas/groups"
53
48
  # Required:: False
54
49
  # Example::
55
50
  # _
56
- # attributes:
57
- # an_attribute: an_output
51
+ # groups:
52
+ # -
53
+ # name: a_group_with_overridden_attributes
54
+ # attributes:
55
+ # an_attribute: an_output
58
56
  # Caveat:: As all Terraform outputs are associated with equivalently named InSpec profile attributes by default, this
59
57
  # key is only necessary to provide alternative attribute names.
60
58
  #
61
- # ==== controls
59
+ # ===== controls
62
60
  #
63
61
  # This key comprises the names of {https://www.inspec.io/docs/reference/dsl_inspec/ InSpec controls} to exclusively
64
- # include from the InSpec profile of the Test Kitchen suite.
62
+ # include from the InSpec profile of the associated Test Kitchen instance.
65
63
  #
66
64
  # Type:: {http://www.yaml.org/spec/1.2/spec.html#id2760118 Sequince of scalars}
67
65
  # Required:: False
68
66
  # Example::
69
67
  # _
70
- # controls:
71
- # - first_control
72
- # - third_control
68
+ # groups:
69
+ # -
70
+ # name: a_group_with_a_first_subset_of_controls
71
+ # controls:
72
+ # - control_one
73
+ # - control_three
74
+ # -
75
+ # name: a_group_with_a_second_subset_of_controls
76
+ # controls:
77
+ # - control_two
78
+ # - control_four
73
79
  #
74
- # ==== hostnames
80
+ # ===== hostnames
75
81
  #
76
- # This key contains the name of a Terraform output.
82
+ # This key contains the name of a Terraform output which provides one or more hostnames to be targeted by the InSpec
83
+ # profile of the associated Test Kitchen instance.
77
84
  #
78
85
  # Type:: {http://www.yaml.org/spec/1.2/spec.html#id2760844 Scalar}
79
86
  # Required:: False
80
- # Example:: <code>hostnames: an_output</code>
81
- # Caveat:: The output must be of type String or Array and must contain one or more hostnames that will be the targets of
82
- # the InSpec profile of the Test Kitchen suite. If this key is omitted then +"localhost"+ will be the target of
83
- # the profile.
87
+ # Example::
88
+ # _
89
+ # groups:
90
+ # -
91
+ # name: a_group_with_hostnames
92
+ # hostnames: an_output
93
+ # Caveat:: The output must be a string or an array of strings. If this key is omitted then +"localhost"+ will be the
94
+ # target of the profile. To connect to the hosts through a bastion host, a +ProxyCommand+ in the
95
+ # appropriate {https://linux.die.net/man/5/ssh_config SSH configuration file} must be configured on the system.
84
96
  #
85
- # ==== port
97
+ # ===== port
86
98
  #
87
99
  # This key contains the port to use when connecting with {https://en.wikipedia.org/wiki/Secure_Shell Secure Shell (SSH)}
88
100
  # to the hosts of the group.
89
101
  #
90
102
  # Type:: {http://www.yaml.org/spec/1.2/spec.html#id2803828 Integer}
91
103
  # Required:: False
92
- # Example:: <code>port: 1234</code>
104
+ # Example::
105
+ # _
106
+ # groups:
107
+ # -
108
+ # name: a_group_with_a_port
109
+ # port: 1234
93
110
  # Caveat:: If this key is omitted then the port of the Test Kitchen SSH transport will be used.
94
111
  #
95
- # ==== ssh_key
112
+ # ===== ssh_key
96
113
  #
97
114
  # This key contains the path to a private SSH key to use when connecting with SSH to the hosts of the group.
98
115
  #
99
116
  # Type:: {http://www.yaml.org/spec/1.2/spec.html#id2760844 Scalar}
100
117
  # Required:: False
101
- # Example:: <code>ssh_key: /path/to/an/ssh/key</code>
118
+ # Example::
119
+ # _
120
+ # groups:
121
+ # -
122
+ # name: a_group_with_an_ssh_key
123
+ # ssh_key: /path/to/an/ssh/key</
102
124
  # Caveat:: If this key is omitted then the private SSH key of the Test Kitchen SSH Transport will be used.
103
125
  #
104
- # ==== username
126
+ # ===== username
105
127
  #
106
128
  # This key contains the username to use when connecting with SSH to the hosts of the group.
107
129
  #
108
130
  # Type:: {http://www.yaml.org/spec/1.2/spec.html#id2760844 Scalar}
109
131
  # Required:: False
110
- # Example:: <code>ssh_key: /path/to/an/ssh/key</code>
132
+ # Example::
133
+ # _
134
+ # groups:
135
+ # -
136
+ # name: a_group_with_a_username
137
+ # username: tester
111
138
  # Caveat:: If this key is omitted then the username of the Test Kitcen SSH Transport will be used.
112
139
  #
113
140
  # @abstract It must be included by a plugin class in order to be used.
@@ -60,7 +60,7 @@ module ::Kitchen::Terraform::ConfigAttribute::Variables
60
60
  def config_variables_flags
61
61
  config_variables
62
62
  .map do |key, value|
63
- "-var='#{key}=#{value}'"
63
+ "-var=\"#{key}=#{value}\""
64
64
  end
65
65
  .join " "
66
66
  end
@@ -0,0 +1,21 @@
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
+ # This class represents errors that occur while Kitchen-Terraform is executing.
20
+ class ::Kitchen::Terraform::Error < ::StandardError
21
+ end
@@ -14,9 +14,8 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require "dry/monads"
18
- require "kitchen/terraform"
19
17
  require "kitchen/terraform"
18
+ require "kitchen/terraform/error"
20
19
  require "mixlib/shellout"
21
20
 
22
21
  # Terraform commands are run by shelling out and using the
@@ -25,42 +24,62 @@ require "mixlib/shellout"
25
24
  # TF_IN_AUTOMATION environment variable as specified by the
26
25
  # {https://www.terraform.io/guides/running-terraform-in-automation.html#controlling-terraform-output-in-automation Running Terraform in Automation guide}.
27
26
  module ::Kitchen::Terraform::ShellOut
28
- extend ::Dry::Monads::Either::Mixin
29
- extend ::Dry::Monads::Try::Mixin
30
-
31
27
  # Runs a Terraform command.
32
28
  #
33
29
  # @param command [::String] the command to run.
34
30
  # @param duration [::Integer] the maximum duration in seconds to run the command.
35
31
  # @param logger [::Kitchen::Logger] a Test Kitchen logger to capture the output from running the command.
36
- # @return [::Dry::Monads::Either] the result of running the command.
32
+ # @raise [::Kitchen::Terraform::Error] if running the command fails.
33
+ # @return [::String] the standard output from running the command.
37
34
  # @see https://rubygems.org/gems/mixlib-shellout mixlib-shellout
38
- def self.run(command:, duration: ::Mixlib::ShellOut::DEFAULT_READ_TIMEOUT, logger:)
39
- Try ::Mixlib::ShellOut::InvalidCommandOption do
40
- ::Mixlib::ShellOut
41
- .new(
42
- "terraform #{command}",
43
- environment: {"TF_IN_AUTOMATION" => "true"},
44
- live_stream: logger,
45
- timeout: duration
46
- )
47
- end
48
- .bind do |shell_out|
49
- Try(
50
- ::Errno::EACCES,
51
- ::Errno::ENOENT,
52
- ::Mixlib::ShellOut::CommandTimeout,
53
- ::Mixlib::ShellOut::ShellCommandFailed
54
- ) do
55
- logger.warn "Running command `#{shell_out.command}`"
56
- shell_out.run_command
57
- shell_out.error!
58
- shell_out.stdout
59
- end
60
- end
61
- .to_either
62
- .or do |error|
63
- Left "Running command resulted in failure: #{error}"
35
+ # @yieldparam standard_output [::String] the standard output from running the command.
36
+ def self.run(command:, duration: ::Mixlib::ShellOut::DEFAULT_READ_TIMEOUT, logger:, &block)
37
+ block ||=
38
+ lambda do |standard_output:|
39
+ standard_output
64
40
  end
41
+
42
+ run_shell_out(
43
+ command: command,
44
+ duration: duration,
45
+ logger: logger,
46
+ &block
47
+ )
48
+ rescue ::Errno::EACCES,
49
+ ::Errno::ENOENT,
50
+ ::Mixlib::ShellOut::InvalidCommandOption,
51
+ ::Mixlib::ShellOut::CommandTimeout,
52
+ ::Mixlib::ShellOut::ShellCommandFailed => error
53
+ handle error: error
54
+ end
55
+
56
+ private_class_method
57
+
58
+ # @api private
59
+ def self.handle(error:)
60
+ raise(
61
+ ::Kitchen::Terraform::Error,
62
+ "Running command resulted in failure: #{error.message}"
63
+ )
64
+ end
65
+
66
+ # @api private
67
+ def self.run_shell_out(command:, duration:, logger:)
68
+ yield(
69
+ standard_output:
70
+ ::Mixlib::ShellOut
71
+ .new(
72
+ "terraform #{command}",
73
+ environment: {"TF_IN_AUTOMATION" => "true"},
74
+ live_stream: logger,
75
+ timeout: duration
76
+ )
77
+ .tap do |shell_out|
78
+ logger.warn "Running command `#{shell_out.command}`"
79
+ shell_out.run_command
80
+ shell_out.error!
81
+ end
82
+ .stdout
83
+ )
65
84
  end
66
85
  end