TerraformDevKit 0.3.8 → 0.4.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.
@@ -1,67 +1,67 @@
1
- require 'aws-sdk-dynamodb'
2
- require 'aws-sdk-s3'
3
-
4
- module TerraformDevKit
5
- module Aws
6
- class TerraformRemoteState
7
- ATTRIBUTES = [
8
- {
9
- attribute_name: 'LockID',
10
- attribute_type: 'S'
11
- }
12
- ]
13
- KEYS = [
14
- {
15
- attribute_name: 'LockID',
16
- key_type: 'HASH'
17
- }
18
- ]
19
-
20
- def initialize(dynamodb, s3)
21
- @dynamodb = dynamodb
22
- @s3 = s3
23
- end
24
-
25
- def init(environment, project)
26
- table_name = table_name(environment, project)
27
- return if lock_table_exists_and_is_active(table_name)
28
-
29
- @dynamodb.create_table(table_name, ATTRIBUTES, KEYS, 1, 1)
30
-
31
- begin
32
- @s3.create_bucket(state_bucket_name(environment, project))
33
- rescue ::Aws::S3::Errors::BucketAlreadyOwnedByYou
34
- return
35
- end
36
-
37
- sleep(0.2) until lock_table_exists_and_is_active(table_name)
38
- end
39
-
40
- def destroy(environment, project)
41
- table_name = table_name(environment, project)
42
-
43
- @dynamodb.delete_table(table_name)
44
- @s3.delete_bucket(state_bucket_name(environment, project))
45
- end
46
-
47
- private_class_method
48
- def lock_table_exists_and_is_active(table_name)
49
- begin
50
- return @dynamodb.get_table_status(table_name) == 'ACTIVE'
51
- rescue ::Aws::DynamoDB::Errors::ResourceNotFoundException
52
- return false
53
- end
54
- end
55
-
56
- private_class_method
57
- def table_name(environment, project)
58
- "#{project.acronym}-#{environment.name}-lock-table"
59
- end
60
-
61
- private_class_method
62
- def state_bucket_name(environment, project)
63
- "#{project.name}-#{environment.name}-state"
64
- end
65
- end
66
- end
67
- end
1
+ require 'aws-sdk-dynamodb'
2
+ require 'aws-sdk-s3'
3
+
4
+ module TerraformDevKit
5
+ module Aws
6
+ class TerraformRemoteState
7
+ ATTRIBUTES = [
8
+ {
9
+ attribute_name: 'LockID',
10
+ attribute_type: 'S'
11
+ }
12
+ ]
13
+ KEYS = [
14
+ {
15
+ attribute_name: 'LockID',
16
+ key_type: 'HASH'
17
+ }
18
+ ]
19
+
20
+ def initialize(dynamodb, s3)
21
+ @dynamodb = dynamodb
22
+ @s3 = s3
23
+ end
24
+
25
+ def init(environment, project)
26
+ table_name = table_name(environment, project)
27
+ return if lock_table_exists_and_is_active(table_name)
28
+
29
+ @dynamodb.create_table(table_name, ATTRIBUTES, KEYS, 1, 1)
30
+
31
+ begin
32
+ @s3.create_bucket(state_bucket_name(environment, project))
33
+ rescue ::Aws::S3::Errors::BucketAlreadyOwnedByYou
34
+ return
35
+ end
36
+
37
+ sleep(0.2) until lock_table_exists_and_is_active(table_name)
38
+ end
39
+
40
+ def destroy(environment, project)
41
+ table_name = table_name(environment, project)
42
+
43
+ @dynamodb.delete_table(table_name)
44
+ @s3.delete_bucket(state_bucket_name(environment, project))
45
+ end
46
+
47
+ private_class_method
48
+ def lock_table_exists_and_is_active(table_name)
49
+ begin
50
+ return @dynamodb.get_table_status(table_name) == 'ACTIVE'
51
+ rescue ::Aws::DynamoDB::Errors::ResourceNotFoundException
52
+ return false
53
+ end
54
+ end
55
+
56
+ private_class_method
57
+ def table_name(environment, project)
58
+ "#{project.acronym}-#{environment.name}-lock-table"
59
+ end
60
+
61
+ private_class_method
62
+ def state_bucket_name(environment, project)
63
+ "#{project.name}-#{environment.name}-state"
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,18 +1,18 @@
1
- require 'fileutils'
2
-
3
- require_relative 'zip_file_generator'
4
-
5
- module TerraformDevKit
6
- class BackupState
7
- def self.backup(prefix)
8
- backup_path = ENV['TM_STATE_BACKUP_PATH']
9
- return if backup_path.nil?
10
-
11
- filename = "#{prefix}failure_state.zip"
12
- ZipFileGenerator.new('.', filename).write
13
-
14
- FileUtils.cp(filename, backup_path)
15
- puts "Copied state to #{File.join(backup_path, filename)}"
16
- end
17
- end
18
- end
1
+ require 'fileutils'
2
+
3
+ require_relative 'zip_file_generator'
4
+
5
+ module TerraformDevKit
6
+ class BackupState
7
+ def self.backup(prefix)
8
+ backup_path = ENV['TM_STATE_BACKUP_PATH']
9
+ return if backup_path.nil?
10
+
11
+ filename = "#{prefix}failure_state.zip"
12
+ ZipFileGenerator.new('.', filename).write
13
+
14
+ FileUtils.cp(filename, backup_path)
15
+ puts "Copied state to #{File.join(backup_path, filename)}"
16
+ end
17
+ end
18
+ end
@@ -1,31 +1,31 @@
1
- require 'open3'
2
-
3
- require 'TerraformDevKit/errors/command_error'
4
-
5
- module TerraformDevKit
6
- class Command
7
- def self.run(cmd, directory: Dir.pwd, print_output: true)
8
- out = IO.popen(cmd, err: %i[child out], chdir: directory) do |io|
9
- begin
10
- out = ''
11
- loop do
12
- chunk = io.readpartial(4096)
13
- print chunk if print_output
14
- out += chunk
15
- end
16
- rescue EOFError; end
17
- out
18
- end
19
-
20
- out = process_output(out)
21
- $?.exitstatus.zero? || (raise CommandError.new(cmd, out))
22
- out
23
- end
24
-
25
- private_class_method
26
- def self.process_output(out)
27
- out.split("\n")
28
- .map { |line| line.tr("\r\n", '') }
29
- end
30
- end
31
- end
1
+ require 'open3'
2
+
3
+ require 'TerraformDevKit/errors/command_error'
4
+
5
+ module TerraformDevKit
6
+ class Command
7
+ def self.run(cmd, directory: Dir.pwd, print_output: true)
8
+ out = IO.popen(cmd, err: %i[child out], chdir: directory) do |io|
9
+ begin
10
+ out = ''
11
+ loop do
12
+ chunk = io.readpartial(4096)
13
+ print chunk if print_output
14
+ out += chunk
15
+ end
16
+ rescue EOFError; end
17
+ out
18
+ end
19
+
20
+ out = process_output(out)
21
+ $?.exitstatus.zero? || (raise CommandError.new(cmd, out))
22
+ out
23
+ end
24
+
25
+ private_class_method
26
+ def self.process_output(out)
27
+ out.split("\n")
28
+ .map { |line| line.tr("\r\n", '') }
29
+ end
30
+ end
31
+ end
@@ -10,7 +10,7 @@ module TerraformDevKit
10
10
  puts "Downloading #{url} to #{filename}..."
