domed-city 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a479bd76c9371672e2c98195ff3f7fb586729754
4
- data.tar.gz: f01115ee5623edc4d6c49ed8a71b10f36c51697c
3
+ metadata.gz: dc30be20e47da94a3dba7850dcbeace2d40dcd7f
4
+ data.tar.gz: 8e9255071a4b955afefdfc7af8dd833b7bb88778
5
5
  SHA512:
6
- metadata.gz: 000d202545551fe348eae862c7efd1f18098e161cfe8a347ff259ab3ed414b6bd1db37482648e27c4189a6c4476d03dec4a575582406d7e33fe9bdab7c582d85
7
- data.tar.gz: 8f6ef5a805ecbf245b9d11abe0ec9b36484b51f5adfc9776d798127518a5d0b6ace3fd4d3815490664ac587688d9f4297de3a2f35dd5b911e6fa389991a48eb2
6
+ metadata.gz: f692ed025597cbda665c7f42dc4442abc71be05d7288fdc3c30b43a5eeb20dfe08e466f0351ae473fa001584a347d45d44249059edca15cfc6189111ab5ff0ab
7
+ data.tar.gz: 0ca6e96eb0c50e23663c45d971ab341d2712748ba7cf982e47974a8c239fb6c5b94b9f133ca6dda4d2684c02498a0e25f1269a73bbc609b741b593577a5f7f21
data/bin/dome CHANGED
@@ -19,22 +19,23 @@ EOS
19
19
  opt :state, 'Synchronises the Terraform state'
20
20
  end
21
21
 
22
+ # TODO: hopefully we can flip this logic to DRY it up
22
23
  if opts[:plan]
23
- @dome = Dome::Environment.new
24
+ @dome = Dome::Terraform.new
24
25
  @dome.validate_environment
25
26
  @dome.plan
26
27
  elsif opts[:apply]
27
- @dome = Dome::Environment.new
28
+ @dome = Dome::Terraform.new
28
29
  @dome.validate_environment
29
30
  @dome.apply
30
31
  elsif opts[:plan_destroy]
31
- @dome = Dome::Environment.new
32
+ @dome = Dome::Terraform.new
32
33
  @dome.validate_environment
33
34
  @dome.plan_destroy
34
35
  elsif opts[:state]
35
- @dome = Dome::Environment.new
36
+ @dome = Dome::Terraform.new
36
37
  @dome.validate_environment
37
- @dome.bootstrap_s3_state
38
+ @dome.state.s3_state
38
39
  else
39
40
  Trollop.educate
40
41
  end
data/lib/dome.rb CHANGED
@@ -5,4 +5,7 @@ require 'aws/profile_parser'
5
5
  require 'fileutils'
6
6
 
7
7
  require 'dome/version'
8
+ require 'dome/helpers/shell'
8
9
  require 'dome/environment'
10
+ require 'dome/state'
11
+ require 'dome/terraform'
@@ -1,225 +1,74 @@
1
1
  module Dome
2
2
  class Environment
3
+ attr_reader :environment, :account, :team
4
+
3
5
  def initialize
4
- @environment = Dir.pwd.split('/')[-1]
5
- @account = Dir.pwd.split('/')[-2]
6
- @team = 'deirdre'
7
- @tfstate_bucket = "#{@team}-tfstate-#{@environment}"
8
- @tfstate_s3_obj = "#{@environment}-terraform.tfstate"
9
- @varfile = 'params/env.tfvars'
10
- @plan = "plans/#{@account}-#{@environment}-plan.tf"
11
- @state_file = "state-files/#{@environment}-terraform.tfstate"
6
+ @environment = Dir.pwd.split('/')[-1]
7
+ @account = Dir.pwd.split('/')[-2]
8
+ @team = @account.match(/(\w+)-\w+\z/)[1]
12
9
  end
13
10
 
14
- # --------------------------------------------------------------
15
- # Environment stuff
16
- # --------------------------------------------------------------
17
-
18
- def valid_accounts
11
+ def accounts
19
12
  %w(deirdre-dev deirdre-prd)
20
13
  end
