aptible-cli 0.16.3 → 0.16.8
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/.travis.yml +1 -0
- data/Gemfile +0 -1
- data/README.md +48 -47
- data/appveyor.yml +1 -7
- data/aptible-cli.gemspec +2 -2
- data/lib/aptible/cli/agent.rb +33 -0
- data/lib/aptible/cli/helpers/database.rb +14 -4
- data/lib/aptible/cli/resource_formatter.rb +36 -1
- data/lib/aptible/cli/subcommands/backup.rb +60 -13
- data/lib/aptible/cli/subcommands/db.rb +60 -8
- data/lib/aptible/cli/subcommands/inspect.rb +1 -1
- data/lib/aptible/cli/version.rb +1 -1
- data/spec/aptible/cli/agent_spec.rb +30 -0
- data/spec/aptible/cli/subcommands/backup_spec.rb +79 -2
- data/spec/aptible/cli/subcommands/db_spec.rb +95 -4
- data/spec/spec_helper.rb +0 -8
- metadata +10 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7f9abbc0bef99a8ca0f69c0b3d9751e529d9b37b5528315b03481acc84b68868
|
|
4
|
+
data.tar.gz: 916d97a558b654865ae9cbcf4532058a9070d19dbe6d984be7a5f233eb2884e6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6ef0c0c9dc25afdf19b680fcabcfd589cd74f246d7442361e79ef5f01d73382bd10ee21c9ca63a31a3f6a003ef0405c651b03e251c6e36525ddfebc86df7aeee
|
|
7
|
+
data.tar.gz: 3457904ef7ab8e5ff0a5a63fd856633fea48460e8dd88b0ae5ba8181494d893bfe45027927e57c7b217cc89fb39f09eb3fe27abdcb929d1b6fd8d6ca7a6a5b18
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
[](https://rubygems.org/gems/aptible-cli)
|
|
4
4
|
[](https://travis-ci.org/aptible/aptible-cli)
|
|
5
5
|
[](https://gemnasium.com/aptible/aptible-cli)
|
|
6
|
-
[](https://codecov.io/gh/aptible/aptible-cli)
|
|
7
6
|
[](http://waffle.io/aptible/aptible-cli)
|
|
8
7
|
|
|
9
8
|
Command-line interface for Aptible services.
|
|
@@ -29,52 +28,54 @@ From `aptible help`:
|
|
|
29
28
|
<!-- BEGIN USAGE -->
|
|
30
29
|
```
|
|
31
30
|
Commands:
|
|
32
|
-
aptible apps
|
|
33
|
-
aptible apps:create HANDLE
|
|
34
|
-
aptible apps:deprovision
|
|
35
|
-
aptible apps:scale SERVICE [--container-count COUNT] [--container-size SIZE_MB]
|
|
36
|
-
aptible backup:list DB_HANDLE
|
|
37
|
-
aptible backup:
|
|
38
|
-
aptible
|
|
39
|
-
aptible
|
|
40
|
-
aptible config
|
|
41
|
-
aptible config:
|
|
42
|
-
aptible config:
|
|
43
|
-
aptible
|
|
44
|
-
aptible
|
|
45
|
-
aptible db:
|
|
46
|
-
aptible db:
|
|
47
|
-
aptible db:
|
|
48
|
-
aptible db:
|
|
49
|
-
aptible db:
|
|
50
|
-
aptible db:
|
|
51
|
-
aptible db:
|
|
52
|
-
aptible db:
|
|
53
|
-
aptible db:
|
|
54
|
-
aptible db:
|
|
55
|
-
aptible db:
|
|
56
|
-
aptible
|
|
57
|
-
aptible
|
|
58
|
-
aptible
|
|
59
|
-
aptible
|
|
60
|
-
aptible endpoints:
|
|
61
|
-
aptible endpoints:
|
|
62
|
-
aptible endpoints:
|
|
63
|
-
aptible endpoints:
|
|
64
|
-
aptible endpoints:
|
|
65
|
-
aptible endpoints:
|
|
66
|
-
aptible endpoints:
|
|
67
|
-
aptible endpoints:
|
|
68
|
-
aptible
|
|
69
|
-
aptible
|
|
70
|
-
aptible
|
|
71
|
-
aptible
|
|
72
|
-
aptible
|
|
73
|
-
aptible
|
|
74
|
-
aptible
|
|
75
|
-
aptible
|
|
76
|
-
aptible
|
|
77
|
-
aptible
|
|
31
|
+
aptible apps # List all applications
|
|
32
|
+
aptible apps:create HANDLE # Create a new application
|
|
33
|
+
aptible apps:deprovision # Deprovision an app
|
|
34
|
+
aptible apps:scale SERVICE [--container-count COUNT] [--container-size SIZE_MB] # Scale a service
|
|
35
|
+
aptible backup:list DB_HANDLE # List backups for a database
|
|
36
|
+
aptible backup:orphaned # List backups associated with deprovisioned databases
|
|
37
|
+
aptible backup:purge BACKUP_ID # Permanently delete a backup and any copies of it
|
|
38
|
+
aptible backup:restore BACKUP_ID [--environment ENVIRONMENT_HANDLE] [--handle HANDLE] [--container-size SIZE_MB] [--disk-size SIZE_GB] [--key-arn KEY_ARN] # Restore a backup
|
|
39
|
+
aptible config # Print an app's current configuration
|
|
40
|
+
aptible config:add [VAR1=VAL1] [VAR2=VAL2] [...] # Add an ENV variable to an app
|
|
41
|
+
aptible config:rm [VAR1] [VAR2] [...] # Remove an ENV variable from an app
|
|
42
|
+
aptible config:set [VAR1=VAL1] [VAR2=VAL2] [...] # Add an ENV variable to an app
|
|
43
|
+
aptible config:unset [VAR1] [VAR2] [...] # Remove an ENV variable from an app
|
|
44
|
+
aptible db:backup HANDLE # Backup a database
|
|
45
|
+
aptible db:clone SOURCE DEST # Clone a database to create a new one
|
|
46
|
+
aptible db:create HANDLE [--type TYPE] [--version VERSION] [--container-size SIZE_MB] [--disk-size SIZE_GB] [--key-arn KEY_ARN] # Create a new database
|
|
47
|
+
aptible db:deprovision HANDLE # Deprovision a database
|
|
48
|
+
aptible db:dump HANDLE [pg_dump options] # Dump a remote database to file
|
|
49
|
+
aptible db:execute HANDLE SQL_FILE [--on-error-stop] # Executes sql against a database
|
|
50
|
+
aptible db:list # List all databases
|
|
51
|
+
aptible db:reload HANDLE # Reload a database
|
|
52
|
+
aptible db:replicate HANDLE REPLICA_HANDLE [--container-size SIZE_MB] [--disk-size SIZE_GB] [--logical --version VERSION] [--key-arn KEY_ARN] # Create a replica/follower of a database
|
|
53
|
+
aptible db:restart HANDLE [--container-size SIZE_MB] [--disk-size SIZE_GB] # Restart a database
|
|
54
|
+
aptible db:tunnel HANDLE # Create a local tunnel to a database
|
|
55
|
+
aptible db:url HANDLE # Display a database URL
|
|
56
|
+
aptible db:versions # List available database versions
|
|
57
|
+
aptible deploy [OPTIONS] [VAR1=VAL1] [VAR2=VAL2] [...] # Deploy an app
|
|
58
|
+
aptible domains # Print an app's current virtual domains - DEPRECATED
|
|
59
|
+
aptible endpoints:database:create DATABASE # Create a Database Endpoint
|
|
60
|
+
aptible endpoints:deprovision [--app APP | --database DATABASE] ENDPOINT_HOSTNAME # Deprovision an App or Database Endpoint
|
|
61
|
+
aptible endpoints:https:create [--app APP] SERVICE # Create an App HTTPS Endpoint
|
|
62
|
+
aptible endpoints:https:modify [--app APP] ENDPOINT_HOSTNAME # Modify an App HTTPS Endpoint
|
|
63
|
+
aptible endpoints:list [--app APP | --database DATABASE] # List Endpoints for an App or Database
|
|
64
|
+
aptible endpoints:renew [--app APP] ENDPOINT_HOSTNAME # Renew an App Managed TLS Endpoint
|
|
65
|
+
aptible endpoints:tcp:create [--app APP] SERVICE # Create an App TCP Endpoint
|
|
66
|
+
aptible endpoints:tcp:modify [--app APP] ENDPOINT_HOSTNAME # Modify an App TCP Endpoint
|
|
67
|
+
aptible endpoints:tls:create [--app APP] SERVICE # Create an App TLS Endpoint
|
|
68
|
+
aptible endpoints:tls:modify [--app APP] ENDPOINT_HOSTNAME # Modify an App TLS Endpoint
|
|
69
|
+
aptible help [COMMAND] # Describe available commands or one specific command
|
|
70
|
+
aptible login # Log in to Aptible
|
|
71
|
+
aptible logs [--app APP | --database DATABASE] # Follows logs from a running app or database
|
|
72
|
+
aptible operation:cancel OPERATION_ID # Cancel a running operation
|
|
73
|
+
aptible ps # Display running processes for an app - DEPRECATED
|
|
74
|
+
aptible rebuild # Rebuild an app, and restart its services
|
|
75
|
+
aptible restart # Restart all services associated with an app
|
|
76
|
+
aptible services # List Services for an App
|
|
77
|
+
aptible ssh [COMMAND] # Run a command against an app
|
|
78
|
+
aptible version # Print Aptible CLI version
|
|
78
79
|
```
|
|
79
80
|
<!-- END USAGE -->
|
|
80
81
|
|
data/appveyor.yml
CHANGED
|
@@ -8,12 +8,6 @@ environment:
|
|
|
8
8
|
- RUBY_VERSION: 23
|
|
9
9
|
|
|
10
10
|
install:
|
|
11
|
-
# The SSL_CERT_* environment variables are here since otherwise calls to
|
|
12
|
-
# codecov.io wtill not work. These variables do have to be set in order for
|
|
13
|
-
# the gem to make calls to the Aptible API, since otherwise Ruby will fail
|
|
14
|
-
# with a certificate verification error.
|
|
15
|
-
- set SSL_CERT_DIR=%PROGRAMFILES%\Git\mingw64\ssl\certs
|
|
16
|
-
- set SSL_CERT_FILE=%PROGRAMFILES%\Git\mingw64\ssl\cert.pem
|
|
17
11
|
# Override PATHEXT so our ssh bat file has a higher precedence.
|
|
18
12
|
- set PATHEXT=.BAT;.COM;.EXE;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
|
|
19
13
|
- set PATH=C:\Ruby%RUBY_VERSION%-x64\bin;%PATH%
|
|
@@ -28,4 +22,4 @@ before_test:
|
|
|
28
22
|
- bundle -v
|
|
29
23
|
|
|
30
24
|
test_script:
|
|
31
|
-
- bundle exec rake ci
|
|
25
|
+
- bundle exec rake ci
|
data/aptible-cli.gemspec
CHANGED
|
@@ -21,8 +21,8 @@ Gem::Specification.new do |spec|
|
|
|
21
21
|
spec.require_paths = ['lib']
|
|
22
22
|
|
|
23
23
|
spec.add_dependency 'aptible-resource', '~> 1.1'
|
|
24
|
-
spec.add_dependency 'aptible-api', '~> 1.
|
|
25
|
-
spec.add_dependency 'aptible-auth', '~> 1.
|
|
24
|
+
spec.add_dependency 'aptible-api', '~> 1.2'
|
|
25
|
+
spec.add_dependency 'aptible-auth', '~> 1.2.3'
|
|
26
26
|
spec.add_dependency 'aptible-billing', '~> 1.0'
|
|
27
27
|
spec.add_dependency 'thor', '~> 0.20.0'
|
|
28
28
|
spec.add_dependency 'git'
|
data/lib/aptible/cli/agent.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'base64'
|
|
1
2
|
require 'uri'
|
|
2
3
|
|
|
3
4
|
require 'aptible/auth'
|
|
@@ -66,6 +67,7 @@ module Aptible
|
|
|
66
67
|
def initialize(*)
|
|
67
68
|
nag_toolbelt unless toolbelt?
|
|
68
69
|
Aptible::Resource.configure { |conf| conf.user_agent = version_string }
|
|
70
|
+
warn_sso_enforcement
|
|
69
71
|
super
|
|
70
72
|
end
|
|
71
73
|
|
|
@@ -84,7 +86,22 @@ module Aptible
|
|
|
84
86
|
option :lifetime, desc: 'The duration the token should be valid for ' \
|
|
85
87
|
'(example usage: 24h, 1d, 600s, etc.)'
|
|
86
88
|
option :otp_token, desc: 'A token generated by your second-factor app'
|
|
89
|
+
option :sso, desc: 'Use a token from a Single Sign On login on the ' \
|
|
90
|
+
'dashboard'
|
|
87
91
|
def login
|
|
92
|
+
if options[:sso]
|
|
93
|
+
begin
|
|
94
|
+
token = options[:sso]
|
|
95
|
+
token = ask('Paste token copied from Dashboard:') if token == 'sso'
|
|
96
|
+
Base64.urlsafe_decode64(token.split('.').first)
|
|
97
|
+
save_token(token)
|
|
98
|
+
CLI.logger.info "Token written to #{token_file}"
|
|
99
|
+
return
|
|
100
|
+
rescue StandardError
|
|
101
|
+
raise Thor::Error, 'Invalid token provided for SSO'
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
88
105
|
email = options[:email] || ask('Email: ')
|
|
89
106
|
password = options[:password] || ask_then_line(
|
|
90
107
|
'Password: ', echo: false
|
|
@@ -216,6 +233,22 @@ module Aptible
|
|
|
216
233
|
end
|
|
217
234
|
end
|
|
218
235
|
|
|
236
|
+
def warn_sso_enforcement
|
|
237
|
+
# If the user is also a member of
|
|
238
|
+
begin
|
|
239
|
+
token = fetch_token
|
|
240
|
+
rescue StandardError
|
|
241
|
+
return
|
|
242
|
+
end
|
|
243
|
+
reauth = Aptible::Auth::ReauthenticateOrganization.all(token: token)
|
|
244
|
+
return if reauth.empty?
|
|
245
|
+
|
|
246
|
+
CLI.logger.warn(['WARNING: You will need to use the appropriate',
|
|
247
|
+
'login method (SSO or Aptible credentials) to access',
|
|
248
|
+
'these organizations:',
|
|
249
|
+
reauth.map(&:name)].join(' '))
|
|
250
|
+
end
|
|
251
|
+
|
|
219
252
|
def version_string
|
|
220
253
|
bits = [
|
|
221
254
|
'aptible-cli',
|
|
@@ -49,11 +49,20 @@ module Aptible
|
|
|
49
49
|
|
|
50
50
|
def replicate_database(source, dest_handle, options)
|
|
51
51
|
replication_params = {
|
|
52
|
-
type: 'replicate',
|
|
53
52
|
handle: dest_handle,
|
|
54
53
|
container_size: options[:container_size],
|
|
55
|
-
disk_size: options[:size]
|
|
54
|
+
disk_size: options[:size],
|
|
55
|
+
key_arn: options[:key_arn]
|
|
56
56
|
}.reject { |_, v| v.nil? }
|
|
57
|
+
|
|
58
|
+
if options[:logical]
|
|
59
|
+
replication_params[:type] = 'replicate_logical'
|
|
60
|
+
replication_params[:docker_ref] =
|
|
61
|
+
options[:database_image].docker_repo
|
|
62
|
+
else
|
|
63
|
+
replication_params[:type] = 'replicate'
|
|
64
|
+
end
|
|
65
|
+
|
|
57
66
|
op = source.create_operation!(replication_params)
|
|
58
67
|
attach_to_operation_logs(op)
|
|
59
68
|
|
|
@@ -96,10 +105,11 @@ module Aptible
|
|
|
96
105
|
|
|
97
106
|
def local_url(credential, local_port)
|
|
98
107
|
remote_url = credential.connection_url
|
|
99
|
-
uri = URI.parse(remote_url)
|
|
100
108
|
|
|
109
|
+
uri = URI.parse(remote_url)
|
|
110
|
+
domain = credential.database.account.stack.internal_domain
|
|
101
111
|
"#{uri.scheme}://#{uri.user}:#{uri.password}@" \
|
|
102
|
-
"localhost
|
|
112
|
+
"localhost.#{domain}:#{local_port}#{uri.path}"
|
|
103
113
|
end
|
|
104
114
|
|
|
105
115
|
def find_credential(database, type = nil)
|
|
@@ -4,6 +4,41 @@ module Aptible
|
|
|
4
4
|
class << self
|
|
5
5
|
NO_NESTING = Object.new.freeze
|
|
6
6
|
|
|
7
|
+
def inject_backup(node, backup, include_db: false)
|
|
8
|
+
description = "#{backup.id}: #{backup.created_at}, " \
|
|
9
|
+
"#{backup.aws_region}"
|
|
10
|
+
|
|
11
|
+
if include_db
|
|
12
|
+
db = backup.database_with_deleted
|
|
13
|
+
node.keyed_object('database', 'id') do |n|
|
|
14
|
+
inject_deleted_database(n, db, backup.account)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
description = "#{description}, " \
|
|
18
|
+
"#{db.handle} deleted at #{db.deleted_at}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
node.value('id', backup.id)
|
|
22
|
+
node.value('description', description)
|
|
23
|
+
node.value('created_at', backup.created_at)
|
|
24
|
+
node.value('region', backup.aws_region)
|
|
25
|
+
node.value('size', backup.size)
|
|
26
|
+
|
|
27
|
+
if backup.copied_from
|
|
28
|
+
node.keyed_object('copied_from', 'description') do |n|
|
|
29
|
+
inject_backup(n, backup.copied_from)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def inject_deleted_database(node, database, account)
|
|
35
|
+
node.value('id', database.id)
|
|
36
|
+
node.value('handle', database.handle)
|
|
37
|
+
node.value('type', database.type)
|
|
38
|
+
node.value('deleted_at', database.deleted_at)
|
|
39
|
+
attach_account(node, account)
|
|
40
|
+
end
|
|
41
|
+
|
|
7
42
|
def inject_account(node, account)
|
|
8
43
|
node.value('id', account.id)
|
|
9
44
|
node.value('handle', account.handle)
|
|
@@ -47,6 +82,7 @@ module Aptible
|
|
|
47
82
|
|
|
48
83
|
node.value('type', database.type)
|
|
49
84
|
node.value('status', database.status)
|
|
85
|
+
|
|
50
86
|
node.value('connection_url', database.connection_url)
|
|
51
87
|
|
|
52
88
|
node.list('credentials') do |creds_list|
|
|
@@ -54,7 +90,6 @@ module Aptible
|
|
|
54
90
|
creds_list.object { |n| inject_credential(n, cred) }
|
|
55
91
|
end
|
|
56
92
|
end
|
|
57
|
-
|
|
58
93
|
attach_account(node, account)
|
|
59
94
|
end
|
|
60
95
|
|
|
@@ -9,12 +9,15 @@ module Aptible
|
|
|
9
9
|
|
|
10
10
|
desc 'backup:restore BACKUP_ID ' \
|
|
11
11
|
'[--environment ENVIRONMENT_HANDLE] [--handle HANDLE] ' \
|
|
12
|
-
'[--container-size SIZE_MB] [--size SIZE_GB]'
|
|
12
|
+
'[--container-size SIZE_MB] [--disk-size SIZE_GB] ' \
|
|
13
|
+
'[--key-arn KEY_ARN]',
|
|
13
14
|
'Restore a backup'
|
|
14
15
|
option :handle, desc: 'a name to use for the new database'
|
|
15
16
|
option :environment, desc: 'a different environment to restore to'
|
|
16
17
|
option :container_size, type: :numeric
|
|
17
18
|
option :size, type: :numeric
|
|
19
|
+
option :disk_size, type: :numeric
|
|
20
|
+
option :key_arn, type: :string
|
|
18
21
|
define_method 'backup:restore' do |backup_id|
|
|
19
22
|
backup = Aptible::Api::Backup.find(backup_id, token: fetch_token)
|
|
20
23
|
raise Thor::Error, "Backup ##{backup_id} not found" if backup.nil?
|
|
@@ -22,7 +25,8 @@ module Aptible
|
|
|
22
25
|
handle = options[:handle]
|
|
23
26
|
unless handle
|
|
24
27
|
ts_suffix = backup.created_at.getgm.strftime '%Y-%m-%d-%H-%M-%S'
|
|
25
|
-
handle =
|
|
28
|
+
handle =
|
|
29
|
+
"#{backup.database_with_deleted.handle}-at-#{ts_suffix}"
|
|
26
30
|
end
|
|
27
31
|
|
|
28
32
|
destination_account = if options[:environment]
|
|
@@ -35,10 +39,17 @@ module Aptible
|
|
|
35
39
|
type: 'restore',
|
|
36
40
|
handle: handle,
|
|
37
41
|
container_size: options[:container_size],
|
|
38
|
-
disk_size: options[:size],
|
|
39
|
-
destination_account: destination_account
|
|
42
|
+
disk_size: options[:disk_size] || options[:size],
|
|
43
|
+
destination_account: destination_account,
|
|
44
|
+
key_arn: options[:key_arn]
|
|
40
45
|
}.delete_if { |_, v| v.nil? }
|
|
41
46
|
|
|
47
|
+
CLI.logger.warn([
|
|
48
|
+
'You have used the "--size" option to specify a disk size.',
|
|
49
|
+
'This option which be deprecated in a future version.',
|
|
50
|
+
'Please use the "--disk-size" option, instead.'
|
|
51
|
+
].join("\n")) if options[:size]
|
|
52
|
+
|
|
42
53
|
operation = backup.create_operation!(opts)
|
|
43
54
|
CLI.logger.info "Restoring backup into #{handle}"
|
|
44
55
|
attach_to_operation_logs(operation)
|
|
@@ -62,22 +73,58 @@ module Aptible
|
|
|
62
73
|
database = ensure_database(options.merge(db: handle))
|
|
63
74
|
|
|
64
75
|
Formatter.render(Renderer.current) do |root|
|
|
65
|
-
root.keyed_list('description') do |
|
|
76
|
+
root.keyed_list('description') do |node|
|
|
66
77
|
database.each_backup do |backup|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
78
|
+
if backup.created_at < min_created_at && !backup.copied_from
|
|
79
|
+
break
|
|
80
|
+
end
|
|
81
|
+
node.object do |n|
|
|
82
|
+
ResourceFormatter.inject_backup(n, backup)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
70
88
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
89
|
+
desc 'backup:orphaned', 'List backups associated with ' \
|
|
90
|
+
'deprovisioned databases'
|
|
91
|
+
option :environment
|
|
92
|
+
option :max_age, default: '1y',
|
|
93
|
+
desc: 'Limit backups returned '\
|
|
94
|
+
'(example usage: 1w, 1y, etc.)'
|
|
95
|
+
define_method 'backup:orphaned' do
|
|
96
|
+
age = ChronicDuration.parse(options[:max_age])
|
|
97
|
+
raise Thor::Error, "Invalid age: #{options[:max_age]}" if age.nil?
|
|
98
|
+
min_created_at = Time.now - age
|
|
99
|
+
|
|
100
|
+
Formatter.render(Renderer.current) do |root|
|
|
101
|
+
root.keyed_list('description') do |node|
|
|
102
|
+
scoped_environments(options).each do |account|
|
|
103
|
+
account.each_orphaned_backup do |backup|
|
|
104
|
+
created_at = backup.created_at
|
|
105
|
+
copied_from = backup.copied_from
|
|
106
|
+
break if created_at < min_created_at && !copied_from
|
|
107
|
+
node.object do |n|
|
|
108
|
+
ResourceFormatter.inject_backup(
|
|
109
|
+
n, backup, include_db: true
|
|
110
|
+
)
|
|
111
|
+
end
|
|
76
112
|
end
|
|
77
113
|
end
|
|
78
114
|
end
|
|
79
115
|
end
|
|
80
116
|
end
|
|
117
|
+
|
|
118
|
+
desc 'backup:purge BACKUP_ID',
|
|
119
|
+
'Permanently delete a backup and any copies of it'
|
|
120
|
+
define_method 'backup:purge' do |backup_id|
|
|
121
|
+
backup = Aptible::Api::Backup.find(backup_id, token: fetch_token)
|
|
122
|
+
raise Thor::Error, "Backup ##{backup_id} not found" if backup.nil?
|
|
123
|
+
|
|
124
|
+
operation = backup.create_operation!(type: 'purge')
|
|
125
|
+
CLI.logger.info "Purging backup #{backup_id}"
|
|
126
|
+
attach_to_operation_logs(operation)
|
|
127
|
+
end
|
|
81
128
|
end
|
|
82
129
|
end
|
|
83
130
|
end
|
|
@@ -53,12 +53,15 @@ module Aptible
|
|
|
53
53
|
|
|
54
54
|
desc 'db:create HANDLE ' \
|
|
55
55
|
'[--type TYPE] [--version VERSION] ' \
|
|
56
|
-
'[--container-size SIZE_MB] [--size SIZE_GB]'
|
|
56
|
+
'[--container-size SIZE_MB] [--disk-size SIZE_GB] ' \
|
|
57
|
+
'[--key-arn KEY_ARN]',
|
|
57
58
|
'Create a new database'
|
|
58
59
|
option :type, type: :string
|
|
59
60
|
option :version, type: :string
|
|
60
61
|
option :container_size, type: :numeric
|
|
61
|
-
option :size,
|
|
62
|
+
option :size, type: :numeric
|
|
63
|
+
option :disk_size, default: 10, type: :numeric
|
|
64
|
+
option :key_arn, type: :string
|
|
62
65
|
option :environment
|
|
63
66
|
define_method 'db:create' do |handle|
|
|
64
67
|
account = ensure_environment(options)
|
|
@@ -66,9 +69,16 @@ module Aptible
|
|
|
66
69
|
db_opts = {
|
|
67
70
|
handle: handle,
|
|
68
71
|
initial_container_size: options[:container_size],
|
|
69
|
-
initial_disk_size: options[:size]
|
|
72
|
+
initial_disk_size: options[:disk_size] || options[:size],
|
|
73
|
+
current_kms_arn: options[:key_arn]
|
|
70
74
|
}.delete_if { |_, v| v.nil? }
|
|
71
75
|
|
|
76
|
+
CLI.logger.warn([
|
|
77
|
+
'You have used the "--size" option to specify a disk size.',
|
|
78
|
+
'This option which be deprecated in a future version.',
|
|
79
|
+
'Please use the "--disk-size" option, instead.'
|
|
80
|
+
].join("\n")) if options[:size]
|
|
81
|
+
|
|
72
82
|
type = options[:type]
|
|
73
83
|
version = options[:version]
|
|
74
84
|
|
|
@@ -87,7 +97,7 @@ module Aptible
|
|
|
87
97
|
op_opts = {
|
|
88
98
|
type: 'provision',
|
|
89
99
|
container_size: options[:container_size],
|
|
90
|
-
disk_size: options[:size]
|
|
100
|
+
disk_size: options[:disk_size] || options[:size]
|
|
91
101
|
}.delete_if { |_, v| v.nil? }
|
|
92
102
|
op = database.create_operation(op_opts)
|
|
93
103
|
|
|
@@ -115,15 +125,50 @@ module Aptible
|
|
|
115
125
|
end
|
|
116
126
|
|
|
117
127
|
desc 'db:replicate HANDLE REPLICA_HANDLE ' \
|
|
118
|
-
'[--container-size SIZE_MB] [--size SIZE_GB]'
|
|
128
|
+
'[--container-size SIZE_MB] [--disk-size SIZE_GB] ' \
|
|
129
|
+
'[--logical --version VERSION] [--key-arn KEY_ARN]',
|
|
119
130
|
'Create a replica/follower of a database'
|
|
120
131
|
option :environment
|
|
121
132
|
option :container_size, type: :numeric
|
|
122
133
|
option :size, type: :numeric
|
|
134
|
+
option :disk_size, type: :numeric
|
|
135
|
+
option :logical, type: :boolean
|
|
136
|
+
option :version, type: :string
|
|
137
|
+
option :key_arn, type: :string
|
|
123
138
|
define_method 'db:replicate' do |source_handle, dest_handle|
|
|
124
139
|
source = ensure_database(options.merge(db: source_handle))
|
|
140
|
+
|
|
141
|
+
if options[:logical]
|
|
142
|
+
if source.type != 'postgresql'
|
|
143
|
+
raise Thor::Error, 'Logical replication only works for ' \
|
|
144
|
+
'PostgreSQL'
|
|
145
|
+
end
|
|
146
|
+
if options[:version]
|
|
147
|
+
image = find_database_image(source.type, options[:version])
|
|
148
|
+
else
|
|
149
|
+
raise Thor::Error, '--version is required for logical ' \
|
|
150
|
+
'replication'
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
125
154
|
CLI.logger.info "Replicating #{source_handle}..."
|
|
126
|
-
|
|
155
|
+
|
|
156
|
+
opts = {
|
|
157
|
+
environment: options[:environment],
|
|
158
|
+
container_size: options[:container_size],
|
|
159
|
+
size: options[:disk_size] || options[:size],
|
|
160
|
+
logical: options[:logical],
|
|
161
|
+
database_image: image || nil,
|
|
162
|
+
key_arn: options[:key_arn]
|
|
163
|
+
}.delete_if { |_, v| v.nil? }
|
|
164
|
+
|
|
165
|
+
CLI.logger.warn([
|
|
166
|
+
'You have used the "--size" option to specify a disk size.',
|
|
167
|
+
'This option which be deprecated in a future version.',
|
|
168
|
+
'Please use the "--disk-size" option, instead.'
|
|
169
|
+
].join("\n")) if options[:size]
|
|
170
|
+
|
|
171
|
+
database = replicate_database(source, dest_handle, opts)
|
|
127
172
|
render_database(database.reload, database.account)
|
|
128
173
|
end
|
|
129
174
|
|
|
@@ -234,10 +279,11 @@ module Aptible
|
|
|
234
279
|
end
|
|
235
280
|
|
|
236
281
|
desc 'db:restart HANDLE ' \
|
|
237
|
-
'[--container-size SIZE_MB] [--size SIZE_GB]',
|
|
282
|
+
'[--container-size SIZE_MB] [--disk-size SIZE_GB]',
|
|
238
283
|
'Restart a database'
|
|
239
284
|
option :environment
|
|
240
285
|
option :container_size, type: :numeric
|
|
286
|
+
option :disk_size, type: :numeric
|
|
241
287
|
option :size, type: :numeric
|
|
242
288
|
define_method 'db:restart' do |handle|
|
|
243
289
|
database = ensure_database(options.merge(db: handle))
|
|
@@ -245,9 +291,15 @@ module Aptible
|
|
|
245
291
|
opts = {
|
|
246
292
|
type: 'restart',
|
|
247
293
|
container_size: options[:container_size],
|
|
248
|
-
disk_size: options[:size]
|
|
294
|
+
disk_size: options[:disk_size] || options[:size]
|
|
249
295
|
}.delete_if { |_, v| v.nil? }
|
|
250
296
|
|
|
297
|
+
CLI.logger.warn([
|
|
298
|
+
'You have used the "--size" option to specify a disk size.',
|
|
299
|
+
'This option which be deprecated in a future version.',
|
|
300
|
+
'Please use the "--disk-size" option, instead.'
|
|
301
|
+
].join("\n")) if options[:size]
|
|
302
|
+
|
|
251
303
|
CLI.logger.info "Restarting #{database.handle}..."
|
|
252
304
|
op = database.create_operation!(opts)
|
|
253
305
|
attach_to_operation_logs(op)
|
|
@@ -19,7 +19,7 @@ module Aptible
|
|
|
19
19
|
raise "Invalid scheme: #{uri.scheme} (use https)"
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
apis = [Aptible::Auth, Aptible::Api
|
|
22
|
+
apis = [Aptible::Auth, Aptible::Api]
|
|
23
23
|
|
|
24
24
|
api = apis.find do |klass|
|
|
25
25
|
uri.host == URI(klass.configuration.root_url).host
|
data/lib/aptible/cli/version.rb
CHANGED
|
@@ -258,6 +258,36 @@ describe Aptible::CLI::Agent do
|
|
|
258
258
|
subject.login
|
|
259
259
|
end
|
|
260
260
|
end
|
|
261
|
+
|
|
262
|
+
context 'SSO logins' do
|
|
263
|
+
let(:token) { 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJpZCI6I' }
|
|
264
|
+
|
|
265
|
+
it 'accepts a token as an argument' do
|
|
266
|
+
options = { sso: token }
|
|
267
|
+
allow(subject).to receive(:options).and_return options
|
|
268
|
+
|
|
269
|
+
expect(subject).to receive(:save_token).with(token)
|
|
270
|
+
|
|
271
|
+
subject.login
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
it 'rejects clearly invalid tokens' do
|
|
275
|
+
options = { sso: 'blarg' }
|
|
276
|
+
allow(subject).to receive(:options).and_return options
|
|
277
|
+
|
|
278
|
+
expect { subject.login }.to raise_error Thor::Error
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
it 'prompts for a token if none provided' do
|
|
282
|
+
options = { sso: 'sso' }
|
|
283
|
+
allow(subject).to receive(:options).and_return options
|
|
284
|
+
|
|
285
|
+
expect(subject).to receive(:ask).once.and_return(token)
|
|
286
|
+
expect(subject).to receive(:save_token).with(token)
|
|
287
|
+
|
|
288
|
+
subject.login
|
|
289
|
+
end
|
|
290
|
+
end
|
|
261
291
|
end
|
|
262
292
|
end
|
|
263
293
|
|
|
@@ -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
|
-
|
|
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
|
|
@@ -13,7 +13,9 @@ describe Aptible::CLI::Agent do
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
let(:handle) { 'foobar' }
|
|
16
|
-
let(:
|
|
16
|
+
let(:stack) { Fabricate(:stack, internal_domain: 'aptible.in') }
|
|
17
|
+
let(:account) { Fabricate(:account, stack: stack) }
|
|
18
|
+
let(:database) { Fabricate(:database, handle: handle, account: account) }
|
|
17
19
|
let(:socat_helper) { SocatHelperMock.new(port: 4242) }
|
|
18
20
|
|
|
19
21
|
describe '#db:create' do
|
|
@@ -55,7 +57,7 @@ describe Aptible::CLI::Agent do
|
|
|
55
57
|
subject.send('db:create', 'foo')
|
|
56
58
|
end
|
|
57
59
|
|
|
58
|
-
it 'creates a new DB with a disk size' do
|
|
60
|
+
it 'creates a new DB with a (implicitly) disk size' do
|
|
59
61
|
expect_provision_database(
|
|
60
62
|
{ handle: 'foo', type: 'postgresql', initial_disk_size: 200 },
|
|
61
63
|
{ disk_size: 200 }
|
|
@@ -65,6 +67,16 @@ describe Aptible::CLI::Agent do
|
|
|
65
67
|
subject.send('db:create', 'foo')
|
|
66
68
|
end
|
|
67
69
|
|
|
70
|
+
it 'creates a new DB with a disk-size' do
|
|
71
|
+
expect_provision_database(
|
|
72
|
+
{ handle: 'foo', type: 'postgresql', initial_disk_size: 200 },
|
|
73
|
+
{ disk_size: 200 }
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
subject.options = { type: 'postgresql', disk_size: 200 }
|
|
77
|
+
subject.send('db:create', 'foo')
|
|
78
|
+
end
|
|
79
|
+
|
|
68
80
|
it 'deprovisions the database if the operation cannot be created' do
|
|
69
81
|
db = Fabricate(:database)
|
|
70
82
|
|
|
@@ -377,7 +389,7 @@ describe Aptible::CLI::Agent do
|
|
|
377
389
|
expect(captured_logs).to match(/restarting foobar/i)
|
|
378
390
|
end
|
|
379
391
|
|
|
380
|
-
it 'allows restarting a database with
|
|
392
|
+
it 'allows restarting a database with (implicitly disk) size' do
|
|
381
393
|
expect(database).to receive(:create_operation!)
|
|
382
394
|
.with(type: 'restart', disk_size: 40).and_return(op)
|
|
383
395
|
|
|
@@ -389,6 +401,18 @@ describe Aptible::CLI::Agent do
|
|
|
389
401
|
expect(captured_logs).to match(/restarting foobar/i)
|
|
390
402
|
end
|
|
391
403
|
|
|
404
|
+
it 'allows restarting a database with a disk-size' do
|
|
405
|
+
expect(database).to receive(:create_operation!)
|
|
406
|
+
.with(type: 'restart', disk_size: 40).and_return(op)
|
|
407
|
+
|
|
408
|
+
expect(subject).to receive(:attach_to_operation_logs).with(op)
|
|
409
|
+
|
|
410
|
+
subject.options = { disk_size: 40 }
|
|
411
|
+
subject.send('db:restart', handle)
|
|
412
|
+
|
|
413
|
+
expect(captured_logs).to match(/restarting foobar/i)
|
|
414
|
+
end
|
|
415
|
+
|
|
392
416
|
it 'fails if the DB is not found' do
|
|
393
417
|
expect { subject.send('db:restart', 'nope') }
|
|
394
418
|
.to raise_error(Thor::Error, 'Could not find database nope')
|
|
@@ -485,14 +509,81 @@ describe Aptible::CLI::Agent do
|
|
|
485
509
|
expect_replicate_database(container_size: 40)
|
|
486
510
|
end
|
|
487
511
|
|
|
488
|
-
it 'allows replicating a database with
|
|
512
|
+
it 'allows replicating a database with an (implicitly) disk size option' do
|
|
489
513
|
expect_replicate_database(size: 40)
|
|
490
514
|
end
|
|
491
515
|
|
|
516
|
+
it 'allows replicating a database with a disk-size option' do
|
|
517
|
+
expect_replicate_database(disk_size: 40)
|
|
518
|
+
end
|
|
519
|
+
|
|
492
520
|
it 'fails if the DB is not found' do
|
|
493
521
|
expect { subject.send('db:replicate', 'nope', 'replica') }
|
|
494
522
|
.to raise_error(Thor::Error, 'Could not find database nope')
|
|
495
523
|
end
|
|
524
|
+
|
|
525
|
+
it 'allows logical replication of a database with --version set' do
|
|
526
|
+
master = Fabricate(:database, handle: 'master')
|
|
527
|
+
databases << master
|
|
528
|
+
replica = Fabricate(:database,
|
|
529
|
+
account: master.account,
|
|
530
|
+
handle: 'replica')
|
|
531
|
+
|
|
532
|
+
dbimg = Fabricate(:database_image,
|
|
533
|
+
type: 'postgresql',
|
|
534
|
+
version: 10,
|
|
535
|
+
docker_repo: 'aptible/postgresql:10')
|
|
536
|
+
|
|
537
|
+
expect(subject).to receive(:find_database_image).with('postgresql', 10)
|
|
538
|
+
.and_return(dbimg)
|
|
539
|
+
|
|
540
|
+
op = Fabricate(:operation)
|
|
541
|
+
|
|
542
|
+
params = { type: 'replicate_logical', handle: 'replica',
|
|
543
|
+
docker_ref: dbimg.docker_repo }
|
|
544
|
+
expect(master).to receive(:create_operation!)
|
|
545
|
+
.with(**params).and_return(op)
|
|
546
|
+
|
|
547
|
+
expect(subject).to receive(:attach_to_operation_logs).with(op) do
|
|
548
|
+
databases << replica
|
|
549
|
+
replica
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
provision = Fabricate(:operation)
|
|
553
|
+
|
|
554
|
+
expect(replica).to receive_message_chain(:operations, :last)
|
|
555
|
+
.and_return(provision)
|
|
556
|
+
|
|
557
|
+
expect(subject).to receive(:attach_to_operation_logs).with(provision)
|
|
558
|
+
|
|
559
|
+
expect(replica).to receive(:reload).and_return(replica)
|
|
560
|
+
|
|
561
|
+
subject.options = { logical: true, version: 10 }
|
|
562
|
+
subject.send('db:replicate', 'master', 'replica')
|
|
563
|
+
|
|
564
|
+
expect(captured_logs).to match(/replicating master/i)
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
it 'fails if logical replication requested without --version' do
|
|
568
|
+
master = Fabricate(:database, handle: 'master', type: 'postgresql')
|
|
569
|
+
databases << master
|
|
570
|
+
|
|
571
|
+
subject.options = { type: 'replicate', handle: 'replica', logical: true }
|
|
572
|
+
expect { subject.send('db:replicate', 'master', 'replica') }
|
|
573
|
+
.to raise_error(Thor::Error, '--version is required for logical ' \
|
|
574
|
+
'replication')
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
it 'fails if logical replication requested for non-postgres db' do
|
|
578
|
+
master = Fabricate(:database, handle: 'master', type: 'mysql')
|
|
579
|
+
databases << master
|
|
580
|
+
|
|
581
|
+
subject.options = { type: 'replicate', handle: 'replica',
|
|
582
|
+
logical: true, version: 10 }
|
|
583
|
+
expect { subject.send('db:replicate', 'master', 'replica') }
|
|
584
|
+
.to raise_error(Thor::Error, 'Logical replication only works for ' \
|
|
585
|
+
'PostgreSQL')
|
|
586
|
+
end
|
|
496
587
|
end
|
|
497
588
|
|
|
498
589
|
describe '#db:dump' do
|
data/spec/spec_helper.rb
CHANGED
|
@@ -3,14 +3,6 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
|
3
3
|
|
|
4
4
|
Bundler.require :development
|
|
5
5
|
|
|
6
|
-
require 'simplecov'
|
|
7
|
-
SimpleCov.start
|
|
8
|
-
|
|
9
|
-
if ENV['CI']
|
|
10
|
-
require 'codecov'
|
|
11
|
-
SimpleCov.formatter = SimpleCov::Formatter::Codecov
|
|
12
|
-
end
|
|
13
|
-
|
|
14
6
|
# Load shared spec files
|
|
15
7
|
Dir["#{File.dirname(__FILE__)}/shared/**/*.rb"].each do |file|
|
|
16
8
|
require file
|
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.
|
|
4
|
+
version: 0.16.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Frank Macreery
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-10-23 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.
|
|
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.
|
|
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:
|
|
47
|
+
version: 1.2.3
|
|
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:
|
|
54
|
+
version: 1.2.3
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: aptible-billing
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -359,7 +359,7 @@ homepage: https://github.com/aptible/aptible-cli
|
|
|
359
359
|
licenses:
|
|
360
360
|
- MIT
|
|
361
361
|
metadata: {}
|
|
362
|
-
post_install_message:
|
|
362
|
+
post_install_message:
|
|
363
363
|
rdoc_options: []
|
|
364
364
|
require_paths:
|
|
365
365
|
- lib
|
|
@@ -374,9 +374,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
374
374
|
- !ruby/object:Gem::Version
|
|
375
375
|
version: '0'
|
|
376
376
|
requirements: []
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
signing_key:
|
|
377
|
+
rubygems_version: 3.0.3
|
|
378
|
+
signing_key:
|
|
380
379
|
specification_version: 4
|
|
381
380
|
summary: Command-line interface for Aptible services
|
|
382
381
|
test_files:
|