aptible-cli 0.3.7 → 0.4.0

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: d8fdc0e031ed20f6fa6ace7447351b6390ca0570
4
- data.tar.gz: 239283ab9b3631162c089d068392dfd50e4c708e
3
+ metadata.gz: 21e712a5221f979075e3b6f8db27ced161633d66
4
+ data.tar.gz: 37333c2bf6da584560dad729525432d41f758598
5
5
  SHA512:
6
- metadata.gz: 97e7e0f9092b65921d299fa2ea0102ce90cf169e9e978fbe82c6c2f2de5abf81a21169faaf91597e374be53a0f942244ea1e35acda7a52cf0d84de9419703b9c
7
- data.tar.gz: e26cd49d39e8d27b9f87149b7d2048da4028ae69e7944a61e06ad78e2ae9d4f8cefdc3bd20cf667ef0d69613509c12a061a5a9e44188da97124144c05d2cbff0
6
+ metadata.gz: 0a2ffa00c630b2f98538db568be48b7af5c9cb1449941c85d1b29f0c249187de755da7cb544aaa0b76322035a5663b5c2c2ccdb1dacee269a426b9cbfec8eaec
7
+ data.tar.gz: d6199b9c406489e3e36a87bf0f315a6070fdc22b4da9dccf5d42ee8b6cfffd34a8426b75054cc5f425d6bf1fc26b6c59b2507c722eb0103c5d1bffd03ce2026d
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem 'pry', github: 'fancyremarker/pry', branch: 'aptible'
4
+
3
5
  # Specify your gem's dependencies in aptible-cli.gemspec
4
6
  gemspec
@@ -9,10 +9,10 @@ require_relative 'helpers/app'
9
9
 
10
10
  require_relative 'subcommands/apps'
11
11
  require_relative 'subcommands/config'
12
+ require_relative 'subcommands/db'
12
13
  require_relative 'subcommands/rebuild'
13
14
  require_relative 'subcommands/restart'
14
15
  require_relative 'subcommands/ssh'
15
- require_relative 'subcommands/tunnel'
16
16
 
17
17
  module Aptible
18
18
  module CLI
@@ -22,10 +22,10 @@ module Aptible
22
22
  include Helpers::Token
23
23
  include Subcommands::Apps
24
24
  include Subcommands::Config
25
+ include Subcommands::DB
25
26
  include Subcommands::Rebuild
26
27
  include Subcommands::Restart
27
28
  include Subcommands::SSH
28
- include Subcommands::Tunnel
29
29
 
30
30
  desc 'version', 'Print Aptible CLI version'
31
31
  def version
@@ -6,6 +6,25 @@ module Aptible
6
6
  def self.included(thor)
7
7
  thor.class_eval do
8
8
  include Helpers::Account
9
+ include Helpers::Token
10
+
11
+ desc 'apps', 'List all applications'
12
+ option :account
13
+ def apps
14
+ if options[:account]
15
+ accounts = [account_from_handle(options[:account])]
16
+ else
17
+ accounts = Aptible::Api::Account.all(token: fetch_token)
18
+ end
19
+
20
+ accounts.each do |account|
21
+ say "=== #{account.handle}"
22
+ account.apps.each do |app|
23
+ say app.handle
24
+ end
25
+ say ''
26
+ end
27
+ end
9
28
 
10
29
  desc 'apps:create HANDLE', 'Create a new application'
11
30
  option :account
@@ -14,7 +33,7 @@ module Aptible
14
33
  app = account.create_app(handle: handle)
15
34
 
16
35
  if app.errors.any?
17
- fail app.errors.full_messages.first
36
+ fail Thor::Error, app.errors.full_messages.first
18
37
  else
19
38
  say "App #{handle} created!"
20
39
  end
