aptible-cli 0.16.2 → 0.16.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.
@@ -2,14 +2,17 @@ require 'spec_helper'
2
2
 
3
3
  describe Aptible::CLI::Agent do
4
4
  let(:token) { 'some-token' }
5
- let(:account) { Fabricate(:account, handle: 'test') }
5
+ let(:account) { Fabricate(:account, handle: 'test', id: 1) }
6
6
  let(:alt_account) { Fabricate(:account, handle: 'alt') }
7
7
  let(:database) { Fabricate(:database, account: account, handle: 'some-db') }
8
8
  let!(:backup) do
9
9
  # created_at: 2016-06-14 13:24:11 +0000
10
10
  Fabricate(
11
11
  :backup,
12
- database: database, created_at: Time.at(1465910651), account: account
12
+ database_with_deleted: database,
13
+ created_at: Time.at(1465910651),
14
+ account: account,
15
+ id: 1
13
16
  )
14
17
  end
15
18
 
@@ -178,4 +181,78 @@ describe Aptible::CLI::Agent do
178
181
  .to raise_error(Thor::Error, 'Could not find database nope')
179
182
  end
180
183
  end
184
+
185
+ describe '#backup:orphaned' do
186
+ before { allow(Aptible::Api::Account).to receive(:all) { [account] } }
187
+ before do
188
+ m = allow(account).to receive(:each_orphaned_backup)
189
+ ages = [
190
+ 1.day, 2.days, 3.days, 4.days,
191
+ 5.days, 2.weeks, 3.weeks, 1.month,
192
+ 1.year
193
+ ]
194
+ ages.each do |age|
195
+ b = Fabricate(:backup, database: database, created_at: age.ago,
196
+ account: account)
197
+ allow(b).to receive(:database_with_deleted).and_return(database)
198
+ m.and_yield(b)
199
+ b
200
+ end
201
+ end
202
+ before { subject.options = { max_age: '1w' } }
203
+
204
+ it 'can show a subset of backups' do
205
+ subject.send('backup:orphaned')
206
+ puts captured_output_text
207
+ expect(captured_output_text.split("\n").size).to eq(5)
208
+ end
209
+
210
+ it 'allows scoping via environment' do
211
+ subject.options = { max_age: '1w', environment: database.account.handle }
212
+ subject.send('backup:orphaned')
213
+ expect(captured_output_text.split("\n").size).to eq(5)
214
+ end
215
+
216
+ it 'shows more backups if requested' do
217
+ subject.options = { max_age: '2y' }
218
+ subject.send('backup:orphaned')
219
+ expect(captured_output_text.split("\n").size).to eq(9)
220
+ end
221
+
222
+ it 'errors out if max_age is invalid' do
223
+ subject.options = { max_age: 'foobar' }
224
+ expect { subject.send('backup:orphaned') }
225
+ .to raise_error(Thor::Error, 'Invalid age: foobar')
226
+ end
227
+ end
228
+
229
+ describe '#backup:purge' do
230
+ it 'fails if the backup cannot be found' do
231
+ expect(Aptible::Api::Backup).to receive(:find)
232
+ .with(1, token: token).and_return(nil)
233
+
234
+ expect { subject.send('backup:purge', 1) }
235
+ .to raise_error('Backup #1 not found')
236
+ end
237
+
238
+ context 'successful purge' do
239
+ let(:op) { Fabricate(:operation, resource: backup) }
240
+
241
+ before do
242
+ expect(Aptible::Api::Backup).to receive(:find)
243
+ .with(1, token: token).and_return(backup)
244
+ end
245
+
246
+ it 'creates a purge operation on the backup' do
247
+ expect(backup).to receive(:create_operation!) do |options|
248
+ expect(options[:type]).to eq('purge')
249
+ op
250
+ end
251
+
252
+ expect(subject).to receive(:attach_to_operation_logs).with(op)
253
+
254
+ subject.send('backup:purge', 1)
255
+ end
256
+ end
257
+ end
181
258
  end
@@ -55,7 +55,7 @@ describe Aptible::CLI::Agent do
55
55
  subject.send('db:create', 'foo')
56
56
  end
57
57
 
