kitchen-terraform 0.5.1 → 0.6.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 (56) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -2
  4. data/README.md +61 -6
  5. data/lib/kitchen/driver/terraform.rb +37 -22
  6. data/lib/kitchen/provisioner/terraform.rb +14 -18
  7. data/lib/kitchen/verifier/terraform.rb +25 -48
  8. data/lib/terraform/apply_command.rb +11 -20
  9. data/lib/terraform/apply_timeout_config.rb +9 -11
  10. data/lib/terraform/cli_config.rb +29 -0
  11. data/lib/terraform/client.rb +57 -52
  12. data/lib/terraform/color_coercer.rb +35 -0
  13. data/lib/terraform/color_config.rb +9 -11
  14. data/lib/terraform/command.rb +16 -30
  15. data/lib/terraform/command_factory.rb +111 -0
  16. data/lib/terraform/command_option.rb +65 -0
  17. data/lib/terraform/command_options.rb +95 -0
  18. data/lib/terraform/configurable.rb +42 -17
  19. data/lib/terraform/{zero_six_output.rb → debug_logger.rb} +10 -7
  20. data/lib/terraform/deprecated_output_parser.rb +41 -0
  21. data/lib/terraform/deprecated_variables_coercer.rb +35 -0
  22. data/lib/terraform/{command_extender.rb → deprecated_version.rb} +10 -7
  23. data/lib/terraform/destructive_plan_command.rb +35 -0
  24. data/lib/terraform/directory_config.rb +10 -5
  25. data/lib/terraform/file_configs.rb +36 -0
  26. data/lib/terraform/get_command.rb +3 -10
  27. data/lib/terraform/group.rb +29 -29
  28. data/lib/terraform/group_attributes.rb +42 -0
  29. data/lib/terraform/group_hostnames.rb +38 -0
  30. data/lib/terraform/groups_coercer.rb +43 -0
  31. data/lib/terraform/groups_config.rb +8 -54
  32. data/lib/terraform/integer_coercer.rb +37 -0
  33. data/lib/terraform/{plan_config.rb → no_output_parser.rb} +8 -7
  34. data/lib/terraform/output_command.rb +3 -39
  35. data/lib/terraform/output_parser.rb +55 -0
  36. data/lib/terraform/parallelism_config.rb +9 -11
  37. data/lib/terraform/pathname_coercer.rb +40 -0
  38. data/lib/terraform/plan_command.rb +7 -41
  39. data/lib/terraform/prepare_input_file.rb +34 -0
  40. data/lib/terraform/{zero_seven_output.rb → prepare_output_file.rb} +11 -9
  41. data/lib/terraform/project_version.rb +19 -0
  42. data/lib/terraform/shell_out.rb +59 -0
  43. data/lib/terraform/show_command.rb +7 -16
  44. data/lib/terraform/simple_coercer.rb +36 -0
  45. data/lib/terraform/{state_config.rb → simple_config.rb} +7 -6
  46. data/lib/terraform/{color_switch.rb → unsupported_version.rb} +6 -8
  47. data/lib/terraform/validate_command.rb +3 -10
  48. data/lib/terraform/variable_files_coercer.rb +40 -0
  49. data/lib/terraform/variable_files_config.rb +9 -10
  50. data/lib/terraform/variables_coercer.rb +49 -0
  51. data/lib/terraform/variables_config.rb +9 -24
  52. data/lib/terraform/version.rb +55 -1
  53. data/lib/terraform/version_command.rb +3 -10
  54. metadata +58 -9
  55. metadata.gz.sig +0 -0
  56. data/lib/terraform/command_executor.rb +0 -41
@@ -14,78 +14,83 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
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'
17
+ require 'terraform/command_factory'
18
+ require 'terraform/no_output_parser'
19
+ require 'terraform/output_parser'
20
+ require 'terraform/shell_out'
21
+ require 'terraform/version'
25
22
 
26
23
  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], parallelism: provisioner[:parallelism],
34
- state: provisioner[:state], target: provisioner[:plan]
35
- ), timeout: provisioner[:apply_timeout]
24
+ # Client to execute commands
25
+ class Client
26
+ def apply_constructively
27
+ apply plan_command: factory.plan_command
36
28
  end
37
29
 
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)/, '') }
30
+ def apply_destructively
31
+ apply plan_command: factory.destructive_plan_command
43
32
  end
44
33
 
45
- def download_modules
46
- execute command: GetCommand.new(target: provisioner[:directory])
34
+ def each_output_name(&block)
35
+ output_parser(name: '').each_name(&block)
47
36
  end
48
37
 
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) }
38
+ def iterate_output(name:, &block)
39
+ output_parser(name: name).iterate_parsed_output(&block)
55
40
  end
56
41
 
