terraform-wrapper 0.0.2 → 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.
- checksums.yaml +4 -4
- data/lib/terraform-wrapper.rb +34 -16
- data/lib/terraform-wrapper/common.rb +12 -23
- data/lib/terraform-wrapper/shared.rb +7 -1
- data/lib/terraform-wrapper/shared/auths.rb +9 -0
- data/lib/terraform-wrapper/shared/auths/azure.rb +179 -0
- data/lib/terraform-wrapper/shared/auths/common.rb +95 -0
- data/lib/terraform-wrapper/shared/backends/aws.rb +34 -29
- data/lib/terraform-wrapper/shared/backends/azure.rb +38 -39
- data/lib/terraform-wrapper/shared/backends/common.rb +18 -14
- data/lib/terraform-wrapper/shared/backends/local.rb +20 -18
- data/lib/terraform-wrapper/shared/binary.rb +16 -5
- data/lib/terraform-wrapper/shared/code.rb +15 -4
- data/lib/terraform-wrapper/shared/config.rb +61 -31
- data/lib/terraform-wrapper/shared/latest.rb +11 -7
- data/lib/terraform-wrapper/shared/logger.rb +80 -0
- data/lib/terraform-wrapper/shared/logging.rb +77 -0
- data/lib/terraform-wrapper/shared/runner.rb +59 -22
- data/lib/terraform-wrapper/shared/variables.rb +66 -0
- data/lib/terraform-wrapper/tasks/apply.rb +16 -14
- data/lib/terraform-wrapper/tasks/binary.rb +25 -21
- data/lib/terraform-wrapper/tasks/clean.rb +15 -11
- data/lib/terraform-wrapper/tasks/destroy.rb +16 -14
- data/lib/terraform-wrapper/tasks/init.rb +16 -14
- data/lib/terraform-wrapper/tasks/plan.rb +16 -14
- data/lib/terraform-wrapper/tasks/plandestroy.rb +16 -14
- data/lib/terraform-wrapper/tasks/validate.rb +7 -3
- data/lib/terraform-wrapper/version.rb +1 -1
- metadata +8 -3
- data/lib/terraform-wrapper/shared/identifiers.rb +0 -70
@@ -21,6 +21,10 @@ module TerraformWrapper
|
|
21
21
|
|
22
22
|
include Singleton
|
23
23
|
|
24
|
+
###############################################################################
|
25
|
+
|
26
|
+
include TerraformWrapper::Shared::Logging
|
27
|
+
|
24
28
|
###############################################################################
|
25
29
|
|
26
30
|
@version
|
@@ -40,22 +44,22 @@ module TerraformWrapper
|
|
40
44
|
###############################################################################
|
41
45
|
|
42
46
|
def refresh
|
43
|
-
|
47
|
+
logger.info("Finding latest available Terraform release...")
|
44
48
|
|
45
49
|
response = Net::HTTP.get_response(URI("https://checkpoint-api.hashicorp.com/v1/check/terraform"))
|
46
50
|
|
47
|
-
|
48
|
-
|
49
|
-
|
51
|
+
logger.fatal("Hashicorp Checkpoint did not return status 200 for latest version check!") if response.code != "200"
|
52
|
+
logger.fatal("Response body from Hashicorp Checkpoint is not permitted!") if not response.class.body_permitted?
|
53
|
+
logger.fatal("Response body from Hashicorp Checkpoint is empty!") if response.body.nil?
|
50
54
|
|
51
55
|
body = JSON.parse(response.body)
|
52
56
|
|
53
|
-
|
54
|
-
|
57
|
+
logger.fatal("Hashicorp Checkpoint JSON response did not include latest available Terraform version!") if not body.key?("current_version")
|
58
|
+
logger.fatal("Hashicorp Checkpoint indicated latest available version of Terraform is blank!") if body["current_version"].empty?
|
55
59
|
|
56
60
|
version = body["current_version"]
|
57
61
|
|
58
|
-
|
62
|
+
logger.success("Latest available Terraform release found: #{version}")
|
59
63
|
|
60
64
|
return version
|
61
65
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
###############################################################################
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
###############################################################################
|
6
|
+
|
7
|
+
module TerraformWrapper
|
8
|
+
|
9
|
+
###############################################################################
|
10
|
+
|
11
|
+
module Shared
|
12
|
+
|
13
|
+
###############################################################################
|
14
|
+
|
15
|
+
class Logger < ::Logger
|
16
|
+
|
17
|
+
###############################################################################
|
18
|
+
|
19
|
+
@colour = false
|
20
|
+
|
21
|
+
###############################################################################
|
22
|
+
|
23
|
+
def colour()
|
24
|
+
@colour
|
25
|
+
end
|
26
|
+
|
27
|
+
###############################################################################
|
28
|
+
|
29
|
+
def colour=(enabled)
|
30
|
+
@colour = [ true, false ].include?(enabled) ? enabled : false
|
31
|
+
end
|
32
|
+
|
33
|
+
###############################################################################
|
34
|
+
|
35
|
+
def success(message)
|
36
|
+
info(format(colour: 32, message: message))
|
37
|
+
end
|
38
|
+
|
39
|
+
###############################################################################
|
40
|
+
|
41
|
+
def warn(message)
|
42
|
+
warn(format(colour: 33, message: message))
|
43
|
+
end
|
44
|
+
|
45
|
+
###############################################################################
|
46
|
+
|
47
|
+
def error(message)
|
48
|
+
error(format(colour: 31, message: message))
|
49
|
+
end
|
50
|
+
|
51
|
+
###############################################################################
|
52
|
+
|
53
|
+
def fatal(message)
|
54
|
+
fatal(format(colour: 31, message: message))
|
55
|
+
exit(1)
|
56
|
+
end
|
57
|
+
|
58
|
+
###############################################################################
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
###############################################################################
|
63
|
+
|
64
|
+
def format(colour: 32, message:)
|
65
|
+
return @colour ? "\e[" + colour.to_s + "m" + message + "\e[0m" : message
|
66
|
+
end
|
67
|
+
|
68
|
+
###############################################################################
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
###############################################################################
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
###############################################################################
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
###############################################################################
|
@@ -0,0 +1,77 @@
|
|
1
|
+
###############################################################################
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
###############################################################################
|
6
|
+
|
7
|
+
module TerraformWrapper
|
8
|
+
|
9
|
+
###############################################################################
|
10
|
+
|
11
|
+
module Shared
|
12
|
+
|
13
|
+
###############################################################################
|
14
|
+
|
15
|
+
module Logging
|
16
|
+
|
17
|
+
###############################################################################
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
###############################################################################
|
22
|
+
|
23
|
+
def logger
|
24
|
+
@logger ||= Logging.logger_for(self.class.name)
|
25
|
+
end
|
26
|
+
|
27
|
+
###############################################################################
|
28
|
+
|
29
|
+
@loggers = {}
|
30
|
+
|
31
|
+
###############################################################################
|
32
|
+
|
33
|
+
class << self
|
34
|
+
|
35
|
+
###############################################################################
|
36
|
+
|
37
|
+
def logger_for(classname)
|
38
|
+
@loggers[classname] ||= configure_logger_for(classname)
|
39
|
+
end
|
40
|
+
|
41
|
+
###############################################################################
|
42
|
+
|
43
|
+
def configure_logger_for(classname)
|
44
|
+
colour = ENV["TERRAFORM_WRAPPER_LOG_COLOUR"] || "true"
|
45
|
+
level = ENV["TERRAFORM_WRAPPER_LOG_LEVEL"] || "INFO"
|
46
|
+
|
47
|
+
logger = ::TerraformWrapper::Shared::Logger.new(STDOUT)
|
48
|
+
|
49
|
+
logger.colour = colour.downcase == "true"
|
50
|
+
logger.level = level.upcase
|
51
|
+
logger.progname = classname
|
52
|
+
|
53
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
54
|
+
sevId = severity.chars.first.upcase
|
55
|
+
"[#{sevId}] [#{progname}] #{msg}\n"
|
56
|
+
end
|
57
|
+
|
58
|
+
logger
|
59
|
+
end
|
60
|
+
|
61
|
+
###############################################################################
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
###############################################################################
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
###############################################################################
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
###############################################################################
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
###############################################################################
|
@@ -10,6 +10,10 @@ module TerraformWrapper
|
|
10
10
|
|
11
11
|
class Runner
|
12
12
|
|
13
|
+
###############################################################################
|
14
|
+
|
15
|
+
include TerraformWrapper::Shared::Logging
|
16
|
+
|
13
17
|
###############################################################################
|
14
18
|
|
15
19
|
attr_reader :binary
|
@@ -30,75 +34,90 @@ module TerraformWrapper
|
|
30
34
|
|
31
35
|
###############################################################################
|
32
36
|
|
33
|
-
def download
|
34
|
-
parameters =
|
37
|
+
def download(upgrade: true)
|
38
|
+
parameters = Array.new
|
39
|
+
parameters.append("-backend=false")
|
40
|
+
parameters.append("-upgrade") if upgrade
|
41
|
+
|
35
42
|
@downloaded = run(action: "init", parameters: parameters)
|
36
|
-
|
43
|
+
logger.fatal("Failed to download Terraform modules.") unless @downloaded
|
37
44
|
end
|
38
45
|
|
39
46
|
###############################################################################
|
40
47
|
|
41
|
-
def init(config:)
|
42
|
-
parameters =
|
48
|
+
def init(config:, upgrade: true)
|
49
|
+
parameters = Array.new
|
50
|
+
parameters.append("-reconfigure")
|
51
|
+
parameters.append("-upgrade") if upgrade
|
52
|
+
|
43
53
|
config.backend.hash.each do |key, value|
|
44
54
|
parameters.append("-backend-config=\"#{key}=#{value}\"")
|
45
55
|
end
|
46
56
|
|
57
|
+
config.auths.map(&:auth)
|
58
|
+
|
47
59
|
@config = config
|
48
60
|
@initialised = run(action: "init", parameters: parameters)
|
49
|
-
|
61
|
+
logger.fatal("Failed to initialise Terraform with backend.") unless @initialised
|
50
62
|
end
|
51
63
|
|
52
64
|
###############################################################################
|
53
65
|
|
54
66
|
def plan(destroy: false, file: nil)
|
55
|
-
|
67
|
+
logger.fatal("Cannot Terraform plan before initialising backend!") unless initialised
|
56
68
|
|
57
|
-
parameters =
|
69
|
+
parameters = Array.new
|
70
|
+
parameters.concat(variable_files)
|
71
|
+
parameters.concat(variable_strings)
|
58
72
|
|
59
73
|
if not file.nil? and file.kind_of?(String) and not file.strip.empty? then
|
60
|
-
|
74
|
+
logger.fatal("Failed to create plan directory: #{directory}") unless ::TerraformWrapper.create_directory(directory: File.dirname(file), purpose: "plan")
|
61
75
|
parameters.append("-out=\"#{file}\"")
|
62
76
|
end
|
63
77
|
|
64
78
|
parameters.append("-destroy") if destroy
|
65
79
|
|
66
|
-
|
80
|
+
logger.fatal("Terraform plan failed!") unless run(action: "plan", parameters: parameters)
|
67
81
|
end
|
68
82
|
|
69
83
|
###############################################################################
|
70
84
|
|
71
85
|
def apply(file: nil)
|
72
|
-
|
86
|
+
logger.fatal("Cannot Terraform apply before initialising backend!") unless initialised
|
73
87
|
|
74
|
-
parameters =
|
88
|
+
parameters = Array.new
|
89
|
+
parameters.concat(variable_files)
|
90
|
+
parameters.concat(variable_strings)
|
91
|
+
parameters.append("-auto-approve")
|
75
92
|
|
76
93
|
if not file.nil? and file.kind_of?(String) and not file.strip.empty? then
|
77
|
-
|
94
|
+
logger.fatal("Plan file: #{file} does not exist!") unless File.file?(file)
|
78
95
|
parameters.append("\"#{file}\"")
|
79
96
|
else
|
80
97
|
parameters.concat(variable_files)
|
81
98
|
end
|
82
99
|
|
83
|
-
|
100
|
+
logger.fatal("Terraform apply failed!") unless run(action: "apply", parameters: parameters)
|
84
101
|
end
|
85
102
|
|
86
103
|
###############################################################################
|
87
104
|
|
88
105
|
def destroy
|
89
|
-
|
106
|
+
logger.fatal("Cannot Terraform destroy before initialising backend!") unless initialised
|
90
107
|
|
91
|
-
parameters =
|
108
|
+
parameters = Array.new
|
92
109
|
parameters.concat(variable_files)
|
110
|
+
parameters.concat(variable_strings)
|
111
|
+
parameters.append("-auto-approve")
|
93
112
|
|
94
|
-
|
113
|
+
logger.fatal("Terraform destroy failed!") unless run(action: "destroy", parameters: parameters)
|
95
114
|
end
|
96
115
|
|
97
116
|
###############################################################################
|
98
117
|
|
99
118
|
def validate
|
100
|
-
|
101
|
-
|
119
|
+
logger.fatal("Cannot Terraform validate before downloading modules!") unless downloaded
|
120
|
+
logger.fatal("Terraform validation failed!") unless run(action: "validate")
|
102
121
|
end
|
103
122
|
|
104
123
|
###############################################################################
|
@@ -108,7 +127,7 @@ module TerraformWrapper
|
|
108
127
|
###############################################################################
|
109
128
|
|
110
129
|
def variable_files
|
111
|
-
|
130
|
+
logger.fatal("Cannot generate variable files until Terraform has been initialised!") unless @initialised
|
112
131
|
|
113
132
|
result = Array.new
|
114
133
|
|
@@ -119,6 +138,24 @@ module TerraformWrapper
|
|
119
138
|
return result
|
120
139
|
end
|
121
140
|
|
141
|
+
###############################################################################
|
142
|
+
|
143
|
+
def variable_strings
|
144
|
+
logger.fatal("Cannot generate variable strings until Terraform has been initialised!") unless @initialised
|
145
|
+
|
146
|
+
result = Array.new
|
147
|
+
|
148
|
+
result.append("-var=\"component=#{@code.name}\"")
|
149
|
+
result.append("-var=\"config=#{@config.name}\"")
|
150
|
+
result.append("-var=\"service=#{@config.service}\"")
|
151
|
+
|
152
|
+
@config.variables.values.each do |key, value|
|
153
|
+
result.append("-var=\"#{key.to_s}=#{value}\"")
|
154
|
+
end
|
155
|
+
|
156
|
+
return result
|
157
|
+
end
|
158
|
+
|
122
159
|
###############################################################################
|
123
160
|
|
124
161
|
def run(action:, parameters: Array.new)
|
@@ -128,14 +165,14 @@ module TerraformWrapper
|
|
128
165
|
|
129
166
|
cmdline = [ "\"#{@binary.path}\"", action ].concat(parameters).join(" ")
|
130
167
|
|
131
|
-
|
168
|
+
logger.info("Starting Terraform, action: #{action}")
|
132
169
|
|
133
170
|
puts("\n" + ('#' * 80) + "\n\n")
|
134
171
|
|
135
172
|
Dir.chdir(@code.path)
|
136
173
|
result = system(cmdline) || false
|
137
174
|
|
138
|
-
puts("\n")
|
175
|
+
puts("\n" + ('#' * 80) + "\n\n")
|
139
176
|
|
140
177
|
return result
|
141
178
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
###############################################################################
|
2
|
+
|
3
|
+
module TerraformWrapper
|
4
|
+
|
5
|
+
###############################################################################
|
6
|
+
|
7
|
+
module Shared
|
8
|
+
|
9
|
+
###############################################################################
|
10
|
+
|
11
|
+
class Variables
|
12
|
+
|
13
|
+
###############################################################################
|
14
|
+
|
15
|
+
include TerraformWrapper::Shared::Logging
|
16
|
+
|
17
|
+
###############################################################################
|
18
|
+
|
19
|
+
@@reserved = [ "component", "config", "service" ]
|
20
|
+
|
21
|
+
###############################################################################
|
22
|
+
|
23
|
+
attr_reader :values
|
24
|
+
|
25
|
+
###############################################################################
|
26
|
+
|
27
|
+
def initialize(values: Hash.new, sort: true)
|
28
|
+
cleansed = cleanse(values: values)
|
29
|
+
@values = sort ? cleansed.sort.to_h : cleansed
|
30
|
+
end
|
31
|
+
|
32
|
+
###############################################################################
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
###############################################################################
|
37
|
+
|
38
|
+
def cleanse(values:)
|
39
|
+
result = Hash.new
|
40
|
+
|
41
|
+
values.keys.each do |key|
|
42
|
+
logger.fatal("Could not clean variables hash. All keys MUST be strings!") unless key.kind_of?(String)
|
43
|
+
logger.fatal("Could not clean variables hash, key: #{key.downcase} is reserved and cannot be used!") if @@reserved.include?(key.downcase)
|
44
|
+
logger.fatal("Could not clean variables hash, duplicate key found: #{key.downcase}!") if result.key?(key.downcase.to_sym)
|
45
|
+
logger.fatal("Could not clean variables hash, value for: #{key.downcase} is not a string!") unless values[key].kind_of?(String)
|
46
|
+
logger.fatal("Could not clean variables hash, value for: #{key.downcase} is empty!") if values[key].strip.empty?
|
47
|
+
|
48
|
+
result[key.downcase.to_sym] = values[key].strip
|
49
|
+
end
|
50
|
+
|
51
|
+
return result
|
52
|
+
end
|
53
|
+
|
54
|
+
###############################################################################
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
###############################################################################
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
###############################################################################
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
###############################################################################
|
@@ -16,22 +16,20 @@ module TerraformWrapper
|
|
16
16
|
|
17
17
|
###############################################################################
|
18
18
|
|
19
|
-
|
19
|
+
include TerraformWrapper::Shared::Logging
|
20
|
+
|
21
|
+
###############################################################################
|
22
|
+
|
20
23
|
@binary
|
21
24
|
@code
|
22
|
-
@
|
23
|
-
@overrides
|
24
|
-
@service
|
25
|
+
@options
|
25
26
|
|
26
27
|
###############################################################################
|
27
28
|
|
28
|
-
def initialize(
|
29
|
-
@
|
30
|
-
@
|
31
|
-
@
|
32
|
-
@configs = configs
|
33
|
-
@overrides = overrides
|
34
|
-
@service = service
|
29
|
+
def initialize(binary:, code:, options:)
|
30
|
+
@binary = binary
|
31
|
+
@code = code
|
32
|
+
@options = options
|
35
33
|
|
36
34
|
yield self if block_given?
|
37
35
|
|
@@ -41,13 +39,17 @@ module TerraformWrapper
|
|
41
39
|
###############################################################################
|
42
40
|
|
43
41
|
def apply_task
|
44
|
-
desc "Applies infrastructure with Terraform for a given configuration on
|
42
|
+
desc "Applies infrastructure with Terraform for a given configuration on an infrastructure component."
|
45
43
|
task :apply, [:config, :plan] => :binary do |t, args|
|
46
|
-
|
44
|
+
options = @options.merge({"name" => args[:config]})
|
47
45
|
|
48
|
-
|
46
|
+
logger.info("Processing configuration for Terraform apply...")
|
47
|
+
|
48
|
+
config = TerraformWrapper::Shared::Config.new(code: @code, options: options)
|
49
49
|
runner = TerraformWrapper::Shared::Runner.new(binary: @binary, code: @code)
|
50
50
|
|
51
|
+
logger.info("Running Terraform apply for service: #{config.service}, component: #{@code.name}...")
|
52
|
+
|
51
53
|
runner.init(config: config)
|
52
54
|
runner.apply(file: args[:plan])
|
53
55
|
end
|