21
14
 
22
- def valid_env_nonprod
15
+ def non_production_environments
23
16
  %w(infradev sit qa stg)
24
17
  end
25
18
 
26
- def valid_env_prod
19
+ def production_environments
27
20
  %w(infraprd prd)
28
21
  end
29
22
 
30
- def validate_environment
31
- puts "Environment: #{@environment}"
32
- puts "Account: #{@account}"
33
-
34
- invalid_account_message(account) unless valid_account? @account
35
- invalid_environment_message(account, environment) unless valid_environment?(@account, @environment)
36
-
37
- set_aws_credentials(@account)
38
- end
39
-
40
- def set_aws_credentials(account)
23
+ def aws_credentials
41
24
  begin
42
- @aws_creds = AWS::ProfileParser.new.get(account)
25
+ @aws_credentials ||= AWS::ProfileParser.new.get(@account)
43
26
  rescue RuntimeError
44
- raise "No credentials found for account: '#{account}'."
27
+ raise "No credentials found for account: '#{@account}'."
45
28
  end
46
- ENV['AWS_ACCESS_KEY_ID'] = @aws_creds[:access_key_id]
47
- ENV['AWS_SECRET_ACCESS_KEY'] = @aws_creds[:secret_access_key]
48
- ENV['AWS_DEFAULT_REGION'] = @aws_creds[:region]
29
+ end
30
+
31
+ def populate_aws_access_keys
32
+ ENV['AWS_ACCESS_KEY_ID'] = aws_credentials[:access_key_id]
33
+ ENV['AWS_SECRET_ACCESS_KEY'] = aws_credentials[:secret_access_key]
34
+ ENV['AWS_DEFAULT_REGION'] = aws_credentials[:region]
49
35
  end
50
36
 
51
37
  def valid_account?(account)
52
- valid_accounts.include? account
38
+ puts "Account: #{account.colorize(:green)}"
39
+ accounts.include? account
53
40
  end
54
41
 
55
42
  def valid_environment?(account, environment)
56
- if valid_accounts[valid_accounts.index(account)] == 'deirdre-dev'
57
- valid_env_nonprod.include? environment
58
- elsif valid_accounts[valid_accounts.index(account)] == 'deirdre-prd'
59
- valid_env_prod.include? environment
43
+ puts "Environment: #{environment.colorize(:green)}"
44
+ if account[-4..-1] == '-dev'
45
+ non_production_environments.include? environment
46
+ else
47
+ production_environments.include? environment
60
48
  end
61
49
  end
62
50
 
63
- def invalid_account_message(account)
64
- puts "\n'#{account}' is not a valid account.\n".colorize(:red)
65
- puts "Valid accounts are: #{valid_accounts}."
51
+ def invalid_account_message
52
+ puts "\n'#{@account}' is not a valid account.\n".colorize(:red)
53
+ puts "The 'account' and 'environment' values are calculated based on your current directory.\n".colorize(:red)
54
+ puts "Valid accounts are: #{accounts}."
66
55
  puts "\nEither:"
67
56
  puts '1. Set your .aws/config to one of the valid accounts above.'
68
57
  puts '2. Ensure you are running this from the correct directory.'
69
58
  exit 1
70
59
  end
71
60
 
