kitchen-terraform 0.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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +1 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/kitchen/driver/terraform.rb +57 -0
  5. data/lib/kitchen/provisioner/terraform.rb +58 -0
  6. data/lib/kitchen/verifier/terraform.rb +109 -0
  7. data/lib/terraform/apply_command.rb +32 -0
  8. data/lib/terraform/client.rb +102 -0
  9. data/lib/terraform/client_holder.rb +26 -0
  10. data/lib/terraform/command.rb +58 -0
  11. data/lib/terraform/command_options.rb +45 -0
  12. data/lib/terraform/error.rb +20 -0
  13. data/lib/terraform/get_command.rb +32 -0
  14. data/lib/terraform/inspec_runner.rb +44 -0
  15. data/lib/terraform/invalid_version.rb +34 -0
  16. data/lib/terraform/output_command.rb +38 -0
  17. data/lib/terraform/output_not_found.rb +23 -0
  18. data/lib/terraform/plan_command.rb +35 -0
  19. data/lib/terraform/validate_command.rb +32 -0
  20. data/lib/terraform/version.rb +19 -0
  21. data/lib/terraform/version_command.rb +32 -0
  22. data/spec/lib/kitchen/driver/terraform_spec.rb +126 -0
  23. data/spec/lib/kitchen/provisioner/terraform_spec.rb +106 -0
  24. data/spec/lib/kitchen/verifier/terraform_spec.rb +302 -0
  25. data/spec/lib/terraform/apply_command_spec.rb +32 -0
  26. data/spec/lib/terraform/client_spec.rb +211 -0
  27. data/spec/lib/terraform/command_options_spec.rb +34 -0
  28. data/spec/lib/terraform/get_command_spec.rb +30 -0
  29. data/spec/lib/terraform/inspec_runner_spec.rb +67 -0
  30. data/spec/lib/terraform/output_command_spec.rb +58 -0
  31. data/spec/lib/terraform/plan_command_spec.rb +46 -0
  32. data/spec/lib/terraform/validate_command_spec.rb +30 -0
  33. data/spec/lib/terraform/version_command_spec.rb +30 -0
  34. data/spec/spec_helper.rb +27 -0
  35. data/spec/support/coverage.rb +21 -0
  36. data/spec/support/terraform/client_holder_context.rb +26 -0
  37. data/spec/support/terraform/client_holder_examples.rb +36 -0
  38. data/spec/support/terraform/command_examples.rb +80 -0
  39. data/spec/support/terraform/versions_are_set_examples.rb +35 -0
  40. metadata +329 -0
  41. metadata.gz.sig +2 -0
@@ -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
@@ -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��
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