tugboat 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: acb3d5fff3be496ee45a238c9219bea4c159ca4e
4
+ data.tar.gz: a88aea864325b1d5b0e7d37642b42418e79ed905
5
+ SHA512:
6
+ metadata.gz: e53bbe9b2bf1e3bd5bef1f748249857045da696f57e250b2819aa7261db9bdd769ed53b21e60258de6f1c5090e05de8906b0f47de4f313cacf62c20c74357c9a
7
+ data.tar.gz: 0806ce448db80b8a5436c647f56e144a4b94394fbc866bc4a676cea6f45bed21d4b1649339c1b3f55ca13c462fa89b08f251b539ab92d3b4358405162a69181a
data/.travis.yml CHANGED
@@ -3,3 +3,6 @@ rvm:
3
3
  - 1.8.7
4
4
  - 1.9.3
5
5
  - 2.0.0
6
+ matrix:
7
+ allow_failures:
8
+ - rvm: 1.8.7
data/CHANGELOG.md CHANGED
@@ -1,6 +1,26 @@
1
- ## 0.0.7 (unreleased)
1
+ ## 0.0.8 (Unreleased)
2
+
3
+ FEATURES:
4
+
5
+ - [Pete](https://github.com/petems) added configuration defaults
6
+ that you can set. [GH-61]
7
+ - [Pete](https://github.com/petems) added log filtering to debug output.
8
+ `DEBUG=1` now gives you filtered logs, `DEBUG=2`, raw. [GH-58]
2
9
 
3
10
  IMPROVEMENTS:
11
+
12
+ - Error messages are now caught at the Faraday level and displayed
13
+ back to the user.
14
+
15
+ BUG FIXES:
16
+
17
+ - [Ørjan](https://github.com/blom) added a color reset on the `list`
18
+ command. [GH-57]
19
+
20
+ ## 0.0.7 (August 2, 2013)
21
+
22
+ IMPROVEMENTS:
23
+
4
24
  - [Pete](https://github.com/petems) made it clearer to the user
5
25
  if they don't have any droplets or images. [GH-48], [GH-49]
6
26
 
data/README.md CHANGED
@@ -19,6 +19,15 @@ Run the configuration utility, `tugboat authorize`. You can grab your keys
19
19
  Enter your SSH key path (optional, defaults to ~/.ssh/id_rsa):
20
20
  Enter your SSH user (optional, defaults to jack):
21
21
  Enter your SSH port number (optional, defaults to 22):
22
+
23
+ To retrieve region, image, size and key ID's, you can use the corresponding tugboat command, such as `tugboat images`.
24
+ Defaults can be changed at any time in your ~/.tugboat configuration file.
25
+
26
+ Enter your default region ID (optional, defaults to 1 (New York)):
27
+ Enter your default image ID (optional, defaults to 284203 (Ubuntu 12.04 x64)):
28
+ Enter your default size ID (optional, defaults to 66 (512MB)):
29
+ Enter your default ssh key ID (optional, defaults to none):
30
+
22
31
  Authentication with DigitalOcean was successful!
23
32
 
24
33
  ## Usage
@@ -180,6 +189,15 @@ For a complete overview of all of the available commands, run:
180
189
 
181
190
  $ tugboat help
182
191
 
192
+ ## Reporting Bugs
193
+
194
+ Yes, please!
195
+
196
+ It's very helpful if you can run `DEBUG=1 tugboat ...` with the command
197
+ that is causing you issues, and then include that in the issue.
198
+
199
+ You can create a new issue [here](https://github.com/pearkes/tugboat/issues/new). Thank you!
200
+
183
201
  ## Contributing
184
202
 
185
203
  See the [contributing guide](CONTRIBUTING.md).
data/lib/tugboat/cli.rb CHANGED
@@ -36,6 +36,15 @@ module Tugboat
36
36
  Middleware.sequence_authorize.call({})
37
37
  end
38
38
 
39
+ desc "verify", "Check your DigitalOcean credentials"
40
+ long_desc "This tests that your credentials created by the \`authorize\`
41
+ command that are stored in ~/.tugboat are correct and allow you to connect
42
+ to the API without errors.
43
+ "
44
+ def verify
45
+ Middleware.sequence_verify.call({})
46
+ end
47
+
39
48
  desc "droplets", "Retrieve a list of your droplets"
40
49
  def droplets
41
50
  Middleware.sequence_list_droplets.call({})
@@ -89,17 +98,14 @@ module Tugboat
89
98
  method_option "size",
90
99
  :type => :numeric,
91
100
  :aliases => "-s",
92
- :default => 66,
93
101
  :desc => "The size_id of the droplet"
94
102
  method_option "image",
95
103
  :type => :numeric,
96
104
  :aliases => "-i",
97
- :default => 284203,
98
105
  :desc => "The image_id of the droplet"
99
106
  method_option "region",
100
107
  :type => :numeric,
101
108
  :aliases => "-r",
102
- :default => 1,
103
109
  :desc => "The region_id of the droplet"
104
110
  method_option "keys",
105
111
  :type => :string,
@@ -12,6 +12,10 @@ module Tugboat
12
12
  FILE_NAME = '.tugboat'
13
13
  DEFAULT_SSH_KEY_PATH = '.ssh/id_rsa'
14
14
  DEFAULT_SSH_PORT = '22'
15
+ DEFAULT_REGION = '1'
16
+ DEFAULT_IMAGE = '284203'
17
+ DEFAULT_SIZE = '66'
18
+ DEFAULT_SSH_KEY = ''
15
19
 
16
20
  def initialize
17
21
  @path = ENV["TUGBOAT_CONFIG_PATH"] || File.join(File.expand_path("~"), FILE_NAME)
@@ -42,11 +46,27 @@ module Tugboat
42
46
  def ssh_user
43
47
  @data['ssh']['ssh_user']
44
48
  end
45
-
49
+
46
50
  def ssh_port
47
51
  @data['ssh']['ssh_port']
48
52
  end
49
53
 
54
+ def default_region
55
+ @data['defaults'].nil? ? DEFAULT_REGION : @data['defaults']['region']
56
+ end
57
+
58
+ def default_image
59
+ @data['defaults'].nil? ? DEFAULT_IMAGE : @data['defaults']['image']
60
+ end
61
+
62
+ def default_size
63
+ @data['defaults'].nil? ? DEFAULT_SIZE : @data['defaults']['size']
64
+ end
65
+
66
+ def default_ssh_key
67
+ @data['defaults'].nil? ? DEFAULT_SSH_KEY : @data['defaults']['ssh_key']
68
+ end
69
+
50
70
  # Re-runs initialize
51
71
  def reset!
52
72
  self.send(:initialize)
@@ -58,7 +78,7 @@ module Tugboat
58
78
  end
59
79
 
60
80
  # Writes a config file
61
- def create_config_file(client, api, ssh_key_path, ssh_user, ssh_port)
81
+ def create_config_file(client, api, ssh_key_path, ssh_user, ssh_port, region, image, size, ssh_key)
62
82
  # Default SSH Key path
63
83
  if ssh_key_path.empty?
64
84
  ssh_key_path = File.join(File.expand_path("~"), DEFAULT_SSH_KEY_PATH)
@@ -72,10 +92,29 @@ module Tugboat
72
92
  ssh_port = DEFAULT_SSH_PORT
73
93
  end
74
94
 
95
+ if region.empty?
96
+ region = DEFAULT_REGION
97
+ end
98
+
99
+ if image.empty?
100
+ image = DEFAULT_IMAGE
101
+ end
102
+
103
+ if size.empty?
104
+ size = DEFAULT_SIZE
105
+ end
106
+
107
+ if ssh_key.empty?
108
+ default_ssh_key = DEFAULT_SSH_KEY
109
+ end
110
+
75
111
  require 'yaml'
76
112
  File.open(@path, File::RDWR|File::TRUNC|File::CREAT, 0600) do |file|
77
- data = {"authentication" => { "client_key" => client, "api_key" => api },
78
- "ssh" => { "ssh_user" => ssh_user, "ssh_key_path" => ssh_key_path , "ssh_port" => ssh_port}}
113
+ data = {
114
+ "authentication" => { "client_key" => client, "api_key" => api },
115
+ "ssh" => { "ssh_user" => ssh_user, "ssh_key_path" => ssh_key_path , "ssh_port" => ssh_port},
116
+ "defaults" => { "region" => region, "image" => image, "size" => size, "ssh_key" => ssh_key }
117
+ }
79
118
  file.write data.to_yaml
80
119
  end
81
120
  end
@@ -42,6 +42,16 @@ module Tugboat
42
42
  end
43
43
  end
44
44
 
45
+ # This checks that the credentials in ~/.tugboat are valid
46
+ def self.sequence_verify
47
+ ::Middleware::Builder.new do
48
+ use InjectConfiguration
49
+ use CheckConfiguration
50
+ use InjectClient
51
+ use CheckCredentials
52
+ end
53
+ end
54
+
45
55
  # Display a list of droplets
46
56
  def self.sequence_list_droplets
47
57
  ::Middleware::Builder.new do
@@ -10,9 +10,17 @@ module Tugboat
10
10
  ssh_key_path = ask "Enter your SSH key path (optional, defaults to ~/.ssh/id_rsa):"
11
11
  ssh_user = ask "Enter your SSH user (optional, defaults to #{ENV['USER']}):"
12
12
  ssh_port = ask "Enter your SSH port number (optional, defaults to 22):"
13
+ say
14
+ say "To retrieve region, image, size and key ID's, you can use the corresponding tugboat command, such as `tugboat images`."
15
+ say "Defaults can be changed at any time in your ~/.tugboat configuration file."
16
+ say
17
+ region = ask "Enter your default region ID (optional, defaults to 1 (New York)):"
18
+ image = ask "Enter your default image ID (optional, defaults to 284203 (Ubuntu 12.04 x64)):"
19
+ size = ask "Enter your default size ID (optional, defaults to 66 (512MB)):"
20
+ ssh_key = ask "Enter your default ssh key ID (optional, defaults to none):"
13
21
 
14
22
  # Write the config file.
15
- env['config'].create_config_file(client_key, api_key, ssh_key_path, ssh_user, ssh_port)
23
+ env['config'].create_config_file(client_key, api_key, ssh_key_path, ssh_user, ssh_port, region, image, size, ssh_key)
16
24
  env['config'].reload!
17
25
 
18
26
  @app.call(env)
@@ -0,0 +1,40 @@
1
+ module Tugboat
2
+ class AuthenticationMiddleware < Faraday::Middleware
3
+ extend Forwardable
4
+ def_delegators :'Faraday::Utils', :parse_query, :build_query
5
+ RED = "\e[31m"
6
+ CLEAR = "\e[0m"
7
+
8
+ def initialize(app, client_id, api_key)
9
+ @client_id = client_id
10
+ @api_key = api_key
11
+
12
+ super(app)
13
+ end
14
+
15
+ def call(env)
16
+ params = { 'client_id' => @client_id, 'api_key' => @api_key }.update query_params(env[:url])
17
+
18
+ env[:url].query = build_query params
19
+
20
+ begin
21
+ @app.call(env)
22
+ rescue Faraday::Error::ClientError => e
23
+ puts "#{RED}#{e}!#{CLEAR}\n"
24
+ if env[:body].status == "ERROR"
25
+ puts "\n#{RED}#{env[:body].error_message}#{CLEAR}\n\n"
26
+ end
27
+ puts "Double-check your parameters and configuration (in your ~/.tugboat file)"
28
+ exit 1
29
+ end
30
+ end
31
+
32
+ def query_params(url)
33
+ if url.query.nil? or url.query.empty?
34
+ {}
35
+ else
36
+ parse_query url.query
37
+ end
38
+ end
39
+ end
40
+ end
@@ -9,7 +9,7 @@ module Tugboat
9
9
  # work.
10
10
  begin
11
11
  env["ocean"].droplets.list
12
- rescue Faraday::Error::ParsingError
12
+ rescue Faraday::Error::ClientError => e
13
13
  say "Authentication with DigitalOcean failed. Run `tugboat authorize`", :red
14
14
  exit 1
15
15
  end
@@ -6,11 +6,27 @@ module Tugboat
6
6
 
7
7
  say "Queueing creation of droplet '#{env["create_droplet_name"]}'...", nil, false
8
8
 
9
- req = ocean.droplets.create :name => env["create_droplet_name"],
10
- :size_id => env["create_droplet_size_id"],
11
- :image_id => env["create_droplet_image_id"],
12
- :region_id => env["create_droplet_region_id"],
13
- :ssh_key_ids => env["create_droplet_ssh_key_ids"]
9
+ env["create_droplet_region_id"] ?
10
+ droplet_region_id = env["create_droplet_region_id"] :
11
+ droplet_region_id = env["config"].default_region
12
+
13
+ env["create_droplet_image_id"] ?
14
+ droplet_image_id = env["create_droplet_image_id"] :
15
+ droplet_image_id = env["config"].default_image
16
+
17
+ env["create_droplet_size_id"] ?
18
+ droplet_size_id = env["create_droplet_size_id"] :
19
+ droplet_size_id = env["config"].default_size
20
+
21
+ env["create_droplet_ssh_key_ids"] ?
22
+ droplet_ssh_key_id = env["create_droplet_ssh_key_ids"] :
23
+ droplet_ssh_key_id = env["config"].default_ssh_key
24
+
25
+ req = ocean.droplets.create :name => env["create_droplet_name"],
26
+ :size_id => droplet_size_id,
27
+ :image_id => droplet_image_id,
28
+ :region_id => droplet_region_id,
29
+ :ssh_key_ids => droplet_ssh_key_id
14
30
 
15
31
  if req.status == "ERROR"
16
32
  say req.error_message, :red
@@ -0,0 +1,72 @@
1
+ module Tugboat
2
+ class CustomLogger < Faraday::Middleware
3
+ extend Forwardable
4
+ def_delegators :@logger, :debug, :info, :warn, :error, :fatal
5
+
6
+ def initialize(app, options = {})
7
+ @app = app
8
+ @logger = options.fetch(:logger) {
9
+ require 'logger'
10
+ ::Logger.new(STDOUT)
11
+ }
12
+ end
13
+
14
+ def call(env)
15
+ start_time = Time.now
16
+ info { request_info(env) }
17
+ debug { request_debug(env) }
18
+ @app.call(env).on_complete do
19
+ end_time = Time.now
20
+ response_time = end_time - start_time
21
+ info { response_info(env, response_time) }
22
+ debug { response_debug(env) }
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def filter(output)
29
+ unless ENV['DEBUG'] == '2'
30
+ output = output.to_s.gsub(/client_id=[a-zA-Z0-9]*/,'client_id=[CLIENT-ID]')
31
+ output = output.to_s.gsub(/api_key=[a-zA-Z0-9]*/,'api_key=[API-KEY]')
32
+ output = output.to_s.gsub(/_digitalocean2_session_v2=[a-zA-Z0-9%-]*/,'_digitalocean2_session_v2=[SESSION_COOKIE]')
33
+ else
34
+ output
35
+ end
36
+ end
37
+
38
+ def request_info(env)
39
+ "Started %s request to: %s" % [ env[:method].to_s.upcase, filter(env[:url]) ]
40
+ end
41
+
42
+ def response_info(env, response_time)
43
+ "Response from %s; Status: %d; Time: %.1fms" % [ filter(env[:url]), env[:status], (response_time * 1_000.0) ]
44
+ end
45
+
46
+ def request_debug(env)
47
+ debug_message("Request", env[:request_headers], env[:body])
48
+ end
49
+
50
+ def response_debug(env)
51
+ debug_message("Response", env[:response_headers], env[:body])
52
+ end
53
+
54
+ def debug_message(name, headers, body)
55
+ <<-MESSAGE.gsub(/^ +([^ ])/m, '\\1')
56
+ #{name} Headers:
57
+ ----------------
58
+ #{format_headers(headers)}
59
+
60
+ #{name} Body:
61
+ -------------
62
+ #{body}
63
+ MESSAGE
64
+ end
65
+
66
+ def format_headers(headers)
67
+ length = headers.map {|k,v| k.to_s.size }.max
68
+ headers.map { |name, value| "#{name.to_s.ljust(length)} : #{filter(value)}" }.join("\n")
69
+ end
70
+
71
+ end
72
+ end
@@ -1,15 +1,34 @@
1
1
  require 'digital_ocean'
2
+ require File.expand_path('../authentication_middleware', __FILE__)
3
+ require File.expand_path('../custom_logger', __FILE__)
4
+
2
5
  module Tugboat
3
6
  module Middleware
4
7
  # Inject the digital ocean client into the environment
5
8
  class InjectClient < Base
9
+
10
+ def tugboat_faraday
11
+ Faraday.new(:url => 'https://api.digitalocean.com/') do |faraday|
12
+ faraday.use AuthenticationMiddleware, @client_id, @api_key
13
+ faraday.use Faraday::Response::RaiseError
14
+ faraday.use CustomLogger if ENV['DEBUG']
15
+ faraday.request :url_encoded
16
+ faraday.response :rashify
17
+ faraday.response :json
18
+ faraday.adapter Faraday.default_adapter
19
+ end
20
+ end
21
+
6
22
  def call(env)
7
23
  # Sets the digital ocean client into the environment for use
8
24
  # later.
25
+ @client_id = env["config"].client_key
26
+ @api_key = env["config"].api_key
27
+
9
28
  env["ocean"] = DigitalOcean::API.new \
10
- :client_id => env["config"].client_key,
11
- :api_key => env["config"].api_key,
12
- :debug => ENV['DEBUG'] || false
29
+ :client_id => @client_id,
30
+ :api_key => @api_key,
31
+ :faraday => tugboat_faraday
13
32
 
14
33
  @app.call(env)
15
34
  end
@@ -9,7 +9,7 @@ module Tugboat
9
9
 
10
10
  if droplet_list.empty?
11
11
  say "You don't appear to have any droplets.", :red
12
- say "Try creating one with #{GREEN}\`tugboat create\`"
12
+ say "Try creating one with #{GREEN}\`tugboat create\`#{CLEAR}"
13
13
  else
14
14
  droplet_list.each do |droplet|
15
15
 
@@ -1,3 +1,3 @@
1
1
  module Tugboat
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.8"
3
3
  end
@@ -3,10 +3,12 @@ require 'spec_helper'
3
3
  describe Tugboat::CLI do
4
4
  include_context "spec"
5
5
 
6
+ let(:tmp_path) { project_path + "/tmp/tugboat" }
7
+
6
8
  describe "authorize" do
7
9
  before do
8
10
  stub_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}").
9
- to_return(:status => 200)
11
+ to_return(:status => 200)
10
12
  end
11
13
 
12
14
  it "asks the right questions and checks credentials" do
@@ -22,10 +24,51 @@ describe Tugboat::CLI do
22
24
  $stdin.should_receive(:gets).and_return(ssh_user)
23
25
  $stdout.should_receive(:print).with("Enter your SSH port number (optional, defaults to 22): ")
24
26
  $stdin.should_receive(:gets).and_return(ssh_port)
27
+ $stdout.should_receive(:print).with("Enter your default region ID (optional, defaults to 1 (New York)): ")
28
+ $stdin.should_receive(:gets).and_return(region)
29
+ $stdout.should_receive(:print).with("Enter your default image ID (optional, defaults to 284203 (Ubuntu 12.04 x64)): ")
30
+ $stdin.should_receive(:gets).and_return(image)
31
+ $stdout.should_receive(:print).with("Enter your default size ID (optional, defaults to 66 (512MB)): ")
32
+ $stdin.should_receive(:gets).and_return(size)
33
+ $stdout.should_receive(:print).with("Enter your default ssh key ID (optional, defaults to none): ")
34
+ $stdin.should_receive(:gets).and_return(ssh_key_id)
25
35
 
26
36
  @cli.authorize
27
37
 
28
38
  expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
39
+
40
+ File.read(tmp_path).should include "image: '#{image}'", "region: '#{region}'", "size: '#{size}'", "ssh_user: #{ssh_user}", "ssh_key_path: #{ssh_key_path}", "ssh_port: '#{ssh_port}'", "ssh_key: '#{ssh_key_id}'"
41
+
42
+ end
43
+
44
+ it "sets defaults if no input given" do
45
+
46
+ $stdout.should_receive(:print).exactly(6).times
47
+ $stdout.should_receive(:print).with("Enter your client key: ")
48
+ $stdin.should_receive(:gets).and_return(client_key)
49
+ $stdout.should_receive(:print).with("Enter your API key: ")
50
+ $stdin.should_receive(:gets).and_return(api_key)
51
+ $stdout.should_receive(:print).with("Enter your SSH key path (optional, defaults to ~/.ssh/id_rsa): ")
52
+ $stdin.should_receive(:gets).and_return(ssh_key_path)
53
+ $stdout.should_receive(:print).with("Enter your SSH user (optional, defaults to #{ENV['USER']}): ")
54
+ $stdin.should_receive(:gets).and_return('')
55
+ $stdout.should_receive(:print).with("Enter your SSH port number (optional, defaults to 22): ")
56
+ $stdin.should_receive(:gets).and_return('')
57
+ $stdout.should_receive(:print).with("Enter your default region ID (optional, defaults to 1 (New York)): ")
58
+ $stdin.should_receive(:gets).and_return('')
59
+ $stdout.should_receive(:print).with("Enter your default image ID (optional, defaults to 284203 (Ubuntu 12.04 x64)): ")
60
+ $stdin.should_receive(:gets).and_return('')
61
+ $stdout.should_receive(:print).with("Enter your default size ID (optional, defaults to 66 (512MB)): ")
62
+ $stdin.should_receive(:gets).and_return('')
63
+ $stdout.should_receive(:print).with("Enter your default ssh key ID (optional, defaults to none): ")
64
+ $stdin.should_receive(:gets).and_return('')
65
+
66
+ @cli.authorize
67
+
68
+ expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
69
+
70
+ File.read(tmp_path).should include "image: '284203'", "region: '1'", "size: '66'", "ssh_user: #{ENV['USER']}", "ssh_key_path: ~/.ssh/id_rsa", "ssh_port: '22'", "ssh_key: ''"
71
+
29
72
  end
30
73
  end
31
74
 
@@ -4,8 +4,8 @@ describe Tugboat::CLI do
4
4
  include_context "spec"
5
5
 
6
6
  describe "create a droplet" do
7
- it "with a name" do
8
- stub_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id&name=#{droplet_name}&region_id&size_id&ssh_key_ids").
7
+ it "with a name, uses defaults from configuration" do
8
+ stub_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=#{image}&name=#{droplet_name}&region_id=#{region}&size_id=#{size}&ssh_key_ids=#{ssh_key_id}").
9
9
  to_return(:status => 200, :body => '{"status":"OK"}')
10
10
 
11
11
  @cli.create(droplet_name)
@@ -13,21 +13,21 @@ describe Tugboat::CLI do
13
13
  expect($stdout.string).to eq <<-eos
14
14
  Queueing creation of droplet '#{droplet_name}'...done
15
15
  eos
16
- expect(a_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id&name=#{droplet_name}&region_id&size_id&ssh_key_ids")).to have_been_made
16
+ expect(a_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=#{image}&name=#{droplet_name}&region_id=#{region}&size_id=#{size}&ssh_key_ids=#{ssh_key_id}")).to have_been_made
17
17
  end
18
18
 
19
- it "with args" do
20
- stub_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=2672&name=#{droplet_name}&region_id=2&size_id=64&ssh_key_ids=1234").
19
+ it "with args does not use defaults from configuration" do
20
+ stub_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=555&name=foo&region_id=3&size_id=666&ssh_key_ids=4321").
21
21
  to_return(:status => 200, :body => '{"status":"OK"}')
22
22
 
23
- @cli.options = @cli.options.merge(:image => 2672, :size => 64, :region => 2, :keys => "1234")
23
+ @cli.options = @cli.options.merge(:image => '555', :size => '666', :region => '3', :keys => '4321')
24
24
  @cli.create(droplet_name)
25
25
 
26
26
  expect($stdout.string).to eq <<-eos
27
27
  Queueing creation of droplet '#{droplet_name}'...done
28
28
  eos
29
29
 
30
- expect(a_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=2672&name=foo&region_id=2&size_id=64&ssh_key_ids=1234")).to have_been_made
30
+ expect(a_request(:get, "https://api.digitalocean.com/droplets/new?api_key=#{api_key}&client_id=#{client_key}&image_id=555&name=foo&region_id=3&size_id=666&ssh_key_ids=4321")).to have_been_made
31
31
  end
32
32
  end
33
33
 
@@ -27,7 +27,7 @@ foo (ip: 33.33.33.10, status: \e[32mactive\e[0m, region: 1, id: 100823)
27
27
 
28
28
  expect($stdout.string).to eq <<-eos
29
29
  You don't appear to have any droplets.
30
- Try creating one with \e[32m`tugboat create`
30
+ Try creating one with \e[32m`tugboat create`\e[0m
31
31
  eos
32
32
 
33
33
  expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tugboat::CLI do
4
+ include_context "spec"
5
+
6
+ describe "verify" do
7
+ it "returns confirmation text when verify passes" do
8
+ stub_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}").
9
+ to_return(:status => 200)
10
+ @cli.verify
11
+ expect($stdout.string).to eq "Authentication with DigitalOcean was successful.\n"
12
+ expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
13
+ end
14
+
15
+ it "returns error string when verify fails" do
16
+ stub_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}").
17
+ to_return(:status => 401, :body => '{"status":"ERROR", "error_message":"Access Denied"}')
18
+ expect { @cli.verify }.to raise_error(SystemExit)
19
+ expect($stdout.string).to eq "\e[31mthe server responded with status 401!\e[0m\n\n\e[31mAccess Denied\e[0m\n\nDouble-check your parameters and configuration (in your ~/.tugboat file)\n"
20
+ expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+
data/spec/config_spec.rb CHANGED
@@ -29,12 +29,16 @@ describe Tugboat::Configuration do
29
29
  let(:ssh_key_path) { "~/.ssh/id_rsa2" }
30
30
  let(:ssh_key_path) { "~/.ssh/id_rsa2.pub" }
31
31
  let(:ssh_port) { "22" }
32
+ let(:region) { "2" }
33
+ let(:image) { "345791" }
34
+ let(:size) { "66" }
35
+ let(:ssh_key_id) { '1234' }
32
36
 
33
37
  let(:config) { config = Tugboat::Configuration.instance }
34
38
 
35
39
  before :each do
36
40
  # Create a temporary file
37
- config.create_config_file(client_key, api_key, ssh_key_path, ssh_user, ssh_port)
41
+ config.create_config_file(client_key, api_key, ssh_key_path, ssh_user, ssh_port, region, image, size, ssh_key_id)
38
42
  end
39
43
 
40
44
  it "can be created" do
@@ -47,39 +51,89 @@ describe Tugboat::Configuration do
47
51
  end
48
52
 
49
53
  describe "the file format"
50
- let(:data) { YAML.load_file(tmp_path) }
51
-
52
- it "should have authentication at the top level" do
53
- expect(data).to have_key("authentication")
54
- end
55
-
56
- it "should have ssh at the top level" do
57
- expect(data).to have_key("ssh")
58
- end
59
-
60
- it "should have a client key" do
61
- auth = data["authentication"]
62
- expect(auth).to have_key("client_key")
63
- end
64
-
65
- it "should have an api key" do
66
- auth = data["authentication"]
67
- expect(auth).to have_key("api_key")
68
- end
69
-
70
- it "should have an ssh key path" do
71
- ssh = data["ssh"]
72
- expect(ssh).to have_key("ssh_key_path")
73
- end
74
-
75
- it "should have an ssh user" do
76
- ssh = data["ssh"]
77
- expect(ssh).to have_key("ssh_user")
78
- end
79
-
80
- it "should have an ssh port" do
81
- ssh = data["ssh"]
82
- expect(ssh).to have_key("ssh_port")
83
- end
54
+ let(:data) { YAML.load_file(tmp_path) }
55
+
56
+ it "should have authentication at the top level" do
57
+ expect(data).to have_key("authentication")
58
+ end
59
+
60
+ it "should have ssh at the top level" do
61
+ expect(data).to have_key("ssh")
62
+ end
63
+
64
+ it "should have a client key" do
65
+ auth = data["authentication"]
66
+ expect(auth).to have_key("client_key")
67
+ end
68
+
69
+ it "should have an api key" do
70
+ auth = data["authentication"]
71
+ expect(auth).to have_key("api_key")
72
+ end
73
+
74
+ it "should have an ssh key path" do
75
+ ssh = data["ssh"]
76
+ expect(ssh).to have_key("ssh_key_path")
77
+ end
78
+
79
+ it "should have an ssh user" do
80
+ ssh = data["ssh"]
81
+ expect(ssh).to have_key("ssh_user")
82
+ end
83
+
84
+ it "should have an ssh port" do
85
+ ssh = data["ssh"]
86
+ expect(ssh).to have_key("ssh_port")
87
+ end
88
+ end
89
+ describe "backwards compatible" do
90
+ let(:client_key) { "foo" }
91
+ let(:api_key) { "bar" }
92
+ let(:ssh_user) { "baz" }
93
+ let(:ssh_key_path) { "~/.ssh/id_rsa2" }
94
+ let(:ssh_key_path) { "~/.ssh/id_rsa2.pub" }
95
+ let(:ssh_port) { "22" }
96
+
97
+ let(:config) { config = Tugboat::Configuration.instance }
98
+ let(:config_default_region) { Tugboat::Configuration::DEFAULT_REGION }
99
+ let(:config_default_image) { Tugboat::Configuration::DEFAULT_IMAGE }
100
+ let(:config_default_size) { Tugboat::Configuration::DEFAULT_SIZE }
101
+ let(:config_default_ssh_key) { Tugboat::Configuration::DEFAULT_SSH_KEY }
102
+ let(:backwards_config) {
103
+ {
104
+ "authentication" => { "client_key" => client_key, "api_key" => api_key },
105
+ "ssh" => { "ssh_user" => ssh_user, "ssh_key_path" => ssh_key_path , "ssh_port" => ssh_port},
106
+ }
107
+ }
108
+
109
+ before :each do
110
+ config.instance_variable_set(:@data, backwards_config)
111
+ end
112
+
113
+ it "should load a backwards compatible config file" do
114
+ data_file = config.instance_variable_get(:@data)
115
+ expect(data_file).to eql backwards_config
116
+ end
117
+
118
+ it "should use default region if not in configuration" do
119
+ region = config.default_region
120
+ expect(region).to eql config_default_region
121
+ end
122
+
123
+ it "should use default image if not in configuration" do
124
+ image = config.default_image
125
+ expect(image).to eql config_default_image
126
+ end
127
+
128
+ it "should use default size if not in configuration" do
129
+ size = config.default_size
130
+ expect(size).to eql config_default_size
131
+ end
132
+
133
+ it "should use default ssh key if not in configuration" do
134
+ ssh_key = config.default_ssh_key
135
+ expect(ssh_key).to eql config_default_ssh_key
136
+ end
137
+
84
138
  end
85
139
  end
@@ -4,7 +4,7 @@ describe Tugboat::Middleware::SSHDroplet do
4
4
  include_context "spec"
5
5
 
6
6
  before do
7
- Kernel.stub!(:exec)
7
+ Kernel.stub(:exec)
8
8
  end
9
9
 
10
10
  describe ".call" do
@@ -6,11 +6,15 @@ shared_context "spec" do
6
6
  let(:client_key) { "foo" }
7
7
  let(:api_key) { "bar" }
8
8
  let(:ssh_user) { "baz" }
9
- let(:ssh_port) { "22" }
9
+ let(:ssh_port) { "33" }
10
10
  let(:ssh_key_path) { "~/.ssh/id_rsa2" }
11
11
  let(:droplet_name) { "foo" }
12
12
  let(:droplet_ip) { "33.33.33.10" }
13
13
  let(:droplet_id) { 1234 }
14
+ let(:region) { '3' }
15
+ let(:image) { '345791'}
16
+ let(:size) { '67'}
17
+ let(:ssh_key_id) { '1234' }
14
18
  let(:ocean) { DigitalOcean::API.new :client_id => client_key, :api_key =>api_key }
15
19
  let(:app) { lambda { |env| } }
16
20
  let(:env) { {} }
@@ -22,7 +26,7 @@ shared_context "spec" do
22
26
  @cli = Tugboat::CLI.new
23
27
 
24
28
  # Set a temprary project path and create fake config.
25
- config.create_config_file(client_key, api_key, ssh_key_path, ssh_user, ssh_port)
29
+ config.create_config_file(client_key, api_key, ssh_key_path, ssh_user, ssh_port, region, image, size, ssh_key_id)
26
30
  config.reload!
27
31
 
28
32
  # Keep track of the old stderr / out
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tugboat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
5
- prerelease:
4
+ version: 0.0.8
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jack Pearkes
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-08-02 00:00:00.000000000 Z
11
+ date: 2013-09-07 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: thor
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
@@ -30,7 +27,6 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: digital_ocean
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ~>
36
32
  - !ruby/object:Gem::Version
@@ -38,7 +34,6 @@ dependencies:
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ~>
44
39
  - !ruby/object:Gem::Version
@@ -46,7 +41,6 @@ dependencies:
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: middleware
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ~>
52
46
  - !ruby/object:Gem::Version
@@ -54,7 +48,6 @@ dependencies:
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - ~>
60
53
  - !ruby/object:Gem::Version
@@ -62,23 +55,20 @@ dependencies:
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: rake
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - '>='
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - '>='
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rspec-core
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
73
  - - ~>
84
74
  - !ruby/object:Gem::Version
@@ -86,7 +76,6 @@ dependencies:
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
80
  - - ~>
92
81
  - !ruby/object:Gem::Version
@@ -94,7 +83,6 @@ dependencies:
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: rspec-expectations
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
87
  - - ~>
100
88
  - !ruby/object:Gem::Version
@@ -102,7 +90,6 @@ dependencies:
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
94
  - - ~>
108
95
  - !ruby/object:Gem::Version
@@ -110,7 +97,6 @@ dependencies:
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: rspec-mocks
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
101
  - - ~>
116
102
  - !ruby/object:Gem::Version
@@ -118,7 +104,6 @@ dependencies:
118
104
  type: :development
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
108
  - - ~>
124
109
  - !ruby/object:Gem::Version
@@ -126,7 +111,6 @@ dependencies:
126
111
  - !ruby/object:Gem::Dependency
127
112
  name: webmock
128
113
  requirement: !ruby/object:Gem::Requirement
129
- none: false
130
114
  requirements:
131
115
  - - ~>
132
116
  - !ruby/object:Gem::Version
@@ -134,7 +118,6 @@ dependencies:
134
118
  type: :development
135
119
  prerelease: false
136
120
  version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
121
  requirements:
139
122
  - - ~>
140
123
  - !ruby/object:Gem::Version
@@ -142,7 +125,6 @@ dependencies:
142
125
  - !ruby/object:Gem::Dependency
143
126
  name: coveralls
144
127
  requirement: !ruby/object:Gem::Requirement
145
- none: false
146
128
  requirements:
147
129
  - - ~>
148
130
  - !ruby/object:Gem::Version
@@ -150,7 +132,6 @@ dependencies:
150
132
  type: :development
151
133
  prerelease: false
152
134
  version_requirements: !ruby/object:Gem::Requirement
153
- none: false
154
135
  requirements:
155
136
  - - ~>
156
137
  - !ruby/object:Gem::Version
@@ -177,6 +158,7 @@ files:
177
158
  - lib/tugboat/config.rb
178
159
  - lib/tugboat/middleware.rb
179
160
  - lib/tugboat/middleware/ask_for_credentials.rb
161
+ - lib/tugboat/middleware/authentication_middleware.rb
180
162
  - lib/tugboat/middleware/base.rb
181
163
  - lib/tugboat/middleware/check_configuration.rb
182
164
  - lib/tugboat/middleware/check_credentials.rb
@@ -184,6 +166,7 @@ files:
184
166
  - lib/tugboat/middleware/check_droplet_inactive.rb
185
167
  - lib/tugboat/middleware/confirm_action.rb
186
168
  - lib/tugboat/middleware/create_droplet.rb
169
+ - lib/tugboat/middleware/custom_logger.rb
187
170
  - lib/tugboat/middleware/destroy_droplet.rb
188
171
  - lib/tugboat/middleware/find_droplet.rb
189
172
  - lib/tugboat/middleware/halt_droplet.rb
@@ -220,6 +203,7 @@ files:
220
203
  - spec/cli/snapshot_cli_spec.rb
221
204
  - spec/cli/ssh_cli_spec.rb
222
205
  - spec/cli/start_cli_spec.rb
206
+ - spec/cli/verify_cli_spec.rb
223
207
  - spec/cli/version_cli_spec.rb
224
208
  - spec/cli/wait_cli_spec.rb
225
209
  - spec/config_spec.rb
@@ -249,27 +233,26 @@ files:
249
233
  - tugboat.gemspec
250
234
  homepage: https://github.com/pearkes/tugboat
251
235
  licenses: []
236
+ metadata: {}
252
237
  post_install_message:
253
238
  rdoc_options: []
254
239
  require_paths:
255
240
  - lib
256
241
  required_ruby_version: !ruby/object:Gem::Requirement
257
- none: false
258
242
  requirements:
259
- - - ! '>='
243
+ - - '>='
260
244
  - !ruby/object:Gem::Version
261
245
  version: '0'
262
246
  required_rubygems_version: !ruby/object:Gem::Requirement
263
- none: false
264
247
  requirements:
265
- - - ! '>='
248
+ - - '>='
266
249
  - !ruby/object:Gem::Version
267
250
  version: '0'
268
251
  requirements: []
269
252
  rubyforge_project:
270
- rubygems_version: 1.8.24
253
+ rubygems_version: 2.0.3
271
254
  signing_key:
272
- specification_version: 3
255
+ specification_version: 4
273
256
  summary: A command line tool for interacting with your DigitalOcean droplets.
274
257
  test_files:
275
258
  - spec/cli/authorize_cli_spec.rb
@@ -289,6 +272,7 @@ test_files:
289
272
  - spec/cli/snapshot_cli_spec.rb
290
273
  - spec/cli/ssh_cli_spec.rb
291
274
  - spec/cli/start_cli_spec.rb
275
+ - spec/cli/verify_cli_spec.rb
292
276
  - spec/cli/version_cli_spec.rb
293
277
  - spec/cli/wait_cli_spec.rb
294
278
  - spec/config_spec.rb
@@ -314,3 +298,4 @@ test_files:
314
298
  - spec/middleware/ssh_droplet_spec.rb
315
299
  - spec/shared/environment.rb
316
300
  - spec/spec_helper.rb
301
+ has_rdoc: