kitchen-terraform 0.5.1 → 0.6.0

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