aptible-cli 0.8.4 → 0.8.5
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/README.md +30 -25
- data/lib/aptible/cli/helpers/tunnel.rb +34 -10
- data/lib/aptible/cli/subcommands/db.rb +9 -0
- data/lib/aptible/cli/version.rb +1 -1
- data/spec/aptible/cli/helpers/tunnel_spec.rb +38 -1
- data/spec/aptible/cli/subcommands/db_spec.rb +23 -1
- data/spec/mock/ssh +1 -0
- data/spec/mock/ssh_mock.rb +4 -1
- data/spec/shared/mock_ssh_context.rb +6 -0
- metadata +3 -3
- data/spec/mock/ssh +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ca32684c92760fd049ba703618258b837950590
|
4
|
+
data.tar.gz: b251f6a123c54002638a7ef0c5567de892f6cb62
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 28e54b39f91cb892b9ce5443321b9049290a302b9e38de9cd3b7162b3567499fa5c00abc5d860d31d8661190fdbc692b24ce0186af410b98a4922a0b62cdd70d
|
7
|
+
data.tar.gz: 772bb6f34a8a07baee41f1682189dbfa6a31c422802649d74721f028c89cd060ae7cfe4c77f3bfd150c9cb90c04b3ddc52acb6bc52be31f71cf83eafb8b05acf
|
data/README.md
CHANGED
@@ -28,31 +28,36 @@ From `aptible help`:
|
|
28
28
|
|
29
29
|
```
|
30
30
|
Commands:
|
31
|
-
aptible apps
|
32
|
-
aptible apps:create HANDLE
|
33
|
-
aptible apps:deprovision
|
34
|
-
aptible apps:scale TYPE NUMBER
|
35
|
-
aptible
|
36
|
-
aptible
|
37
|
-
aptible config
|
38
|
-
aptible config:
|
39
|
-
aptible config:
|
40
|
-
aptible
|
41
|
-
aptible
|
42
|
-
aptible db:
|
43
|
-
aptible db:
|
44
|
-
aptible db:
|
45
|
-
aptible db:
|
46
|
-
aptible db:
|
47
|
-
aptible
|
48
|
-
aptible
|
49
|
-
aptible
|
50
|
-
aptible
|
51
|
-
aptible
|
52
|
-
aptible
|
53
|
-
aptible
|
54
|
-
aptible
|
55
|
-
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 TYPE NUMBER # Scale app to NUMBER of instances
|
35
|
+
aptible backup:list DB_HANDLE # List backups for a database
|
36
|
+
aptible backup:restore [--handle HANDLE] [--size SIZE_GB] # Restore a backup
|
37
|
+
aptible config # Print an app's current configuration
|
38
|
+
aptible config:add # Add an ENV variable to an app
|
39
|
+
aptible config:rm # Remove an ENV variable from an app
|
40
|
+
aptible config:set # Alias for config:add
|
41
|
+
aptible config:unset # Alias for config:rm
|
42
|
+
aptible db:backup HANDLE # Backup a database
|
43
|
+
aptible db:clone SOURCE DEST # Clone a database to create a new one
|
44
|
+
aptible db:create HANDLE # Create a new database
|
45
|
+
aptible db:deprovision HANDLE # Deprovision a database
|
46
|
+
aptible db:dump HANDLE # Dump a remote database to file
|
47
|
+
aptible db:execute HANDLE SQL_FILE # Executes sql against a database
|
48
|
+
aptible db:list # List all databases
|
49
|
+
aptible db:reload HANDLE # Reload a database
|
50
|
+
aptible db:tunnel HANDLE # Create a local tunnel to a database
|
51
|
+
aptible domains # Print an app's current virtual domains
|
52
|
+
aptible help [COMMAND] # Describe available commands or one specific command
|
53
|
+
aptible login # Log in to Aptible
|
54
|
+
aptible logs # Follows logs from a running app or database
|
55
|
+
aptible operation:cancel OPERATION_ID # Cancel a running operation
|
56
|
+
aptible ps # Display running processes for an app - DEPRECATED
|
57
|
+
aptible rebuild # Rebuild an app, and restart its services
|
58
|
+
aptible restart # Restart all services associated with an app
|
59
|
+
aptible ssh [COMMAND] # Run a command against an app
|
60
|
+
aptible version # Print Aptible CLI version
|
56
61
|
```
|
57
62
|
|
58
63
|
## Contributing
|
@@ -11,16 +11,18 @@ module Aptible
|
|
11
11
|
:SIGHUP
|
12
12
|
end
|
13
13
|
|
14
|
+
STOP_TIMEOUT = 5
|
15
|
+
|
14
16
|
# The :new_pgroup key specifies the CREATE_NEW_PROCESS_GROUP flag for
|
15
17
|
# CreateProcessW() in the Windows API. This is a Windows only option.
|
16
18
|
# true means the new process is the root process of the new process
|
17
19
|
# group. This flag is necessary to be able to signal the subprocess on
|
18
20
|
# Windows.
|
19
|
-
SPAWN_OPTS =
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
SPAWN_OPTS = if Gem.win_platform?
|
22
|
+
{ new_pgroup: true }
|
23
|
+
else
|
24
|
+
{}
|
25
|
+
end
|
24
26
|
|
25
27
|
class Tunnel
|
26
28
|
def initialize(env, ssh_cmd, socket_path)
|
@@ -61,18 +63,40 @@ module Aptible
|
|
61
63
|
|
62
64
|
def stop
|
63
65
|
raise 'You must call #start before calling #stop' if @pid.nil?
|
66
|
+
|
64
67
|
begin
|
65
68
|
Process.kill(STOP_SIGNAL, @pid)
|
66
69
|
rescue Errno::ESRCH
|
67
|
-
|
70
|
+
# Already dead.
|
71
|
+
return
|
72
|
+
end
|
73
|
+
|
74
|
+
begin
|
75
|
+
STOP_TIMEOUT.times do
|
76
|
+
return if Process.wait(@pid, Process::WNOHANG)
|
77
|
+
sleep 1
|
78
|
+
end
|
79
|
+
Process.kill(:SIGKILL, @pid)
|
80
|
+
rescue Errno::ECHILD, Errno::ESRCH
|
81
|
+
# Died at some point, that's fine.
|
68
82
|
end
|
69
|
-
wait
|
70
83
|
end
|
71
84
|
|
72
85
|
def wait
|
73
|
-
|
74
|
-
|
75
|
-
|
86
|
+
# NOTE: Ruby is kind enough to retry when EINTR is thrown, so we
|
87
|
+
# don't need to retry or anything here.
|
88
|
+
_, status = Process.wait2(@pid)
|
89
|
+
|
90
|
+
code = status.exitstatus
|
91
|
+
|
92
|
+
case code
|
93
|
+
when 0
|
94
|
+
# No-op: we're happy with this.
|
95
|
+
when 124
|
96
|
+
raise Thor::Error, 'Tunnel timed out'
|
97
|
+
else
|
98
|
+
raise Thor::Error, "Tunnel crashed (#{code})"
|
99
|
+
end
|
76
100
|
end
|
77
101
|
|
78
102
|
def port
|
@@ -129,6 +129,15 @@ module Aptible
|
|
129
129
|
op = database.create_operation!(type: 'backup')
|
130
130
|
attach_to_operation_logs(op)
|
131
131
|
end
|
132
|
+
|
133
|
+
desc 'db:reload HANDLE', 'Reload a database'
|
134
|
+
option :environment
|
135
|
+
define_method 'db:reload' do |handle|
|
136
|
+
database = ensure_database(options.merge(db: handle))
|
137
|
+
say "Reloading #{database.handle}..."
|
138
|
+
op = database.create_operation!(type: 'reload')
|
139
|
+
attach_to_operation_logs(op)
|
140
|
+
end
|
132
141
|
end
|
133
142
|
end
|
134
143
|
end
|
data/lib/aptible/cli/version.rb
CHANGED
@@ -30,8 +30,21 @@ describe Aptible::CLI::Helpers::Tunnel do
|
|
30
30
|
expect(mock_argv.shift).to eq('5678:/some.sock')
|
31
31
|
end
|
32
32
|
|
33
|
+
it 'provides the port it picked' do
|
34
|
+
helper = described_class.new({}, ['ssh'], '/some.sock')
|
35
|
+
helper.start
|
36
|
+
port = helper.port
|
37
|
+
helper.stop
|
38
|
+
|
39
|
+
mock_argv = read_mock_argv
|
40
|
+
expect(mock_argv.size).to eq(4)
|
41
|
+
|
42
|
+
expect(mock_argv.shift).to eq('-L')
|
43
|
+
expect(mock_argv.shift).to eq("#{port}:/some.sock")
|
44
|
+
end
|
45
|
+
|
33
46
|
it 'captures and displays tunnel errors' do
|
34
|
-
helper = described_class.new({ '
|
47
|
+
helper = described_class.new({ 'SSH_MOCK_FAIL_TUNNEL' => '1' }, ['ssh'],
|
35
48
|
'/some.sock')
|
36
49
|
|
37
50
|
expect { helper.start(0) }
|
@@ -47,4 +60,28 @@ describe Aptible::CLI::Helpers::Tunnel do
|
|
47
60
|
socat = described_class.new({}, [], '/some.sock')
|
48
61
|
expect { socat.stop }.to raise_error(/You must call #start/)
|
49
62
|
end
|
63
|
+
|
64
|
+
it 'understands an exit status of 0' do
|
65
|
+
helper = described_class.new(
|
66
|
+
{ 'SSH_MOCK_EXITCODE' => '0' }, ['ssh'], '/some.sock'
|
67
|
+
)
|
68
|
+
helper.start
|
69
|
+
helper.wait
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'understands an exit status of 1' do
|
73
|
+
helper = described_class.new(
|
74
|
+
{ 'SSH_MOCK_EXITCODE' => '1' }, ['ssh'], '/some.sock'
|
75
|
+
)
|
76
|
+
helper.start
|
77
|
+
expect { helper.wait }.to raise_error(/tunnel crashed/im)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'understands an exit status of 124' do
|
81
|
+
helper = described_class.new(
|
82
|
+
{ 'SSH_MOCK_EXITCODE' => '124' }, ['ssh'], '/some.sock'
|
83
|
+
)
|
84
|
+
helper.start
|
85
|
+
expect { helper.wait }.to raise_error(/tunnel timed out/im)
|
86
|
+
end
|
50
87
|
end
|
@@ -199,7 +199,8 @@ describe Aptible::CLI::Agent do
|
|
199
199
|
let(:op) { Fabricate(:operation) }
|
200
200
|
|
201
201
|
it 'allows creating a new backup' do
|
202
|
-
expect(database).to receive(:create_operation!)
|
202
|
+
expect(database).to receive(:create_operation!)
|
203
|
+
.with(type: 'backup').and_return(op)
|
203
204
|
expect(subject).to receive(:say).with('Backing up foobar...')
|
204
205
|
expect(subject).to receive(:attach_to_operation_logs).with(op)
|
205
206
|
|
@@ -211,4 +212,25 @@ describe Aptible::CLI::Agent do
|
|
211
212
|
.to raise_error(Thor::Error, 'Could not find database nope')
|
212
213
|
end
|
213
214
|
end
|
215
|
+
|
216
|
+
describe '#db:reload' do
|
217
|
+
before { allow(Aptible::Api::Account).to receive(:all) { [account] } }
|
218
|
+
before { allow(Aptible::Api::Database).to receive(:all) { [database] } }
|
219
|
+
|
220
|
+
let(:op) { Fabricate(:operation) }
|
221
|
+
|
222
|
+
it 'allows reloading a database' do
|
223
|
+
expect(database).to receive(:create_operation!)
|
224
|
+
.with(type: 'reload').and_return(op)
|
225
|
+
expect(subject).to receive(:say).with('Reloading foobar...')
|
226
|
+
expect(subject).to receive(:attach_to_operation_logs).with(op)
|
227
|
+
|
228
|
+
subject.send('db:reload', handle)
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'fails if the DB is not found' do
|
232
|
+
expect { subject.send('db:reload', 'nope') }
|
233
|
+
.to raise_error(Thor::Error, 'Could not find database nope')
|
234
|
+
end
|
235
|
+
end
|
214
236
|
end
|
data/spec/mock/ssh
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ssh_mock.rb
|
data/spec/mock/ssh_mock.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'json'
|
3
3
|
|
4
|
-
raise 'Something went wrong!' if ENV['
|
4
|
+
raise 'Something went wrong!' if ENV['SSH_MOCK_FAIL_TUNNEL']
|
5
5
|
|
6
6
|
# Log arguments to SSH_MOCK_OUTFILE
|
7
7
|
File.open(ENV.fetch('SSH_MOCK_OUTFILE'), 'w') do |f|
|
8
8
|
f.write({
|
9
|
+
'pid' => $PID,
|
9
10
|
'argc' => ARGV.size,
|
10
11
|
'argv' => ARGV,
|
11
12
|
'env' => ENV.to_hash
|
@@ -13,3 +14,5 @@ File.open(ENV.fetch('SSH_MOCK_OUTFILE'), 'w') do |f|
|
|
13
14
|
end
|
14
15
|
|
15
16
|
puts 'TUNNEL READY'
|
17
|
+
|
18
|
+
exit Integer(ENV.fetch('SSH_MOCK_EXITCODE', 0))
|
@@ -16,6 +16,12 @@ shared_context 'mock ssh' do
|
|
16
16
|
ClimateControl.modify(env) { example.run }
|
17
17
|
end
|
18
18
|
|
19
|
+
def read_mock_pid
|
20
|
+
File.open(ssh_mock_outfile) do |f|
|
21
|
+
return JSON.load(f.read).fetch('pid')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
19
25
|
def read_mock_argv
|
20
26
|
File.open(ssh_mock_outfile) do |f|
|
21
27
|
return JSON.load(f.read).fetch('argv')
|
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.8.
|
4
|
+
version: 0.8.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Frank Macreery
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aptible-api
|
@@ -295,7 +295,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
295
295
|
version: '0'
|
296
296
|
requirements: []
|
297
297
|
rubyforge_project:
|
298
|
-
rubygems_version: 2.4
|
298
|
+
rubygems_version: 2.6.4
|
299
299
|
signing_key:
|
300
300
|
specification_version: 4
|
301
301
|
summary: Command-line interface for Aptible services
|
data/spec/mock/ssh
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'json'
|
3
|
-
|
4
|
-
raise 'Something went wrong!' if ENV['FAIL_TUNNEL']
|
5
|
-
|
6
|
-
# Log arguments to SSH_MOCK_OUTFILE
|
7
|
-
File.open(ENV.fetch('SSH_MOCK_OUTFILE'), 'w') do |f|
|
8
|
-
f.write({
|
9
|
-
'argc' => ARGV.size,
|
10
|
-
'argv' => ARGV,
|
11
|
-
'env' => ENV.to_hash
|
12
|
-
}.to_json)
|
13
|
-
end
|
14
|
-
|
15
|
-
puts 'TUNNEL READY'
|