kitchen-terraform 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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