@@ -0,0 +1,124 @@
1
+ module Aptible
2
+ module CLI
3
+ module Subcommands
4
+ module DB
5
+ # rubocop:disable MethodLength
6
+ # rubocop:disable CyclomaticComplexity
7
+ def self.included(thor)
8
+ thor.class_eval do
9
+ include Helpers::Operation
10
+ include Helpers::Token
11
+
12
+ desc 'db:create HANDLE', 'Create a new database'
13
+ option :type, default: 'postgresql'
14
+ option :size, default: 10
15
+ option :account
16
+ define_method 'db:create' do |handle|
17
+ account = ensure_account(options)
18
+ database = account.create_database(handle: handle,
19
+ type: options[:type])
20
+
21
+ if database.errors.any?
22
+ fail Thor::Error, database.errors.full_messages.first
23
+ else
24
+ op = database.create_operation(type: 'provision',
25
+ disk_size: options[:size])
26
+ poll_for_success(op)
27
+ say database.reload.connection_url
28
+ end
29
+ end
30
+
31
+ desc 'db:clone SOURCE DEST', 'Clone a database to create a new one'
32
+ define_method 'db:clone' do |source_handle, dest_handle|
33
+ source = database_from_handle(source_handle)
34
+
35
+ unless source
36
+ fail Thor::Error, "Could not find database #{source_handle}"
37
+ end
38
+
39
+ op = database.create_operation(type: clone, handle: dest_handle)
40
+ poll_for_success(op)
41
+ dest = database_from_handle(dest_handle)
42
+ say dest.connection_url
43
+ end
44
+
45
+ desc 'db:dump HANDLE', 'Dump a remote database to file'
46
+ define_method 'db:dump' do |handle|
47
+ begin
48
+ database = database_from_handle(handle)
49
+ unless database
50
+ fail Thor::Error, "Could not find database #{handle}"
51
+ end
52
+ unless database.type == 'postgresql'
53
+ fail Thor::Error, 'db:dump only works for PostgreSQL'
54
+ end
55
+
56
+ local_port = random_port
57
+ pid = fork { establish_connection(database, local_port) }
58
+
59
+ # TODO: Better test for connection readiness
60
+ sleep 10
61
+
62
+ filename = "#{handle}.dump"
63
+ puts "Dumping to #{filename}"
64
+ url = "aptible:#{database.passphrase}@localhost:#{local_port}"
65
+ `pg_dump postgresql://#{url}/db > #{filename}`
66
+ ensure
67
+ Process.kill('HUP', pid) if pid
68
+ end
69
+ end
70
+
71
+ desc 'db:tunnel HANDLE', 'Create a local tunnel to a database'
72
+ option :port, type: :numeric
73
+ define_method 'db:tunnel' do |handle|
74
+ database = database_from_handle(handle)
75
+ unless database
76
+ fail Thor::Error, "Could not find database #{handle}"
77
+ end
78
+
79
+ local_port = options[:port] || random_port
80
+ puts "Creating tunnel at localhost:#{local_port}..."
81
+ establish_connection(database, local_port)
82
+ end
83
+
84
+ private
85
+
86
+ def establish_connection(database, local_port)
87
+ host = database.account.bastion_host
88
+ port = database.account.bastion_port
89
+
90
+ ENV['ACCESS_TOKEN'] = fetch_token
91
+ ENV['APTIBLE_DATABASE'] = database.handle
92
+ tunnel_args = "-L #{local_port}:localhost:#{remote_port}"
93
+ connection_args = "-o 'SendEnv=*' -p #{port} root@#{host}"
94
+ opts = " -o 'SendEnv=*' -o StrictHostKeyChecking=no " \
95
+ '-o UserKnownHostsFile=/dev/null'
96
+ command = "ssh #{opts} #{tunnel_args} #{connection_args}"
97
+ Kernel.exec(command)
98
+ end
99
+
100
+ def database_from_handle(handle)
101
+ Aptible::Api::Database.all(token: fetch_token).find do |a|
102
+ a.handle == handle
103
+ end
104
+ end
105
+
106
+ def random_port
107
+ # Allocate a dummy server to discover an available port
108
+ dummy = TCPServer.new('127.0.0.1', 0)
109
+ port = dummy.addr[1]
110
+ dummy.close
111
+ port
112
+ end
113
+
114
+ def remote_port
115
+ 8080
116
+ end
117
+ end
118
+ end
119
+ # rubocop:enable CyclomaticComplexity
120
+ # rubocop:enable MethodLength
121
+ end
122
+ end
123
+ end
124
+ end
@@ -10,7 +10,7 @@ module Aptible
10
10
  include Helpers::Operation