58
- it 'creates a new DB with a disk size' do
58
+ it 'creates a new DB with a (implicitly) disk size' do
59
59
  expect_provision_database(
60
60
  { handle: 'foo', type: 'postgresql', initial_disk_size: 200 },
61
61
  { disk_size: 200 }
@@ -65,6 +65,16 @@ describe Aptible::CLI::Agent do
65
65
  subject.send('db:create', 'foo')
66
66
  end
67
67
 
68
+ it 'creates a new DB with a disk-size' do
69
+ expect_provision_database(
70
+ { handle: 'foo', type: 'postgresql', initial_disk_size: 200 },
71
+ { disk_size: 200 }
72
+ )
73
+
74
+ subject.options = { type: 'postgresql', disk_size: 200 }
75
+ subject.send('db:create', 'foo')
76
+ end
77
+
68
78
  it 'deprovisions the database if the operation cannot be created' do
69
79
  db = Fabricate(:database)
70
80
 
@@ -377,7 +387,7 @@ describe Aptible::CLI::Agent do
377
387
  expect(captured_logs).to match(/restarting foobar/i)
378
388
  end
379
389
 
380
- it 'allows restarting a database with a disk size' do
390
+ it 'allows restarting a database with (implicitly disk) size' do
381
391
  expect(database).to receive(:create_operation!)
382
392
  .with(type: 'restart', disk_size: 40).and_return(op)
383
393
 
@@ -389,6 +399,18 @@ describe Aptible::CLI::Agent do
389
399
  expect(captured_logs).to match(/restarting foobar/i)
390
400
  end
391
401
 
402
+ it 'allows restarting a database with a disk-size' do
403
+ expect(database).to receive(:create_operation!)
404
+ .with(type: 'restart', disk_size: 40).and_return(op)
405
+
406
+ expect(subject).to receive(:attach_to_operation_logs).with(op)
407
+
408
+ subject.options = { disk_size: 40 }
409
+ subject.send('db:restart', handle)
410
+
411
+ expect(captured_logs).to match(/restarting foobar/i)
412
+ end
413
+
392
414
  it 'fails if the DB is not found' do
393
415
  expect { subject.send('db:restart', 'nope') }
394
416
  .to raise_error(Thor::Error, 'Could not find database nope')
@@ -439,6 +461,129 @@ describe Aptible::CLI::Agent do
439
461
  end
440
462
  end
441
463
 
464
+ describe '#db:replicate' do
465
+ let(:databases) { [] }
466
+ before { allow(Aptible::Api::Database).to receive(:all) { databases } }
467
+
468
+ def expect_replicate_database(opts = {})
469
+ master = Fabricate(:database, handle: 'master')
470
+ databases << master
471
+ replica = Fabricate(:database,
472
+ account: master.account,
473
+ handle: 'replica')
474
+
475
+ op = Fabricate(:operation)
476
+
477
+ params = { type: 'replicate', handle: 'replica' }.merge(opts)
478
+ params[:disk_size] = params.delete(:size) if params[:size]
479
+ expect(master).to receive(:create_operation!)
480
+ .with(**params).and_return(op)
481
+
482
+ expect(subject).to receive(:attach_to_operation_logs).with(op) do
483
+ databases << replica
484
+ replica
485
+ end
486
+
487
+ provision = Fabricate(:operation)
488
+
489
+ expect(replica).to receive_message_chain(:operations, :last)
490
+ .and_return(provision)
491
+
492
+ expect(subject).to receive(:attach_to_operation_logs).with(provision)
493
+
494
+ expect(replica).to receive(:reload).and_return(replica)
495
+
496
+ subject.options = opts
497
+ subject.send('db:replicate', 'master', 'replica')
498
+
499
+ expect(captured_logs).to match(/replicating master/i)
500
+ end
501
+
502
+ it 'allows replicating an existing database' do
503
+ expect_replicate_database
504
+ end
505
+
506
+ it 'allows replicating a database with a container size' do
507
+ expect_replicate_database(container_size: 40)
508
+ end
509
+
510
+ it 'allows replicating a database with an (implicitly) disk size option' do
511
+ expect_replicate_database(size: 40)
512
+ end
513
+
514
+ it 'allows replicating a database with a disk-size option' do
515
+ expect_replicate_database(disk_size: 40)
516
+ end
517
+
518
+ it 'fails if the DB is not found' do
519
+ expect { subject.send('db:replicate', 'nope', 'replica') }
520
+ .to raise_error(Thor::Error, 'Could not find database nope')
521
+ end
522
+
523
+ it 'allows logical replication of a database with --version set' do
524
+ master = Fabricate(:database, handle: 'master')
525
+ databases << master
526
+ replica = Fabricate(:database,
527
+ account: master.account,
528
+ handle: 'replica')
529
+
530
+ dbimg = Fabricate(:database_image,
531
+ type: 'postgresql',
532
+ version: 10,
533
+ docker_repo: 'aptible/postgresql:10')
534
+
535
+ expect(subject).to receive(:find_database_image).with('postgresql', 10)
536
+ .and_return(dbimg)
537
+
538
+ op = Fabricate(:operation)
539
+
540
+ params = { type: 'replicate_logical', handle: 'replica',
541
+ docker_ref: dbimg.docker_repo }
542
+ expect(master).to receive(:create_operation!)
543
+ .with(**params).and_return(op)
544
+
545
+ expect(subject).to receive(:attach_to_operation_logs).with(op) do
546
+ databases << replica
547
+ replica
548
+ end
549
+
550
+ provision = Fabricate(:operation)
551
+
552
+ expect(replica).to receive_message_chain(:operations, :last)
553
+ .and_return(provision)
554
+
555
+ expect(subject).to receive(:attach_to_operation_logs).with(provision)
556
+
557
+ expect(replica).to receive(:reload).and_return(replica)
558
+
559
+ subject.options = { logical: true, version: 10 }
560
+ subject.send('db:replicate', 'master', 'replica')
561
+
562
+ expect(captured_logs).to match(/replicating master/i)
563
+ end
564
+
565
+ it 'fails if logical replication requested without --version' do
566
+ master = Fabricate(:database, handle: 'master', type: 'postgresql')
567
+ databases << master
568
+
569
+ subject.options = { type: 'replicate', handle: 'replica', logical: true }
570
+ expect { subject.send('db:replicate', 'master', 'replica') }
571
+ .to raise_error(Thor::Error, '--version is required for logical ' \
572
+ 'replication')
573
+ end
574
+
575
+ it 'fails if logical replication requested for non-postgres db' do
576
+ master = Fabricate(:database, handle: 'master', type: 'mysql')
577
+ databases << master
578
+
579
+ subject.options = { type: 'replicate', handle: 'replica',
580
+ logical: true, version: 10 }
581
+ expect { subject.send('db:replicate', 'master', 'replica') }
582
+ .to raise_error(Thor::Error, 'Logical replication only works for ' \
583
+ 'PostgreSQL')
584
+ end
585
+ end
586
+
442
587
  describe '#db:dump' do
443
588
  it 'should fail if database is non-existent' do
444
589
  allow(Aptible::Api::Database).to receive(:all) { [] }
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.16.2
4
+ version: 0.16.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: 2019-07-11 00:00:00.000000000 Z
11
+ date: 2020-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aptible-resource
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.0'
33
+ version: '1.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.0'
40
+ version: '1.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: aptible-auth
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.0'
47
+ version: 1.1.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.0'
54
+ version: 1.1.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: aptible-billing
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -277,7 +277,9 @@ files:
277
277
  - lib/aptible/cli/helpers/database.rb
278
278
  - lib/aptible/cli/helpers/environment.rb
279
279
  - lib/aptible/cli/helpers/operation.rb
280
+ - lib/aptible/cli/helpers/security_key.rb
280
281
  - lib/aptible/cli/helpers/ssh.rb
282
+ - lib/aptible/cli/helpers/system.rb
281
283
  - lib/aptible/cli/helpers/token.rb
282
284
  - lib/aptible/cli/helpers/tunnel.rb
283
285
  - lib/aptible/cli/helpers/vhost.rb
@@ -372,8 +374,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
372
374
  - !ruby/object:Gem::Version
373
375
  version: '0'
374
376
  requirements: []
375
- rubyforge_project:
376
- rubygems_version: 2.7.6
377
+ rubygems_version: 3.0.3
377
378
  signing_key:
378
379
  specification_version: 4
379
380
  summary: Command-line interface for Aptible services