-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfull_installation.rb
executable file
·276 lines (244 loc) · 9.68 KB
/
full_installation.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#!/usr/bin/env ruby
# frozen_string_literal: true
# Use Bundler inline for your real installation script
# require "bundler/inline"
# gemfile do
# source "https://rubygems.org"
# gem "convox_installer"
# end
require 'English'
$LOAD_PATH << File.expand_path('../lib', __dir__)
require 'pry-byebug'
require 'convox_installer'
include ConvoxInstaller
@log_level = Logger::DEBUG
MINIMAL_HEALTH_CHECK_PATH = '/health/site'
COMPLETE_HEALTH_CHECK_PATH = '/health'
S3_BUCKET_CORS_RULE = <<-TERRAFORM
cors_rule {
allowed_headers = ["Authorization", "cache-control", "x-requested-with"]
allowed_methods = ["PUT", "POST", "GET"]
allowed_origins = ["*"]
expose_headers = []
max_age_seconds = 3000
}
TERRAFORM
@prompts = ConvoxInstaller::Config::DEFAULT_PROMPTS + [
{
section: 'Docker Registry Authentication',
info: "You should have received authentication details for the Docker Registry\n" \
'via email. If not, please contact [email protected]'
},
{
key: :docker_registry_url,
title: 'Docker Registry URL',
value: '691950705664.dkr.ecr.us-east-1.amazonaws.com'
},
{
key: :docker_registry_username,
title: 'Docker Registry Username'
},
{
key: :docker_registry_password,
title: 'Docker Registry Password'
},
{
key: :convox_app_name,
title: 'Convox App Name',
value: 'convox-app'
},
{
key: :default_service,
title: 'Default Convox Service (for domain)',
value: 'web',
hidden: true
},
{
key: :admin_email,
title: 'Admin User Email',
prompt: 'Please enter the email address you would like to use ' \
'for the default admin user',
default: '[email protected]'
},
{
key: :admin_password,
title: 'Admin User Password',
value: -> { SecureRandom.hex(8) }
},
{
key: :s3_bucket_name,
title: 'S3 Bucket for Uploads',
value: -> { "app-uploads-#{SecureRandom.hex(4)}" }
},
{
key: :s3_bucket_cors_rule,
value: S3_BUCKET_CORS_RULE,
hidden: true
},
{
key: :database_username,
value: 'example_app',
hidden: true
},
{
key: :database_password,
value: -> { SecureRandom.hex(16) },
hidden: true
}
]
ensure_requirements!
config = prompt_for_config
backup_convox_host_and_rack
install_convox
validate_convox_rack_and_write_current!
validate_convox_rack_api!
create_convox_app!
set_default_app_for_directory!
add_docker_registry!
add_s3_bucket
add_rds_database
add_elasticache_cluster
apply_terraform_update!
unless config[:sidekiq_cloudwatch_iam_credentials]
logger.info "Looking up IAM user for Sidekiq CloudWatch metrics (#{config.fetch(:sidekiq_cloudwatch_iam_username)})..."
aws_cli_credentials = "AWS_ACCESS_KEY_ID=#{config.fetch(:aws_access_key_id)} " \
"AWS_SECRET_ACCESS_KEY=#{config.fetch(:aws_secret_access_key)}"
`#{aws_cli_credentials} aws iam get-user \
--user-name #{config.fetch(:sidekiq_cloudwatch_iam_username)} 2>/dev/null`
unless $CHILD_STATUS.success?
logger.info "Creating IAM user: #{config.fetch(:sidekiq_cloudwatch_iam_username)} with CloudWatchAgentServerPolicy..."
# IAM user needs the CloudWatchAgentServerPolicy policy
`#{aws_cli_credentials} aws iam create-user \
--user-name #{config.fetch(:sidekiq_cloudwatch_iam_username)}`
unless $CHILD_STATUS.success?
raise "Sorry, something went wrong while creating the #{config.fetch(:sidekiq_cloudwatch_iam_username)} IAM user!"
end
logger.info 'Attaching CloudWatchAgentServerPolicy...'
`#{aws_cli_credentials} aws iam attach-user-policy \
--user-name #{config.fetch(:sidekiq_cloudwatch_iam_username)} \
--policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy`
unless $CHILD_STATUS.success?
raise 'Sorry, something went wrong while attaching the CloudWatchAgentServerPolicy policy!'
end
end
logger.info "Creating IAM access token for #{config.fetch(:sidekiq_cloudwatch_iam_username)}..."
create_access_key_output_json = `#{aws_cli_credentials} aws iam create-access-key \
--user-name #{config.fetch(:sidekiq_cloudwatch_iam_username)}`
unless $CHILD_STATUS.success?
raise "Sorry, something went wrong while creating the access token for #{config.fetch(:sidekiq_cloudwatch_iam_username)}!"
end
config[:sidekiq_cloudwatch_iam_credentials] =
JSON.parse(create_access_key_output_json)['AccessKey']
# Save credentials in the cached config file
File.open('./.installer_config.json', 'w') do |f|
f.puts(JSON.pretty_generate(config: config))
end
end
logger.info "======> Default domain: #{default_service_domain_name}"
logger.info ' You can use this as a CNAME record after configuring a domain in convox.yml'
logger.info ' (Note: SSL will be configured automatically.)'
logger.info 'Checking convox env...'
convox_env_output = `convox env --rack #{config.fetch(:stack_name)}`
raise 'Error running convox env' unless $CHILD_STATUS.success?
convox_env = begin
convox_env_output.split("\n").map { |s| s.split('=', 2) }.to_h
rescue StandardError
{}
end
# Add database and redis
desired_env = {
'DATABASE_URL' => rds_details[:postgres_url],
'REDIS_URL' => elasticache_details[:redis_url],
'AWS_ACCESS_KEY_ID' => s3_bucket_details.fetch(:access_key_id),
'AWS_ACCESS_KEY_SECRET' => s3_bucket_details.fetch(:secret_access_key),
'AWS_UPLOADS_S3_BUCKET' => s3_bucket_details.fetch(:name),
'AWS_UPLOADS_S3_REGION' => config.fetch(:aws_region),
'SECRET_KEY_BASE' => config.fetch(:secret_key_base),
'SUBMISSION_DATA_ENCRYPTION_KEY' => config.fetch(:data_encryption_key),
'ADMIN_NAME' => 'Admin',
'ADMIN_EMAIL' => config.fetch(:admin_email),
'ADMIN_PASSWORD' => config.fetch(:admin_password),
'DOCSPRING_LICENSE' => config.fetch(:docspring_license),
'DISABLE_EMAILS' => 'true'
}
# Only set health check path and domain if it's not already present.
desired_env['HEALTH_CHECK_PATH'] = MINIMAL_HEALTH_CHECK_PATH if convox_env['HEALTH_CHECK_PATH'].nil?
desired_env['DOMAIN_NAME'] = default_service_domain_name if convox_env['DOMAIN_NAME'].nil?
updated_keys = []
desired_env.each_key do |key|
updated_keys << key if convox_env[key] != desired_env[key]
end
if updated_keys.none?
logger.info '=> Convox env has already been configured.'
logger.info ' You can update this by running: convox env set ...'
else
logger.info "=> Setting environment variables to configure DocSpring: #{updated_keys.join(', ')}"
env_command_params = desired_env.map { |k, v| "#{k}=\"#{v}\"" }.join(' ')
run_convox_command! "env set #{env_command_params}"
end
# If we are already using the complete health check path, then we can skip the rest.
if convox_env['HEALTH_CHECK_PATH'] == COMPLETE_HEALTH_CHECK_PATH
logger.info 'DocSpring is already set up and running.'
else
logger.info 'Checking convox processes...'
convox_processes = `convox ps --rack #{config.fetch(:stack_name)}`
if convox_processes.include?('web') && convox_processes.include?('worker')
logger.info '=> Initial deploy for DocSpring Enterprise is already done.'
else
logger.info '=> Initial deploy for DocSpring Enterprise...'
logger.info '-----> Documentation: https://docs.convox.com/deployment/deploying-changes/'
run_convox_command! 'deploy'
end
logger.info '=> Ensuring the DocSpring application container can boot successfully...'
run_convox_command! 'run command ./bin/smoke_test'
logger.info '=> Setting up the DocSpring database...'
run_convox_command! 'run command rake db:create db:migrate db:seed'
logger.info '=> Checking Postgres, Redis, Rails cache, S3 uploads, Sidekiq job processing...'
run_convox_command! 'run command rake tests:health_check'
logger.info '=> Updating the health check path to include database tests...'
run_convox_command! "env set --promote HEALTH_CHECK_PATH=#{COMPLETE_HEALTH_CHECK_PATH}"
end
puts
logger.info 'All done!'
puts
puts "You can now visit #{default_service_domain_name} and sign in with:"
puts
puts " Email: #{config.fetch(:admin_email)}"
puts " Password: #{config.fetch(:admin_password)}"
puts
puts 'You can configure a custom domain name, auto-scaling, and other options in convox.yml.'
puts 'To deploy your changes, run: convox deploy --wait'
puts
puts "IMPORTANT: You should be very careful with the 'resources' section in convox.yml."
puts 'If you remove, rename, or change these resources, then Convox will delete'
puts 'your database. This will result in downtime and a loss of data.'
puts 'To prevent this from happening, you can sign into your AWS account,'
puts 'visit the RDS and ElastiCache services, and enable "Termination Protection"'
puts 'for your database resources.'
puts
puts 'To learn more about the convox CLI, run: convox --help'
puts
puts ' * View the Convox documentation: https://docs.convox.com/'
puts ' * View the DocSpring documentation: https://docspring.com/docs/'
puts
puts
puts 'To completely uninstall Convox and DocSpring from your AWS account,'
puts 'run the following steps (in this order):'
puts
puts ' 1) Disable "Termination Protection" for any resource where it was enabled.'
puts
puts " 2) Delete all files from the #{s3_bucket_details.fetch(:name)} S3 bucket:"
puts
puts " export AWS_ACCESS_KEY_ID=#{config.fetch(:aws_access_key_id)}"
puts " export AWS_SECRET_ACCESS_KEY=#{config.fetch(:aws_secret_access_key)}"
puts " aws s3 rm s3://#{s3_bucket_details.fetch(:name)} --recursive"
puts
puts ' 3) Uninstall Convox (deletes all AWS resources via Terraform):'
puts
puts " convox rack uninstall #{config.fetch(:stack_name)}"
puts
puts
puts '------------------------------------------------------------------------------------'
puts 'Thank you for using DocSpring! Please contact [email protected] if you need any help.'
puts '------------------------------------------------------------------------------------'
puts