11
11
  include Helpers::App
12
12
 
13
- desc 'ssh COMMAND', 'Run a command against an app'
13
+ desc 'ssh [COMMAND]', 'Run a command against an app'
14
14
  long_desc <<-LONGDESC
15
15
  Runs an interactive command against a remote Aptible app
16
16
 
@@ -1,5 +1,5 @@
1
1
  module Aptible
2
2
  module CLI
3
- VERSION = '0.3.7'
3
+ VERSION = '0.4.0'
4
4
  end
5
5
  end
@@ -2,6 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Aptible::CLI::Agent do
4
4
  before { subject.stub(:ask) }
5
+ before { subject.stub(:save_token) }
5
6
 
6
7
  describe '#version' do
7
8
  it 'should print the version' do
data/spec/spec_helper.rb CHANGED
@@ -8,3 +8,7 @@ end
8
8
 
9
9
  # Require library up front
10
10
  require 'aptible/cli'
11
+
12
+ RSpec.configure do |config|
13
+ config.before {}
14
+ 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.3.7
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frank Macreery
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-17 00:00:00.000000000 Z
11
+ date: 2014-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aptible-api
@@ -147,10 +147,10 @@ files:
147
147
  - lib/aptible/cli/helpers/token.rb
148
148
  - lib/aptible/cli/subcommands/apps.rb
149
149
  - lib/aptible/cli/subcommands/config.rb
150
+ - lib/aptible/cli/subcommands/db.rb
150
151
  - lib/aptible/cli/subcommands/rebuild.rb
151
152
  - lib/aptible/cli/subcommands/restart.rb
152
153
  - lib/aptible/cli/subcommands/ssh.rb
153
- - lib/aptible/cli/subcommands/tunnel.rb
154
154
  - lib/aptible/cli/version.rb
155
155
  - spec/aptible/cli/agent_spec.rb
156
156
  - spec/spec_helper.rb
@@ -181,4 +181,3 @@ summary: Command-line interface for Aptible services
181
181
  test_files:
182
182
  - spec/aptible/cli/agent_spec.rb
183
183
  - spec/spec_helper.rb
184
- has_rdoc:
@@ -1,57 +0,0 @@
1
- module Aptible
2
- module CLI
3
- module Subcommands
4
- module Tunnel
5
- # rubocop:disable MethodLength
6
- def self.included(thor)
7
- thor.class_eval do
8
- include Helpers::Operation
9
- include Helpers::Token
10
-
11
- desc 'tunnel DATABASE', 'Create a local tunnel to a database'
12
- def tunnel(handle)
13
- database = database_from_handle(handle)
14
- unless database
15
- fail Thor::Error, "Could not find database #{handle}"
16
- end
17
- host = database.account.bastion_host
18
- port = database.account.bastion_port
19
-
20
- ENV['ACCESS_TOKEN'] = fetch_token
21
- ENV['APTIBLE_DATABASE'] = handle
22
- tunnel_args = "-L #{local_port}:localhost:#{remote_port}"
23
- connection_args = "-o 'SendEnv=*' -p #{port} root@#{host}"
24
- puts "Creating tunnel at localhost:#{local_port}..."
25
- opts = " -o 'SendEnv=*' -o StrictHostKeyChecking=no " \
26
- '-o UserKnownHostsFile=/dev/null'
27
- Kernel.exec "ssh #{opts} #{tunnel_args} #{connection_args}"
28
- end
29
-
30
- private
31
-
32
- def database_from_handle(handle)
33
- Aptible::Api::Database.all(token: fetch_token).find do |a|
34
- a.handle == handle
35
- end
36
- end
37
-
38
- def local_port
39
- return @local_port if @local_port
40
-
41
- # Allocate a dummy server to discover an available port
42
- dummy = TCPServer.new('127.0.0.1', 0)
43
- port = dummy.addr[1]
44
- dummy.close
45
- @local_port = port
46
- end
47
-
48
- def remote_port
49
- 8080
50
- end
51
- end
52
- end
53
- # rubocop:enable MethodLength
54
- end
55
- end
56
- end
57
- end