kitchen-terraform 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/lib/kitchen/driver/terraform.rb +57 -0
- data/lib/kitchen/provisioner/terraform.rb +58 -0
- data/lib/kitchen/verifier/terraform.rb +109 -0
- data/lib/terraform/apply_command.rb +32 -0
- data/lib/terraform/client.rb +102 -0
- data/lib/terraform/client_holder.rb +26 -0
- data/lib/terraform/command.rb +58 -0
- data/lib/terraform/command_options.rb +45 -0
- data/lib/terraform/error.rb +20 -0
- data/lib/terraform/get_command.rb +32 -0
- data/lib/terraform/inspec_runner.rb +44 -0
- data/lib/terraform/invalid_version.rb +34 -0
- data/lib/terraform/output_command.rb +38 -0
- data/lib/terraform/output_not_found.rb +23 -0
- data/lib/terraform/plan_command.rb +35 -0
- data/lib/terraform/validate_command.rb +32 -0
- data/lib/terraform/version.rb +19 -0
- data/lib/terraform/version_command.rb +32 -0
- data/spec/lib/kitchen/driver/terraform_spec.rb +126 -0
- data/spec/lib/kitchen/provisioner/terraform_spec.rb +106 -0
- data/spec/lib/kitchen/verifier/terraform_spec.rb +302 -0
- data/spec/lib/terraform/apply_command_spec.rb +32 -0
- data/spec/lib/terraform/client_spec.rb +211 -0
- data/spec/lib/terraform/command_options_spec.rb +34 -0
- data/spec/lib/terraform/get_command_spec.rb +30 -0
- data/spec/lib/terraform/inspec_runner_spec.rb +67 -0
- data/spec/lib/terraform/output_command_spec.rb +58 -0
- data/spec/lib/terraform/plan_command_spec.rb +46 -0
- data/spec/lib/terraform/validate_command_spec.rb +30 -0
- data/spec/lib/terraform/version_command_spec.rb +30 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/support/coverage.rb +21 -0
- data/spec/support/terraform/client_holder_context.rb +26 -0
- data/spec/support/terraform/client_holder_examples.rb +36 -0
- data/spec/support/terraform/command_examples.rb +80 -0
- data/spec/support/terraform/versions_are_set_examples.rb +35 -0
- metadata +329 -0
- metadata.gz.sig +2 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f03cf599dfe3f84c964a2ee046ee339fec308920
|
4
|
+
data.tar.gz: a796e35249231547ce68cef067bd1408f30295b7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fee5b34d17854a32f579363580050bd6406e3fa3e9628e88102d1b0c888e19546d2df7e259c4bdb4bfa3f133323304f4d3bf41daa5e6469ef61f44a9cbae38eb
|
7
|
+
data.tar.gz: 1c1cff573cf5973649ec40728443a78f7aaa147204ec09d10db9ffd21d6eeab99ccc89c33edf418bd67d49c0104691cec0884d41bcc440f9285f4ca4b5082e06
|
checksums.yaml.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
y�ޭ�H#�&��lmD���5��ō:N��/���[!�?�*�\a1f�2<�r�I�zi�OH8���o؊���xo�\����r�Ў��R#ҶL���ӓ�z�RJb~ĭ��M�-E,�q��*I�u��+�=��3�JK�"..��6��U�m1S�B�����b)�`�Z%�ħy��U�'��S�'ce�'���]v=���]�5Mi�n���L��[g�.�����r�au":�L��6���h���J��
|
data.tar.gz.sig
ADDED
Binary file
|
@@ -0,0 +1,57 @@
|
|
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 'terraform/client_holder'
|
19
|
+
require 'terraform/invalid_version'
|
20
|
+
require 'terraform/version'
|
21
|
+
|
22
|
+
module Kitchen
|
23
|
+
module Driver
|
24
|
+
# Terraform state lifecycle activities manager
|
25
|
+
class Terraform < Base
|
26
|
+
include ::Terraform::ClientHolder
|
27
|
+
|
28
|
+
kitchen_driver_api_version 2
|
29
|
+
|
30
|
+
plugin_version ::Terraform::VERSION
|
31
|
+
|
32
|
+
no_parallel_for
|
33
|
+
|
34
|
+
def create(_state = nil)
|
35
|
+
client.fetch_version do |output|
|
36
|
+
raise ::Terraform::InvalidVersion, supported_version, caller unless
|
37
|
+
output.match supported_version
|
38
|
+
end
|
39
|
+
rescue => error
|
40
|
+
raise Kitchen::ActionFailed, error.message, error.backtrace
|
41
|
+
end
|
42
|
+
|
43
|
+
def destroy(_state = nil)
|
44
|
+
client.validate_configuration_files
|
45
|
+
client.download_modules
|
46
|
+
client.plan_destructive_execution
|
47
|
+
client.apply_execution_plan
|
48
|
+
rescue => error
|
49
|
+
raise Kitchen::ActionFailed, error.message, error.backtrace
|
50
|
+
end
|
51
|
+
|
52
|
+
def supported_version
|
53
|
+
'v0.6'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,58 @@
|
|
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 'pathname'
|
19
|
+
require 'terraform/client_holder'
|
20
|
+
require 'terraform/version'
|
21
|
+
|
22
|
+
module Kitchen
|
23
|
+
module Provisioner
|
24
|
+
# Terraform configuration applier
|
25
|
+
class Terraform < Base
|
26
|
+
include ::Terraform::ClientHolder
|
27
|
+
|
28
|
+
kitchen_provisioner_api_version 2
|
29
|
+
|
30
|
+
plugin_version ::Terraform::VERSION
|
31
|
+
|
32
|
+
def call(_state = nil)
|
33
|
+
client.validate_configuration_files
|
34
|
+
client.download_modules
|
35
|
+
client.plan_execution
|
36
|
+
client.apply_execution_plan
|
37
|
+
rescue => error
|
38
|
+
raise Kitchen::ActionFailed, error.message, error.backtrace
|
39
|
+
end
|
40
|
+
|
41
|
+
def directory
|
42
|
+
config.fetch(:directory) { kitchen_root }
|
43
|
+
end
|
44
|
+
|
45
|
+
def kitchen_root
|
46
|
+
Pathname.new config.fetch :kitchen_root
|
47
|
+
end
|
48
|
+
|
49
|
+
def variable_files
|
50
|
+
config.fetch(:variable_files) { [] }
|
51
|
+
end
|
52
|
+
|
53
|
+
def variables
|
54
|
+
config.fetch(:variables) { [] }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,109 @@
|
|
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/verifier/inspec'
|
19
|
+
require 'terraform/client_holder'
|
20
|
+
require 'terraform/inspec_runner'
|
21
|
+
require 'terraform/version'
|
22
|
+
|
23
|
+
module Kitchen
|
24
|
+
module Verifier
|
25
|
+
# Runs tests post-converge to confirm that instances in the Terraform state
|
26
|
+
# are in an expected state
|
27
|
+
class Terraform < Inspec
|
28
|
+
include ::Terraform::ClientHolder
|
29
|
+
|
30
|
+
kitchen_verifier_api_version 2
|
31
|
+
|
32
|
+
plugin_version ::Terraform::VERSION
|
33
|
+
|
34
|
+
def attributes(group:)
|
35
|
+
group.fetch(:attributes) { {} }
|
36
|
+
end
|
37
|
+
|
38
|
+
def call(state)
|
39
|
+
groups.each do |group|
|
40
|
+
client.extract_list_output name: group.fetch(:hostnames) do |output|
|
41
|
+
verify group: group, hostnames: output, state: state
|
42
|
+
end
|
43
|
+
end
|
44
|
+
rescue => error
|
45
|
+
raise ActionFailed, error.message, error.backtrace
|
46
|
+
end
|
47
|
+
|
48
|
+
def controls(group:)
|
49
|
+
group.fetch(:controls) { [] }
|
50
|
+
end
|
51
|
+
|
52
|
+
def evaluate(exit_code:)
|
53
|
+
raise "Inspec Runner returns #{exit_code}" unless 0 == exit_code
|
54
|
+
end
|
55
|
+
|
56
|
+
def groups
|
57
|
+
config.fetch(:groups) { [] }
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize_runner(group:, hostname:, state:)
|
61
|
+
::Terraform::InspecRunner
|
62
|
+
.new runner_options_for_terraform group: group, hostname: hostname,
|
63
|
+
state: state do |runner|
|
64
|
+
resolve_attributes group: group do |name, value|
|
65
|
+
runner.define_attribute name: name, value: value
|
66
|
+
end
|
67
|
+
runner.add targets: collect_tests
|
68
|
+
yield runner
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def port(group:)
|
73
|
+
# FIXME: apply the principle of least knowledge
|
74
|
+
group.fetch(:port) { instance.transport.send(:config).fetch :port }
|
75
|
+
end
|
76
|
+
|
77
|
+
def resolve_attributes(group:)
|
78
|
+
attributes(group: group).each_pair do |method_name, variable_name|
|
79
|
+
client.extract_output name: variable_name do |output|
|
80
|
+
yield method_name, output
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def runner_options_for_terraform(group:, hostname:, state:)
|
86
|
+
runner_options(instance.transport, state)
|
87
|
+
.merge controls: controls(group: group), host: hostname,
|
88
|
+
port: port(group: group), user: username(group: group)
|
89
|
+
end
|
90
|
+
|
91
|
+
def username(group:)
|
92
|
+
# FIXME: apply the principle of least knowledge
|
93
|
+
group.fetch :username do
|
94
|
+
instance.transport.send(:config).fetch :username
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def verify(group:, hostnames:, state:)
|
99
|
+
hostnames.each do |hostname|
|
100
|
+
info "Verifying group: #{group.fetch :name}; hostname #{hostname}\n"
|
101
|
+
initialize_runner group: group, hostname: hostname,
|
102
|
+
state: state do |runner|
|
103
|
+
runner.verify_run verifier: self
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,32 @@
|
|
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 'command'
|
18
|
+
|
19
|
+
module Terraform
|
20
|
+
# Command to apply an execution plan
|
21
|
+
class ApplyCommand
|
22
|
+
include Command
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def initialize_attributes(state:, plan:)
|
27
|
+
self.name = 'apply'
|
28
|
+
self.options = { input: false, state: state }
|
29
|
+
self.target = plan
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,102 @@
|
|
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 'get_command'
|
19
|
+
require_relative 'output_command'
|
20
|
+
require_relative 'plan_command'
|
21
|
+
require_relative 'validate_command'
|
22
|
+
require_relative 'version_command'
|
23
|
+
|
24
|
+
module Terraform
|
25
|
+
# Runs Mixlib Terraform Command instances
|
26
|
+
class Client
|
27
|
+
extend Forwardable
|
28
|
+
|
29
|
+
def_delegators :provisioner, :directory, :info, :kitchen_root,
|
30
|
+
:variable_files, :variables
|
31
|
+
|
32
|
+
def apply_execution_plan
|
33
|
+
run command_class: ApplyCommand, state: state_pathname,
|
34
|
+
plan: plan_pathname
|
35
|
+
end
|
36
|
+
|
37
|
+
def download_modules
|
38
|
+
run command_class: GetCommand, dir: directory
|
39
|
+
end
|
40
|
+
|
41
|
+
def extract_list_output(name:)
|
42
|
+
extract_output(name: name) { |output| yield output.split ',' }
|
43
|
+
end
|
44
|
+
|
45
|
+
def extract_output(name:)
|
46
|
+
run(
|
47
|
+
command_class: OutputCommand, state: state_pathname, name: name
|
48
|
+
) { |output| yield output.chomp }
|
49
|
+
end
|
50
|
+
|
51
|
+
def fetch_version
|
52
|
+
run(command_class: VersionCommand) { |output| yield output }
|
53
|
+
end
|
54
|
+
|
55
|
+
def instance_directory
|
56
|
+
kitchen_root.join '.kitchen', 'kitchen-terraform', instance_name
|
57
|
+
end
|
58
|
+
|
59
|
+
def plan_destructive_execution
|
60
|
+
run command_class: PlanCommand, destroy: true, out: plan_pathname,
|
61
|
+
state: state_pathname, var: variables, var_file: variable_files,
|
62
|
+
dir: directory
|
63
|
+
end
|
64
|
+
|
65
|
+
def plan_execution
|
66
|
+
run command_class: PlanCommand, destroy: false, out: plan_pathname,
|
67
|
+
state: state_pathname, var: variables, var_file: variable_files,
|
68
|
+
dir: directory
|
69
|
+
end
|
70
|
+
|
71
|
+
def plan_pathname
|
72
|
+
instance_directory.join 'terraform.tfplan'
|
73
|
+
end
|
74
|
+
|
75
|
+
def run(command_class:, **parameters)
|
76
|
+
command_class.new(**parameters) do |command|
|
77
|
+
info command
|
78
|
+
command.execute do |output|
|
79
|
+
info output
|
80
|
+
yield output if block_given?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def state_pathname
|
86
|
+
instance_directory.join 'terraform.tfstate'
|
87
|
+
end
|
88
|
+
|
89
|
+
def validate_configuration_files
|
90
|
+
run command_class: ValidateCommand, dir: directory
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
attr_accessor :instance_name, :provisioner
|
96
|
+
|
97
|
+
def initialize(instance:)
|
98
|
+
self.instance_name = instance.name
|
99
|
+
self.provisioner = instance.provisioner
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,26 @@
|
|
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 'client'
|
18
|
+
|
19
|
+
module Terraform
|
20
|
+
# Logic to provide a lazily initialized Client instance
|
21
|
+
module ClientHolder
|
22
|
+
def client
|
23
|
+
@client ||= Client.new instance: instance
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,58 @@
|
|
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 'mixlib/shellout'
|
18
|
+
require 'pathname'
|
19
|
+
require_relative 'command_options'
|
20
|
+
require_relative 'error'
|
21
|
+
|
22
|
+
module Terraform
|
23
|
+
# Common logic for Mixlib::ShellOut Terraform commands
|
24
|
+
module Command
|
25
|
+
attr_reader :name, :options, :target
|
26
|
+
|
27
|
+
def execute
|
28
|
+
# TODO: use the live output stream
|
29
|
+
shell_out.run_command
|
30
|
+
shell_out.error!
|
31
|
+
yield shell_out.stdout if block_given?
|
32
|
+
rescue => error
|
33
|
+
handle error: error
|
34
|
+
raise Error, error.message, error.backtrace
|
35
|
+
end
|
36
|
+
|
37
|
+
def handle(**_)
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
CommandOptions.new options do |command_options|
|
42
|
+
return "terraform #{name} #{command_options} #{target}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
attr_accessor :shell_out
|
49
|
+
|
50
|
+
attr_writer :name, :options, :target
|
51
|
+
|
52
|
+
def initialize(**keyword_arguments)
|
53
|
+
initialize_attributes(**keyword_arguments)
|
54
|
+
self.shell_out = Mixlib::ShellOut.new to_s, returns: 0
|
55
|
+
yield self if block_given?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|