aptible-cli 0.3.7 → 0.4.0

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 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