57
- def each_output_name(&block)
58
- execute(
59
- command: OutputCommand.new(
60
- list: false, state: provisioner[:state], version: version,
61
- return_raw: true
62
- )
63
- ) { |output| JSON.parse(output).each_key(&block) }
64
- end
65
-
66
- def plan_execution(destroy:)
67
- execute command: plan_command(destroy: destroy)
42
+ def load_state(&block)
43
+ execute(command: factory.show_command) do |state|
44
+ /\w+/.match state, &block
45
+ end
68
46
  end
69
47
 
70
- def validate_configuration_files
71
- execute command: ValidateCommand.new(target: provisioner[:directory])
48
+ def output(name:)
49
+ output_parser(name: name).parsed_output
72
50
  end
73
51
 
74
52
  def version
75
- execute command: VersionCommand.new do |value|
76
- return value.slice(/v\d+\.\d+\.\d+/)
53
+ execute command: factory.version_command do |value|
54
+ return ::Terraform::Version.create value: value
77
55
  end
78
56
  end
79
57
 
80
58
  private
81
59
 
82
- def plan_command(destroy:)
83
- PlanCommand
84
- .new color: provisioner[:color], destroy: destroy,
85
- out: provisioner[:plan], parallelism: provisioner[:parallelism],
86
- state: provisioner[:state], target: provisioner[:directory],
87
- variables: provisioner[:variables],
88
- variable_files: provisioner[:variable_files]
60
+ attr_accessor :apply_timeout, :cli, :factory, :logger
61
+
62
+ def apply(plan_command:)
63
+ execute command: factory.validate_command
64
+ execute command: factory.get_command
65
+ execute command: plan_command
66
+ ::Terraform::ShellOut.new(
67
+ cli: cli, command: factory.apply_command, logger: logger,
68
+ timeout: apply_timeout
69
+ ).execute
70
+ end
71
+
72
+ def execute(command:, &block)
73
+ ::Terraform::ShellOut
74
+ .new(cli: cli, command: command, logger: logger).execute(&block)
75
+ end
76
+
77
+ def initialize(config: {}, logger:)
78
+ self.apply_timeout = config[:apply_timeout]
79
+ self.cli = config[:cli]
80
+ self.factory = ::Terraform::CommandFactory.new config: config
81
+ self.logger = logger
82
+ end
83
+
84
+ def output_parser(name:)
85
+ execute(
86
+ command: factory.output_command(target: name, version: version)
87
+ ) do |value|
88
+ return ::Terraform::OutputParser.create output: value, version: version
89
+ end
90
+ rescue ::Kitchen::StandardError => exception
91
+ raise exception unless exception.message =~ /no outputs/
92
+
93
+ ::Terraform::NoOutputParser.new
89
94
  end
90
95
  end
91
96
  end
@@ -0,0 +1,35 @@
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
+ # A coercer for the [:color] value
19
+ class ColorCoercer
20
+ def coerce(attr:, value:)
21
+ configurable[attr] = [true, false].find(
22
+ proc { configurable.config_error attr: attr, expected: 'a boolean' },
23
+ &value.method(:==)
24
+ )
25
+ end
26
+
27
+ private
28
+
29
+ attr_accessor :configurable
30
+
31
+ def initialize(configurable:)
32
+ self.configurable = configurable
33
+ end
34
+ end
35
+ end
@@ -14,21 +14,19 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
+ require_relative 'color_coercer'
18
+ require_relative 'simple_config'
19
+
17
20
  module Terraform
18
21
  # Behaviour for the [:color] config option
19
22
  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
23
+ include ::Terraform::SimpleConfig
26
24
 
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'
25
+ def self.extended(configurable_class)
26
+ configurable_class
27
+ .configure_required attr: :color,
28
+ coercer_class: ::Terraform::ColorCoercer,
29
+ default_value: true
32
30
  end
33
31
  end
34
32
  end
@@ -14,54 +14,40 @@
14
14
  # See the License for the specific language governing permissions and
15
15
  # limitations under the License.
16
16
 
17
- require 'mixlib/shellout'
17
+ require 'terraform/command_options'
18
18
 
19
19
  module Terraform
20
20
  # Terraform command to be executed
21
21
  class Command
22
- def name
23
- ''
24
- end
22
+ attr_reader :options, :target
25
23
 
26
- def options
27
- '--help'
28
- end
24
+ def name
25
+ /(\w+)Command/.match(self.class.to_s) { |match| return match[1].downcase }
29
26
 
30
- def output
31
- processed_output raw_output: shell_out.stdout
27
+ 'help'
32
28
  end
33
29
 
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
- rescue => exception
40
- handle_error exception: exception
30
+ def prepare
31
+ preparations.each(&:execute)
41
32
  end
42
33
 
43
34
  def to_s
44
- shell_out.command
35
+ "#{name} #{options} #{target}".strip
45
36
  end
46
37
 
47
38
  private
48
39
 
49
- attr_accessor :shell_out
40
+ attr_accessor :preparations
50
41
 
