domed-city 1.0.2 → 1.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 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: []