aptible-cli 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cd702a7afbcc8290e375387617c228b388b69918
4
- data.tar.gz: bbbcb95f4ebc9deac6671049c7534c83e2127d1e
3
+ metadata.gz: 7ca32684c92760fd049ba703618258b837950590
4
+ data.tar.gz: b251f6a123c54002638a7ef0c5567de892f6cb62
5
5
  SHA512:
6
- metadata.gz: c975747091a4d3232c190baee45865bd38dcde4fe8c585ac78a3b86050f5e382432ed78e719e6fb3ae947fd5e1f213e765ff336d3e07886d97b26feb4ae6fae9
7
- data.tar.gz: e2b3152c9a2e6a9398b8dc87031b7791b7ad614836d9a548fa9721db3b7864101f53734cf55701940e8c9cd0db93c73b6fbd0ff694c1a7a5f8e0d6733ee02fac
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 # 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 config # Print an app's current configuration
36
- aptible config:add # Add an ENV variable to an app
37
- aptible config:rm # Remove an ENV variable from an app
38
- aptible config:set # Alias for config:add
39
- aptible config:unset # Alias for config:rm
40
- aptible db:clone SOURCE DEST # Clone a database to create a new one
41
- aptible db:create HANDLE # Create a new database
42
- aptible db:deprovision HANDLE # Deprovision a database
43
- aptible db:dump HANDLE # Dump a remote database to file
44
- aptible db:execute HANDLE SQL_FILE # Executes sql against a database
45
- aptible db:list # List all databases
46
- aptible db:tunnel HANDLE # Create a local tunnel to a database
47
- aptible domains # Print an app's current virtual domains
48
- aptible help [COMMAND] # Describe available commands or one specific command
49
- aptible login # Log in to Aptible
50
- aptible logs # Follows logs from a running app
51
- aptible ps # Display running processes for an app - DEPRECATED
52
- aptible rebuild # Rebuild an app, and restart its services
53
- aptible restart # Restart all services associated with an app
54
- aptible ssh [COMMAND] # Run a command against an app
55
- aptible version # Print Aptible CLI version
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 = if Gem.win_platform?
20
- { new_pgroup: true }
21
- else
22
- {}
23
- end
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
- nil # Dear Rubocop: I know what I'm doing.
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
- Process.wait @pid
74
- rescue Errno::ECHILD
75
- nil
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
@@ -1,5 +1,5 @@
1
1
  module Aptible
2
2
  module CLI
3
- VERSION = '0.8.4'.freeze
3
+ VERSION = '0.8.5'.freeze
4
4
  end
5
5
  end
@@ -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({ 'FAIL_TUNNEL' => '1' }, ['ssh'],
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!).and_return(op)
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
@@ -0,0 +1 @@
1
+ ssh_mock.rb
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'json'
3
3
 
4
- raise 'Something went wrong!' if ENV['FAIL_TUNNEL']
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
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-01-25 00:00:00.000000000 Z
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.5.1
298
+ rubygems_version: 2.6.4
299
299
  signing_key:
300
300
  specification_version: 4
301
301
  summary: Command-line interface for Aptible services
@@ -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'