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.
data/lib/convox/client.rb CHANGED
@@ -1,140 +1,184 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "logger"
4
- require "json"
5
- require "fileutils"
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
- CONVOX_DIR = File.expand_path("~/.convox").freeze
10
- AUTH_FILE = File.join(CONVOX_DIR, "auth")
11
- HOST_FILE = File.join(CONVOX_DIR, "host")
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(STDOUT)
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 CONVOX_DIR
27
-
28
- %w[host rack].each do |f|
29
- path = File.join(CONVOX_DIR, f)
30
- if File.exist?(path)
31
- bak_file = "#{path}.bak"
32
- logger.info "Moving existing #{path} to #{bak_file}..."
33
- FileUtils.mv(path, bak_file)
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[ aws_region stack_name ])
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 stack named #{stack_name} " \
45
- "in the #{region} AWS region. Using this rack. "
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
- aws_region
51
- aws_access_key_id
52
- aws_secret_access_key
53
- stack_name
54
- instance_type
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
- "AWS_REGION" => region,
61
- "AWS_ACCESS_KEY_ID" => config.fetch(:aws_access_key_id),
62
- "AWS_SECRET_ACCESS_KEY" => config.fetch(:aws_secret_access_key),
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 = %Q{rack install aws \
65
- --name "#{config.fetch(:stack_name)}" \
66
- "InstanceType=#{config.fetch(:instance_type)}" \
67
- "BuildInstance="}
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[ aws_region stack_name ])
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 |host, password|
81
- if host.match?(/^#{stack_name}-\d+\.#{region}\.elb\.amazonaws\.com$/)
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
- def validate_convox_auth_and_set_host!
89
- require_config(%i[ aws_region stack_name ])
90
-
91
- unless File.exist?(AUTH_FILE)
92
- raise "Could not find auth file at #{AUTH_FILE}!"
93
- end
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
- if match_count == 1
108
- set_host(matching_host)
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
- if match_count > 1
113
- error_message = "Found multiple matching hosts for "
114
- else
115
- error_message = "Could not find matching authentication for "
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 set_host(host)
122
- logger.debug "Setting convox host to #{host} (in #{HOST_FILE})..."
123
- File.open(HOST_FILE, "w") { |f| f.puts host }
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 validate_convox_rack!
169
+ def validate_convox_rack_api!
127
170
  require_config(%i[
128
- aws_region
129
- stack_name
130
- instance_type
131
- ])
132
- logger.debug "Validating that convox rack has the correct attributes..."
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: "aws",
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 "=> Convox rack has the correct attributes."
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 "Fetching convox rack attributes..."
152
- convox_output = `convox api get /system`
153
- raise "convox command failed!" unless $?.success?
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 "=> Documentation: " \
166
- "https://docs.convox.com/deployment/creating-an-application"
224
+ logger.info '=> Documentation: ' \
225
+ 'https://docs.convox.com/reference/cli/apps/'
167
226
 
168
- run_convox_command! "apps create #{app_name} --wait"
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
- "(Please wait a few moments and then restart the installation script.)"
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 "Setting default app in ./.convox/app..."
187
- FileUtils.mkdir_p File.expand_path("./.convox")
188
- File.open(File.expand_path("./.convox/app"), "w") do |f|
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 "convox command failed!" unless $?.success?
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["name"] == app_name
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
- def create_s3_bucket!
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
- if retries > 10
229
- raise "Something went wrong while creating the #{bucket_name} S3 bucket! " \
230
- "(Please wait a few moments and then restart the installation script.)"
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
- set_s3_bucket_cors_policy
284
+ write_terraform_template('s3_bucket')
241
285
  end
242
286
 
243
- def s3_bucket_exists?
244
- require_config(%i[s3_bucket_name])
245
- bucket_name = config.fetch(:s3_bucket_name)
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 s3_bucket_details
252
- require_config(%i[s3_bucket_name])
253
- @s3_bucket_details ||= begin
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
- access_key_id: matches[:access_key_id],
273
- secret_access_key: matches[:secret_access_key],
274
- name: matches[:bucket_name],
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 set_s3_bucket_cors_policy
280
- require_config(%i[aws_access_key_id aws_secret_access_key])
281
- access_key_id = config.fetch(:aws_access_key_id)
282
- secret_access_key = config.fetch(:aws_secret_access_key)
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
- unless config.key? :s3_bucket_cors_policy
285
- logger.debug "No CORS policy provided in config: s3_bucket_cors_policy"
286
- return
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
- cors_policy_string = config.fetch(:s3_bucket_cors_policy)
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
- if existing_cors_policy == cors_policy_json
312
- logger.debug "=> CORS policy is already up to date for #{bucket_name}."
313
- return
314
- end
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
- begin
318
- logger.info "Setting CORS policy for #{bucket_name}..."
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
- File.open("cors-policy.json", "w") { |f| f.puts cors_policy_string }
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
- `AWS_ACCESS_KEY_ID=#{access_key_id} \
323
- AWS_SECRET_ACCESS_KEY=#{secret_access_key} \
324
- aws s3api put-bucket-cors \
325
- --bucket #{bucket_name} \
326
- --cors-configuration "file://cors-policy.json"`
327
- unless $?.success?
328
- raise "Something went wrong while setting the S3 bucket CORS policy!"
329
- end
330
- logger.info "=> Successfully set CORS policy for #{bucket_name}."
331
- ensure
332
- FileUtils.rm_f "cors-policy.json"
333
- end
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 "Looking up existing Docker registries..."
342
- registries_response = `convox api get /registries`
343
- unless $?.success?
344
- raise "Something went wrong while fetching the list of registries!"
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["server"] == registry_url }
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 "=> Documentation: " \
355
- "https://docs.convox.com/deployment/private-registries"
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
- unless $?.success?
361
- raise "Something went wrong while adding the #{registry_url} registry!"
362
- end
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 default_service])
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
- # Need to return downcase host so that `config.hosts` works with Rails applications
379
- "#{app}-#{service}.#{elb_name_and_region}.convox.site".downcase
380
- end
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 $?.success?
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
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "convox/client"
3
+ require 'convox/client'