kitchen-terraform 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -3
- data/README.md +31 -28
- data/lib/kitchen/driver/terraform.rb +24 -8
- data/lib/kitchen/provisioner/terraform.rb +20 -144
- data/lib/kitchen/verifier/terraform.rb +32 -19
- data/lib/terraform/apply_command.rb +2 -2
- data/lib/terraform/apply_timeout_config.rb +34 -0
- data/lib/terraform/client.rb +76 -0
- data/lib/terraform/color_config.rb +34 -0
- data/lib/terraform/color_switch.rb +6 -2
- data/lib/terraform/command.rb +22 -27
- data/lib/terraform/command_executor.rb +41 -0
- data/lib/terraform/command_extender.rb +27 -0
- data/lib/terraform/configurable.rb +25 -10
- data/lib/terraform/directory_config.rb +27 -0
- data/lib/terraform/group.rb +26 -63
- data/lib/terraform/groups_config.rb +78 -0
- data/lib/terraform/inspec_runner.rb +5 -15
- data/lib/terraform/output_command.rb +13 -6
- data/lib/terraform/plan_command.rb +3 -4
- data/lib/terraform/plan_config.rb +27 -0
- data/lib/terraform/show_command.rb +39 -0
- data/lib/terraform/state_config.rb +27 -0
- data/lib/terraform/validate_command.rb +4 -0
- data/lib/terraform/variable_files_config.rb +33 -0
- data/lib/terraform/variables_config.rb +47 -0
- data/lib/terraform/version.rb +1 -1
- data/lib/terraform/version_command.rb +4 -0
- data/lib/terraform/zero_seven_output.rb +33 -0
- data/lib/terraform/zero_six_output.rb +30 -0
- metadata +90 -5
- metadata.gz.sig +0 -0
@@ -27,12 +27,12 @@ module Terraform
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def options
|
30
|
-
"-input=false -state=#{state}#{color_switch}"
|
30
|
+
"-input=false -state=#{state} #{color_switch}"
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
34
34
|
|
35
|
-
attr_accessor :
|
35
|
+
attr_accessor :state
|
36
36
|
|
37
37
|
def initialize_attributes(color:, state:)
|
38
38
|
self.color = color
|
@@ -0,0 +1,34 @@
|
|
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
|
+
module Terraform
|
18
|
+
# Behaviour for the [:apply_timeout] config option
|
19
|
+
module ApplyTimeoutConfig
|
20
|
+
def self.included(configurable_class)
|
21
|
+
configurable_class
|
22
|
+
.required_config :apply_timeout do |_, value, configurable|
|
23
|
+
configurable.coerce_apply_timeout value: value
|
24
|
+
end
|
25
|
+
configurable_class.default_config :apply_timeout, 600
|
26
|
+
end
|
27
|
+
|
28
|
+
def coerce_apply_timeout(value:)
|
29
|
+
config[:apply_timeout] = Integer value
|
30
|
+
rescue ArgumentError, TypeError
|
31
|
+
config_error attribute: 'apply_timeout', expected: 'an integer'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,76 @@
|
|
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_relative 'apply_command'
|
18
|
+
require_relative 'command_executor'
|
19
|
+
require_relative 'get_command'
|
20
|
+
require_relative 'output_command'
|
21
|
+
require_relative 'plan_command'
|
22
|
+
require_relative 'show_command'
|
23
|
+
require_relative 'validate_command'
|
24
|
+
require_relative 'version_command'
|
25
|
+
|
26
|
+
module Terraform
|
27
|
+
# Behaviour for implementing the workflow
|
28
|
+
module Client
|
29
|
+
include CommandExecutor
|
30
|
+
|
31
|
+
def apply_execution_plan
|
32
|
+
execute command: ApplyCommand.new(
|
33
|
+
color: provisioner[:color], state: provisioner[:state],
|
34
|
+
target: provisioner[:plan]
|
35
|
+
), timeout: provisioner[:apply_timeout]
|
36
|
+
end
|
37
|
+
|
38
|
+
def current_state
|
39
|
+
execute(
|
40
|
+
command: ShowCommand
|
41
|
+
.new(color: provisioner[:color], target: provisioner[:state])
|
42
|
+
) { |value| return value.gsub(/(\e\[\d+m|\n)/, '') }
|
43
|
+
end
|
44
|
+
|
45
|
+
def download_modules
|
46
|
+
execute command: GetCommand.new(target: provisioner[:directory])
|
47
|
+
end
|
48
|
+
|
49
|
+
def output_value(list: false, name:, &block)
|
50
|
+
execute(
|
51
|
+
command: OutputCommand.new(
|
52
|
+
list: list, state: provisioner[:state], target: name, version: version
|
53
|
+
)
|
54
|
+
) { |value| list ? value.each(&block) : (return value) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def plan_execution(destroy:)
|
58
|
+
execute command: PlanCommand.new(
|
59
|
+
color: provisioner[:color], destroy: destroy, out: provisioner[:plan],
|
60
|
+
state: provisioner[:state], target: provisioner[:directory],
|
61
|
+
variables: provisioner[:variables],
|
62
|
+
variable_files: provisioner[:variable_files]
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def validate_configuration_files
|
67
|
+
execute command: ValidateCommand.new(target: provisioner[:directory])
|
68
|
+
end
|
69
|
+
|
70
|
+
def version
|
71
|
+
execute command: VersionCommand.new do |value|
|
72
|
+
return value.slice(/v\d+\.\d+\.\d+/)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,34 @@
|
|
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
|
+
module Terraform
|
18
|
+
# Behaviour for the [:color] config option
|
19
|
+
module ColorConfig
|
20
|
+
def self.included(configurable_class)
|
21
|
+
configurable_class.required_config :color do |_, value, configurable|
|
22
|
+
configurable.coerce_color value: value
|
23
|
+
end
|
24
|
+
configurable_class.default_config :color, true
|
25
|
+
end
|
26
|
+
|
27
|
+
def coerce_color(value:)
|
28
|
+
raise TypeError unless [TrueClass, FalseClass].include? value.class
|
29
|
+
config[:color] = value
|
30
|
+
rescue TypeError
|
31
|
+
config_error attribute: 'color', expected: 'a boolean'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -15,10 +15,14 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
17
|
module Terraform
|
18
|
-
# Shared color
|
18
|
+
# Shared color switch for Terraform
|
19
19
|
module ColorSwitch
|
20
20
|
def color_switch
|
21
|
-
color ? '' : '
|
21
|
+
color ? '' : '-no-color'
|
22
22
|
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_accessor :color
|
23
27
|
end
|
24
28
|
end
|
data/lib/terraform/command.rb
CHANGED
@@ -14,27 +14,11 @@
|
|
14
14
|
# See the License for the specific language governing permissions and
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
|
-
require 'kitchen'
|
18
17
|
require 'mixlib/shellout'
|
19
18
|
|
20
19
|
module Terraform
|
21
|
-
#
|
20
|
+
# Terraform command to be executed
|
22
21
|
class Command
|
23
|
-
def self.execute(**keyword_arguments, &block)
|
24
|
-
new(**keyword_arguments).execute(&block)
|
25
|
-
end
|
26
|
-
|
27
|
-
def execute
|
28
|
-
shell_out.run_command
|
29
|
-
shell_out.error!
|
30
|
-
yield shell_out.stdout if block_given?
|
31
|
-
rescue Errno::EACCES, Errno::ENOENT => error
|
32
|
-
command_error error: error, type: Kitchen::InstanceFailure
|
33
|
-
rescue Mixlib::ShellOut::CommandTimeout,
|
34
|
-
Mixlib::ShellOut::ShellCommandFailed => error
|
35
|
-
command_error error: error, type: Kitchen::TransientFailure
|
36
|
-
end
|
37
|
-
|
38
22
|
def name
|
39
23
|
''
|
40
24
|
end
|
@@ -43,25 +27,36 @@ module Terraform
|
|
43
27
|
'--help'
|
44
28
|
end
|
45
29
|
|
46
|
-
|
30
|
+
def output
|
31
|
+
processed_output raw_output: shell_out.stdout
|
32
|
+
end
|
47
33
|
|
48
|
-
|
34
|
+
def run(logger:, timeout:)
|
35
|
+
shell_out.live_stream = logger
|
36
|
+
shell_out.timeout = timeout
|
37
|
+
shell_out.run_command
|
38
|
+
shell_out.error!
|
39
|
+
end
|
49
40
|
|
50
|
-
def
|
51
|
-
|
41
|
+
def to_s
|
42
|
+
shell_out.command
|
52
43
|
end
|
53
44
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
45
|
+
private
|
46
|
+
|
47
|
+
attr_accessor :shell_out
|
48
|
+
|
49
|
+
def initialize(target: '', **keyword_arguments)
|
58
50
|
initialize_attributes(**keyword_arguments)
|
59
51
|
self.shell_out = Mixlib::ShellOut
|
60
|
-
.new "terraform #{name} #{options} #{target}",
|
61
|
-
live_stream: logger, returns: 0, timeout: timeout
|
52
|
+
.new "terraform #{name} #{options} #{target}", returns: 0
|
62
53
|
end
|
63
54
|
|
64
55
|
def initialize_attributes(**_keyword_arguments)
|
65
56
|
end
|
57
|
+
|
58
|
+
def processed_output(raw_output:)
|
59
|
+
raw_output
|
60
|
+
end
|
66
61
|
end
|
67
62
|
end
|
@@ -0,0 +1,41 @@
|
|
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 'mixlib/shellout'
|
19
|
+
|
20
|
+
module Terraform
|
21
|
+
# Behaviour for executing commands
|
22
|
+
module CommandExecutor
|
23
|
+
def execute(command:, timeout: Mixlib::ShellOut::DEFAULT_READ_TIMEOUT)
|
24
|
+
command.run logger: logger, timeout: timeout
|
25
|
+
yield command.output if block_given?
|
26
|
+
rescue Errno::EACCES, Errno::ENOENT => error
|
27
|
+
command_error command: command, error: error,
|
28
|
+
type: Kitchen::InstanceFailure
|
29
|
+
rescue Mixlib::ShellOut::CommandTimeout,
|
30
|
+
Mixlib::ShellOut::ShellCommandFailed => error
|
31
|
+
command_error command: command, error: error,
|
32
|
+
type: Kitchen::TransientFailure
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def command_error(command:, error:, type:)
|
38
|
+
raise type, %(`#{command}` failed: "#{error}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,27 @@
|
|
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
|
+
module Terraform
|
18
|
+
# Logic to extend a command's behaviour based on the Terraform version
|
19
|
+
module CommandExtender
|
20
|
+
def extend_behaviour(version:)
|
21
|
+
extend version_behaviours.fetch(
|
22
|
+
version_behaviours.keys
|
23
|
+
.find { |extended_version| extended_version =~ version }
|
24
|
+
) { return }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -16,30 +16,45 @@
|
|
16
16
|
|
17
17
|
require 'forwardable'
|
18
18
|
require 'kitchen'
|
19
|
+
require_relative 'version'
|
19
20
|
|
20
21
|
module Terraform
|
21
22
|
# Common logic for classes that include Kitchen::Configurable
|
22
23
|
module Configurable
|
23
24
|
extend Forwardable
|
24
25
|
|
25
|
-
def_delegators :instance, :provisioner, :transport
|
26
|
+
def_delegators :instance, :driver, :provisioner, :transport
|
26
27
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
def self.included(configurable_class)
|
29
|
+
configurable_class.plugin_version VERSION
|
30
|
+
end
|
31
|
+
|
32
|
+
def config_deprecated(attribute:, remediation:, type:, version:)
|
33
|
+
log_deprecation aspect: "#{formatted(attribute: attribute)} as #{type}",
|
34
|
+
remediation: remediation, version: version
|
31
35
|
end
|
32
36
|
|
33
37
|
def config_error(attribute:, expected:)
|
34
|
-
raise Kitchen::UserError, formatted
|
35
|
-
|
36
|
-
|
38
|
+
raise Kitchen::UserError, "#{formatted attribute: attribute} must be " \
|
39
|
+
"interpretable as #{expected}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def instance_pathname(filename:)
|
43
|
+
File.join config[:kitchen_root], '.kitchen', 'kitchen-terraform',
|
44
|
+
instance.name, filename
|
45
|
+
end
|
46
|
+
|
47
|
+
def log_deprecation(aspect:, remediation:, version:)
|
48
|
+
logger.warn 'DEPRECATION NOTICE'
|
49
|
+
logger.warn "Support for #{aspect} will be dropped in " \
|
50
|
+
"kitchen-terraform v#{version}"
|
51
|
+
logger.warn remediation
|
37
52
|
end
|
38
53
|
|
39
54
|
private
|
40
55
|
|
41
|
-
def formatted(attribute
|
42
|
-
"#{self.class}#{instance.to_str}#config[:#{attribute}]
|
56
|
+
def formatted(attribute:)
|
57
|
+
"#{self.class}#{instance.to_str}#config[:#{attribute}]"
|
43
58
|
end
|
44
59
|
end
|
45
60
|
end
|
@@ -0,0 +1,27 @@
|
|
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
|
+
module Terraform
|
18
|
+
# Behaviour for the [:directory] config option
|
19
|
+
module DirectoryConfig
|
20
|
+
def self.included(configurable_class)
|
21
|
+
configurable_class.default_config :directory do |configurable|
|
22
|
+
configurable[:kitchen_root]
|
23
|
+
end
|
24
|
+
configurable_class.expand_path_for :directory
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/terraform/group.rb
CHANGED
@@ -14,81 +14,44 @@
|
|
14
14
|
# See the License for the specific language governing permissions and
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
|
-
require 'delegate'
|
18
|
-
|
19
17
|
module Terraform
|
20
|
-
# Group to be verified
|
21
|
-
class Group
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
verifier.info "Verifying group: #{dig :name}; current host #{hostname}"
|
34
|
-
InspecRunner.run_and_verify group: self, options: options.merge(self),
|
35
|
-
verifier: verifier
|
18
|
+
# Group of Terraform server instances to be verified
|
19
|
+
class Group
|
20
|
+
def each_attribute(&block)
|
21
|
+
data[:attributes].each_pair(&block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def evaluate(verifier:)
|
25
|
+
verifier.merge options: options
|
26
|
+
verifier.resolve_attributes group: self
|
27
|
+
verifier.resolve_hostnames group: self do |hostname|
|
28
|
+
verifier.info "Verifying host '#{hostname}' of group '#{data[:name]}'"
|
29
|
+
verifier.merge options: { host: hostname }
|
30
|
+
verifier.execute
|
36
31
|
end
|
37
32
|
end
|
38
33
|
|
39
|
-
|
40
|
-
|
41
|
-
attr_accessor :provisioner, :transport, :verifier
|
42
|
-
|
43
|
-
def coerce_attributes
|
44
|
-
store :attributes, Hash(dig(:attributes))
|
45
|
-
rescue ArgumentError, TypeError
|
46
|
-
verifier.config_error attribute: "groups][#{self}][:attributes",
|
47
|
-
expected: 'a mapping of Inspec attribute names ' \
|
48
|
-
'to Terraform output variable names'
|
49
|
-
end
|
50
|
-
|
51
|
-
def coerce_controls
|
52
|
-
store :controls, Array(dig(:controls))
|
53
|
-
end
|
54
|
-
|
55
|
-
def coerce_hostnames
|
56
|
-
store :hostnames, String(dig(:hostnames))
|
34
|
+
def hostnames
|
35
|
+
data[:hostnames]
|
57
36
|
end
|
58
37
|
|
59
|
-
def
|
60
|
-
|
38
|
+
def store_attribute(key:, value:)
|
39
|
+
data[:attributes][key] = value
|
61
40
|
end
|
62
41
|
|
63
|
-
|
64
|
-
coerce_attributes
|
65
|
-
coerce_controls
|
66
|
-
coerce_hostnames
|
67
|
-
coerce_name
|
68
|
-
coerce_port
|
69
|
-
coerce_username
|
70
|
-
end
|
42
|
+
private
|
71
43
|
|
72
|
-
|
73
|
-
store :port, Integer(dig(:port) || transport[:port])
|
74
|
-
rescue ArgumentError, TypeError
|
75
|
-
verifier.config_error attribute: "groups][#{self}][:port",
|
76
|
-
expected: 'an integer'
|
77
|
-
end
|
44
|
+
attr_accessor :data
|
78
45
|
|
79
|
-
def
|
80
|
-
|
46
|
+
def initialize(data:)
|
47
|
+
self.data = data
|
81
48
|
end
|
82
49
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
coerce_parameters
|
89
|
-
rescue ArgumentError, TypeError
|
90
|
-
verifier.config_error attribute: "groups][#{self}",
|
91
|
-
expected: 'a group mapping'
|
50
|
+
def options
|
51
|
+
{
|
52
|
+
attributes: data[:attributes], controls: data[:controls],
|
53
|
+
port: data[:port], user: data[:username]
|
54
|
+
}
|
92
55
|
end
|
93
56
|
end
|
94
57
|
end
|