11
11
 
12
12
  open(filename, 'wb') do |file|
13
- file << open(url, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE).read
13
+ file << URI.open(url, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE).read
14
14
  end
15
15
  end
16
16
  end
@@ -1,21 +1,21 @@
1
- require 'fileutils'
2
- require 'TerraformDevKit/command'
3
- require 'TerraformDevKit/os'
4
-
5
- module TerraformDevKit::ExtendedFileUtils
6
- def self.copy(files, dest_base_path)
7
- files.to_h.each do |dest, src|
8
- dest = File.join(dest_base_path, dest)
9
- FileUtils.copy_entry(src, dest)
10
- end
11
- end
12
-
13
- def self.rm_rf(list, options = {})
14
- if TerraformDevKit::OS.host_os == 'windows'
15
- windows_path = TerraformDevKit::OS.convert_to_local_path(list)
16
- TerraformDevKit::Command.run("rmdir /s/q \"#{windows_path}\"")
17
- else
18
- FileUtils.rm_rf(list, options)
19
- end
20
- end
21
- end
1
+ require 'fileutils'
2
+ require 'TerraformDevKit/command'
3
+ require 'TerraformDevKit/os'
4
+
5
+ module TerraformDevKit::ExtendedFileUtils
6
+ def self.copy(files, dest_base_path)
7
+ files.to_h.each do |dest, src|
8
+ dest = File.join(dest_base_path, dest)
9
+ FileUtils.copy_entry(src, dest)
10
+ end
11
+ end
12
+
13
+ def self.rm_rf(list, options = {})
14
+ if TerraformDevKit::OS.host_os == 'windows'
15
+ windows_path = TerraformDevKit::OS.convert_to_local_path(list)
16
+ TerraformDevKit::Command.run("rmdir /s/q \"#{windows_path}\"")
17
+ else
18
+ FileUtils.rm_rf(list, options)
19
+ end
20
+ end
21
+ end
@@ -1,10 +1,10 @@
1
- module TerraformDevKit
2
- class ProjectConfig
3
- attr_reader :name, :acronym
4
-
5
- def initialize(project_name, project_acronym = nil)
6
- @name = project_name.tr(' ', '-').downcase
7
- @acronym = project_acronym || project_name.scan(/\b[a-z]/i).join.upcase
8
- end
9
- end
10
- end
1
+ module TerraformDevKit
2
+ class ProjectConfig
3
+ attr_reader :name, :acronym
4
+
5
+ def initialize(project_name, project_acronym = nil)
6
+ @name = project_name.tr(' ', '-').downcase
7
+ @acronym = project_acronym || project_name.scan(/\b[a-z]/i).join.upcase
8
+ end
9
+ end
10
+ end
@@ -18,7 +18,7 @@ module TerraformDevKit
18
18
  ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE
