aptible-cli 0.26.5 → 0.26.7
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/Gemfile.lock +1 -1
- data/README.md +1 -0
- data/lib/aptible/cli/helpers/app.rb +11 -0
- data/lib/aptible/cli/helpers/vhost/option_set_builder.rb +154 -1
- data/lib/aptible/cli/helpers/vhost.rb +5 -2
- data/lib/aptible/cli/renderer/text.rb +3 -1
- data/lib/aptible/cli/resource_formatter.rb +24 -6
- data/lib/aptible/cli/subcommands/apps.rb +28 -1
- data/lib/aptible/cli/subcommands/endpoints.rb +27 -9
- data/lib/aptible/cli/version.rb +1 -1
- data/spec/aptible/cli/helpers/vhost/option_set_builder_spec.rb +94 -0
- data/spec/aptible/cli/resource_formatter_spec.rb +3 -0
- data/spec/aptible/cli/subcommands/apps_spec.rb +202 -82
- data/spec/aptible/cli/subcommands/endpoints_spec.rb +178 -4
- data/spec/fabricators/app_fabricator.rb +6 -0
- data/spec/fabricators/setting_fabricator.rb +8 -0
- data/spec/fabricators/vhost_fabricator.rb +2 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d11060c760d01bcedf1163619f8412205f95dec58b2fe1f40f58378854e7aefb
|
|
4
|
+
data.tar.gz: a1b8645bb717f084310500ac86e8e1d92c14ac78cc5883019c7de29a737fc1be
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: edc9d96e02224c1d9520bc382a5415c9425bdc108ff045d6f55d87aca2376985c99749a82d2496c37a18c9066da704bb2625edde5bb00ef870e95e2bd4e3a948
|
|
7
|
+
data.tar.gz: 91c07735699ab92a1ca5f0facb86835a0271e3a5486f8965b45d2dd4f9579268edb240ba3be6f0682c3f341db31fb3e207500ef87284704fedcde301786b839a
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -31,6 +31,7 @@ Commands:
|
|
|
31
31
|
aptible apps:deprovision [--app APP] # Deprovision an app
|
|
32
32
|
aptible apps:rename OLD_HANDLE NEW_HANDLE [--environment ENVIRONMENT_HANDLE] # Rename an app handle. In order for the new app handle to appear in log drain and metric drain destinations, you must restart the app.
|
|
33
33
|
aptible apps:scale [--app APP] SERVICE [--container-count COUNT] [--container-size SIZE_MB] [--container-profile PROFILE] # Scale a service
|
|
34
|
+
aptible apps:settings HANDLE # Display deployment related settings for an app
|
|
34
35
|
aptible backup:list DB_HANDLE # List backups for a database
|
|
35
36
|
aptible backup:orphaned # List backups associated with deprovisioned databases
|
|
36
37
|
aptible backup:purge BACKUP_ID # Permanently delete a backup and any copies of it
|
|
@@ -209,6 +209,17 @@ module Aptible
|
|
|
209
209
|
)
|
|
210
210
|
end
|
|
211
211
|
|
|
212
|
+
def current_setting(app)
|
|
213
|
+
setting_link = app.links['current_setting']
|
|
214
|
+
return unless setting_link
|
|
215
|
+
|
|
216
|
+
Aptible::Api::Setting.find_by_url(
|
|
217
|
+
setting_link.href,
|
|
218
|
+
token: fetch_token,
|
|
219
|
+
headers: { 'Prefer' => 'no_sensitive_extras=false' }
|
|
220
|
+
)
|
|
221
|
+
end
|
|
222
|
+
|
|
212
223
|
private
|
|
213
224
|
|
|
214
225
|
def handle_strategies
|
|
@@ -14,6 +14,35 @@ module Aptible
|
|
|
14
14
|
alb
|
|
15
15
|
).freeze
|
|
16
16
|
|
|
17
|
+
SSL_PROTOCOL_VALUES = [
|
|
18
|
+
'TLSv1 TLSv1.1 TLSv1.2',
|
|
19
|
+
'TLSv1 TLSv1.1 TLSv1.2 PFS',
|
|
20
|
+
'TLSv1.1 TLSv1.2',
|
|
21
|
+
'TLSv1.1 TLSv1.2 PFS',
|
|
22
|
+
'TLSv1.2',
|
|
23
|
+
'TLSv1.2 PFS',
|
|
24
|
+
'TLSv1.2 PFS TLSv1.3',
|
|
25
|
+
'TLSv1.3'
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
ALB_PROTOCOL_VALUES = SSL_PROTOCOL_VALUES
|
|
29
|
+
|
|
30
|
+
ELB_PROTOCOL_VALUES =
|
|
31
|
+
SSL_PROTOCOL_VALUES.reject { |v| v.include?(' PFS') }.freeze
|
|
32
|
+
|
|
33
|
+
SSL_PROTOCOL_ALB_DESC = (
|
|
34
|
+
'Specify the allowed SSL protocols. Valid options: ' +
|
|
35
|
+
ALB_PROTOCOL_VALUES.map { |v| "\"#{v}\"" }.join(', ') +
|
|
36
|
+
'. PFS options require an HTTPS (ALB) endpoint. ' \
|
|
37
|
+
'Use "default" to reset to the platform default'
|
|
38
|
+
).freeze
|
|
39
|
+
|
|
40
|
+
SSL_PROTOCOL_ELB_DESC = (
|
|
41
|
+
'Specify the allowed SSL protocols. Valid options: ' +
|
|
42
|
+
ELB_PROTOCOL_VALUES.map { |v| "\"#{v}\"" }.join(', ') +
|
|
43
|
+
'. Use "default" to reset to the platform default'
|
|
44
|
+
).freeze
|
|
45
|
+
|
|
17
46
|
def initialize(&block)
|
|
18
47
|
FLAGS.each { |f| instance_variable_set("@#{f}", false) }
|
|
19
48
|
instance_exec(&block) if block
|
|
@@ -53,6 +82,14 @@ module Aptible
|
|
|
53
82
|
)
|
|
54
83
|
end
|
|
55
84
|
|
|
85
|
+
option(
|
|
86
|
+
:idle_timeout,
|
|
87
|
+
type: :string,
|
|
88
|
+
desc: 'Timeout (seconds) to enforce idle timeouts while ' \
|
|
89
|
+
'sending and receiving responses. Use "default" to ' \
|
|
90
|
+
'reset to the platform default'
|
|
91
|
+
)
|
|
92
|
+
|
|
56
93
|
if builder.alb?
|
|
57
94
|
option(
|
|
58
95
|
:load_balancing_algorithm_type,
|
|
@@ -69,6 +106,50 @@ module Aptible
|
|
|
69
106
|
desc: "Share this Endpoint's load balancer with other " \
|
|
70
107
|
'Endpoints'
|
|
71
108
|
)
|
|
109
|
+
|
|
110
|
+
option(
|
|
111
|
+
:force_ssl,
|
|
112
|
+
type: :boolean,
|
|
113
|
+
desc: 'Redirect all HTTP requests to HTTPS, and ' \
|
|
114
|
+
'enable the Strict-Transport-Security header (HSTS)'
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
option(
|
|
118
|
+
:maintenance_page_url,
|
|
119
|
+
type: :string,
|
|
120
|
+
desc: 'The URL of a maintenance page to cache and serve ' \
|
|
121
|
+
'when requests time out, or your app is unhealthy. ' \
|
|
122
|
+
'Use "default" to reset to the platform default'
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
option(
|
|
126
|
+
:release_healthcheck_timeout,
|
|
127
|
+
type: :string,
|
|
128
|
+
desc: 'Timeout (seconds) to wait for your app to ' \
|
|
129
|
+
'respond to a release health check. Use "default" ' \
|
|
130
|
+
'to reset to the platform default'
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
option(
|
|
134
|
+
:show_elb_healthchecks,
|
|
135
|
+
type: :boolean,
|
|
136
|
+
desc: 'Show all runtime health check requets in the ' \
|
|
137
|
+
"endpoint's logs"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
option(
|
|
141
|
+
:ssl_protocols_override,
|
|
142
|
+
type: :string,
|
|
143
|
+
desc: SSL_PROTOCOL_ALB_DESC
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
option(
|
|
147
|
+
:strict_health_checks,
|
|
148
|
+
type: :boolean,
|
|
149
|
+
desc: 'Require containers to respond to health checks ' \
|
|
150
|
+
'with a 200 OK HTTP response.'
|
|
151
|
+
)
|
|
152
|
+
|
|
72
153
|
end
|
|
73
154
|
end
|
|
74
155
|
|
|
@@ -128,6 +209,27 @@ module Aptible
|
|
|
128
209
|
desc: 'The fingerprint of an existing Certificate to use ' \
|
|
129
210
|
'on this Endpoint'
|
|
130
211
|
)
|
|
212
|
+
|
|
213
|
+
unless builder.alb?
|
|
214
|
+
option(
|
|
215
|
+
:ssl_protocols_override,
|
|
216
|
+
type: :string,
|
|
217
|
+
desc: SSL_PROTOCOL_ELB_DESC
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
option(
|
|
221
|
+
:ssl_ciphers_override,
|
|
222
|
+
type: :string,
|
|
223
|
+
desc: 'Specify the allowed SSL ciphers. ' \
|
|
224
|
+
'Use "default" to reset to the platform default'
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
option(
|
|
228
|
+
:disable_weak_cipher_suites,
|
|
229
|
+
type: :boolean,
|
|
230
|
+
desc: 'Block the SSLv3 protocol and RC4 ciphers'
|
|
231
|
+
)
|
|
232
|
+
end
|
|
131
233
|
end
|
|
132
234
|
end
|
|
133
235
|
end
|
|
@@ -137,6 +239,7 @@ module Aptible
|
|
|
137
239
|
verify_option_conflicts(options)
|
|
138
240
|
|
|
139
241
|
params = {}
|
|
242
|
+
settings = {}
|
|
140
243
|
|
|
141
244
|
params[:ip_whitelist] = options.delete(:ip_whitelist) do
|
|
142
245
|
create? ? [] : nil
|
|
@@ -203,6 +306,56 @@ module Aptible
|
|
|
203
306
|
params[:shared] = options.delete(:shared)
|
|
204
307
|
end
|
|
205
308
|
|
|
309
|
+
if (proto = options[:ssl_protocols_override]) &&
|
|
310
|
+
proto != 'default'
|
|
311
|
+
unless ALB_PROTOCOL_VALUES.include?(proto)
|
|
312
|
+
raise Thor::Error,
|
|
313
|
+
"Invalid --ssl-protocols-override: \"#{proto}\". " \
|
|
314
|
+
"Valid options are: #{ALB_PROTOCOL_VALUES.join(', ')}"
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
if !ELB_PROTOCOL_VALUES.include?(proto) && !alb?
|
|
318
|
+
raise Thor::Error,
|
|
319
|
+
"Invalid --ssl-protocols-override: \"#{proto}\". " \
|
|
320
|
+
'PFS options are only valid for an HTTPS (ALB) endpoint. ' \
|
|
321
|
+
"Valid options are: #{ELB_PROTOCOL_VALUES.join(', ')}"
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
vhost_settings = %i(
|
|
326
|
+
idle_timeout
|
|
327
|
+
maintenance_page_url
|
|
328
|
+
release_healthcheck_timeout
|
|
329
|
+
ssl_protocols_override
|
|
330
|
+
ssl_ciphers_override
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
vhost_settings.each do |key|
|
|
334
|
+
val = options.delete(key)
|
|
335
|
+
next if val.nil?
|
|
336
|
+
|
|
337
|
+
settings[key.to_s.upcase] = case val
|
|
338
|
+
when 'default'
|
|
339
|
+
''
|
|
340
|
+
else
|
|
341
|
+
val
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
boolean_vhost_settings = %i(
|
|
346
|
+
force_ssl
|
|
347
|
+
show_elb_healthchecks
|
|
348
|
+
strict_health_checks
|
|
349
|
+
disable_weak_cipher_suites
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
boolean_vhost_settings.each do |key|
|
|
353
|
+
value = options.delete(key)
|
|
354
|
+
next if value.nil?
|
|
355
|
+
|
|
356
|
+
settings[key.to_s.upcase] = value.to_s
|
|
357
|
+
end
|
|
358
|
+
|
|
206
359
|
options.delete(:environment)
|
|
207
360
|
|
|
208
361
|
# NOTE: This is here to ensure that specs don't test for options
|
|
@@ -210,7 +363,7 @@ module Aptible
|
|
|
210
363
|
# this.
|
|
211
364
|
raise "Unexpected options: #{options}" if options.any?
|
|
212
365
|
|
|
213
|
-
params.delete_if { |_, v| v.nil? }
|
|
366
|
+
[params.delete_if { |_, v| v.nil? }, settings]
|
|
214
367
|
end
|
|
215
368
|
|
|
216
369
|
FLAGS.each do |f|
|
|
@@ -2,8 +2,11 @@ module Aptible
|
|
|
2
2
|
module CLI
|
|
3
3
|
module Helpers
|
|
4
4
|
module Vhost
|
|
5
|
-
def provision_vhost_and_explain(service, vhost)
|
|
6
|
-
op = vhost.create_operation!(
|
|
5
|
+
def provision_vhost_and_explain(service, vhost, settings)
|
|
6
|
+
op = vhost.create_operation!(
|
|
7
|
+
type: 'provision',
|
|
8
|
+
**(settings.empty? ? {} : { settings: settings })
|
|
9
|
+
)
|
|
7
10
|
attach_to_operation_logs(op)
|
|
8
11
|
|
|
9
12
|
Formatter.render(Renderer.current) do |root|
|
|
@@ -95,11 +95,14 @@ module Aptible
|
|
|
95
95
|
node.value('created_at', operation.created_at)
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
-
def inject_app(node, app, account
|
|
98
|
+
def inject_app(node, app, account, setting = nil,
|
|
99
|
+
include_services: true)
|
|
99
100
|
node.value('id', app.id)
|
|
100
101
|
node.value('handle', app.handle)
|
|
101
102
|
node.value('created_at', app.created_at)
|
|
102
103
|
|
|
104
|
+
attach_account(node, account)
|
|
105
|
+
|
|
103
106
|
node.value('status', app.status)
|
|
104
107
|
node.value('git_remote', app.git_repo)
|
|
105
108
|
|
|
@@ -109,15 +112,24 @@ module Aptible
|
|
|
109
112
|
end
|
|
110
113
|
end
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
if include_services
|
|
116
|
+
node.list('services') do |services_list|
|
|
117
|
+
app.each_service do |service|
|
|
118
|
+
services_list.object do |n|
|
|
119
|
+
inject_service(n, service, NO_NESTING)
|
|
120
|
+
end
|
|
116
121
|
end
|
|
117
122
|
end
|
|
118
123
|
end
|
|
119
124
|
|
|
120
|
-
|
|
125
|
+
unless setting.nil?
|
|
126
|
+
node.value('docker_image',
|
|
127
|
+
setting.settings['APTIBLE_DOCKER_IMAGE'])
|
|
128
|
+
node.value('private_registry_username',
|
|
129
|
+
setting.sensitive_settings['APTIBLE_PRIVATE_REGISTRY_USERNAME'])
|
|
130
|
+
node.value('private_registry_password',
|
|
131
|
+
setting.sensitive_settings['APTIBLE_PRIVATE_REGISTRY_PASSWORD'])
|
|
132
|
+
end
|
|
121
133
|
end
|
|
122
134
|
|
|
123
135
|
def inject_database_minimal(node, database, account)
|
|
@@ -213,6 +225,12 @@ module Aptible
|
|
|
213
225
|
|
|
214
226
|
node.value('internal', vhost.internal)
|
|
215
227
|
|
|
228
|
+
unless vhost.current_setting.nil?
|
|
229
|
+
vhost.current_setting.settings.each do |k, v|
|
|
230
|
+
node.value(k.downcase, v)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
216
234
|
ip_whitelist = if vhost.ip_whitelist.any?
|
|
217
235
|
vhost.ip_whitelist.join(' ')
|
|
218
236
|
else
|
|
@@ -26,7 +26,8 @@ module Aptible
|
|
|
26
26
|
accounts.each do |account|
|
|
27
27
|
account.each_app do |app|
|
|
28
28
|
node.object do |n|
|
|
29
|
-
|
|
29
|
+
setting = current_setting(app)
|
|
30
|
+
ResourceFormatter.inject_app(n, app, account, setting)
|
|
30
31
|
end
|
|
31
32
|
end
|
|
32
33
|
end
|
|
@@ -125,6 +126,32 @@ module Aptible
|
|
|
125
126
|
end
|
|
126
127
|
end
|
|
127
128
|
|
|
129
|
+
desc 'apps:settings HANDLE', 'Display deployment related settings for an app'
|
|
130
|
+
option :environment, aliases: '--env'
|
|
131
|
+
define_method 'apps:settings' do |handle|
|
|
132
|
+
telemetry(__method__, options.merge(handle: handle))
|
|
133
|
+
|
|
134
|
+
environment = nil
|
|
135
|
+
if options[:environment]
|
|
136
|
+
environment = environment_from_handle(options[:environment])
|
|
137
|
+
end
|
|
138
|
+
app = app_from_handle(handle, environment)
|
|
139
|
+
|
|
140
|
+
raise Thor::Error, "Could not find app #{handle}" if app.nil?
|
|
141
|
+
|
|
142
|
+
app = with_sensitive(app)
|
|
143
|
+
setting = current_setting(app)
|
|
144
|
+
|
|
145
|
+
Formatter.render(Renderer.current) do |root|
|
|
146
|
+
root.object do |node|
|
|
147
|
+
ResourceFormatter.inject_app(
|
|
148
|
+
node, app, app.account, setting,
|
|
149
|
+
include_services: false
|
|
150
|
+
)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
128
155
|
desc 'apps:rename OLD_HANDLE NEW_HANDLE [--environment'\
|
|
129
156
|
' ENVIRONMENT_HANDLE]', 'Rename an app handle. In order'\
|
|
130
157
|
' for the new app handle to appear in log drain and metric'\
|
|
@@ -27,13 +27,18 @@ module Aptible
|
|
|
27
27
|
service = database.service
|
|
28
28
|
raise Thor::Error, 'Database is not provisioned' if service.nil?
|
|
29
29
|
|
|
30
|
+
prepared_params, settings = database_create_flags.prepare(
|
|
31
|
+
database.account,
|
|
32
|
+
options
|
|
33
|
+
)
|
|
34
|
+
|
|
30
35
|
vhost = service.create_vhost!(
|
|
31
36
|
type: 'tcp',
|
|
32
37
|
platform: 'elb',
|
|
33
|
-
**
|
|
38
|
+
**prepared_params
|
|
34
39
|
)
|
|
35
40
|
|
|
36
|
-
provision_vhost_and_explain(service, vhost)
|
|
41
|
+
provision_vhost_and_explain(service, vhost, settings)
|
|
37
42
|
end
|
|
38
43
|
|
|
39
44
|
database_modify_flags = Helpers::Vhost::OptionSetBuilder.new do
|
|
@@ -49,9 +54,14 @@ module Aptible
|
|
|
49
54
|
|
|
50
55
|
database = ensure_database(options.merge(db: options[:database]))
|
|
51
56
|
vhost = find_vhost(each_service(database), hostname)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
|
|
58
|
+
prepared_params, settings = database_modify_flags.prepare(
|
|
59
|
+
database.account,
|
|
60
|
+
options
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
vhost.update!(**prepared_params)
|
|
64
|
+
provision_vhost_and_explain(vhost.service, vhost, settings)
|
|
55
65
|
end
|
|
56
66
|
|
|
57
67
|
tcp_create_flags = Helpers::Vhost::OptionSetBuilder.new do
|
|
@@ -246,18 +256,26 @@ module Aptible
|
|
|
246
256
|
no_commands do
|
|
247
257
|
def create_app_vhost(flags, options, process_type, **attrs)
|
|
248
258
|
service = ensure_service(options, process_type)
|
|
259
|
+
|
|
260
|
+
prepared_params, settings =
|
|
261
|
+
flags.prepare(service.account, options)
|
|
262
|
+
|
|
249
263
|
vhost = service.create_vhost!(
|
|
250
|
-
**
|
|
264
|
+
**prepared_params,
|
|
251
265
|
**attrs
|
|
252
266
|
)
|
|
253
|
-
provision_vhost_and_explain(service, vhost)
|
|
267
|
+
provision_vhost_and_explain(service, vhost, settings)
|
|
254
268
|
end
|
|
255
269
|
|
|
256
270
|
def modify_app_vhost(flags, options, hostname)
|
|
257
271
|
app = ensure_app(options)
|
|
258
272
|
vhost = find_vhost(each_service(app), hostname)
|
|
259
|
-
|
|
260
|
-
|
|
273
|
+
|
|
274
|
+
prepared_params, settings =
|
|
275
|
+
flags.prepare(vhost.service.account, options)
|
|
276
|
+
|
|
277
|
+
vhost.update!(**prepared_params)
|
|
278
|
+
provision_vhost_and_explain(vhost.service, vhost, settings)
|
|
261
279
|
end
|
|
262
280
|
end
|
|
263
281
|
end
|
data/lib/aptible/cli/version.rb
CHANGED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Aptible::CLI::Helpers::Vhost::OptionSetBuilder do
|
|
4
|
+
def register_options(builder)
|
|
5
|
+
klass = Class.new(Thor) { include Aptible::CLI::Helpers::App }
|
|
6
|
+
builder.declare_options(klass)
|
|
7
|
+
klass.instance_variable_get(:@method_options)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe '--ssl-protocols-override option description' do
|
|
11
|
+
context 'HTTPS endpoints (ALB, alb! flag set)' do
|
|
12
|
+
let(:builder) do
|
|
13
|
+
described_class.new do
|
|
14
|
+
app!
|
|
15
|
+
tls!
|
|
16
|
+
alb!
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'includes PFS values' do
|
|
21
|
+
desc = register_options(builder)[:ssl_protocols_override].description
|
|
22
|
+
expect(desc).to include('PFS')
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context 'TLS endpoints (ELB, tls! without alb!)' do
|
|
27
|
+
let(:builder) do
|
|
28
|
+
described_class.new do
|
|
29
|
+
app!
|
|
30
|
+
tls!
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'does not include PFS values' do
|
|
35
|
+
desc = register_options(builder)[:ssl_protocols_override].description
|
|
36
|
+
expect(desc).not_to include('PFS')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'is still present' do
|
|
40
|
+
expect(register_options(builder)).to have_key(:ssl_protocols_override)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context 'gRPC endpoints (ELB, tls! without alb!)' do
|
|
45
|
+
let(:builder) do
|
|
46
|
+
described_class.new do
|
|
47
|
+
app!
|
|
48
|
+
port!
|
|
49
|
+
tls!
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'does not include PFS values' do
|
|
54
|
+
desc = register_options(builder)[:ssl_protocols_override].description
|
|
55
|
+
expect(desc).not_to include('PFS')
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context 'TCP endpoints (no tls! flag)' do
|
|
60
|
+
let(:builder) do
|
|
61
|
+
described_class.new do
|
|
62
|
+
app!
|
|
63
|
+
ports!
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'is absent' do
|
|
68
|
+
expect(register_options(builder)).not_to have_key(:ssl_protocols_override)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe 'SSL_PROTOCOL_ALB_DESC' do
|
|
74
|
+
subject { described_class::SSL_PROTOCOL_ALB_DESC }
|
|
75
|
+
|
|
76
|
+
it 'lists all PFS protocol values' do
|
|
77
|
+
pfs_values = described_class::SSL_PROTOCOL_VALUES.select { |v| v.include?('PFS') }
|
|
78
|
+
pfs_values.each { |v| is_expected.to include(v) }
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe 'SSL_PROTOCOL_ELB_DESC' do
|
|
83
|
+
subject { described_class::SSL_PROTOCOL_ELB_DESC }
|
|
84
|
+
|
|
85
|
+
it 'contains no PFS values' do
|
|
86
|
+
is_expected.not_to include('PFS')
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'lists all non-PFS protocol values' do
|
|
90
|
+
non_pfs_values = described_class::SSL_PROTOCOL_VALUES.reject { |v| v.include?('PFS') }
|
|
91
|
+
non_pfs_values.each { |v| is_expected.to include(v) }
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -101,98 +101,218 @@ describe Aptible::CLI::Agent do
|
|
|
101
101
|
.to eq("=== #{account2.handle}\n#{app2.handle}\n")
|
|
102
102
|
end
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
allow(Aptible::Api::App).to receive(:all).and_return([app])
|
|
104
|
+
context 'with JSON output format' do
|
|
105
|
+
around do |example|
|
|
106
|
+
ClimateControl.modify(APTIBLE_OUTPUT_FORMAT: 'json') { example.run }
|
|
107
|
+
end
|
|
109
108
|
|
|
110
|
-
|
|
111
|
-
:
|
|
112
|
-
app:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
109
|
+
it 'includes services in JSON' do
|
|
110
|
+
account = Fabricate(:account, handle: 'account')
|
|
111
|
+
app = Fabricate(:app, account: account, handle: 'app')
|
|
112
|
+
allow(Aptible::Api::Account).to receive(:all).and_return([account])
|
|
113
|
+
allow(Aptible::Api::App).to receive(:all).and_return([app])
|
|
114
|
+
|
|
115
|
+
s1 = Fabricate(
|
|
116
|
+
:service,
|
|
117
|
+
app: app, process_type: 's1', command: 'true', container_count: 2,
|
|
118
|
+
instance_class: 'm5'
|
|
119
|
+
)
|
|
120
|
+
s2 = Fabricate(
|
|
121
|
+
:service,
|
|
122
|
+
app: app, process_type: 's2', container_memory_limit_mb: 2048,
|
|
123
|
+
instance_class: 'r5'
|
|
124
|
+
)
|
|
120
125
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
},
|
|
128
|
-
'handle' => app.handle,
|
|
129
|
-
'id' => app.id,
|
|
130
|
-
'status' => app.status,
|
|
131
|
-
'git_remote' => app.git_repo,
|
|
132
|
-
'created_at' => fmt_time(app.created_at),
|
|
133
|
-
'services' => [
|
|
134
|
-
{
|
|
135
|
-
'service' => s1.process_type,
|
|
136
|
-
'id' => s1.id,
|
|
137
|
-
'command' => s1.command,
|
|
138
|
-
'container_count' => s1.container_count,
|
|
139
|
-
'container_profile' => 'm',
|
|
140
|
-
'container_size' => s1.container_memory_limit_mb,
|
|
141
|
-
'created_at' => fmt_time(s1.created_at)
|
|
126
|
+
expected_json = [
|
|
127
|
+
{
|
|
128
|
+
'environment' => {
|
|
129
|
+
'id' => account.id,
|
|
130
|
+
'handle' => account.handle,
|
|
131
|
+
'created_at' => fmt_time(account.created_at)
|
|
142
132
|
},
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
133
|
+
'handle' => app.handle,
|
|
134
|
+
'id' => app.id,
|
|
135
|
+
'status' => app.status,
|
|
136
|
+
'git_remote' => app.git_repo,
|
|
137
|
+
'created_at' => fmt_time(app.created_at),
|
|
138
|
+
'services' => [
|
|
139
|
+
{
|
|
140
|
+
'service' => s1.process_type,
|
|
141
|
+
'id' => s1.id,
|
|
142
|
+
'command' => s1.command,
|
|
143
|
+
'container_count' => s1.container_count,
|
|
144
|
+
'container_profile' => 'm',
|
|
145
|
+
'container_size' => s1.container_memory_limit_mb,
|
|
146
|
+
'created_at' => fmt_time(s1.created_at)
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
'service' => s2.process_type,
|
|
150
|
+
'id' => s2.id,
|
|
151
|
+
'command' => 'CMD',
|
|
152
|
+
'container_count' => s2.container_count,
|
|
153
|
+
'container_profile' => 'r',
|
|
154
|
+
'container_size' => s2.container_memory_limit_mb,
|
|
155
|
+
'created_at' => fmt_time(s2.created_at)
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
]
|
|
155
160
|
|
|
156
|
-
|
|
161
|
+
subject.send('apps')
|
|
157
162
|
|
|
158
|
-
|
|
159
|
-
|
|
163
|
+
expect(captured_output_json).to eq(expected_json)
|
|
164
|
+
end
|
|
160
165
|
|
|
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
|
-
|
|
166
|
+
it 'includes the last deploy operation in JSON' do
|
|
167
|
+
account = Fabricate(:account, handle: 'account')
|
|
168
|
+
op = Fabricate(:operation, type: 'deploy', status: 'succeeded')
|
|
169
|
+
app = Fabricate(:app, account: account, handle: 'app',
|
|
170
|
+
last_deploy_operation: op)
|
|
171
|
+
allow(Aptible::Api::Account).to receive(:all).and_return([account])
|
|
172
|
+
allow(Aptible::Api::App).to receive(:all).and_return([app])
|
|
173
|
+
|
|
174
|
+
expected_json = [
|
|
175
|
+
{
|
|
176
|
+
'environment' => {
|
|
177
|
+
'id' => account.id,
|
|
178
|
+
'handle' => account.handle,
|
|
179
|
+
'created_at' => fmt_time(account.created_at)
|
|
180
|
+
},
|
|
181
|
+
'handle' => app.handle,
|
|
182
|
+
'id' => app.id,
|
|
183
|
+
'status' => app.status,
|
|
184
|
+
'git_remote' => app.git_repo,
|
|
185
|
+
'created_at' => fmt_time(app.created_at),
|
|
186
|
+
'last_deploy_operation' =>
|
|
187
|
+
{
|
|
188
|
+
'id' => op.id,
|
|
189
|
+
'status' => op.status,
|
|
190
|
+
'git_ref' => op.git_ref,
|
|
191
|
+
'user_email' => op.user_email,
|
|
192
|
+
'created_at' => op.created_at
|
|
193
|
+
},
|
|
194
|
+
'services' => []
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
|
|
198
|
+
subject.send('apps')
|
|
199
|
+
|
|
200
|
+
expect(captured_output_json).to eq(expected_json)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it 'includes docker image and registry settings' do
|
|
204
|
+
account = Fabricate(:account, handle: 'account')
|
|
205
|
+
setting = Fabricate(
|
|
206
|
+
:setting,
|
|
207
|
+
settings: { 'APTIBLE_DOCKER_IMAGE' => 'quay.io/myorg/myapp:latest' },
|
|
208
|
+
sensitive_settings: {
|
|
209
|
+
'APTIBLE_PRIVATE_REGISTRY_USERNAME' => 'registryuser',
|
|
210
|
+
'APTIBLE_PRIVATE_REGISTRY_PASSWORD' => 'registrypass'
|
|
211
|
+
}
|
|
212
|
+
)
|
|
213
|
+
app = Fabricate(:app, account: account, handle: 'app')
|
|
214
|
+
allow(Aptible::Api::Account).to receive(:all).and_return([account])
|
|
215
|
+
allow(subject).to receive(:current_setting).with(app)
|
|
216
|
+
.and_return(setting)
|
|
217
|
+
|
|
218
|
+
expected_json = [
|
|
219
|
+
{
|
|
220
|
+
'environment' => {
|
|
221
|
+
'id' => account.id,
|
|
222
|
+
'handle' => account.handle,
|
|
223
|
+
'created_at' => fmt_time(account.created_at)
|
|
188
224
|
},
|
|
189
|
-
|
|
225
|
+
'handle' => app.handle,
|
|
226
|
+
'id' => app.id,
|
|
227
|
+
'status' => app.status,
|
|
228
|
+
'git_remote' => app.git_repo,
|
|
229
|
+
'created_at' => fmt_time(app.created_at),
|
|
230
|
+
'services' => [],
|
|
231
|
+
'docker_image' => 'quay.io/myorg/myapp:latest',
|
|
232
|
+
'private_registry_username' => 'registryuser',
|
|
233
|
+
'private_registry_password' => 'registrypass'
|
|
234
|
+
}
|
|
235
|
+
]
|
|
236
|
+
|
|
237
|
+
subject.send('apps')
|
|
238
|
+
|
|
239
|
+
expect(captured_output_json).to eq(expected_json)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it 'omits docker image and registry settings when no current_setting' do
|
|
243
|
+
account = Fabricate(:account, handle: 'account')
|
|
244
|
+
app = Fabricate(:app, account: account, handle: 'app')
|
|
245
|
+
allow(Aptible::Api::Account).to receive(:all).and_return([account])
|
|
246
|
+
allow(subject).to receive(:current_setting).with(app)
|
|
247
|
+
.and_return(nil)
|
|
248
|
+
|
|
249
|
+
subject.send('apps')
|
|
250
|
+
|
|
251
|
+
json = captured_output_json
|
|
252
|
+
expect(json.first).not_to have_key('docker_image')
|
|
253
|
+
expect(json.first).not_to have_key('private_registry_username')
|
|
254
|
+
expect(json.first).not_to have_key('private_registry_password')
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
describe '#apps:settings' do
|
|
260
|
+
it 'displays app settings in JSON' do
|
|
261
|
+
ClimateControl.modify(APTIBLE_OUTPUT_FORMAT: 'json') do
|
|
262
|
+
setting = Fabricate(
|
|
263
|
+
:setting,
|
|
264
|
+
settings: { 'APTIBLE_DOCKER_IMAGE' => 'quay.io/myorg/myapp:latest' },
|
|
265
|
+
sensitive_settings: {
|
|
266
|
+
'APTIBLE_PRIVATE_REGISTRY_USERNAME' => 'registryuser',
|
|
267
|
+
'APTIBLE_PRIVATE_REGISTRY_PASSWORD' => 'registrypass'
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
allow(subject).to receive(:app_from_handle)
|
|
271
|
+
.with('hello', nil).and_return(app)
|
|
272
|
+
allow(subject).to receive(:current_setting).with(app)
|
|
273
|
+
.and_return(setting)
|
|
274
|
+
|
|
275
|
+
subject.send('apps:settings', 'hello')
|
|
276
|
+
|
|
277
|
+
json = captured_output_json
|
|
278
|
+
expect(json['handle']).to eq('hello')
|
|
279
|
+
expect(json['docker_image']).to eq('quay.io/myorg/myapp:latest')
|
|
280
|
+
expect(json['private_registry_username']).to eq('registryuser')
|
|
281
|
+
expect(json['private_registry_password']).to eq('registrypass')
|
|
282
|
+
expect(json).not_to have_key('services')
|
|
283
|
+
expect(json).not_to have_key('last_deploy_operation')
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
it 'displays app settings in text' do
|
|
288
|
+
setting = Fabricate(
|
|
289
|
+
:setting,
|
|
290
|
+
settings: { 'APTIBLE_DOCKER_IMAGE' => 'quay.io/myorg/myapp:latest' },
|
|
291
|
+
sensitive_settings: {
|
|
292
|
+
'APTIBLE_PRIVATE_REGISTRY_USERNAME' => 'registryuser',
|
|
293
|
+
'APTIBLE_PRIVATE_REGISTRY_PASSWORD' => 'registrypass'
|
|
190
294
|
}
|
|
191
|
-
|
|
295
|
+
)
|
|
296
|
+
allow(subject).to receive(:app_from_handle)
|
|
297
|
+
.with('hello', nil).and_return(app)
|
|
298
|
+
allow(subject).to receive(:current_setting).with(app)
|
|
299
|
+
.and_return(setting)
|
|
300
|
+
|
|
301
|
+
subject.send('apps:settings', 'hello')
|
|
302
|
+
|
|
303
|
+
output = captured_output_text
|
|
304
|
+
expect(output).to include('quay.io/myorg/myapp:latest')
|
|
305
|
+
expect(output).to include('registryuser')
|
|
306
|
+
expect(output).to include('registrypass')
|
|
307
|
+
expect(output).not_to include('services')
|
|
308
|
+
end
|
|
192
309
|
|
|
193
|
-
|
|
310
|
+
it 'raises an error when app is not found' do
|
|
311
|
+
allow(subject).to receive(:app_from_handle)
|
|
312
|
+
.with('nope', nil).and_return(nil)
|
|
194
313
|
|
|
195
|
-
expect(
|
|
314
|
+
expect { subject.send('apps:settings', 'nope') }
|
|
315
|
+
.to raise_error(Thor::Error, /Could not find app nope/)
|
|
196
316
|
end
|
|
197
317
|
end
|
|
198
318
|
|
|
@@ -25,12 +25,12 @@ describe Aptible::CLI::Agent do
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def expect_create_vhost(service, options)
|
|
28
|
+
def expect_create_vhost(service, options, settings: nil)
|
|
29
29
|
expect(service).to receive(:create_vhost!).with(
|
|
30
30
|
hash_including(options)
|
|
31
31
|
) do |args|
|
|
32
32
|
Fabricate(:vhost, service: service, **args).tap do |v|
|
|
33
|
-
expect_operation(v, 'provision')
|
|
33
|
+
expect_operation(v, 'provision', settings: settings)
|
|
34
34
|
expect(v).to receive(:reload).and_return(v)
|
|
35
35
|
expect(Aptible::CLI::ResourceFormatter).to receive(:inject_vhost)
|
|
36
36
|
.with(an_instance_of(Aptible::CLI::Formatter::Object), v, service)
|
|
@@ -49,8 +49,16 @@ describe Aptible::CLI::Agent do
|
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
def expect_operation(vhost, type)
|
|
53
|
-
expect(vhost).to receive(:create_operation!)
|
|
52
|
+
def expect_operation(vhost, type, settings: nil)
|
|
53
|
+
expect(vhost).to receive(:create_operation!) do |args|
|
|
54
|
+
expect(args[:type]).to eq(type)
|
|
55
|
+
|
|
56
|
+
if settings.nil?
|
|
57
|
+
expect(args).not_to have_key(:settings)
|
|
58
|
+
else
|
|
59
|
+
expect(args[:settings]).to eq(settings)
|
|
60
|
+
end
|
|
61
|
+
|
|
54
62
|
Fabricate(:operation).tap do |o|
|
|
55
63
|
expect(subject).to receive(:attach_to_operation_logs).with(o)
|
|
56
64
|
end
|
|
@@ -170,7 +178,13 @@ describe Aptible::CLI::Agent do
|
|
|
170
178
|
it 'lists Endpoints' do
|
|
171
179
|
s = Fabricate(:service, database: db)
|
|
172
180
|
v1 = Fabricate(:vhost, service: s)
|
|
181
|
+
v1.current_setting = Fabricate(:setting,
|
|
182
|
+
settings: { 'IDLE_TIMEOUT' => '123' },
|
|
183
|
+
vhost: v1)
|
|
173
184
|
v2 = Fabricate(:vhost, service: s)
|
|
185
|
+
v2.current_setting = Fabricate(:setting,
|
|
186
|
+
settings: { 'FORCE_SSL' => 'true' },
|
|
187
|
+
vhost: v2)
|
|
174
188
|
|
|
175
189
|
stub_options(database: db.handle)
|
|
176
190
|
subject.send('endpoints:list')
|
|
@@ -179,6 +193,8 @@ describe Aptible::CLI::Agent do
|
|
|
179
193
|
|
|
180
194
|
expect(lines).to include("Hostname: #{v1.external_host}")
|
|
181
195
|
expect(lines).to include("Hostname: #{v2.external_host}")
|
|
196
|
+
expect(lines).to include('Idle Timeout: 123')
|
|
197
|
+
expect(lines).to include('Force SSL: true')
|
|
182
198
|
|
|
183
199
|
expect(lines[0]).not_to eq("\n")
|
|
184
200
|
expect(lines[-1]).not_to eq("\n")
|
|
@@ -243,6 +259,105 @@ describe Aptible::CLI::Agent do
|
|
|
243
259
|
stub_options
|
|
244
260
|
end
|
|
245
261
|
|
|
262
|
+
shared_examples 'shared create and modify ALB settings examples' do |method|
|
|
263
|
+
context 'App Vhost Settings (string)' do
|
|
264
|
+
string_options = %i(
|
|
265
|
+
idle_timeout
|
|
266
|
+
maintenance_page_url
|
|
267
|
+
release_healthcheck_timeout
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
let(:value) { 'some value' }
|
|
271
|
+
|
|
272
|
+
string_options.each do |option|
|
|
273
|
+
context "--#{option.to_s.tr('_', '-')}" do
|
|
274
|
+
it 'passes a value if provided' do
|
|
275
|
+
wanted = { option.to_s.upcase => value }
|
|
276
|
+
expect_create_vhost(service, {}, { settings: wanted })
|
|
277
|
+
stub_options(option => value)
|
|
278
|
+
subject.send(method, 'web')
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
it 'passes nothing if not provided' do
|
|
282
|
+
expect_create_vhost(service, {})
|
|
283
|
+
subject.send(method, 'web')
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
context 'reverting to default' do
|
|
287
|
+
it 'sends an empty string if passed an empty string' do
|
|
288
|
+
wanted = { option.to_s.upcase => '' }
|
|
289
|
+
expect_create_vhost(service, {}, { settings: wanted })
|
|
290
|
+
stub_options(option => '')
|
|
291
|
+
subject.send(method, 'web')
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
it 'sends an empty string if passed the string "default"' do
|
|
295
|
+
wanted = { option.to_s.upcase => '' }
|
|
296
|
+
expect_create_vhost(service, {}, { settings: wanted })
|
|
297
|
+
stub_options(option => 'default')
|
|
298
|
+
subject.send(method, 'web')
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
context '--ssl-protocols-override' do
|
|
306
|
+
it 'passes a valid non-PFS value' do
|
|
307
|
+
wanted = { 'SSL_PROTOCOLS_OVERRIDE' => 'TLSv1.2' }
|
|
308
|
+
expect_create_vhost(service, {}, { settings: wanted })
|
|
309
|
+
stub_options(ssl_protocols_override: 'TLSv1.2')
|
|
310
|
+
subject.send(method, 'web')
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
it 'passes a valid PFS value' do
|
|
314
|
+
wanted = { 'SSL_PROTOCOLS_OVERRIDE' => 'TLSv1.2 PFS' }
|
|
315
|
+
expect_create_vhost(service, {}, { settings: wanted })
|
|
316
|
+
stub_options(ssl_protocols_override: 'TLSv1.2 PFS')
|
|
317
|
+
subject.send(method, 'web')
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
it 'raises an error for an invalid value' do
|
|
321
|
+
stub_options(ssl_protocols_override: 'TLSv1.0')
|
|
322
|
+
expect { subject.send(method, 'web') }
|
|
323
|
+
.to raise_error(/invalid --ssl-protocols-override/im)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
it 'passes nothing if not provided' do
|
|
327
|
+
expect_create_vhost(service, {})
|
|
328
|
+
subject.send(method, 'web')
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
it 'sends an empty string if passed the string "default"' do
|
|
332
|
+
wanted = { 'SSL_PROTOCOLS_OVERRIDE' => '' }
|
|
333
|
+
expect_create_vhost(service, {}, { settings: wanted })
|
|
334
|
+
stub_options(ssl_protocols_override: 'default')
|
|
335
|
+
subject.send(method, 'web')
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
context 'App Vhost Settings (boolean)' do
|
|
340
|
+
boolean_options = %i(
|
|
341
|
+
force_ssl
|
|
342
|
+
show_elb_healthchecks
|
|
343
|
+
strict_health_checks
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
boolean_options.each do |option|
|
|
347
|
+
[true, false].each do |value|
|
|
348
|
+
context "--#{value ? '' : 'no-'}#{option.to_s.tr('_', '-')}" do
|
|
349
|
+
it "sets the value to the string '#{value}'" do
|
|
350
|
+
wanted = { option.to_s.upcase => value.to_s }
|
|
351
|
+
expect_create_vhost(service, {}, { settings: wanted })
|
|
352
|
+
stub_options(option => value)
|
|
353
|
+
subject.send(method, 'web')
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
246
361
|
shared_examples 'shared create app vhost examples' do |method|
|
|
247
362
|
context 'App Vhost Options' do
|
|
248
363
|
it 'fails if the app does not exist' do
|
|
@@ -440,10 +555,64 @@ describe Aptible::CLI::Agent do
|
|
|
440
555
|
end
|
|
441
556
|
end
|
|
442
557
|
|
|
558
|
+
shared_examples 'shared create idle timeout examples' do |method|
|
|
559
|
+
context 'IDLE_TIMEOUT' do
|
|
560
|
+
it 'passes idle_timeout if provided' do
|
|
561
|
+
expect_create_vhost(service, {}, { settings: { 'IDLE_TIMEOUT' => '30' } })
|
|
562
|
+
stub_options(idle_timeout: '30')
|
|
563
|
+
subject.send(method, 'web')
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
shared_examples 'shared create non-alb tls settings examples' do |method|
|
|
569
|
+
context '--ssl-protocols-override' do
|
|
570
|
+
it 'passes a valid non-PFS value' do
|
|
571
|
+
wanted = { 'SSL_PROTOCOLS_OVERRIDE' => 'TLSv1.2' }
|
|
572
|
+
expect_create_vhost(service, {}, { settings: wanted })
|
|
573
|
+
stub_options(ssl_protocols_override: 'TLSv1.2')
|
|
574
|
+
subject.send(method, 'web')
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
it 'raises an error for a PFS value' do
|
|
578
|
+
stub_options(ssl_protocols_override: 'TLSv1.2 PFS')
|
|
579
|
+
expect { subject.send(method, 'web') }
|
|
580
|
+
.to raise_error(/pfs.*only.*alb/im)
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
it 'raises an error for an invalid value' do
|
|
584
|
+
stub_options(ssl_protocols_override: 'TLSv1.0')
|
|
585
|
+
expect { subject.send(method, 'web') }
|
|
586
|
+
.to raise_error(/invalid --ssl-protocols-override/im)
|
|
587
|
+
end
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
context 'SSL_CIPHERS_OVERRIDE' do
|
|
591
|
+
it 'passes ssl_ciphers_override if provided' do
|
|
592
|
+
wanted = { 'SSL_CIPHERS_OVERRIDE' => 'HIGH:!aNULL' }
|
|
593
|
+
expect_create_vhost(service, {}, { settings: wanted })
|
|
594
|
+
stub_options(ssl_ciphers_override: 'HIGH:!aNULL')
|
|
595
|
+
subject.send(method, 'web')
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
context 'DISABLE_WEAK_CIPHER_SUITES' do
|
|
600
|
+
[true, false].each do |value|
|
|
601
|
+
it "sets disable_weak_cipher_suites to '#{value}'" do
|
|
602
|
+
wanted = { 'DISABLE_WEAK_CIPHER_SUITES' => value.to_s }
|
|
603
|
+
expect_create_vhost(service, {}, { settings: wanted })
|
|
604
|
+
stub_options(disable_weak_cipher_suites: value)
|
|
605
|
+
subject.send(method, 'web')
|
|
606
|
+
end
|
|
607
|
+
end
|
|
608
|
+
end
|
|
609
|
+
end
|
|
610
|
+
|
|
443
611
|
describe 'endpoints:tcp:create' do
|
|
444
612
|
m = 'endpoints:tcp:create'
|
|
445
613
|
include_examples 'shared create app vhost examples', m
|
|
446
614
|
include_examples 'shared create tcp vhost examples', m
|
|
615
|
+
include_examples 'shared create idle timeout examples', m
|
|
447
616
|
|
|
448
617
|
it 'creates a TCP Endpoint' do
|
|
449
618
|
expect_create_vhost(
|
|
@@ -465,6 +634,8 @@ describe Aptible::CLI::Agent do
|
|
|
465
634
|
include_examples 'shared create app vhost examples', m
|
|
466
635
|
include_examples 'shared create tcp vhost examples', m
|
|
467
636
|
include_examples 'shared create tls vhost examples', m
|
|
637
|
+
include_examples 'shared create idle timeout examples', m
|
|
638
|
+
include_examples 'shared create non-alb tls settings examples', m
|
|
468
639
|
|
|
469
640
|
it 'creates a TLS Endpoint' do
|
|
470
641
|
expect_create_vhost(
|
|
@@ -484,6 +655,7 @@ describe Aptible::CLI::Agent do
|
|
|
484
655
|
m = 'endpoints:https:create'
|
|
485
656
|
include_examples 'shared create app vhost examples', m
|
|
486
657
|
include_examples 'shared create tls vhost examples', m
|
|
658
|
+
include_examples 'shared create and modify ALB settings examples', m
|
|
487
659
|
|
|
488
660
|
it 'creates a HTTP Endpoint' do
|
|
489
661
|
expect_create_vhost(
|
|
@@ -516,6 +688,8 @@ describe Aptible::CLI::Agent do
|
|
|
516
688
|
m = 'endpoints:grpc:create'
|
|
517
689
|
include_examples 'shared create app vhost examples', m
|
|
518
690
|
include_examples 'shared create tls vhost examples', m
|
|
691
|
+
include_examples 'shared create idle timeout examples', m
|
|
692
|
+
include_examples 'shared create non-alb tls settings examples', m
|
|
519
693
|
|
|
520
694
|
it 'creates a gRPC Endpoint' do
|
|
521
695
|
expect_create_vhost(
|
|
@@ -28,6 +28,7 @@ Fabricator(:app, from: :stub_app) do
|
|
|
28
28
|
services { [] }
|
|
29
29
|
configurations { [] }
|
|
30
30
|
current_configuration { nil }
|
|
31
|
+
current_setting { nil }
|
|
31
32
|
errors { Aptible::Resource::Errors.new }
|
|
32
33
|
created_at { Time.now }
|
|
33
34
|
|
|
@@ -37,6 +38,11 @@ Fabricator(:app, from: :stub_app) do
|
|
|
37
38
|
href: "/accounts/#{attrs[:account].id}"
|
|
38
39
|
)
|
|
39
40
|
}
|
|
41
|
+
if attrs[:current_setting]
|
|
42
|
+
hash[:current_setting] = OpenStruct.new(
|
|
43
|
+
href: "/settings/#{attrs[:current_setting].id}"
|
|
44
|
+
)
|
|
45
|
+
end
|
|
40
46
|
OpenStruct.new(hash)
|
|
41
47
|
end
|
|
42
48
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aptible-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.26.
|
|
4
|
+
version: 0.26.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Frank Macreery
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-06-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -563,6 +563,7 @@ files:
|
|
|
563
563
|
- spec/aptible/cli/helpers/ssh_spec.rb
|
|
564
564
|
- spec/aptible/cli/helpers/token_spec.rb
|
|
565
565
|
- spec/aptible/cli/helpers/tunnel_spec.rb
|
|
566
|
+
- spec/aptible/cli/helpers/vhost/option_set_builder_spec.rb
|
|
566
567
|
- spec/aptible/cli/renderer/json_spec.rb
|
|
567
568
|
- spec/aptible/cli/renderer/text_spec.rb
|
|
568
569
|
- spec/aptible/cli/resource_formatter_spec.rb
|
|
@@ -608,6 +609,7 @@ files:
|
|
|
608
609
|
- spec/fabricators/operation_fabricator.rb
|
|
609
610
|
- spec/fabricators/service_fabricator.rb
|
|
610
611
|
- spec/fabricators/service_sizing_policy_fabricator.rb
|
|
612
|
+
- spec/fabricators/setting_fabricator.rb
|
|
611
613
|
- spec/fabricators/stack_fabricator.rb
|
|
612
614
|
- spec/fabricators/vhost_fabricator.rb
|
|
613
615
|
- spec/mock/git
|
|
@@ -657,6 +659,7 @@ test_files:
|
|
|
657
659
|
- spec/aptible/cli/helpers/ssh_spec.rb
|
|
658
660
|
- spec/aptible/cli/helpers/token_spec.rb
|
|
659
661
|
- spec/aptible/cli/helpers/tunnel_spec.rb
|
|
662
|
+
- spec/aptible/cli/helpers/vhost/option_set_builder_spec.rb
|
|
660
663
|
- spec/aptible/cli/renderer/json_spec.rb
|
|
661
664
|
- spec/aptible/cli/renderer/text_spec.rb
|
|
662
665
|
- spec/aptible/cli/resource_formatter_spec.rb
|
|
@@ -702,6 +705,7 @@ test_files:
|
|
|
702
705
|
- spec/fabricators/operation_fabricator.rb
|
|
703
706
|
- spec/fabricators/service_fabricator.rb
|
|
704
707
|
- spec/fabricators/service_sizing_policy_fabricator.rb
|
|
708
|
+
- spec/fabricators/setting_fabricator.rb
|
|
705
709
|
- spec/fabricators/stack_fabricator.rb
|
|
706
710
|
- spec/fabricators/vhost_fabricator.rb
|
|
707
711
|
- spec/mock/git
|