terraform-wrapper 0.0.2 → 0.2.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/.gitlab-ci.yml +2 -0
- data/Gemfile +0 -4
- data/lib/terraform-wrapper.rb +36 -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 +71 -33
- 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 +79 -21
- data/lib/terraform-wrapper/shared/variables.rb +66 -0
- data/lib/terraform-wrapper/tasks.rb +6 -0
- data/lib/terraform-wrapper/tasks/apply.rb +16 -18
- data/lib/terraform-wrapper/tasks/binary.rb +26 -23
- data/lib/terraform-wrapper/tasks/clean.rb +15 -15
- data/lib/terraform-wrapper/tasks/destroy.rb +16 -18
- data/lib/terraform-wrapper/tasks/import.rb +66 -0
- data/lib/terraform-wrapper/tasks/init.rb +16 -18
- data/lib/terraform-wrapper/tasks/plan.rb +16 -18
- data/lib/terraform-wrapper/tasks/plandestroy.rb +16 -18
- data/lib/terraform-wrapper/tasks/upgrade.rb +58 -0
- data/lib/terraform-wrapper/tasks/validate.rb +7 -7
- data/lib/terraform-wrapper/version.rb +1 -1
- data/terraform-wrapper.gemspec +3 -0
- metadata +39 -4
- data/lib/terraform-wrapper/shared/identifiers.rb +0 -70
@@ -14,6 +14,10 @@ module TerraformWrapper
|
|
14
14
|
|
15
15
|
class AWS < Common
|
16
16
|
|
17
|
+
###############################################################################
|
18
|
+
|
19
|
+
include TerraformWrapper::Shared::Logging
|
20
|
+
|
17
21
|
###############################################################################
|
18
22
|
|
19
23
|
@@default_class = "terraform-state"
|
@@ -25,24 +29,30 @@ module TerraformWrapper
|
|
25
29
|
###############################################################################
|
26
30
|
|
27
31
|
attr_reader :bucket
|
28
|
-
attr_reader :
|
32
|
+
attr_reader :encrypt
|
29
33
|
attr_reader :key
|
30
34
|
attr_reader :region
|
31
35
|
|
32
36
|
###############################################################################
|
33
37
|
|
34
|
-
def initialize(
|
35
|
-
construct(
|
38
|
+
def initialize(code:, config:, options:, service:, variables:)
|
39
|
+
construct(code: code, config: config, options: options, service: service, variables: variables)
|
36
40
|
end
|
37
41
|
|
38
42
|
###############################################################################
|
39
43
|
|
40
44
|
def hash()
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
45
|
+
result = Hash.new
|
46
|
+
|
47
|
+
result["bucket"] = @bucket
|
48
|
+
result["region"] = @region
|
49
|
+
result["key"] = @key
|
50
|
+
result["encrypt"] = @encrypt.to_s
|
51
|
+
|
52
|
+
result["kms_key_id"] = @kms unless @kms.nil?
|
53
|
+
result["role_arn"] = @role unless @role.nil?
|
54
|
+
|
55
|
+
return result
|
46
56
|
end
|
47
57
|
|
48
58
|
###############################################################################
|
@@ -52,39 +62,67 @@ module TerraformWrapper
|
|
52
62
|
###############################################################################
|
53
63
|
|
54
64
|
def specific()
|
55
|
-
|
56
|
-
|
57
|
-
else
|
58
|
-
@class = @@default_class
|
59
|
-
end
|
65
|
+
kms = nil
|
66
|
+
role = nil
|
60
67
|
|
61
|
-
|
62
|
-
|
63
|
-
else
|
64
|
-
raise "Mandatory identifier 'region' or override 'region' must be set in provided configuration to backend of type: #{@@type}" unless @identifier.key?("region")
|
65
|
-
raise "Mandatory identifier 'region' is not a string in provided configuration to backend of type: #{@@type}" unless @identifier["region"].kind_of?(String)
|
66
|
-
raise "Mandatory identifier 'region' is empty in provided configuration to backend of type: #{@@type}" if @identifier["region"].strip.empty?
|
68
|
+
logger.fatal("AWS backend mandatory option 'bucket' has not been set!") unless @options.key?("bucket")
|
69
|
+
logger.fatal("AWS backend mandatory option 'region' has not been set!") unless @options.key?("region")
|
67
70
|
|
68
|
-
|
69
|
-
|
71
|
+
bucket = @options["bucket"]
|
72
|
+
|
73
|
+
logger.fatal("AWS backend S3 bucket name must be a String!") unless bucket.kind_of?(String)
|
74
|
+
logger.fatal("AWS backend S3 bucket name must not be blank!") if bucket.strip.empty?
|
75
|
+
|
76
|
+
region = @options["region"]
|
70
77
|
|
71
|
-
|
72
|
-
|
73
|
-
else
|
74
|
-
raise "Mandatory identifier 'account' or override 'bucket' must be set in provided configuration to backend of type: #{@@type}" unless @identifier.key?("account")
|
75
|
-
raise "Mandatory identifier 'account' is not a string in provided configuration to backend of type: #{@@type}" unless @identifier["account"].kind_of?(String)
|
76
|
-
raise "Mandatory identifier 'account' is empty in provided configuration to backend of type: #{@@type}" if @identifier["account"].strip.empty?
|
78
|
+
logger.fatal("AWS backend S3 bucket region must be a String!") unless region.kind_of?(String)
|
79
|
+
logger.fatal("AWS backend S3 bucket region must not be blank!") if region.strip.empty?
|
77
80
|
|
78
|
-
|
81
|
+
key = @options.key?("key") ? @options["key"] : File.join("%{service}", "%{config}", "%{component}" + @@ext)
|
82
|
+
|
83
|
+
logger.fatal("AWS backend S3 bucket key must be a String!") unless key.kind_of?(String)
|
84
|
+
logger.fatal("AWS backend S3 bucket key must not be blank!") if key.strip.empty?
|
85
|
+
|
86
|
+
encrypt = @options.key?("encrypt") ? @options["encrypt"] : true
|
87
|
+
|
88
|
+
logger.fatal("AWS backend S3 bucket encryption enabled must be a Boolean!") unless [ true, false ].include?(encrypt)
|
89
|
+
|
90
|
+
if @options.key?("kms") then
|
91
|
+
kms = @options["kms"]
|
92
|
+
|
93
|
+
logger.fatal("AWS backend S3 bucket encryption KMS key ARN must be a String if specified!") unless kms.kind_of?(String)
|
94
|
+
logger.fatal("AWS backend S3 bucket encryption KMS key ARN must not be blank if specified!") if kms.strip.empty?
|
79
95
|
end
|
80
96
|
|
81
|
-
|
97
|
+
if @options.key?("role") then
|
98
|
+
role = @options["role"]
|
82
99
|
|
83
|
-
|
84
|
-
|
85
|
-
else
|
86
|
-
@key = key
|
100
|
+
logger.fatal("AWS backend role to assume ARN must be a String if specified!") unless role.kind_of?(String)
|
101
|
+
logger.fatal("AWS backend role to assume ARN must not be blank if specified!") if role.strip.empty?
|
87
102
|
end
|
103
|
+
|
104
|
+
logger.fatal("AWS backend S3 bucket name or key must include %{service}.") unless (bucket.include?("%{service}") or key.include?("%{service}"))
|
105
|
+
logger.fatal("AWS backend S3 bucket name or key must include %{config}.") unless (bucket.include?("%{config}") or key.include?("%{config}"))
|
106
|
+
logger.fatal("AWS backend S3 bucket name or key must include %{component}.") unless (bucket.include?("%{component}") or key.include?("%{component}"))
|
107
|
+
|
108
|
+
begin
|
109
|
+
bucket = bucket % @variables
|
110
|
+
region = region % @variables
|
111
|
+
key = key % @variables
|
112
|
+
kms = kms % @variables unless kms.nil?
|
113
|
+
role = role % @variables unless role.nil?
|
114
|
+
rescue
|
115
|
+
logger.fatal("AWS backend options contain variables that are not included in the configuration file!")
|
116
|
+
end
|
117
|
+
|
118
|
+
logger.fatal("Key: #{key} is too long for backend of type: #{@@type}") if key.length > 1024
|
119
|
+
|
120
|
+
@bucket = bucket
|
121
|
+
@region = region
|
122
|
+
@key = key
|
123
|
+
@encrypt = encrypt
|
124
|
+
@kms = kms
|
125
|
+
@role = role
|
88
126
|
end
|
89
127
|
|
90
128
|
###############################################################################
|
@@ -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
|
###############################################################################
|