19
19
  }
20
20
  options.merge!(@headers)
21
- open(url, options)
21
+ URI.open(url, options)
22
22
  rescue OpenURI::HTTPError => error
23
23
  response = error.io
24
24
  raise if raise_on_codes.include?(response.status[0])
@@ -1,3 +1,3 @@
1
- module TerraformDevKit
2
- VERSION = '0.3.8'.freeze
3
- end
1
+ module TerraformDevKit
2
+ VERSION = '0.4.0'.freeze
3
+ end
@@ -1,47 +1,47 @@
1
- require 'zip'
2
-
3
- module TerraformDevKit
4
- class ZipFileGenerator
5
- def initialize(input_dir, output_file)
6
- @input_dir = input_dir
7
- @output_file = output_file
8
- end
9
-
10
- def write
11
- entries = Dir.entries(@input_dir)
12
- entries.delete('.')
13
- entries.delete('..')
14
- Zip::File.open(@output_file, Zip::File::CREATE) do |zipfile|
15
- write_entries(entries, '', zipfile)
16
- end
17
- end
18
-
19
- private
20
-
21
- def write_entries(entries, path, zipfile)
22
- entries.each do |e|
23
- zip_file_path = path == '' ? e : File.join(path, e)
24
- disk_file_path = File.join(@input_dir, zip_file_path)
25
- if File.directory?(disk_file_path)
26
- write_directory(disk_file_path, zip_file_path, zipfile)
27
- else
28
- write_file(disk_file_path, zip_file_path, zipfile)
29
- end
30
- end
31
- end
32
-
33
- def write_directory(disk_file_path, zip_file_path, zipfile)
34
- zipfile.mkdir(zip_file_path)
35
- subdir = Dir.entries(disk_file_path)
36
- subdir.delete('.')
37
- subdir.delete('..')
38
- write_entries(subdir, zip_file_path, zipfile)
39
- end
40
-
41
- def write_file(disk_file_path, zip_file_path, zipfile)
42
- zipfile.get_output_stream(zip_file_path) do |f|
43
- f.puts(File.open(disk_file_path, 'rb').read)
44
- end
45
- end
46
- end
47
- end
1
+ require 'zip'
2
+
3
+ module TerraformDevKit
4
+ class ZipFileGenerator
5
+ def initialize(input_dir, output_file)
6
+ @input_dir = input_dir
7
+ @output_file = output_file
8
+ end
9
+
10
+ def write
11
+ entries = Dir.entries(@input_dir)
12
+ entries.delete('.')
13
+ entries.delete('..')
14
+ Zip::File.open(@output_file, Zip::File::CREATE) do |zipfile|
15
+ write_entries(entries, '', zipfile)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def write_entries(entries, path, zipfile)
22
+ entries.each do |e|
23
+ zip_file_path = path == '' ? e : File.join(path, e)
24
+ disk_file_path = File.join(@input_dir, zip_file_path)
25
+ if File.directory?(disk_file_path)
26
+ write_directory(disk_file_path, zip_file_path, zipfile)
27
+ else
28
+ write_file(disk_file_path, zip_file_path, zipfile)
29
+ end
30
+ end
31
+ end
32
+
33
+ def write_directory(disk_file_path, zip_file_path, zipfile)
34
+ zipfile.mkdir(zip_file_path)
35
+ subdir = Dir.entries(disk_file_path)
36
+ subdir.delete('.')
37
+ subdir.delete('..')
38
+ write_entries(subdir, zip_file_path, zipfile)
39
+ end
40
+
41
+ def write_file(disk_file_path, zip_file_path, zipfile)
42
+ zipfile.get_output_stream(zip_file_path) do |f|
43
+ f.puts(File.open(disk_file_path, 'rb').read)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,187 +1,187 @@
1
- require 'rainbow'
2
- require 'TerraformDevKit'
3
-
4
- TDK = TerraformDevKit
5
-
6
- raise 'ROOT_PATH is not defined' if defined?(ROOT_PATH).nil?
7
- BIN_PATH = File.join(ROOT_PATH, 'bin')
8
- CONFIG_FILE ||= File.join(ROOT_PATH, 'config', 'config-%s.yml')
9
-
10
- # Ensure terraform is in the PATH
11
- ENV['PATH'] = TDK::OS.join_env_path(
12
- TDK::OS.convert_to_local_path(BIN_PATH),
13
- ENV['PATH']
14
- )
15
-
16
- PLAN_FILE = 'plan.tfplan'.freeze
17
-
18
- def destroy_if_fails(env, task)
19
- yield
20
- rescue Exception => e
21
- puts "ERROR: #{e.message}"
22
- puts e.backtrace.join("\n")
23
- invoke('destroy', task, env.name) if env.local_backend?
24
- raise
25
- end
26
-
27
- def invoke(task_name, task_context, env, safe_invoke: false)
28
- task_in_context = task_in_current_namespace(task_name, task_context)
29
- should_invoke = !safe_invoke || Rake::Task.task_defined?(task_in_context)
30
- Rake::Task[task_in_context].invoke(env) if should_invoke
31
- end
32
-
33
- def task_in_current_namespace(task_name, current_task)
34
- namespace = current_task.scope.path.to_s
35
- namespace.empty? ? task_name : "#{namespace}:#{task_name}"
36
- end
37
-
38
- def remote_state
39
- aws_config = TDK::Aws::AwsConfig.new(TDK::Configuration.get('aws'))
40
- dynamo_db = TDK::Aws::DynamoDB.new(
41
- aws_config.credentials,
42
- aws_config.region
43
- )
44
- s3 = TDK::Aws::S3.new(
45
- aws_config.credentials,
46
- aws_config.region
47
- )
48
- TDK::Aws::TerraformRemoteState.new(dynamo_db, s3)
49
- end
50
-
51
- desc 'Prepares the environment to create the infrastructure'
52
- task :prepare, [:env] do |_, args|
53
- env = TDK::Environment.new(args.env)
54
-
55
- puts "== Configuring environment #{env.name}"
56
-
57
- config_file = CONFIG_FILE % env.config
58
- puts "== Loading configuration from #{config_file}"
59
- TDK::Configuration.init(config_file)
60
-
61
- invoke('custom_prepare', task, env.name, safe_invoke: true)
62
-
63
- TDK::TerraformInstaller.install_local(
64
- TDK::Configuration.get('terraform-version'),
65
- directory: BIN_PATH
66
- )
67
-
68
- project_config = TDK::ProjectConfig.new(
69
- TDK::Configuration.get('project-name'),
70
- TDK::Configuration.get('project-acronym')
71
- )
72
- TDK::TerraformConfigManager.setup(env, project_config)
73
-
74
- unless env.local_backend?
75
- puts '== Initializing remote state'
76
- remote_state.init(env, project_config)
77
- end
78
-
79
- if File.exist?(File.join(env.working_dir, '.terraform'))
80
- get_cmd = 'terraform get'
81
- get_cmd += ' -update=true' if TDK::TerraformConfigManager.update_modules?
82
- TDK::Command.run(get_cmd, directory: env.working_dir)
83
- else
84
- init_cmd = 'terraform init'
85
- init_cmd += ' -upgrade=false' unless TDK::TerraformConfigManager.update_modules?
86
- TDK::Command.run(init_cmd, directory: env.working_dir)
87
- end
88
- end
89
-
90
- desc 'Shows the plan to create the infrastructure'
91
- task :plan, [:env] => :prepare do |_, args|
92
- env = TDK::Environment.new(args.env)
93
- cmd = "terraform plan -out=#{PLAN_FILE}"
94
- TDK::Command.run(cmd, directory: env.working_dir)
95
- end
96
-
97
- desc 'Creates the infrastructure'
98
- task :apply, [:env] => :prepare do |task, args|
99
- env = TDK::Environment.new(args.env)
100
-
101
- invoke('plan', task, env.name)
102
-
103
- unless env.local_backend? || allow_remote_apply?
104
- puts Rainbow("Are you sure you want to apply the above plan?\n" \
105
- "Only 'yes' will be accepted.").green
106
- response = STDIN.gets.strip
107
- unless response == 'yes'
108
- raise "Apply cancelled because response was not 'yes'.\n" \
109
- "Response was: #{response}"
110
- end
111
- end
112
-
113
- invoke('pre_apply', task, env.name, safe_invoke: true)
114
-
115
- destroy_if_fails(env, task) do
116
- cmd = "terraform apply \"#{PLAN_FILE}\""
117
- TDK::Command.run(cmd, directory: env.working_dir)
118
- end
119
-
120
- invoke('post_apply', task, env.name, safe_invoke: true)
121
- end
122
-
123
- def allow_remote_apply?
124
- aws = TDK::Configuration.get('aws')
125
- aws.key?('remote_apply') && aws['remote_apply']
126
- end
127
-
128
- desc 'Tests a local environment'
129
- task :test, [:env] do |task, args|
130
- env = TDK::Environment.new(args.env)
131
- env.local_backend? || (raise 'Testing is only allowed for local environments')
132
-
133
- invoke('apply', task, env.name)
134
-
135
- destroy_if_fails(env, task) do
136
- invoke('custom_test', task, env.name, safe_invoke: true)
137
- end
138
- end
139
-
140
- desc 'Creates the infrastructure and runs the tests'
141
- task :preflight, [:prefix, :teardown] do |task, args|
142
- args.with_defaults(teardown: 'true')
143
- args.with_defaults(prefix: TDK::Environment.temp_name)
144
- env = TDK::Environment.new(args.prefix)
145
-
146
- invoke('test', task, env.name)
147
- invoke('clean', task, env.name) if args.teardown == 'true'
148
- end
149
-
150
- desc 'Destroys the infrastructure'
151
- task :destroy, [:env] => :prepare do |task, args|
152
- env = TDK::Environment.new(args.env)
153
-
154
- unless env.local_backend?
155
- puts Rainbow("\n\n!!!! WARNING !!!!\n\n" \
156
- "You are about to destroy #{env.name} and its remote state.\n" \
157
- "Are you sure you want to proceed?\n" \
158
- "Only 'yes' will be accepted.").red.bright
159
- response = STDIN.gets.strip
160
-
161
- unless response == 'yes'
162
- raise "Destroy cancelled because response was not 'yes'.\n" \
163
- "Response was: #{response}"
164
- end
165
- end
166
-
167
- invoke('pre_destroy', task, env.name, safe_invoke: true)
168
-
169
- TDK::Command.run('terraform destroy -force', directory: env.working_dir)
170
-
171
- unless env.local_backend?
172
- project_config = TDK::ProjectConfig.new(
173
- TDK::Configuration.get('project-name'),
174
- TDK::Configuration.get('project-acronym')
175
- )
176
- remote_state.destroy(env, project_config)
177
- end
178
-
179
- invoke('post_destroy', task, env.name, safe_invoke: true)
180
- end
181
-
182
- desc 'Cleans an environment (infrastructure is destroyed too)'
183
- task :clean, [:env] => :destroy do |_, args|
184
- env = TDK::Environment.new(args.env)
185
- puts "Deleting environment #{env.name} in #{env.working_dir}"
186
- TDK::ExtendedFileUtils.rm_rf(env.working_dir, secure: true)
187
- end
1
+ require 'rainbow'
2
+ require 'TerraformDevKit'
3
+
4
+ TDK = TerraformDevKit
5
+
6
+ raise 'ROOT_PATH is not defined' if defined?(ROOT_PATH).nil?
7
+ BIN_PATH = File.join(ROOT_PATH, 'bin')
8
+ CONFIG_FILE ||= File.join(ROOT_PATH, 'config', 'config-%s.yml')
9
+
10
+ # Ensure terraform is in the PATH
11
+ ENV['PATH'] = TDK::OS.join_env_path(
12
+ TDK::OS.convert_to_local_path(BIN_PATH),
13
+ ENV['PATH']
14
+ )
15
+
16
+ PLAN_FILE = 'plan.tfplan'.freeze
17
+
18
+ def destroy_if_fails(env, task)
19
+ yield
20
+ rescue Exception => e
21
+ puts "ERROR: #{e.message}"
22
+ puts e.backtrace.join("\n")
23
+ invoke('destroy', task, env.name) if env.local_backend?
24
+ raise
25
+ end
26
+
27
+ def invoke(task_name, task_context, env, safe_invoke: false)
28
+ task_in_context = task_in_current_namespace(task_name, task_context)
29
+ should_invoke = !safe_invoke || Rake::Task.task_defined?(task_in_context)
30
+ Rake::Task[task_in_context].invoke(env) if should_invoke
31
+ end
32
+
33
+ def task_in_current_namespace(task_name, current_task)
34
+ namespace = current_task.scope.path.to_s
35
+ namespace.empty? ? task_name : "#{namespace}:#{task_name}"
36
+ end
37
+
38
+ def remote_state
39
+ aws_config = TDK::Aws::AwsConfig.new(TDK::Configuration.get('aws'))
40
+ dynamo_db = TDK::Aws::DynamoDB.new(
41
+ aws_config.credentials,
42
+ aws_config.region
43
+ )
44
+ s3 = TDK::Aws::S3.new(
45
+ aws_config.credentials,
46
+ aws_config.region
47
+ )
48
+ TDK::Aws::TerraformRemoteState.new(dynamo_db, s3)
49
+ end
50
+
51
+ desc 'Prepares the environment to create the infrastructure'
52
+ task :prepare, [:env] do |_, args|
53
+ env = TDK::Environment.new(args.env)
54
+
55
+ puts "== Configuring environment #{env.name}"
56
+
57
+ config_file = CONFIG_FILE % env.config
58
+ puts "== Loading configuration from #{config_file}"
59
+ TDK::Configuration.init(config_file)
60
+
61
+ invoke('custom_prepare', task, env.name, safe_invoke: true)
62
+
63
+ TDK::TerraformInstaller.install_local(
64
+ TDK::Configuration.get('terraform-version'),
65
+ directory: BIN_PATH
66
+ )
67
+
68
+ project_config = TDK::ProjectConfig.new(
69
+ TDK::Configuration.get('project-name'),
70
+ TDK::Configuration.get('project-acronym')
71
+ )
72
+ TDK::TerraformConfigManager.setup(env, project_config)
73
+
74
+ unless env.local_backend?
75
+ puts '== Initializing remote state'
76
+ remote_state.init(env, project_config)
77
+ end
78
+
79
+ if File.exist?(File.join(env.working_dir, '.terraform'))
80
+ get_cmd = 'terraform get'
81
+ get_cmd += ' -update=true' if TDK::TerraformConfigManager.update_modules?
82
+ TDK::Command.run(get_cmd, directory: env.working_dir)
83
+ else
84
+ init_cmd = 'terraform init'
85
+ init_cmd += ' -upgrade=false' unless TDK::TerraformConfigManager.update_modules?
86
+ TDK::Command.run(init_cmd, directory: env.working_dir)
87
+ end
88
+ end
89
+
90
+ desc 'Shows the plan to create the infrastructure'
91
+ task :plan, [:env] => :prepare do |_, args|
92
+ env = TDK::Environment.new(args.env)
93
+ cmd = "terraform plan -out=#{PLAN_FILE}"
94
+ TDK::Command.run(cmd, directory: env.working_dir)
95
+ end
96
+
97
+ desc 'Creates the infrastructure'
98
+ task :apply, [:env] => :prepare do |task, args|
99
+ env = TDK::Environment.new(args.env)
100
+
101
+ invoke('plan', task, env.name)
102
+
103
+ unless env.local_backend? || allow_remote_apply?
104
+ puts Rainbow("Are you sure you want to apply the above plan?\n" \
105
+ "Only 'yes' will be accepted.").green
106
+ response = STDIN.gets.strip
107
+ unless response == 'yes'
108
+ raise "Apply cancelled because response was not 'yes'.\n" \
109
+ "Response was: #{response}"
110
+ end
111
+ end
112
+
113
+ invoke('pre_apply', task, env.name, safe_invoke: true)
114
+
115
+ destroy_if_fails(env, task) do
116
+ cmd = "terraform apply \"#{PLAN_FILE}\""
117
+ TDK::Command.run(cmd, directory: env.working_dir)
118
+ end
119
+
120
+ invoke('post_apply', task, env.name, safe_invoke: true)
121
+ end
122
+
123
+ def allow_remote_apply?
124
+ aws = TDK::Configuration.get('aws')
125
+ aws.key?('remote_apply') && aws['remote_apply']
126
+ end
127
+
128
+ desc 'Tests a local environment'
129
+ task :test, [:env] do |task, args|
130
+ env = TDK::Environment.new(args.env)
131
+ env.local_backend? || (raise 'Testing is only allowed for local environments')
132
+
133
+ invoke('apply', task, env.name)
134
+
135
+ destroy_if_fails(env, task) do
136
+ invoke('custom_test', task, env.name, safe_invoke: true)
137
+ end
138
+ end
139
+
140
+ desc 'Creates the infrastructure and runs the tests'
141
+ task :preflight, [:prefix, :teardown] do |task, args|
142
+ args.with_defaults(teardown: 'true')
143
+ args.with_defaults(prefix: TDK::Environment.temp_name)
144
+ env = TDK::Environment.new(args.prefix)
145
+
146
+ invoke('test', task, env.name)
147
+ invoke('clean', task, env.name) if args.teardown == 'true'
148
+ end
149
+
150
+ desc 'Destroys the infrastructure'
151
+ task :destroy, [:env] => :prepare do |task, args|
152
+ env = TDK::Environment.new(args.env)
153
+
154
+ unless env.local_backend?
155
+ puts Rainbow("\n\n!!!! WARNING !!!!\n\n" \
156
+ "You are about to destroy #{env.name} and its remote state.\n" \
157
+ "Are you sure you want to proceed?\n" \
158
+ "Only 'yes' will be accepted.").red.bright
159
+ response = STDIN.gets.strip
160
+
161
+ unless response == 'yes'
162
+ raise "Destroy cancelled because response was not 'yes'.\n" \
163
+ "Response was: #{response}"
164
+ end
165
+ end
166
+
167
+ invoke('pre_destroy', task, env.name, safe_invoke: true)
168
+
169
+ TDK::Command.run('terraform destroy -force', directory: env.working_dir)
170
+
171
+ unless env.local_backend?
172
+ project_config = TDK::ProjectConfig.new(
173
+ TDK::Configuration.get('project-name'),
174
+ TDK::Configuration.get('project-acronym')
175
+ )
176
+ remote_state.destroy(env, project_config)
177
+ end
178
+
179
+ invoke('post_destroy', task, env.name, safe_invoke: true)
180
+ end
181
+
182
+ desc 'Cleans an environment (infrastructure is destroyed too)'
183
+ task :clean, [:env] => :destroy do |_, args|
184
+ env = TDK::Environment.new(args.env)
185
+ puts "Deleting environment #{env.name} in #{env.working_dir}"
186
+ TDK::ExtendedFileUtils.rm_rf(env.working_dir, secure: true)
187
+ end