72
- def invalid_environment_message(account, environment)
73
- puts "\n'#{environment}' is not a valid environment for the account: '#{account}'.\n".colorize(:red)
74
- (account == 'deirdre-dev') ? env = valid_env_nonprod : env = valid_env_prod
75
- puts "Valid environments are: #{env}"
76
- exit 1
77
- end
78
-
79
- # --------------------------------------------------------------
80
- # Terraform commands
81
- # --------------------------------------------------------------
82
-
83
- def plan
84
- puts "current dir: #{Dir.pwd}"
85
- delete_terraform_directory
86
- delete_plan_file
87
- install_terraform_modules
88
- fetch_s3_state
89
- create_plan
90
- end
91
-
92
- def apply
93
- command = "terraform apply #{@plan}"
94
- failure_message = 'something went wrong when applying the TF plan'
95
- execute_command(command, failure_message)
96
- end
97
-
98
- def create_plan
99
- command = "terraform plan -module-depth=1 -refresh=true -out=#{@plan} -var-file=#{@varfile}"
100
- failure_message = 'something went wrong when creating the TF plan'
101
- execute_command(command, failure_message)
102
- end
103
-
104
- def delete_terraform_directory
105
- puts 'Deleting older terraform module cache dir ...'.colorize(:green)
106
- terraform_directory = '.terraform'
107
- puts "About to delete directory: #{terraform_directory}"
108
- FileUtils.rm_rf '.terraform/'
109
- end
110
-
111
- def delete_plan_file
112
- puts 'Deleting older terraform plan ...'.colorize(:green)
113
- puts "About to delete: #{@plan}"
114
- FileUtils.rm_f @plan
115
- end
116
-
117
- def plan_destroy
118
- delete_terraform_directory
119
- delete_plan_file
120
- install_terraform_modules
121
- create_destroy_plan
122
- end
123
-
124
- def create_destroy_plan
125
- command = "terraform plan -destroy -module-depth=1 -out=#{@plan} -var-file=#{@varfile}"
126
- failure_message = 'something went wrong when creating the TF plan'
127
- execute_command(command, failure_message)
128
- end
129
-
130
- def install_terraform_modules
131
- command = 'terraform get -update=true'
132
- failure_message = 'something went wrong when pulling remote TF modules'
133
- execute_command(command, failure_message)
134
- end
61
+ def invalid_environment_message
62
+ puts "\n'#{@environment}' is not a valid environment for the account: '#{@account}'.\n".colorize(:red)
63
+ puts "The 'account' and 'environment' values are calculated based on your current directory.\n".colorize(:red)
135
64
 
136
- # S3 stuff
137
-
138
- def s3_client
139
- @s3_client ||= Aws::S3::Client.new(@aws_creds)
140
- end
141
-
142
- def s3_bucket_exists?(tfstate_bucket)
143
- resp = s3_client.list_buckets
144
- resp.buckets.each { |bucket| return true if bucket.name == tfstate_bucket }
145
- false
146
- end
147
-
148
- def create_bucket(name)
149
- begin
150
- s3_client.create_bucket(bucket: name, acl: 'private')
151
- rescue Aws::S3::Errors::BucketAlreadyExists
152
- raise 'The S3 bucket must be globally unique. See https://docs.aws.amazon.com/AmazonS3/latest/gsg/CreatingABucket.html'.colorize(:red)
153
- end
154
- end
155
-
156
- def enable_bucket_versioning(bucket_name)
157
- puts 'Enabling versioning on the S3 bucket - http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html'.colorize(:green)
158
- s3_client.put_bucket_versioning(bucket: bucket_name,
159
- versioning_configuration: {
160
- mfa_delete: 'Disabled',
161
- status: 'Enabled'
162
- })
163
- end
164
-
165
- def put_empty_object_in_bucket(bucket_name, key_name)
166
- puts "Putting an empty object with key: #{key_name} into bucket: #{bucket_name}".colorize(:green)
167
- s3_client.put_object(
168
- bucket: bucket_name,
169
- key: key_name,
170
- body: ''
171
- )
172
- end
173
-
174
- def create_remote_state_bucket(tfstate_bucket, tfstate_s3_obj)
175
- create_bucket tfstate_bucket
176
- enable_bucket_versioning tfstate_bucket
177
- put_empty_object_in_bucket(tfstate_bucket, tfstate_s3_obj)
178
- end
179
-
180
- def bootstrap_s3_state
181
- if s3_bucket_exists?(@tfstate_bucket)
182
- synchronise_s3_state
183
- else
184
- create_remote_state_bucket(@tfstate_bucket, @tfstate_s3_obj)
185
- end
186
- end
187
-
188
- def synchronise_s3_state
189
- puts 'Synchronising the remote S3 state...'
190
- # not clear for me if the -state in the below command matters
191
- command = 'terraform remote config'\
192
- ' -backend=S3'\
193
- " -backend-config='bucket=#{@tfstate_bucket}' -backend-config='key=#{@tfstate_s3_obj}'"\
194
- " -state=#{@state_file}"
195
- failure_message = 'something went wrong when creating the S3 state'
196
- execute_command(command, failure_message)
197
- end
198
-
199
- def synchronise_s3_state_setup
200
- puts "Setting up the initial terraform S3 state in the S3 bucket: #{@tfstate_bucket.colorize(:green)} for account: #{@account.colorize(:green)} and environment: #{@environment.colorize(:green)} ..."
201
- command = 'terraform remote config'\
202
- ' -backend=S3'\
203
- " -backend-config='bucket=#{@tfstate_bucket}' -backend-config='key=#{@tfstate_s3_obj}'"
204
- failure_message = 'something went wrong when creating the S3 state'
205
- execute_command(command, failure_message)
206
- end
207
-
208
- def fetch_s3_state
209
- command = 'terraform remote config -backend=S3'\
210
- " -backend-config='bucket=#{@tfstate_bucket}' -backend-config='key=#{@tfstate_s3_obj}'"
211
- failure_message = 'something went wrong when fetching the S3 state'
212
- execute_command(command, failure_message)
213
- end
214
-
215
- # --------------------------------------------------------------
216
- # Misc.
217
- # --------------------------------------------------------------
218
-
219
- def execute_command(command, failure_message)
220
- puts "About to execute command: #{command}"
221
- success = system command
222
- puts failure_message unless success
65
+ env = if account[-4..-1] == '-dev'
66
+ non_production_environments
67
+ else
68
+ production_environments
69
+ end
70
+ puts "Valid environments are: #{env}."
71
+ exit 1
223
72
  end
