aptible-cli 0.26.2 → 0.26.4
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 +5 -0
- data/Gemfile.lock +1 -1
- data/lib/aptible/cli/agent.rb +7 -4
- data/lib/aptible/cli/helpers/app.rb +11 -0
- data/lib/aptible/cli/helpers/database.rb +29 -13
- data/lib/aptible/cli/helpers/log_drain.rb +3 -1
- data/lib/aptible/cli/helpers/metric_drain.rb +3 -1
- data/lib/aptible/cli/resource_formatter.rb +14 -1
- data/lib/aptible/cli/subcommands/config.rb +2 -2
- data/lib/aptible/cli/subcommands/db.rb +4 -3
- data/lib/aptible/cli/subcommands/log_drain.rb +2 -0
- data/lib/aptible/cli/subcommands/logs.rb +5 -5
- data/lib/aptible/cli/subcommands/metric_drain.rb +2 -0
- data/lib/aptible/cli/version.rb +1 -1
- data/lib/aptible/cli.rb +14 -0
- data/spec/aptible/cli/subcommands/config_spec.rb +8 -0
- data/spec/aptible/cli/subcommands/db_spec.rb +3 -51
- data/spec/aptible/cli/subcommands/log_drain_spec.rb +6 -0
- data/spec/aptible/cli/subcommands/metric_drain_spec.rb +4 -0
- data/spec/fabricators/account_fabricator.rb +9 -1
- data/spec/fabricators/app_external_aws_rds_connection_fabricator.rb +1 -1
- data/spec/fabricators/app_fabricator.rb +1 -1
- data/spec/fabricators/backup_fabricator.rb +1 -1
- data/spec/fabricators/backup_retention_policy_fabricator.rb +1 -1
- data/spec/fabricators/certificate_fabricator.rb +1 -1
- data/spec/fabricators/configuration_fabricator.rb +1 -1
- data/spec/fabricators/database_credential_fabricator.rb +1 -1
- data/spec/fabricators/database_disk_fabricator.rb +1 -1
- data/spec/fabricators/database_fabricator.rb +10 -1
- data/spec/fabricators/database_image_fabricator.rb +1 -1
- data/spec/fabricators/external_aws_account_fabricator.rb +1 -1
- data/spec/fabricators/external_aws_database_credential_fabricator.rb +1 -1
- data/spec/fabricators/external_aws_resource_fabricator.rb +1 -1
- data/spec/fabricators/log_drain_fabricator.rb +1 -1
- data/spec/fabricators/maintenance_app_fabricator.rb +1 -1
- data/spec/fabricators/maintenance_database_fabricator.rb +1 -1
- data/spec/fabricators/metric_drain_fabricator.rb +15 -1
- data/spec/fabricators/operation_fabricator.rb +1 -1
- data/spec/fabricators/service_fabricator.rb +1 -1
- data/spec/fabricators/service_sizing_policy_fabricator.rb +1 -1
- data/spec/fabricators/stack_fabricator.rb +1 -1
- data/spec/fabricators/vhost_fabricator.rb +1 -1
- data/spec/spec_helper.rb +5 -0
- data/spec/support/stub_aptible_resource.rb +25 -0
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1c756f930a26ab5b060f01270b80c9ec2963c8f739be4ffcd2a5d56e9dac2860
|
|
4
|
+
data.tar.gz: 55fdde5cde257bd36c6c16a17e7f639745f85947b1cf40269c0d73ab0093615c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 01122dab06813f9b67100c11e6e59ec6942f5263340efc26bbf73440b51c39c7cd0be7258b987fa39056092b29bf181ded4d14423d27ff795cd18bf85b97fe96
|
|
7
|
+
data.tar.gz: d7ed67882c43c958dcc60c7ef5ba518f3eb6ad72ca014f4c0b761478f2748054af64286aca26b8ac97b5ca5ea03964bc34fd422d3cf42f4996b4c6949815d870
|
data/.rubocop.yml
ADDED
data/Gemfile.lock
CHANGED
data/lib/aptible/cli/agent.rb
CHANGED
|
@@ -92,10 +92,13 @@ module Aptible
|
|
|
92
92
|
level = Logger::WARN
|
|
93
93
|
debug_level = ENV['APTIBLE_DEBUG']
|
|
94
94
|
level = debug_level if debug_level
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
if ENV['BUNDLER_VERSION'] && \
|
|
96
|
+
ENV['APTIBLE_LOG_HTTP_REQUEST_RESPONSE'] && \
|
|
97
|
+
!ENV['APTIBLE_LOG_HTTP_REQUEST_RESPONSE'] \
|
|
98
|
+
.downcase.start_with?('f')
|
|
99
|
+
require 'httplog'
|
|
100
|
+
HttpLog.configure { |c| c.log_headers = true }
|
|
101
|
+
end
|
|
99
102
|
conf.logger.tap { |l| l.level = level }
|
|
100
103
|
end
|
|
101
104
|
warn_sso_enforcement
|
|
@@ -196,6 +196,17 @@ module Aptible
|
|
|
196
196
|
raise Thor::Error, "Invalid argument: #{k}" if v.nil?
|
|
197
197
|
end
|
|
198
198
|
|
|
199
|
+
def current_configuration(app)
|
|
200
|
+
conf_link = app.links['current_configuration']
|
|
201
|
+
return unless conf_link
|
|
202
|
+
|
|
203
|
+
Aptible::Api::Configuration.find_by_url(
|
|
204
|
+
conf_link.href,
|
|
205
|
+
token: fetch_token,
|
|
206
|
+
headers: { 'Prefer' => 'no_sensitive_extras=false' }
|
|
207
|
+
)
|
|
208
|
+
end
|
|
209
|
+
|
|
199
210
|
private
|
|
200
211
|
|
|
201
212
|
def handle_strategies
|
|
@@ -185,6 +185,14 @@ module Aptible
|
|
|
185
185
|
# Creates a local tunnel and yields the helper
|
|
186
186
|
|
|
187
187
|
def with_local_tunnel(credential, port = 0, target_account = nil)
|
|
188
|
+
# Credential has the senstive header set, and for some reason
|
|
189
|
+
# credential.create_operation! _lists all operations_. This would
|
|
190
|
+
# generate a show activity for every previous tunnel operation.
|
|
191
|
+
# So, we strip the sensitive header first to prevent that from happening
|
|
192
|
+
# This will also strip the connection_url, but we don't need it from
|
|
193
|
+
# this point on.
|
|
194
|
+
credential = without_sensitive(credential)
|
|
195
|
+
# Twice by here??
|
|
188
196
|
op = if target_account.nil?
|
|
189
197
|
credential.create_operation!(
|
|
190
198
|
type: 'tunnel',
|
|
@@ -284,7 +292,7 @@ module Aptible
|
|
|
284
292
|
raise Thor::Error, 'This command only works for PostgreSQL'
|
|
285
293
|
end
|
|
286
294
|
|
|
287
|
-
credential = find_credential(database)
|
|
295
|
+
credential, _credentials = find_credential(database)
|
|
288
296
|
|
|
289
297
|
with_local_tunnel(credential) do |tunnel_helper|
|
|
290
298
|
yield local_url(credential, tunnel_helper.port)
|
|
@@ -304,7 +312,7 @@ module Aptible
|
|
|
304
312
|
remote_url = credential.connection_url
|
|
305
313
|
|
|
306
314
|
uri = URI.parse(remote_url)
|
|
307
|
-
domain = credential.database.account.stack.internal_domain
|
|
315
|
+
domain = without_sensitive(credential).database.account.stack.internal_domain
|
|
308
316
|
"#{uri.scheme}://#{uri.user}:#{uri.password}@" \
|
|
309
317
|
"localhost.#{domain}:#{local_port}#{uri.path}"
|
|
310
318
|
end
|
|
@@ -314,21 +322,25 @@ module Aptible
|
|
|
314
322
|
raise Thor::Error, "Database #{database.handle} is not provisioned"
|
|
315
323
|
end
|
|
316
324
|
|
|
325
|
+
# Get the database credentials, without going using `with_senstive(database)`, as that
|
|
326
|
+
# would get the embedded last_operation, and generate an extra show activity
|
|
327
|
+
creds_link = database.links['database_credentials']
|
|
328
|
+
database_credentials = Aptible::Api::DatabaseCredential.all(
|
|
329
|
+
href: creds_link.href,
|
|
330
|
+
token: fetch_token,
|
|
331
|
+
headers: { 'Prefer' => 'no_sensitive_extras=false' }
|
|
332
|
+
)
|
|
333
|
+
|
|
317
334
|
finder = proc { |c| c.default }
|
|
318
335
|
finder = proc { |c| c.type == type } if type
|
|
319
|
-
credential =
|
|
336
|
+
credential = database_credentials.find(&finder)
|
|
320
337
|
|
|
321
|
-
return credential
|
|
338
|
+
# It may be weird to return the credential and all the credentials, but the db:tunnel
|
|
339
|
+
# command lists all the credential types if you do not provide one, and we want to avoid
|
|
340
|
+
# generating more show activity than needed
|
|
341
|
+
return credential, database_credentials if credential
|
|
322
342
|
|
|
323
|
-
types =
|
|
324
|
-
|
|
325
|
-
# On v1, we fallback to the DB. We make sure to make --type work, to
|
|
326
|
-
# avoid a confusing experience for customers.
|
|
327
|
-
if database.account.stack.version == 'v1'
|
|
328
|
-
types << database.type
|
|
329
|
-
types.uniq!
|
|
330
|
-
return database if type.nil? || type == database.type
|
|
331
|
-
end
|
|
343
|
+
types = database_credentials.map(&:type)
|
|
332
344
|
|
|
333
345
|
valid = types.join(', ')
|
|
334
346
|
|
|
@@ -365,6 +377,10 @@ module Aptible
|
|
|
365
377
|
end
|
|
366
378
|
|
|
367
379
|
def render_database(database, account)
|
|
380
|
+
# Maybe reload with senstive data
|
|
381
|
+
# Definately don't load the embedded last_operation
|
|
382
|
+
database.href = database.href + '?no_embed=true'
|
|
383
|
+
database = with_sensitive(database) if database.connection_url.nil?
|
|
368
384
|
Formatter.render(Renderer.current) do |root|
|
|
369
385
|
root.keyed_object('connection_url') do |node|
|
|
370
386
|
ResourceFormatter.inject_database(node, database, account)
|
|
@@ -65,7 +65,9 @@ module Aptible
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def ensure_log_drain(account, handle)
|
|
68
|
-
|
|
68
|
+
link = account.links['log_drains'].base_href
|
|
69
|
+
account_drains = Aptible::Api::LogDrain.all(href: link, token: fetch_token)
|
|
70
|
+
drains = account_drains.select { |d| d.handle == handle }
|
|
69
71
|
|
|
70
72
|
if drains.empty?
|
|
71
73
|
raise Thor::Error, "No drain found with handle #{handle}"
|
|
@@ -19,7 +19,9 @@ module Aptible
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def ensure_metric_drain(account, handle)
|
|
22
|
-
|
|
22
|
+
link = account.links['metric_drains'].base_href
|
|
23
|
+
account_drains = Aptible::Api::MetricDrain.all(href: link, token: fetch_token)
|
|
24
|
+
drains = account_drains.select { |d| d.handle == handle }
|
|
23
25
|
|
|
24
26
|
if drains.empty?
|
|
25
27
|
raise Thor::Error, "No drain found with handle #{handle}"
|
|
@@ -128,6 +128,10 @@ module Aptible
|
|
|
128
128
|
end
|
|
129
129
|
|
|
130
130
|
def inject_database(node, database, account)
|
|
131
|
+
# Some callers pass a database object with sensitive attributes already, others do not.
|
|
132
|
+
# Avoid creating extra 'show' activity if we already have the needed info
|
|
133
|
+
database = with_sensitive(database) if database.objects[:database_credentials].nil?
|
|
134
|
+
|
|
131
135
|
node.value('id', database.id)
|
|
132
136
|
node.value('handle', database.handle)
|
|
133
137
|
node.value('created_at', database.created_at)
|
|
@@ -243,6 +247,9 @@ module Aptible
|
|
|
243
247
|
log_drain.drain_ephemeral_sessions)
|
|
244
248
|
node.value('drain_proxies', log_drain.drain_proxies)
|
|
245
249
|
|
|
250
|
+
# These can be either optional for the drain type,
|
|
251
|
+
# or sensitive attributes we don't need to worry about
|
|
252
|
+
# in text output
|
|
246
253
|
optional_attrs = %w(drain_username drain_host drain_port url)
|
|
247
254
|
optional_attrs.each do |attr|
|
|
248
255
|
value = log_drain.attributes[attr]
|
|
@@ -257,7 +264,13 @@ module Aptible
|
|
|
257
264
|
node.value('handle', metric_drain.handle)
|
|
258
265
|
node.value('drain_type', metric_drain.drain_type)
|
|
259
266
|
node.value('created_at', metric_drain.created_at)
|
|
260
|
-
|
|
267
|
+
|
|
268
|
+
# Sensitive attributes we don't need to worry about being missing in text output
|
|
269
|
+
optional_attrs = %w(drain_configuration)
|
|
270
|
+
optional_attrs.each do |attr|
|
|
271
|
+
value = metric_drain.attributes[attr]
|
|
272
|
+
node.value(attr, value) unless value.nil?
|
|
273
|
+
end
|
|
261
274
|
|
|
262
275
|
attach_account(node, account)
|
|
263
276
|
end
|
|
@@ -15,7 +15,7 @@ module Aptible
|
|
|
15
15
|
telemetry(__method__, options)
|
|
16
16
|
|
|
17
17
|
app = ensure_app(options)
|
|
18
|
-
config = app
|
|
18
|
+
config = current_configuration(app)
|
|
19
19
|
env = config ? config.env : {}
|
|
20
20
|
|
|
21
21
|
Formatter.render(Renderer.current) do |root|
|
|
@@ -38,7 +38,7 @@ module Aptible
|
|
|
38
38
|
telemetry(__method__, options)
|
|
39
39
|
|
|
40
40
|
app = ensure_app(options)
|
|
41
|
-
config = app
|
|
41
|
+
config = current_configuration(app)
|
|
42
42
|
env = config ? config.env : {}
|
|
43
43
|
|
|
44
44
|
Formatter.render(Renderer.current) do |root|
|
|
@@ -335,13 +335,13 @@ module Aptible
|
|
|
335
335
|
return use_rds_tunnel(handle, desired_port) if aws_rds_db?(handle)
|
|
336
336
|
|
|
337
337
|
database = ensure_database(options.merge(db: handle))
|
|
338
|
-
credential = find_credential(database, options[:type])
|
|
338
|
+
credential, credentials = find_credential(database, options[:type])
|
|
339
339
|
|
|
340
340
|
m = "Creating #{credential.type} tunnel to #{database.handle}..."
|
|
341
341
|
CLI.logger.info m
|
|
342
342
|
|
|
343
343
|
if options[:type].nil?
|
|
344
|
-
types =
|
|
344
|
+
types = credentials.map(&:type)
|
|
345
345
|
unless types.empty?
|
|
346
346
|
valid = types.join(', ')
|
|
347
347
|
CLI.logger.info 'Use --type TYPE to specify a tunnel type'
|
|
@@ -481,7 +481,8 @@ module Aptible
|
|
|
481
481
|
telemetry(__method__, options.merge(handle: handle))
|
|
482
482
|
|
|
483
483
|
database = ensure_database(options.merge(db: handle))
|
|
484
|
-
|
|
484
|
+
|
|
485
|
+
credential, _credentials = find_credential(database, options[:type])
|
|
485
486
|
|
|
486
487
|
Formatter.render(Renderer.current) do |root|
|
|
487
488
|
root.keyed_object('connection_url') do |node|
|
|
@@ -44,6 +44,8 @@ module Aptible
|
|
|
44
44
|
account = acc_map[drain.links.account.href]
|
|
45
45
|
next if account.nil?
|
|
46
46
|
|
|
47
|
+
# JSON output format we potentially show sensitive attributes
|
|
48
|
+
drain = with_sensitive(drain) if Renderer.format == 'json'
|
|
47
49
|
node.object do |n|
|
|
48
50
|
ResourceFormatter.inject_log_drain(n, drain, account)
|
|
49
51
|
end
|
|
@@ -134,11 +134,11 @@ module Aptible
|
|
|
134
134
|
options[:string_matches]
|
|
135
135
|
)
|
|
136
136
|
elsif id_options.any?
|
|
137
|
-
if options[:container_id]
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
137
|
+
search_attrs = if options[:container_id]
|
|
138
|
+
{ container_id: options[:container_id] }
|
|
139
|
+
else
|
|
140
|
+
{ type: r_type, id: id_options.compact.first }
|
|
141
|
+
end
|
|
142
142
|
files = find_s3_files_by_attrs(
|
|
143
143
|
options[:region],
|
|
144
144
|
options[:bucket],
|
|
@@ -38,6 +38,8 @@ module Aptible
|
|
|
38
38
|
account = acc_map[drain.links.account.href]
|
|
39
39
|
next if account.nil?
|
|
40
40
|
|
|
41
|
+
# JSON output format we potentially show sensitive attributes
|
|
42
|
+
drain = with_sensitive(drain) if Renderer.format == 'json'
|
|
41
43
|
node.object do |n|
|
|
42
44
|
ResourceFormatter.inject_metric_drain(n, drain, account)
|
|
43
45
|
end
|
data/lib/aptible/cli/version.rb
CHANGED
data/lib/aptible/cli.rb
CHANGED
|
@@ -7,6 +7,20 @@ require 'aptible/cli/formatter'
|
|
|
7
7
|
require 'aptible/cli/renderer'
|
|
8
8
|
require 'aptible/cli/resource_formatter'
|
|
9
9
|
|
|
10
|
+
# Set no_sensitive_extras=true as the default for all API resources.
|
|
11
|
+
# This avoids returning sensitive embedded data unless explicitly requested.
|
|
12
|
+
Aptible::Api::Resource.headers = { 'Prefer' => 'no_sensitive_extras=true' }
|
|
13
|
+
|
|
14
|
+
def with_sensitive(resource)
|
|
15
|
+
resource.headers['Prefer'] = 'no_sensitive_extras=false'
|
|
16
|
+
resource.find_by_url(resource.href)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def without_sensitive(resource)
|
|
20
|
+
resource.headers['Prefer'] = 'no_sensitive_extras=true'
|
|
21
|
+
resource.find_by_url(resource.href)
|
|
22
|
+
end
|
|
23
|
+
|
|
10
24
|
module Aptible
|
|
11
25
|
module CLI
|
|
12
26
|
class TtyLogFormatter
|
|
@@ -17,6 +17,9 @@ describe Aptible::CLI::Agent do
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
before { allow(subject).to receive(:options) { { app: app.handle } } }
|
|
20
|
+
before do
|
|
21
|
+
allow(subject).to receive(:current_configuration, &:current_configuration)
|
|
22
|
+
end
|
|
20
23
|
let(:operation) { Fabricate(:operation, resource: app) }
|
|
21
24
|
|
|
22
25
|
describe '#config' do
|
|
@@ -60,6 +63,11 @@ describe Aptible::CLI::Agent do
|
|
|
60
63
|
end
|
|
61
64
|
|
|
62
65
|
describe '#config:get' do
|
|
66
|
+
it 'shows nothing for an unconfigured app' do
|
|
67
|
+
subject.send('config:get', 'FOO')
|
|
68
|
+
expect(captured_output_text).to eq('')
|
|
69
|
+
end
|
|
70
|
+
|
|
63
71
|
it 'should show single environment variable specified' do
|
|
64
72
|
app.current_configuration = Fabricate(
|
|
65
73
|
:configuration, app: app, env: { 'FOO' => 'BAR', 'QUX' => 'two words' }
|
|
@@ -10,6 +10,9 @@ describe Aptible::CLI::Agent do
|
|
|
10
10
|
allow(subject).to receive(:ask)
|
|
11
11
|
allow(subject).to receive(:save_token)
|
|
12
12
|
allow(subject).to receive(:fetch_token) { token }
|
|
13
|
+
allow(Aptible::Api::DatabaseCredential).to receive(:all) do
|
|
14
|
+
database.database_credentials
|
|
15
|
+
end
|
|
13
16
|
end
|
|
14
17
|
|
|
15
18
|
let(:handle) { 'foobar' }
|
|
@@ -226,41 +229,6 @@ describe Aptible::CLI::Agent do
|
|
|
226
229
|
expect { subject.send('db:tunnel', handle) }
|
|
227
230
|
.to raise_error(/foobar is not provisioned/im)
|
|
228
231
|
end
|
|
229
|
-
|
|
230
|
-
context 'v1 stack' do
|
|
231
|
-
before do
|
|
232
|
-
allow(database.account.stack).to receive(:version) { 'v1' }
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
it 'falls back to the database itself if no type is given' do
|
|
236
|
-
expect(subject).to receive(:with_local_tunnel).with(database, 0)
|
|
237
|
-
subject.send('db:tunnel', handle)
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
it 'falls back to the database itself if type matches' do
|
|
241
|
-
subject.options = { type: 'bar' }
|
|
242
|
-
allow(database).to receive(:type) { 'bar' }
|
|
243
|
-
|
|
244
|
-
expect(subject).to receive(:with_local_tunnel).with(database, 0)
|
|
245
|
-
subject.send('db:tunnel', handle)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
it 'does not fall back to the database itself if type mismatches' do
|
|
249
|
-
subject.options = { type: 'bar' }
|
|
250
|
-
allow(database).to receive(:type) { 'foo' }
|
|
251
|
-
|
|
252
|
-
expect { subject.send('db:tunnel', handle) }
|
|
253
|
-
.to raise_error(/no credential with type bar/im)
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
it 'does not suggest other types that do not exist' do
|
|
257
|
-
expect(subject).to receive(:with_local_tunnel).with(database, 0)
|
|
258
|
-
|
|
259
|
-
subject.send('db:tunnel', handle)
|
|
260
|
-
|
|
261
|
-
expect(captured_logs).not_to match(/use --type type/i)
|
|
262
|
-
end
|
|
263
|
-
end
|
|
264
232
|
end
|
|
265
233
|
end
|
|
266
234
|
|
|
@@ -845,22 +813,6 @@ describe Aptible::CLI::Agent do
|
|
|
845
813
|
expect { subject.send('db:url', handle) }
|
|
846
814
|
.to raise_error(/Multiple databases/)
|
|
847
815
|
end
|
|
848
|
-
|
|
849
|
-
context 'v1 stack' do
|
|
850
|
-
before do
|
|
851
|
-
allow(database.account.stack).to receive(:version) { 'v1' }
|
|
852
|
-
end
|
|
853
|
-
|
|
854
|
-
it 'returns the URL of a specified DB' do
|
|
855
|
-
connection_url = 'postgresql://aptible-v1:password@lega.cy:4242/db'
|
|
856
|
-
expect(database).to receive(:connection_url)
|
|
857
|
-
.and_return(connection_url)
|
|
858
|
-
|
|
859
|
-
subject.send('db:url', handle)
|
|
860
|
-
|
|
861
|
-
expect(captured_output_text.chomp).to eq(connection_url)
|
|
862
|
-
end
|
|
863
|
-
end
|
|
864
816
|
end
|
|
865
817
|
end
|
|
866
818
|
|
|
@@ -14,9 +14,15 @@ describe Aptible::CLI::Agent do
|
|
|
14
14
|
.with(token: token, href: '/log_drains?per_page=5000')
|
|
15
15
|
.and_return([log_drain])
|
|
16
16
|
|
|
17
|
+
allow(Aptible::Api::LogDrain).to receive(:all)
|
|
18
|
+
.with(token: token, href: "/accounts/#{account.id}/log_drains")
|
|
19
|
+
.and_return([log_drain])
|
|
20
|
+
|
|
17
21
|
allow(Aptible::Api::Account).to receive(:all)
|
|
18
22
|
.with(token: token, href: '/accounts?per_page=5000&no_embed=true')
|
|
19
23
|
.and_return([account])
|
|
24
|
+
|
|
25
|
+
allow(account).to receive(:reload).and_return(account)
|
|
20
26
|
end
|
|
21
27
|
|
|
22
28
|
describe '#log_drain:list' do
|
|
@@ -14,6 +14,10 @@ describe Aptible::CLI::Agent do
|
|
|
14
14
|
.with(token: token, href: '/metric_drains?per_page=5000')
|
|
15
15
|
.and_return([metric_drain])
|
|
16
16
|
|
|
17
|
+
allow(Aptible::Api::MetricDrain).to receive(:all)
|
|
18
|
+
.with(token: token, href: "/accounts/#{account.id}/metric_drains")
|
|
19
|
+
.and_return([metric_drain])
|
|
20
|
+
|
|
17
21
|
allow(Aptible::Api::Account).to receive(:all)
|
|
18
22
|
.with(token: token, href: '/accounts?per_page=5000&no_embed=true')
|
|
19
23
|
.and_return([account])
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class StubAccount <
|
|
1
|
+
class StubAccount < StubAptibleResource
|
|
2
2
|
def each_app(&block)
|
|
3
3
|
return enum_for(:each_app) if block.nil?
|
|
4
4
|
apps.each(&block)
|
|
@@ -34,6 +34,14 @@ Fabricator(:account, from: :stub_account) do
|
|
|
34
34
|
hash = {
|
|
35
35
|
self: OpenStruct.new(
|
|
36
36
|
href: "/accounts/#{attrs[:id]}"
|
|
37
|
+
),
|
|
38
|
+
metric_drains: OpenStruct.new(
|
|
39
|
+
base_href: "/accounts/#{attrs[:id]}/metric_drains",
|
|
40
|
+
href: "/accounts/#{attrs[:id]}/metric_drains"
|
|
41
|
+
),
|
|
42
|
+
log_drains: OpenStruct.new(
|
|
43
|
+
base_href: "/accounts/#{attrs[:id]}/log_drains",
|
|
44
|
+
href: "/accounts/#{attrs[:id]}/log_drains"
|
|
37
45
|
)
|
|
38
46
|
}
|
|
39
47
|
OpenStruct.new(hash)
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
class StubDatabase <
|
|
1
|
+
class StubDatabase < StubAptibleResource
|
|
2
2
|
def provisioned?
|
|
3
3
|
status == 'provisioned'
|
|
4
4
|
end
|
|
5
|
+
|
|
6
|
+
def objects
|
|
7
|
+
{
|
|
8
|
+
'database_credentials' => database_credentials
|
|
9
|
+
}
|
|
10
|
+
end
|
|
5
11
|
end
|
|
6
12
|
|
|
7
13
|
Fabricator(:database, from: :stub_database) do
|
|
@@ -23,6 +29,9 @@ Fabricator(:database, from: :stub_database) do
|
|
|
23
29
|
hash = {
|
|
24
30
|
account: OpenStruct.new(
|
|
25
31
|
href: "/accounts/#{attrs[:account].id}"
|
|
32
|
+
),
|
|
33
|
+
database_credentials: OpenStruct.new(
|
|
34
|
+
href: "/databases/#{attrs[:handle]}/database_credentials"
|
|
26
35
|
)
|
|
27
36
|
}
|
|
28
37
|
OpenStruct.new(hash)
|
|
@@ -1,7 +1,21 @@
|
|
|
1
|
-
class StubMetricDrain <
|
|
1
|
+
class StubMetricDrain < StubAptibleResource
|
|
2
|
+
def attributes
|
|
3
|
+
# Don't blame me, I'm just following the example in StubLogDrain,
|
|
4
|
+
# see the comment there.
|
|
5
|
+
{
|
|
6
|
+
'drain_configuration' => drain_configuration
|
|
7
|
+
}
|
|
8
|
+
end
|
|
9
|
+
end
|
|
2
10
|
|
|
3
11
|
Fabricator(:metric_drain, from: :stub_metric_drain) do
|
|
4
12
|
id { sequence(:metric_drain_id) }
|
|
13
|
+
drain_configuration do
|
|
14
|
+
{
|
|
15
|
+
'api_key' => 'asdf',
|
|
16
|
+
'series_url' => 'https://localhost.aptible.in/api/v1/series'
|
|
17
|
+
}
|
|
18
|
+
end
|
|
5
19
|
account
|
|
6
20
|
links do |attrs|
|
|
7
21
|
hash = {
|
data/spec/spec_helper.rb
CHANGED
|
@@ -8,6 +8,11 @@ Dir["#{File.dirname(__FILE__)}/shared/**/*.rb"].each do |file|
|
|
|
8
8
|
require file
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
# Load support files (shared classes used by fabricators, etc.)
|
|
12
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each do |file|
|
|
13
|
+
require file
|
|
14
|
+
end
|
|
15
|
+
|
|
11
16
|
# Require library up front
|
|
12
17
|
require 'aptible/cli'
|
|
13
18
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
class StubAptibleResource < OpenStruct
|
|
2
|
+
def headers
|
|
3
|
+
@headers ||= {}
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def find_by_url(_url)
|
|
7
|
+
self
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def href
|
|
11
|
+
self[:href] || "/#{self.class.resource_path}/#{id}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.resource_path
|
|
15
|
+
name = to_s.sub(/^Stub/, '')
|
|
16
|
+
snake = name.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
17
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
18
|
+
.downcase
|
|
19
|
+
if snake.end_with?('y')
|
|
20
|
+
snake.sub(/y$/, 'ies')
|
|
21
|
+
else
|
|
22
|
+
"#{snake}s"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
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.4
|
|
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-03-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -478,6 +478,7 @@ files:
|
|
|
478
478
|
- ".github/workflows/test.yml"
|
|
479
479
|
- ".gitignore"
|
|
480
480
|
- ".rspec"
|
|
481
|
+
- ".rubocop.yml"
|
|
481
482
|
- Dockerfile
|
|
482
483
|
- Gemfile
|
|
483
484
|
- Gemfile.lock
|
|
@@ -619,6 +620,7 @@ files:
|
|
|
619
620
|
- spec/script/ssh-spawn
|
|
620
621
|
- spec/shared/mock_ssh_context.rb
|
|
621
622
|
- spec/spec_helper.rb
|
|
623
|
+
- spec/support/stub_aptible_resource.rb
|
|
622
624
|
homepage: https://github.com/aptible/aptible-cli
|
|
623
625
|
licenses:
|
|
624
626
|
- MIT
|
|
@@ -712,3 +714,4 @@ test_files:
|
|
|
712
714
|
- spec/script/ssh-spawn
|
|
713
715
|
- spec/shared/mock_ssh_context.rb
|
|
714
716
|
- spec/spec_helper.rb
|
|
717
|
+
- spec/support/stub_aptible_resource.rb
|