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
@@ -16,9 +16,7 @@ module TerraformWrapper
|
|
16
16
|
|
17
17
|
###############################################################################
|
18
18
|
|
19
|
-
|
20
|
-
@@default_container = "default"
|
21
|
-
@@default_suffix = "tf"
|
19
|
+
include TerraformWrapper::Shared::Logging
|
22
20
|
|
23
21
|
###############################################################################
|
24
22
|
|
@@ -27,16 +25,14 @@ module TerraformWrapper
|
|
27
25
|
###############################################################################
|
28
26
|
|
29
27
|
attr_reader :account
|
30
|
-
attr_reader :class
|
31
28
|
attr_reader :container
|
32
29
|
attr_reader :group
|
33
30
|
attr_reader :key
|
34
|
-
attr_reader :suffix
|
35
31
|
|
36
32
|
###############################################################################
|
37
33
|
|
38
|
-
def initialize(
|
39
|
-
construct(
|
34
|
+
def initialize(code:, config:, options:, service:, variables:)
|
35
|
+
construct(code: code, config: config, options: options, service: service, variables: variables)
|
40
36
|
end
|
41
37
|
|
42
38
|
###############################################################################
|
@@ -57,48 +53,51 @@ module TerraformWrapper
|
|
57
53
|
###############################################################################
|
58
54
|
|
59
55
|
def specific()
|
60
|
-
|
61
|
-
@class = @overrides["class"]
|
62
|
-
else
|
63
|
-
@class = @@default_class
|
64
|
-
end
|
56
|
+
logger.fatal("Azure backend mandatory option 'group' has not been set!") unless @options.key?("group")
|
65
57
|
|
66
|
-
|
67
|
-
@container = @overrides["container"]
|
68
|
-
else
|
69
|
-
@container = @@default_container
|
70
|
-
end
|
58
|
+
group = @options["group"]
|
71
59
|
|
72
|
-
|
73
|
-
|
74
|
-
else
|
75
|
-
@suffix = @@default_suffix
|
76
|
-
end
|
60
|
+
logger.fatal("Azure backend group must be a String!") unless group.kind_of?(String)
|
61
|
+
logger.fatal("Azure backend group must not be blank!") if group.strip.empty?
|
77
62
|
|
78
|
-
|
79
|
-
@group = @overrides["group"]
|
80
|
-
else
|
81
|
-
raise "Mandatory identifier 'account' or override 'group' must be set in provided configuration to backend of type: #{@@type}" unless @identifier.key?("account")
|
82
|
-
raise "Mandatory identifier 'account' is not a string in provided configuration to backend of type: #{@@type}" unless @identifier["account"].kind_of?(String)
|
83
|
-
raise "Mandatory identifier 'account' is empty in provided configuration to backend of type: #{@@type}" if @identifier["account"].strip.empty?
|
63
|
+
account = @options.key?("account") ? @options["account"] : group + "tf"
|
84
64
|
|
85
|
-
|
86
|
-
|
65
|
+
logger.fatal("Azure backend storage account must be a String!") unless account.kind_of?(String)
|
66
|
+
logger.fatal("Azure backend storage account must not be blank!") if account.strip.empty?
|
87
67
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
68
|
+
container = @options.key?("container") ? @options["container"] : "default"
|
69
|
+
|
70
|
+
logger.fatal("Azure backend storage account container must be a String!") unless container.kind_of?(String)
|
71
|
+
logger.fatal("Azure backend storage account container must not be blank!") if container.strip.empty?
|
72
|
+
|
73
|
+
key = @options.key?("key") ? @options["key"] : File.join("%{service}", "%{config}", "%{component}" + @@ext)
|
93
74
|
|
94
|
-
key
|
75
|
+
logger.fatal("Azure backend storage account key must be a String!") unless key.kind_of?(String)
|
76
|
+
logger.fatal("Azure backend storage account key must not be blank!") if key.strip.empty?
|
77
|
+
|
78
|
+
logger.fatal("Azure backend container or key must include %{service}.") unless (container.include?("%{service}") or key.include?("%{service}"))
|
79
|
+
logger.fatal("Azure backend container or key must include %{config}.") unless (container.include?("%{config}") or key.include?("%{config}"))
|
80
|
+
logger.fatal("Azure backend container or key must include %{component}.") unless (container.include?("%{component}") or key.include?("%{component}"))
|
81
|
+
|
82
|
+
begin
|
83
|
+
group = group % @variables
|
84
|
+
account = account % @variables
|
85
|
+
container = container % @variables
|
86
|
+
key = key % @variables
|
87
|
+
rescue
|
88
|
+
logger.fatal("Azure backend options contain variables that are not included in the configuration file!")
|
89
|
+
end
|
95
90
|
|
96
91
|
if key.length > 1024 then
|
97
|
-
|
92
|
+
logger.fatal("Key: #{key} is too long for backend of type: #{@@type}")
|
98
93
|
else
|
99
|
-
|
100
|
-
@key = key
|
94
|
+
logger.warn("Key for backend of type: #{@@type} exceeds 256 characters. This will not work with the Azure Storage Emulator. If key is not being overriden, consider using less identifiers.") if key.length > 256
|
101
95
|
end
|
96
|
+
|
97
|
+
@group = group
|
98
|
+
@account = account
|
99
|
+
@container = container
|
100
|
+
@key = key
|
102
101
|
end
|
103
102
|
|
104
103
|
###############################################################################
|
@@ -14,6 +14,10 @@ module TerraformWrapper
|
|
14
14
|
|
15
15
|
class Common
|
16
16
|
|
17
|
+
###############################################################################
|
18
|
+
|
19
|
+
include TerraformWrapper::Shared::Logging
|
20
|
+
|
17
21
|
###############################################################################
|
18
22
|
|
19
23
|
@@ext = ".tfstate"
|
@@ -21,27 +25,25 @@ module TerraformWrapper
|
|
21
25
|
|
22
26
|
###############################################################################
|
23
27
|
|
24
|
-
@
|
25
|
-
@
|
26
|
-
@overrides
|
27
|
-
@service
|
28
|
+
@options
|
29
|
+
@variables
|
28
30
|
|
29
31
|
###############################################################################
|
30
32
|
|
31
|
-
def initialize(
|
32
|
-
|
33
|
+
def initialize(code:, config:, options:, service:, variables:)
|
34
|
+
logger.fatal("This class should not be used directly! Please create a backend-specific class instead!")
|
33
35
|
end
|
34
36
|
|
35
37
|
###############################################################################
|
36
38
|
|
37
39
|
def hash()
|
38
|
-
|
40
|
+
logger.fatal("The backend specific class should override the 'hash' method to return a hash of parameters for Terraform to set!")
|
39
41
|
end
|
40
42
|
|
41
43
|
###############################################################################
|
42
44
|
|
43
45
|
def type()
|
44
|
-
|
46
|
+
logger.fatal("The backend specific class should set the 'type' class variable to a string!") unless @@type.kind_of?(String)
|
45
47
|
|
46
48
|
return @@type
|
47
49
|
end
|
@@ -52,11 +54,13 @@ module TerraformWrapper
|
|
52
54
|
|
53
55
|
###############################################################################
|
54
56
|
|
55
|
-
def construct(
|
56
|
-
@
|
57
|
-
@
|
58
|
-
|
59
|
-
|
57
|
+
def construct(code:, config:, options:, service:, variables:)
|
58
|
+
@options = options
|
59
|
+
@variables = variables.values.merge({
|
60
|
+
component: code.name,
|
61
|
+
config: config,
|
62
|
+
service: service
|
63
|
+
})
|
60
64
|
|
61
65
|
specific
|
62
66
|
end
|
@@ -64,7 +68,7 @@ module TerraformWrapper
|
|
64
68
|
###############################################################################
|
65
69
|
|
66
70
|
def specific()
|
67
|
-
|
71
|
+
logger.fatal("The backend specific class should override the 'specific' method to include backend specific validation and setup, or simply return 'true' if it is not required.")
|
68
72
|
end
|
69
73
|
|
70
74
|
###############################################################################
|
@@ -16,7 +16,7 @@ module TerraformWrapper
|
|
16
16
|
|
17
17
|
###############################################################################
|
18
18
|
|
19
|
-
|
19
|
+
include TerraformWrapper::Shared::Logging
|
20
20
|
|
21
21
|
###############################################################################
|
22
22
|
|
@@ -24,23 +24,19 @@ module TerraformWrapper
|
|
24
24
|
|
25
25
|
###############################################################################
|
26
26
|
|
27
|
-
attr_reader :base
|
28
|
-
attr_reader :directory
|
29
|
-
attr_reader :key
|
30
|
-
attr_reader :name
|
31
27
|
attr_reader :path
|
32
28
|
|
33
29
|
###############################################################################
|
34
30
|
|
35
|
-
def initialize(
|
36
|
-
construct(
|
31
|
+
def initialize(code:, config:, options:, service:, variables:)
|
32
|
+
construct(code: code, config: config, options: options, service: service, variables: variables)
|
37
33
|
end
|
38
34
|
|
39
35
|
###############################################################################
|
40
36
|
|
41
37
|
def hash()
|
42
38
|
return {
|
43
|
-
"path" => @path
|
39
|
+
"path" => @path
|
44
40
|
}
|
45
41
|
end
|
46
42
|
|
@@ -51,20 +47,26 @@ module TerraformWrapper
|
|
51
47
|
###############################################################################
|
52
48
|
|
53
49
|
def specific()
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
50
|
+
path = @options.key?("path") ? @options["path"] : File.join(Dir.pwd, "state", "terraform", "%{config}", "%{component}" + @@ext)
|
51
|
+
|
52
|
+
logger.fatal("Local backend path must be a String!") unless path.kind_of?(String)
|
53
|
+
logger.fatal("Local backend path must not be blank!") if path.strip.empty?
|
54
|
+
|
55
|
+
logger.fatal("Local backend path must include %{service} or the path to this repository.") unless (path.include?("%{service}") or path.include?(Dir.pwd))
|
56
|
+
logger.fatal("Local backend path must include %{config}") unless path.include?("%{config}")
|
57
|
+
logger.fatal("Local backend path must include %{component}") unless path.include?("%{component}")
|
58
|
+
|
59
|
+
begin
|
60
|
+
path = path % @variables
|
61
|
+
rescue
|
62
|
+
logger.fatal("Local backend options contain variables that are not included in the configuration file!")
|
58
63
|
end
|
59
64
|
|
60
|
-
|
65
|
+
directory = File.dirname(path)
|
61
66
|
|
62
|
-
directory
|
63
|
-
raise "Failed to create state directory: #{directory}" unless create_directory(directory: directory, purpose: "state")
|
67
|
+
logger.fatal("Failed to create state directory: #{directory}") unless ::TerraformWrapper.create_directory(directory: directory, purpose: "state")
|
64
68
|
|
65
|
-
@
|
66
|
-
@key = File.join(@identifiers.path, @name)
|
67
|
-
@path = File.join(@directory, @name)
|
69
|
+
@path = path
|
68
70
|
end
|
69
71
|
|
70
72
|
###############################################################################
|
@@ -10,6 +10,10 @@ module TerraformWrapper
|
|
10
10
|
|
11
11
|
class Binary
|
12
12
|
|
13
|
+
###############################################################################
|
14
|
+
|
15
|
+
include TerraformWrapper::Shared::Logging
|
16
|
+
|
13
17
|
###############################################################################
|
14
18
|
|
15
19
|
attr_accessor :name
|
@@ -23,11 +27,18 @@ module TerraformWrapper
|
|
23
27
|
|
24
28
|
###############################################################################
|
25
29
|
|
26
|
-
def initialize(
|
27
|
-
|
30
|
+
def initialize(options:)
|
31
|
+
logger.fatal("Binary base path must be a String!") unless options["base"].kind_of?(String)
|
32
|
+
logger.fatal("Binary base path must not be blank!") if options["base"].strip.empty?
|
28
33
|
|
29
|
-
@base = base
|
30
|
-
|
34
|
+
@base = options["base"]
|
35
|
+
|
36
|
+
logger.fatal("Binary version must be a String!") unless options["version"].kind_of?(String)
|
37
|
+
logger.fatal("Binary version must not be blank!") if options["version"].strip.empty?
|
38
|
+
|
39
|
+
@version = options["version"]
|
40
|
+
|
41
|
+
@platform = platform_detect
|
31
42
|
|
32
43
|
@directory = File.join(@base, @version, @platform)
|
33
44
|
@name = "terraform"
|
@@ -72,7 +83,7 @@ module TerraformWrapper
|
|
72
83
|
def platform_detect
|
73
84
|
return "darwin" if platform_is_mac
|
74
85
|
return "linux" if platform_is_linux
|
75
|
-
|
86
|
+
logger.fatal("Platform is NOT supported: #{RUBY_PLATFORM}")
|
76
87
|
end
|
77
88
|
|
78
89
|
###############################################################################
|
@@ -10,6 +10,10 @@ module TerraformWrapper
|
|
10
10
|
|
11
11
|
class Code
|
12
12
|
|
13
|
+
###############################################################################
|
14
|
+
|
15
|
+
include TerraformWrapper::Shared::Logging
|
16
|
+
|
13
17
|
###############################################################################
|
14
18
|
|
15
19
|
attr_reader :base
|
@@ -18,13 +22,20 @@ module TerraformWrapper
|
|
18
22
|
|
19
23
|
###############################################################################
|
20
24
|
|
21
|
-
def initialize(
|
22
|
-
|
23
|
-
|
25
|
+
def initialize(options:)
|
26
|
+
logger.fatal("Code base path must be a String!") unless options["base"].kind_of?(String)
|
27
|
+
logger.fatal("Code base path must not be blank!") if options["base"].strip.empty?
|
28
|
+
|
29
|
+
@base = options["base"]
|
30
|
+
|
31
|
+
logger.fatal("Code component name must be a String!") unless options["name"].kind_of?(String)
|
32
|
+
logger.fatal("Code component name must not be blank!") if options["name"].strip.empty?
|
33
|
+
|
34
|
+
@name = options["name"]
|
24
35
|
|
25
36
|
@path = File.join(@base, @name)
|
26
37
|
|
27
|
-
|
38
|
+
logger.fatal("Terraform code location: #{@path} does not exist!") unless exists
|
28
39
|
end
|
29
40
|
|
30
41
|
###############################################################################
|
@@ -14,6 +14,10 @@ module TerraformWrapper
|
|
14
14
|
|
15
15
|
class Config
|
16
16
|
|
17
|
+
###############################################################################
|
18
|
+
|
19
|
+
include TerraformWrapper::Shared::Logging
|
20
|
+
|
17
21
|
###############################################################################
|
18
22
|
|
19
23
|
@@config_exts = [ "", ".yaml", ".yml" ]
|
@@ -25,53 +29,79 @@ module TerraformWrapper
|
|
25
29
|
|
26
30
|
###############################################################################
|
27
31
|
|
32
|
+
attr_reader :auths
|
28
33
|
attr_reader :backend
|
29
34
|
attr_reader :base
|
30
35
|
attr_reader :code
|
31
36
|
attr_reader :name
|
32
37
|
attr_reader :path
|
33
|
-
attr_reader :overrides
|
34
38
|
attr_reader :service
|
35
39
|
attr_reader :variable_files
|
40
|
+
attr_reader :variables
|
36
41
|
|
37
42
|
###############################################################################
|
38
43
|
|
39
|
-
def initialize(
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
44
|
+
def initialize(code:, options:)
|
45
|
+
logger.fatal("Configuration base path must be a String!") unless options["base"].kind_of?(String)
|
46
|
+
logger.fatal("Configuration base path must not be blank!") if options["base"].strip.empty?
|
47
|
+
|
48
|
+
@base = options["base"]
|
49
|
+
|
50
|
+
logger.fatal("Configuration service name must be a String!") unless options["service"].kind_of?(String)
|
51
|
+
logger.fatal("Configuration service name must not be blank!") if options["service"].strip.empty?
|
52
|
+
|
53
|
+
@service = options["service"]
|
54
|
+
|
55
|
+
logger.fatal("Configuration name must be a String!") unless options["name"].kind_of?(String)
|
56
|
+
logger.fatal("Configuration name must not be blank!") if options["name"].strip.empty?
|
57
|
+
|
58
|
+
@name = options["name"]
|
59
|
+
|
60
|
+
logger.fatal("Configuration authenticator for Azure enabled must be a Boolean!") unless [ true, false ].include?(options["auth-azure"])
|
45
61
|
|
46
|
-
|
47
|
-
@code = code
|
48
|
-
@name = name
|
49
|
-
@overrides = overrides
|
50
|
-
@service = service
|
62
|
+
auth_azure = options["auth-azure"]
|
51
63
|
|
64
|
+
logger.fatal("Configuration authenticator for Azure options must be a Hash!") unless options["auth-azure-options"].kind_of?(Hash)
|
65
|
+
|
66
|
+
auth_azure_options = options["auth-azure-options"]
|
67
|
+
|
68
|
+
logger.fatal("Configuration backend name must be a String!") unless options["backend"].kind_of?(String)
|
69
|
+
logger.fatal("Configuration backend name must not be blank!") if options["backend"].strip.empty?
|
70
|
+
|
71
|
+
backend = options["backend"]
|
72
|
+
|
73
|
+
logger.fatal("Configuration backend options must be a Hash!") unless options["backend-options"].kind_of?(Hash)
|
74
|
+
|
75
|
+
backend_options = options["backend-options"]
|
76
|
+
|
77
|
+
@code = code
|
52
78
|
@path = find
|
53
79
|
|
54
80
|
yaml = YAML.load(File.read(@path))
|
55
81
|
|
56
|
-
|
82
|
+
logger.fatal("Invalid YAML in configuration file: #{@path}") unless yaml.kind_of?(Hash)
|
57
83
|
|
58
|
-
|
59
|
-
|
60
|
-
|
84
|
+
if yaml.key?("variables") then
|
85
|
+
logger.fatal("Key 'variables' is not a hash in configuration file: #{@path}") unless yaml["variables"].kind_of?(Hash)
|
86
|
+
@variables = TerraformWrapper::Shared::Variables.new(values: yaml["variables"])
|
87
|
+
else
|
88
|
+
@variables = TerraformWrapper::Shared::Variables.new()
|
89
|
+
end
|
61
90
|
|
62
|
-
|
91
|
+
@variable_files = yaml.key?("terraform") ? validate(variable_files: yaml["terraform"]) : Array.new
|
92
|
+
|
93
|
+
@auths = Array.new
|
94
|
+
@auths.append(TerraformWrapper::Shared::Auths::Azure.new(code: @code, config: @name, options: auth_azure_options, service: @service, variables: @variables)) if auth_azure
|
63
95
|
|
64
96
|
if backend == "local" then
|
65
|
-
@backend = TerraformWrapper::Shared::Backends::Local.new(
|
97
|
+
@backend = TerraformWrapper::Shared::Backends::Local.new(code: @code, config: @name, options: backend_options, service: @service, variables: @variables)
|
66
98
|
elsif backend == "aws" then
|
67
|
-
@backend = TerraformWrapper::Shared::Backends::AWS.new(
|
99
|
+
@backend = TerraformWrapper::Shared::Backends::AWS.new(code: @code, config: @name, options: backend_options, service: @service, variables: @variables)
|
68
100
|
elsif backend == "azure" then
|
69
|
-
@backend = TerraformWrapper::Shared::Backends::Azure.new(
|
101
|
+
@backend = TerraformWrapper::Shared::Backends::Azure.new(code: @code, config: @name, options: backend_options, service: @service, variables: @variables)
|
70
102
|
else
|
71
|
-
|
103
|
+
logger.fatal("Backend: #{backend} is not valid!")
|
72
104
|
end
|
73
|
-
|
74
|
-
@variable_files = yaml.key?("tfvars") ? tfvars(tfvars: yaml["tfvars"]) : Array.new
|
75
105
|
end
|
76
106
|
|
77
107
|
###############################################################################
|
@@ -86,24 +116,24 @@ module TerraformWrapper
|
|
86
116
|
return path if File.file?(path)
|
87
117
|
end
|
88
118
|
|
89
|
-
|
119
|
+
logger.fatal("Terraform configuration name: #{@name} not found in location: #{@base}!")
|
90
120
|
end
|
91
121
|
|
92
122
|
###############################################################################
|
93
123
|
|
94
|
-
def
|
95
|
-
|
124
|
+
def validate(variable_files:)
|
125
|
+
logger.fatal("Optional key 'variable_files' must be a list of strings!") unless variable_files.kind_of?(Array)
|
96
126
|
|
97
127
|
result = Array.new
|
98
128
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
path = File.join(@base, @@variable_files_name,
|
129
|
+
variable_files.each do |variable_file|
|
130
|
+
logger.fatal("All elements of 'variable_files' must be strings!") unless variable_file.kind_of?(String)
|
131
|
+
logger.fatal("All elements of 'variable_files' must not be blank!") if variable_file.strip.empty?
|
132
|
+
path = File.join(@base, @@variable_files_name, variable_file.strip + @@variable_files_ext)
|
103
133
|
if File.file?(path) then
|
104
134
|
result.append(path)
|
105
135
|
else
|
106
|
-
|
136
|
+
logger.fatal("Terraform variables file: #{variable_file}, path: #{path} does not exist!")
|
107
137
|
end
|
108
138
|
end
|
109
139
|
|