224
73
  end
225
74
  end
@@ -0,0 +1,9 @@
1
+ module Dome
2
+ module Shell
3
+ def execute_command(command, failure_message)
4
+ puts "About to execute command: #{command}"
5
+ success = system command
6
+ puts failure_message unless success
7
+ end
8
+ end
9
+ end
data/lib/dome/state.rb ADDED
@@ -0,0 +1,69 @@
1
+ module Dome
2
+ class State
3
+ include Dome::Shell
4
+
5
+ def initialize(environment)
6
+ @environment = environment
7
+ @state_bucket = "#{@environment.team}-tfstate-#{@environment.environment}"
8
+ @state_file = "#{@environment.environment}-terraform.tfstate"
9
+ end
10
+
11
+ def s3_client
12
+ @s3_client ||= Aws::S3::Client.new(@environment.aws_credentials)
13
+ end
14
+
15
+ def s3_bucket_exists?(bucket_name)
16
+ resp = s3_client.list_buckets
17
+ resp.buckets.each { |bucket| return true if bucket.name == bucket_name }
18
+ false
19
+ end
20
+
21
+ def create_bucket(name)
22
+ begin
23
+ s3_client.create_bucket(bucket: name, acl: 'private')
24
+ rescue Aws::S3::Errors::BucketAlreadyExists
25
+ raise 'The S3 bucket must be globally unique. See https://docs.aws.amazon.com/AmazonS3/latest/gsg/CreatingABucket.html'.colorize(:red)
26
+ end
27
+ end
28
+
29
+ def enable_bucket_versioning(bucket_name)
30
+ puts 'Enabling versioning on the S3 bucket - http://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html'.colorize(:green)
31
+ s3_client.put_bucket_versioning(bucket: bucket_name,
32
+ versioning_configuration: {
33
+ mfa_delete: 'Disabled',
34
+ status: 'Enabled'
35
+ })
36
+ end
37
+
38
+ def put_empty_object_in_bucket(bucket_name, key_name)
39
+ puts "Putting an empty object with key: #{key_name} into bucket: #{bucket_name}".colorize(:green)
40
+ s3_client.put_object(
41
+ bucket: bucket_name,
42
+ key: key_name,
43
+ body: ''
44
+ )
45
+ end
46
+
47
+ def create_remote_state_bucket(state_bucket, state_file)
48
+ create_bucket state_bucket
49
+ enable_bucket_versioning state_bucket
50
+ put_empty_object_in_bucket(state_bucket, state_file)
51
+ end
52
+
53
+ def s3_state
54
+ if s3_bucket_exists?(@state_bucket)
55
+ synchronise_s3_state
56
+ else
57
+ create_remote_state_bucket(@state_bucket, @state_file)
58
+ end
59
+ end
60
+
61
+ def synchronise_s3_state
62
+ puts 'Synchronising the remote S3 state...'
63
+ command = 'terraform remote config -backend=S3'\
64
+ " -backend-config='bucket=#{@state_bucket}' -backend-config='key=#{@state_file}'"
65
+ failure_message = 'Something went wrong when synchronising the S3 state.'
66
+ execute_command(command, failure_message)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,74 @@
1
+ module Dome
2
+ class Terraform
3
+ include Dome::Shell
4
+
5
+ attr_reader :state
6
+
7
+ def initialize
8
+ @environment = Dome::Environment.new
9
+ @state = Dome::State.new(@environment)
10
+ @plan_file = "plans/#{@environment.account}-#{@environment.environment}-plan.tf"
11
+ end
12
+
13
+ def validate_environment
14
+ environment_name = @environment.environment
15
+ account_name = @environment.account
16
+ @environment.invalid_account_message unless @environment.valid_account? account_name
17
+ @environment.invalid_environment_message unless @environment.valid_environment?(account_name, environment_name)
18
+ @environment.populate_aws_access_keys
19
+ end
20
+
21
+ def plan
22
+ delete_terraform_directory
23
+ delete_plan_file
24
+ install_terraform_modules
25
+ @state.synchronise_s3_state
26
+ create_plan
27
+ end
28
+
29
+ def plan_destroy
30
+ delete_terraform_directory
31
+ delete_plan_file
32
+ install_terraform_modules
33
+ @state.synchronise_s3_state
34
+ create_destroy_plan
35
+ end
36
+
37
+ def apply
38
+ command = "terraform apply #{@plan_file}"
39
+ failure_message = 'something went wrong when applying the TF plan'
40
+ execute_command(command, failure_message)
41
+ end
42
+
43
+ def create_plan
44
+ command = "terraform plan -module-depth=1 -refresh=true -out=#{@plan_file} -var-file=params/env.tfvars"
45
+ failure_message = 'something went wrong when creating the TF plan'
46
+ execute_command(command, failure_message)
47
+ end
48
+
49
+ def delete_terraform_directory
50
+ puts 'Deleting older terraform module cache dir ...'.colorize(:green)
51
+ terraform_directory = '.terraform'
52
+ puts "About to delete directory: #{terraform_directory}"
53
+ FileUtils.rm_rf '.terraform/'
54
+ end
55
+
56
+ def delete_plan_file
57
+ puts 'Deleting older terraform plan ...'.colorize(:green)
58
+ puts "About to delete: #{@plan_file}"
59
+ FileUtils.rm_f @plan_file
60
+ end
61
+
62
+ def create_destroy_plan
63
+ command = "terraform plan -destroy -module-depth=1 -out=#{@plan_file} -var-file=params/env.tfvars"
64
+ failure_message = 'something went wrong when creating the TF plan'
65
+ execute_command(command, failure_message)
66
+ end
67
+
68
+ def install_terraform_modules
69
+ command = 'terraform get -update=true'
70
+ failure_message = 'something went wrong when pulling remote TF modules'
71
+ execute_command(command, failure_message)
72
+ end
73
+ end
74
+ end
data/lib/dome/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dome
2
- VERSION = '1.0.2'
2
+ VERSION = '1.1.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: domed-city
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Snape
@@ -141,6 +141,9 @@ files:
141
141
  - dome.gemspec
142
142
  - lib/dome.rb
143
143
  - lib/dome/environment.rb
144
+ - lib/dome/helpers/shell.rb
145
+ - lib/dome/state.rb
146
+ - lib/dome/terraform.rb
144
147
  - lib/dome/version.rb
145
148
  homepage: https://github.com/ITV/dome
146
149
  licenses: []