convox_installer 1.0.8 → 3.0.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/.rubocop.yml +24 -2
- data/.vscode/settings.json +3 -2
- data/Gemfile +3 -2
- data/README.md +112 -39
- data/convox_installer.gemspec +18 -17
- data/examples/full_installation.rb +85 -78
- data/lib/convox/client.rb +278 -225
- data/lib/convox.rb +1 -1
- data/lib/convox_installer/config.rb +43 -30
- data/lib/convox_installer/requirements.rb +38 -18
- data/lib/convox_installer/version.rb +1 -1
- data/lib/convox_installer.rb +16 -10
- data/spec/lib/convox/client_spec.rb +92 -56
- data/spec/lib/convox_installer/config_spec.rb +140 -140
- data/spec/lib/convox_installer/requirements_spec.rb +62 -34
- data/spec/spec_helper.rb +1 -1
- data/terraform/elasticache.tf.erb +46 -0
- data/terraform/rds.tf.erb +45 -0
- data/terraform/s3_bucket.tf.erb +73 -0
- metadata +23 -19
data/lib/convox/client.rb
CHANGED
@@ -1,140 +1,184 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require 'logger'
|
4
|
+
require 'json'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'rubygems'
|
7
|
+
require 'os'
|
8
|
+
require 'erb'
|
6
9
|
|
7
10
|
module Convox
|
8
11
|
class Client
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
+
CONVOX_CONFIG_DIR = if OS.mac?
|
13
|
+
# Convox v3 moved this to ~/Library/Preferences/convox/ on Mac
|
14
|
+
File.expand_path('~/Library/Preferences/convox').freeze
|
15
|
+
else
|
16
|
+
File.expand_path('~/.convox').freeze
|
17
|
+
end
|
18
|
+
|
19
|
+
AUTH_FILE = File.join(CONVOX_CONFIG_DIR, 'auth')
|
20
|
+
CURRENT_FILE = File.join(CONVOX_CONFIG_DIR, 'current')
|
12
21
|
|
13
22
|
attr_accessor :logger, :config
|
14
23
|
|
24
|
+
def cli_version_string
|
25
|
+
return @cli_version_string if @cli_version_string
|
26
|
+
|
27
|
+
cli_version_string ||= `convox --version`
|
28
|
+
return unless $CHILD_STATUS.success?
|
29
|
+
|
30
|
+
@cli_version_string = cli_version_string.chomp
|
31
|
+
end
|
32
|
+
|
33
|
+
def cli_version
|
34
|
+
return unless cli_version_string.is_a?(String)
|
35
|
+
|
36
|
+
if cli_version_string.match?(/^\d+\.\d+\.\d+/)
|
37
|
+
@cli_version ||= Gem::Version.new(version_string)
|
38
|
+
end
|
39
|
+
@cli_version
|
40
|
+
end
|
41
|
+
|
42
|
+
def convox_2_cli?
|
43
|
+
return false unless cli_version_string.is_a?(String)
|
44
|
+
|
45
|
+
cli_version_string.match?(/^20\d+$/)
|
46
|
+
end
|
47
|
+
|
48
|
+
def convox_3_cli?
|
49
|
+
return false if !cli_version_string.is_a?(String) ||
|
50
|
+
convox_2_cli? ||
|
51
|
+
!cli_version_string.match?(/^\d+\.\d+\.\d+/)
|
52
|
+
|
53
|
+
cli_version = Gem::Version.new(cli_version_string)
|
54
|
+
cli_version >= Gem::Version.new('3.0.0') &&
|
55
|
+
cli_version < Gem::Version.new('4.0.0')
|
56
|
+
end
|
57
|
+
|
15
58
|
def auth
|
16
59
|
load_auth_from_file
|
17
60
|
end
|
18
61
|
|
19
62
|
def initialize(options = {})
|
20
|
-
@logger = Logger.new(
|
63
|
+
@logger = Logger.new($stdout)
|
21
64
|
logger.level = options[:log_level] || Logger::INFO
|
22
65
|
@config = options[:config] || {}
|
23
66
|
end
|
24
67
|
|
68
|
+
# Convox v3 creates a folder for each rack for the Terraform config
|
69
|
+
def rack_dir
|
70
|
+
stack_name = config.fetch(:stack_name)
|
71
|
+
File.join(CONVOX_CONFIG_DIR, 'racks', stack_name)
|
72
|
+
end
|
73
|
+
|
25
74
|
def backup_convox_host_and_rack
|
26
|
-
FileUtils.mkdir_p
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
35
|
-
end
|
75
|
+
FileUtils.mkdir_p CONVOX_CONFIG_DIR
|
76
|
+
|
77
|
+
path = File.join(CONVOX_CONFIG_DIR, 'current')
|
78
|
+
return unless File.exist?(path)
|
79
|
+
|
80
|
+
bak_file = "#{path}.bak"
|
81
|
+
logger.info "Moving existing #{path} to #{bak_file}..."
|
82
|
+
FileUtils.mv(path, bak_file)
|
36
83
|
end
|
37
84
|
|
38
85
|
def install_convox
|
39
|
-
require_config(%i[
|
86
|
+
require_config(%i[aws_region stack_name])
|
40
87
|
region = config.fetch(:aws_region)
|
41
88
|
stack_name = config.fetch(:stack_name)
|
42
89
|
|
43
90
|
if rack_already_installed?
|
44
|
-
logger.info "There is already a Convox
|
45
|
-
|
91
|
+
logger.info "There is already a Convox rack named #{stack_name}. Using this rack."
|
92
|
+
logger.debug 'If you need to start over, you can run: ' \
|
93
|
+
"convox rack uninstall #{stack_name} " \
|
94
|
+
'(Make sure you export AWS_ACCESS_KEY_ID and ' \
|
95
|
+
"AWS_SECRET_ACCESS_KEY first.)\n" \
|
96
|
+
"If this fails, you can try deleting the rack directory: rm -rf #{rack_dir}"
|
46
97
|
return true
|
47
98
|
end
|
48
99
|
|
49
100
|
require_config(%i[
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
101
|
+
aws_region
|
102
|
+
aws_access_key_id
|
103
|
+
aws_secret_access_key
|
104
|
+
stack_name
|
105
|
+
instance_type
|
106
|
+
])
|
56
107
|
|
57
108
|
logger.info "Installing Convox (#{stack_name})..."
|
58
109
|
|
59
110
|
env = {
|
60
|
-
|
61
|
-
|
62
|
-
|
111
|
+
'AWS_REGION' => region,
|
112
|
+
'AWS_ACCESS_KEY_ID' => config.fetch(:aws_access_key_id),
|
113
|
+
'AWS_SECRET_ACCESS_KEY' => config.fetch(:aws_secret_access_key)
|
63
114
|
}
|
64
|
-
command = %
|
65
|
-
|
66
|
-
"
|
67
|
-
"
|
115
|
+
command = %(rack install aws \
|
116
|
+
"#{config.fetch(:stack_name)}" \
|
117
|
+
"node_type=#{config.fetch(:instance_type)}" \
|
118
|
+
"region=#{config.fetch(:aws_region)}")
|
119
|
+
# us-east constantly has problems with the us-east-1c AZ:
|
120
|
+
# "Cannot create cluster 'ds-enterprise-cx3' because us-east-1c, the targeted
|
121
|
+
# availability zone, does not currently have sufficient capacity to support the cluster.
|
122
|
+
# Retry and choose from these availability zones:
|
123
|
+
# us-east-1a, us-east-1b, us-east-1d, us-east-1e, us-east-1f
|
124
|
+
if config.fetch(:aws_region) == 'us-east-1'
|
125
|
+
command += ' "availability_zones=us-east-1a,us-east-1b,us-east-1d,us-east-1e,us-east-1f"'
|
126
|
+
end
|
68
127
|
|
69
|
-
run_convox_command!(command, env)
|
128
|
+
run_convox_command!(command, env, rack_arg: false)
|
70
129
|
end
|
71
130
|
|
72
131
|
def rack_already_installed?
|
73
|
-
require_config(%i[
|
132
|
+
require_config(%i[aws_region stack_name])
|
74
133
|
|
75
134
|
return unless File.exist?(AUTH_FILE)
|
76
135
|
|
77
|
-
region = config.fetch(:aws_region)
|
136
|
+
# region = config.fetch(:aws_region)
|
78
137
|
stack_name = config.fetch(:stack_name)
|
138
|
+
return true if File.exist?(rack_dir)
|
79
139
|
|
80
|
-
auth.each do |
|
81
|
-
if
|
82
|
-
return true
|
83
|
-
end
|
140
|
+
auth.each do |rack_name, _password|
|
141
|
+
return true if rack_name == stack_name
|
84
142
|
end
|
85
143
|
false
|
86
144
|
end
|
87
145
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
region = config.fetch(:aws_region)
|
96
|
-
stack = config.fetch(:stack_name)
|
97
|
-
|
98
|
-
match_count = 0
|
99
|
-
matching_host = nil
|
100
|
-
auth.each do |host, password|
|
101
|
-
if host.match?(/^#{stack}-\d+\.#{region}\.elb\.amazonaws\.com$/)
|
102
|
-
matching_host = host
|
103
|
-
match_count += 1
|
104
|
-
end
|
105
|
-
end
|
146
|
+
# Auth for a detached rack is not saved in the auth file anymore.
|
147
|
+
# It can be found in the terraform state:
|
148
|
+
# ~/Library/Preferences/convox/racks/ds-enterprise-cx3/terraform.tfstate
|
149
|
+
# Under outputs/api/value. The API URL contains the convox username and API token as basic auth.
|
150
|
+
def validate_convox_rack_and_write_current!
|
151
|
+
require_config(%i[aws_region stack_name])
|
106
152
|
|
107
|
-
|
108
|
-
|
109
|
-
return matching_host
|
153
|
+
unless rack_already_installed?
|
154
|
+
raise "Could not find rack terraform directory at: #{rack_dir}"
|
110
155
|
end
|
111
156
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
117
|
-
error_message += "region: #{region}, stack: #{stack}"
|
118
|
-
raise error_message
|
157
|
+
# Tells the Convox CLI to use our terraform stack
|
158
|
+
stack_name = config.fetch(:stack_name)
|
159
|
+
write_current(stack_name)
|
160
|
+
stack_name
|
119
161
|
end
|
120
162
|
|
121
|
-
def
|
122
|
-
logger.debug "Setting convox
|
123
|
-
|
163
|
+
def write_current(rack_name)
|
164
|
+
logger.debug "Setting convox rack to #{rack_name} (in #{CURRENT_FILE})..."
|
165
|
+
current_hash = { name: rack_name, type: 'terraform' }
|
166
|
+
File.open(CURRENT_FILE, 'w') { |f| f.puts current_hash.to_json }
|
124
167
|
end
|
125
168
|
|
126
|
-
def
|
169
|
+
def validate_convox_rack_api!
|
127
170
|
require_config(%i[
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
logger.debug
|
171
|
+
aws_region
|
172
|
+
stack_name
|
173
|
+
instance_type
|
174
|
+
])
|
175
|
+
logger.debug 'Validating that convox rack has the correct attributes...'
|
176
|
+
# Convox 3 racks no longer return info about region or type. (These are blank strings.)
|
133
177
|
{
|
134
|
-
provider:
|
135
|
-
region: config.fetch(:aws_region),
|
136
|
-
type: config.fetch(:instance_type),
|
137
|
-
name: config.fetch(:stack_name)
|
178
|
+
provider: 'aws',
|
179
|
+
# region: config.fetch(:aws_region),
|
180
|
+
# type: config.fetch(:instance_type),
|
181
|
+
name: config.fetch(:stack_name)
|
138
182
|
}.each do |k, v|
|
139
183
|
convox_value = convox_rack_data[k.to_s]
|
140
184
|
if convox_value != v
|
@@ -142,15 +186,30 @@ module Convox
|
|
142
186
|
"but was: '#{convox_value}'"
|
143
187
|
end
|
144
188
|
end
|
145
|
-
logger.debug
|
189
|
+
logger.debug '=> Convox rack has the correct attributes.'
|
146
190
|
true
|
147
191
|
end
|
148
192
|
|
149
193
|
def convox_rack_data
|
150
194
|
@convox_rack_data ||= begin
|
151
|
-
logger.debug
|
152
|
-
|
153
|
-
|
195
|
+
logger.debug 'Fetching convox rack attributes...'
|
196
|
+
command = "convox api get /system --rack #{config.fetch(:stack_name)}"
|
197
|
+
logger.debug "+ #{command}"
|
198
|
+
# It can take a while for the API to be ready.
|
199
|
+
start_time = Time.now
|
200
|
+
convox_output = nil
|
201
|
+
loop do
|
202
|
+
convox_output = `#{command}`
|
203
|
+
break if $CHILD_STATUS.success?
|
204
|
+
|
205
|
+
if Time.now - start_time > 360
|
206
|
+
raise 'Could not connect to Convox rack API!'
|
207
|
+
end
|
208
|
+
|
209
|
+
logger.debug 'Waiting for Convox rack API to be ready... (can take a few minutes)'
|
210
|
+
sleep 5
|
211
|
+
end
|
212
|
+
|
154
213
|
JSON.parse(convox_output)
|
155
214
|
end
|
156
215
|
end
|
@@ -162,17 +221,19 @@ module Convox
|
|
162
221
|
app_name = config.fetch(:convox_app_name)
|
163
222
|
|
164
223
|
logger.info "Creating app: #{app_name}..."
|
165
|
-
logger.info
|
166
|
-
|
224
|
+
logger.info '=> Documentation: ' \
|
225
|
+
'https://docs.convox.com/reference/cli/apps/'
|
167
226
|
|
168
|
-
|
227
|
+
# NOTE: --wait flags were removed in Convox 3. It now waits by default.
|
228
|
+
run_convox_command! "apps create #{app_name}"
|
169
229
|
|
170
230
|
retries = 0
|
171
231
|
loop do
|
172
232
|
break if convox_app_exists?
|
233
|
+
|
173
234
|
if retries > 5
|
174
235
|
raise "Something went wrong while creating the #{app_name} app! " \
|
175
|
-
|
236
|
+
'(Please wait a few moments and then restart the installation script.)'
|
176
237
|
end
|
177
238
|
logger.info "Waiting for #{app_name} to be ready..."
|
178
239
|
sleep 3
|
@@ -183,9 +244,9 @@ module Convox
|
|
183
244
|
end
|
184
245
|
|
185
246
|
def set_default_app_for_directory!
|
186
|
-
logger.info
|
187
|
-
FileUtils.mkdir_p File.expand_path(
|
188
|
-
File.open(File.expand_path(
|
247
|
+
logger.info 'Setting default app in ./.convox/app...'
|
248
|
+
FileUtils.mkdir_p File.expand_path('./.convox')
|
249
|
+
File.open(File.expand_path('./.convox/app'), 'w') do |f|
|
189
250
|
f.puts config.fetch(:convox_app_name)
|
190
251
|
end
|
191
252
|
end
|
@@ -195,12 +256,12 @@ module Convox
|
|
195
256
|
app_name = config.fetch(:convox_app_name)
|
196
257
|
|
197
258
|
logger.debug "Looking for existing #{app_name} app..."
|
198
|
-
convox_output = `convox api get /apps`
|
199
|
-
raise
|
259
|
+
convox_output = `convox api get /apps --rack #{config.fetch(:stack_name)}`
|
260
|
+
raise 'convox command failed!' unless $CHILD_STATUS.success?
|
200
261
|
|
201
262
|
apps = JSON.parse(convox_output)
|
202
263
|
apps.each do |app|
|
203
|
-
if app[
|
264
|
+
if app['name'] == app_name
|
204
265
|
logger.debug "=> Found #{app_name} app."
|
205
266
|
return true
|
206
267
|
end
|
@@ -210,127 +271,117 @@ module Convox
|
|
210
271
|
end
|
211
272
|
|
212
273
|
# Create the s3 bucket, and also apply a CORS configuration
|
213
|
-
|
274
|
+
# Convox v3 update - They removed support for S3 resources, so we have to do
|
275
|
+
# in terraform now (which is actually pretty nice!)
|
276
|
+
def add_s3_bucket
|
214
277
|
require_config(%i[s3_bucket_name])
|
215
|
-
bucket_name = config.fetch(:s3_bucket_name)
|
216
|
-
if s3_bucket_exists?
|
217
|
-
logger.info "#{bucket_name} S3 bucket already exists!"
|
218
|
-
else
|
219
|
-
logger.info "Creating S3 bucket resource (#{bucket_name})..."
|
220
|
-
run_convox_command! "rack resources create s3 " \
|
221
|
-
"--name \"#{bucket_name}\" " \
|
222
|
-
"--wait"
|
223
|
-
|
224
|
-
retries = 0
|
225
|
-
loop do
|
226
|
-
break if s3_bucket_exists?
|
227
278
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
end
|
232
|
-
logger.debug "Waiting for S3 bucket to be ready..."
|
233
|
-
sleep 3
|
234
|
-
retries += 1
|
235
|
-
end
|
236
|
-
|
237
|
-
logger.debug "=> S3 bucket created!"
|
279
|
+
unless config.key? :s3_bucket_cors_rule
|
280
|
+
logger.debug 'No CORS rule provided in config: s3_bucket_cors_rule (optional)'
|
281
|
+
return
|
238
282
|
end
|
239
283
|
|
240
|
-
|
284
|
+
write_terraform_template('s3_bucket')
|
241
285
|
end
|
242
286
|
|
243
|
-
def
|
244
|
-
require_config(%i[
|
245
|
-
|
246
|
-
logger.debug "Looking up S3 bucket resource: #{bucket_name}"
|
247
|
-
`convox api get /resources/#{bucket_name} 2>/dev/null`
|
248
|
-
$?.success?
|
287
|
+
def add_rds_database
|
288
|
+
require_config(%i[database_username database_password])
|
289
|
+
write_terraform_template('rds')
|
249
290
|
end
|
250
291
|
|
251
|
-
def
|
252
|
-
|
253
|
-
|
254
|
-
bucket_name = config.fetch(:s3_bucket_name)
|
255
|
-
logger.debug "Fetching S3 bucket resource details for #{bucket_name}..."
|
256
|
-
|
257
|
-
response = `convox api get /resources/#{bucket_name}`
|
258
|
-
raise "convox command failed!" unless $?.success?
|
259
|
-
|
260
|
-
bucket_data = JSON.parse(response)
|
261
|
-
s3_url = bucket_data["url"]
|
262
|
-
matches = s3_url.match(
|
263
|
-
/^s3:\/\/(?<access_key_id>[^:]*):(?<secret_access_key>[^@]*)@(?<bucket_name>.*)$/
|
264
|
-
)
|
265
|
-
|
266
|
-
match_keys = %i[access_key_id secret_access_key bucket_name]
|
267
|
-
unless matches && match_keys.all? { |k| matches[k].present? }
|
268
|
-
raise "#{s3_url} is an invalid S3 URL!"
|
269
|
-
end
|
292
|
+
def add_elasticache_cluster
|
293
|
+
write_terraform_template('elasticache')
|
294
|
+
end
|
270
295
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
}
|
296
|
+
def write_terraform_template(name)
|
297
|
+
template_path = File.join(__dir__, "../../terraform/#{name}.tf.erb")
|
298
|
+
unless File.exist?(template_path)
|
299
|
+
raise "Could not find terraform template at: #{template_path}"
|
276
300
|
end
|
301
|
+
|
302
|
+
template = ERB.new(File.read(template_path))
|
303
|
+
template_output = template.result(binding)
|
304
|
+
|
305
|
+
tf_file_path = File.join(rack_dir, "#{name}.tf")
|
306
|
+
logger.debug "Writing terraform config to #{tf_file_path}..."
|
307
|
+
File.open(tf_file_path, 'w') { |f| f.puts template_output }
|
277
308
|
end
|
278
309
|
|
279
|
-
def
|
280
|
-
|
281
|
-
|
282
|
-
|
310
|
+
def apply_terraform_update!
|
311
|
+
logger.info 'Applying terraform update...'
|
312
|
+
command = if ENV['DEBUG_TERRAFORM']
|
313
|
+
'terraform plan'
|
314
|
+
else
|
315
|
+
'terraform apply -auto-approve'
|
316
|
+
end
|
317
|
+
logger.debug "+ #{command}"
|
283
318
|
|
284
|
-
|
285
|
-
|
286
|
-
|
319
|
+
env = {
|
320
|
+
'AWS_ACCESS_KEY_ID' => config.fetch(:aws_access_key_id),
|
321
|
+
'AWS_SECRET_ACCESS_KEY' => config.fetch(:aws_secret_access_key)
|
322
|
+
}
|
323
|
+
Dir.chdir(rack_dir) do
|
324
|
+
system env, command
|
325
|
+
raise 'terraform command failed!' unless $CHILD_STATUS.success?
|
287
326
|
end
|
288
|
-
|
289
|
-
|
290
|
-
bucket_name = s3_bucket_details[:name]
|
291
|
-
|
292
|
-
logger.debug "Looking up existing CORS policy for #{bucket_name}"
|
293
|
-
existing_cors_policy_string =
|
294
|
-
`AWS_ACCESS_KEY_ID=#{access_key_id} \
|
295
|
-
AWS_SECRET_ACCESS_KEY=#{secret_access_key} \
|
296
|
-
aws s3api get-bucket-cors --bucket #{bucket_name} 2>/dev/null`
|
297
|
-
if $?.success? && existing_cors_policy_string.present?
|
298
|
-
# Sort all the nested arrays so that the equality operator works
|
299
|
-
existing_cors_policy = JSON.parse(existing_cors_policy_string)
|
300
|
-
cors_policy_json = JSON.parse(cors_policy_string)
|
301
|
-
[existing_cors_policy, cors_policy_json].each do |policy_json|
|
302
|
-
if policy_json.is_a?(Hash) && policy_json["CORSRules"]
|
303
|
-
policy_json["CORSRules"].each do |rule|
|
304
|
-
rule["AllowedHeaders"].sort! if rule["AllowedHeaders"]
|
305
|
-
rule["AllowedMethods"].sort! if rule["AllowedMethods"]
|
306
|
-
rule["AllowedOrigins"].sort! if rule["AllowedOrigins"]
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
327
|
+
end
|
310
328
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
329
|
+
def terraform_state
|
330
|
+
tf_state_file = File.join(rack_dir, 'terraform.tfstate')
|
331
|
+
JSON.parse(File.read(tf_state_file))
|
332
|
+
end
|
333
|
+
|
334
|
+
def terraform_resource(resource_type, resource_name)
|
335
|
+
resource = terraform_state['resources'].find do |resource|
|
336
|
+
resource['type'] == resource_type && resource['name'] == resource_name
|
315
337
|
end
|
338
|
+
return resource if resource
|
316
339
|
|
317
|
-
|
318
|
-
|
340
|
+
raise "Could not find #{resource_type} resource named #{resource_name} in terraform state!"
|
341
|
+
end
|
342
|
+
|
343
|
+
def s3_bucket_details
|
344
|
+
require_config(%i[s3_bucket_name])
|
319
345
|
|
320
|
-
|
346
|
+
s3_bucket = terraform_resource('aws_s3_bucket', 'docs_s3_bucket')
|
347
|
+
bucket_attributes = s3_bucket['instances'][0]['attributes']
|
348
|
+
access_key = terraform_resource('aws_iam_access_key', 'docspring_user_access_key')
|
349
|
+
key_attributes = access_key['instances'][0]['attributes']
|
321
350
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
351
|
+
{
|
352
|
+
access_key_id: key_attributes['id'],
|
353
|
+
secret_access_key: key_attributes['secret'],
|
354
|
+
name: bucket_attributes['bucket']
|
355
|
+
}
|
356
|
+
end
|
357
|
+
|
358
|
+
def rds_details
|
359
|
+
require_config(%i[database_username database_password])
|
360
|
+
|
361
|
+
database = terraform_resource('aws_db_instance', 'rds_database')
|
362
|
+
database_attributes = database['instances'][0]['attributes']
|
363
|
+
|
364
|
+
username = database_attributes['username']
|
365
|
+
password = database_attributes['password']
|
366
|
+
endpoint = database_attributes['endpoint']
|
367
|
+
postgres_url = "postgres://#{username}:#{password}@#{endpoint}/app"
|
368
|
+
{
|
369
|
+
postgres_url: postgres_url
|
370
|
+
}
|
371
|
+
end
|
372
|
+
|
373
|
+
def elasticache_details
|
374
|
+
require_config(%i[s3_bucket_name])
|
375
|
+
|
376
|
+
# Just ensure that the bucket exists in the state
|
377
|
+
cluster = terraform_resource('aws_elasticache_cluster', 'elasticache_cluster')
|
378
|
+
cluster_attributes = cluster['instances'][0]['attributes']
|
379
|
+
cache_node = cluster_attributes['cache_nodes'][0]
|
380
|
+
redis_url = "redis://#{cache_node['address']}:#{cache_node['port']}/0"
|
381
|
+
|
382
|
+
{
|
383
|
+
redis_url: redis_url
|
384
|
+
}
|
334
385
|
end
|
335
386
|
|
336
387
|
def add_docker_registry!
|
@@ -338,52 +389,54 @@ module Convox
|
|
338
389
|
|
339
390
|
registry_url = config.fetch(:docker_registry_url)
|
340
391
|
|
341
|
-
logger.debug
|
342
|
-
registries_response = `convox api get /registries`
|
343
|
-
unless
|
344
|
-
raise
|
392
|
+
logger.debug 'Looking up existing Docker registries...'
|
393
|
+
registries_response = `convox api get /registries --rack #{config.fetch(:stack_name)}`
|
394
|
+
unless $CHILD_STATUS.success?
|
395
|
+
raise 'Something went wrong while fetching the list of registries!'
|
345
396
|
end
|
397
|
+
|
346
398
|
registries = JSON.parse(registries_response)
|
347
399
|
|
348
|
-
if registries.any? { |r| r[
|
400
|
+
if registries.any? { |r| r['server'] == registry_url }
|
349
401
|
logger.debug "=> Docker Registry already exists: #{registry_url}"
|
350
402
|
return true
|
351
403
|
end
|
352
404
|
|
353
405
|
logger.info "Adding Docker Registry: #{registry_url}..."
|
354
|
-
logger.info
|
355
|
-
|
406
|
+
logger.info '=> Documentation: ' \
|
407
|
+
'https://docs.convox.com/configuration/private-registries/'
|
356
408
|
|
357
409
|
`convox registries add "#{registry_url}" \
|
358
410
|
"#{config.fetch(:docker_registry_username)}" \
|
359
|
-
"#{config.fetch(:docker_registry_password)}"
|
360
|
-
|
361
|
-
|
362
|
-
|
411
|
+
"#{config.fetch(:docker_registry_password)}" \
|
412
|
+
--rack #{config.fetch(:stack_name)}`
|
413
|
+
return if $CHILD_STATUS.success?
|
414
|
+
|
415
|
+
raise "Something went wrong while adding the #{registry_url} registry!"
|
363
416
|
end
|
364
417
|
|
365
418
|
def default_service_domain_name
|
366
|
-
require_config(%i[convox_app_name
|
367
|
-
|
368
|
-
@default_service_domain_name ||= begin
|
369
|
-
convox_domain = convox_rack_data["domain"]
|
370
|
-
elb_name_and_region = convox_domain[/([^\.]*\.[^\.]*)\..*/, 1]
|
371
|
-
unless elb_name_and_region.present?
|
372
|
-
raise "Something went wrong while parsing the ELB name and region! " \
|
373
|
-
"(#{elb_name_and_region})"
|
374
|
-
end
|
375
|
-
app = config.fetch(:convox_app_name)
|
376
|
-
service = config.fetch(:default_service)
|
419
|
+
require_config(%i[convox_app_name])
|
377
420
|
|
378
|
-
|
379
|
-
|
380
|
-
|
421
|
+
app_name = config.fetch(:convox_app_name)
|
422
|
+
default_service = config[:default_service] || 'web'
|
423
|
+
|
424
|
+
convox_api_url = terraform_state['outputs']['api']['value']
|
425
|
+
convox_router_host = convox_api_url.split('@').last.sub(/^api\./, '')
|
426
|
+
|
427
|
+
[default_service, app_name, convox_router_host].join('.').downcase
|
381
428
|
end
|
382
429
|
|
383
|
-
def run_convox_command!(cmd, env = {})
|
430
|
+
def run_convox_command!(cmd, env = {}, rack_arg: true)
|
431
|
+
# Always include the rack as an argument, to
|
432
|
+
# make sure that 'convox switch' doesn't affect any commands
|
384
433
|
command = "convox #{cmd}"
|
434
|
+
if rack_arg
|
435
|
+
command = "#{command} --rack #{config.fetch(:stack_name)}"
|
436
|
+
end
|
437
|
+
logger.debug "+ #{command}"
|
385
438
|
system env, command
|
386
|
-
raise "Error running: #{command}" unless
|
439
|
+
raise "Error running: #{command}" unless $CHILD_STATUS.success?
|
387
440
|
end
|
388
441
|
|
389
442
|
private
|
@@ -393,7 +446,7 @@ module Convox
|
|
393
446
|
|
394
447
|
begin
|
395
448
|
JSON.parse(File.read(AUTH_FILE))
|
396
|
-
rescue
|
449
|
+
rescue StandardError
|
397
450
|
{}
|
398
451
|
end
|
399
452
|
end
|
data/lib/convox.rb
CHANGED