51
- def handle_error(exception:)
52
- raise exception
53
- end
54
-
55
- def initialize(target: '', **keyword_arguments)
56
- initialize_attributes(**keyword_arguments)
57
- self.shell_out = Mixlib::ShellOut
58
- .new "terraform #{name} #{options} #{target}", returns: 0
59
- end
42
+ attr_writer :options, :target
60
43
 
61
- def initialize_attributes(**_keyword_arguments) end
44
+ def initialize(target: '', &block)
45
+ block ||= proc {}
62
46
 
63
- def processed_output(raw_output:)
64
- raw_output
47
+ self.options = ::Terraform::CommandOptions.new
48
+ self.preparations = []
49
+ self.target = target
50
+ block.call options
65
51
  end
66
52
  end
67
53
  end
@@ -0,0 +1,111 @@
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 'terraform/apply_command'
18
+ require 'terraform/destructive_plan_command'
19
+ require 'terraform/get_command'
20
+ require 'terraform/output_command'
21
+ require 'terraform/plan_command'
22
+ require 'terraform/show_command'
23
+ require 'terraform/validate_command'
24
+ require 'terraform/version_command'
25
+
26
+ module Terraform
27
+ # A factory to create commands
28
+ class CommandFactory
29
+ def apply_command
30
+ ::Terraform::ApplyCommand.new target: config[:plan] do |options|
31
+ options.color = config[:color]
32
+ options.input = false
33
+ options.parallelism = config[:parallelism]
34
+ options.state = config[:state]
35
+ end
36
+ end
37
+
38
+ def destructive_plan_command
39
+ ::Terraform::DestructivePlanCommand
40
+ .new target: config[:directory] do |options|
41
+ configure_plan options: options
42
+ options.destroy = true
43
+ options.state = config[:state]
44
+ end
45
+ end
46
+
47
+ def get_command
48
+ ::Terraform::GetCommand.new target: config[:directory] do |options|
49
+ options.update = true
50
+ end
51
+ end
52
+
53
+ def output_command(target:, version:)
54
+ version
55
+ .if_json_not_supported { return base_output_command target: target }
56
+
57
+ json_output_command target: target
58
+ end
59
+
60
+ def plan_command
61
+ ::Terraform::PlanCommand.new target: config[:directory] do |options|
62
+ configure_plan options: options
63
+ end
64
+ end
65
+
66
+ def show_command
67
+ ::Terraform::ShowCommand.new target: config[:state] do |options|
68
+ options.color = config[:color]
69
+ end
70
+ end
71
+
72
+ def validate_command
73
+ ::Terraform::ValidateCommand.new target: config[:directory]
74
+ end
75
+
76
+ def version_command
77
+ ::Terraform::VersionCommand.new
78
+ end
79
+
80
+ private
81
+
82
+ attr_accessor :config
83
+
84
+ def base_output_command(target:, &block)
85
+ block ||= proc {}
86
+
87
+ ::Terraform::OutputCommand.new target: target do |options|
88
+ options.color = config[:color]
89
+ options.state = config[:state]
90
+ block.call options
91
+ end
92
+ end
93
+
94
+ def configure_plan(options:)
95
+ options.color = config[:color]
96
+ options.input = false
97
+ options.out = config[:plan]
98
+ options.parallelism = config[:parallelism]
99
+ options.var = config[:variables]
100
+ options.var_file = config[:variable_files]
101
+ end
102
+
103
+ def initialize(config:)
104
+ self.config = config
105
+ end
106
+
107
+ def json_output_command(target:)
108
+ base_output_command(target: target) { |options| options.json = true }
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,65 @@
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
+ # An option for a command
19
+ class CommandOption
20
+ attr_reader :key, :value
21
+
22
+ def ==(other)
23
+ tuple == other.tuple
24
+ end
25
+
26
+ alias eql? ==
27
+
28
+ def hash
29
+ stripped_key.hash & stripped_value.hash
30
+ end
31
+
32
+ def to_s
33
+ "#{formatted_key}#{formatted_value}"
34
+ end
35
+
36
+ def tuple
37
+ [stripped_key, stripped_value]
38
+ end
39
+
40
+ private
41
+
42
+ attr_accessor :stripped_key, :stripped_value
43
+
44
+ attr_writer :key, :value
45
+
46
+ def initialize(key:, value: '')
47
+ self.key = key
48
+ self.stripped_key = stripped_string config_string: key
49
+ self.stripped_value = stripped_string config_string: value
50
+ self.value = value
51
+ end
52
+
53
+ def formatted_key
54
+ "-#{stripped_key}"
55
+ end
56
+
57
+ def formatted_value
58
+ stripped_value.sub(/(\S)/, '=\1')
59
+ end
60
+
61
+ def stripped_string(config_string:)
62
+ String(config_string).gsub(/\s/, '')
63
+ end
64
+ end
65
+ end