Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wait #46

Merged
merged 5 commits into from
Jun 25, 2013
Merged

Wait #46

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,19 @@ Optionally, list images provided by DigitalOcean as well.
pearkes (id: 10501)
...

### Wait for Droplet State

Sometimes you want to wait for a droplet to enter some state, for
example "off".

$ tugboat wait admin --state off
Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001)
Waiting for droplet to become off....
...

This will simply block until the droplet returns a state of "off".
A period will be printed after each request.

## Help

If you're curious about command flags for a specific command, you can
Expand Down
44 changes: 43 additions & 1 deletion lib/tugboat/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ class CLI < Thor

!check_unknown_options

map "--version" => :version, "-v" => :version
map "--version" => :version,
"-v" => :version,
"password-reset" => :password_reset

desc "help [COMMAND]", "Describe commands or a specific command"
def help(meth=nil)
Expand Down Expand Up @@ -273,6 +275,46 @@ def resize(name=nil)
"user_droplet_fuzzy_name" => name
})
end

desc "password-reset FUZZY_NAME", "Reset root password"
method_option "id",
:type => :numeric,
:aliases => "-i",
:desc => "The ID of the droplet."
method_option "name",
:type => :string,
:aliases => "-n",
:desc => "The exact name of the droplet"
def password_reset(name=nil)
Middleware.sequence_password_reset.call({
"user_droplet_id" => options[:id],
"user_droplet_name" => options[:name],
"user_droplet_fuzzy_name" => name
})
end

desc "wait FUZZY_NAME", "Wait for a droplet to reach a state"
method_option "id",
:type => :numeric,
:aliases => "-i",
:desc => "The ID of the droplet."
method_option "name",
:type => :string,
:aliases => "-n",
:desc => "The exact name of the droplet"
method_option "state",
:type => :string,
:aliases => "-s",
:default => "active",
:desc => "The state of the droplet to wait for"
def wait(name=nil)
Middleware.sequence_wait.call({
"user_droplet_id" => options[:id],
"user_droplet_name" => options[:name],
"user_droplet_desired_state" => options[:state],
"user_droplet_fuzzy_name" => name
})
end
end
end

24 changes: 24 additions & 0 deletions lib/tugboat/middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ module Middleware
autoload :ListSizes, "tugboat/middleware/list_sizes"
autoload :CheckDropletActive, "tugboat/middleware/check_droplet_active"
autoload :CheckDropletInactive, "tugboat/middleware/check_droplet_inactive"
autoload :PasswordReset, "tugboat/middleware/password_reset"
autoload :WaitForState, "tugboat/middleware/wait_for_state"

# Start the authorization flow.
# This writes a ~/.tugboat file, which can be edited manually.
Expand Down Expand Up @@ -192,5 +194,27 @@ def self.sequence_resize_droplet
use ResizeDroplet
end
end

# Reset root password
def self.sequence_password_reset
::Middleware::Builder.new do
use InjectConfiguration
use CheckConfiguration
use InjectClient
use FindDroplet
use PasswordReset
end
end

# Wait for a droplet to enter a desired state
def self.sequence_wait
::Middleware::Builder.new do
use InjectConfiguration
use CheckConfiguration
use InjectClient
use FindDroplet
use WaitForState
end
end
end
end
23 changes: 23 additions & 0 deletions lib/tugboat/middleware/password_reset.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Tugboat
module Middleware
class PasswordReset < Base
def call(env)
ocean = env["ocean"]

say "Queuing password reset for #{env["droplet_id"]} #{env["droplet_name"]}...", nil, false
res = ocean.droplets.password_reset env["droplet_id"]

if res.status == "ERROR"
say res.error_message, :red
exit 1
end

say "done", :green
say "Your new root password will be emailed to you"

@app.call(env)
end
end
end
end

35 changes: 35 additions & 0 deletions lib/tugboat/middleware/wait_for_state.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module Tugboat
module Middleware
class WaitForState < Base
def call(env)
ocean = env["ocean"]

say "Waiting for droplet to become #{env["user_droplet_desired_state"]}.", nil, false

start_time = Time.now

req = ocean.droplets.show env["droplet_id"]

say ".", nil, false

if req.status == "ERROR"
say req.error_message, :red
exit 1
end

while req.droplet.status != env["user_droplet_desired_state"] do
sleep 2
req = ocean.droplets.show env["droplet_id"]
say ".", nil, false
end

total_time = (Time.now - start_time).to_i

say "done#{CLEAR} (#{total_time}s)", :green

@app.call(env)
end
end
end
end

83 changes: 83 additions & 0 deletions spec/cli/password_reset_cli_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
require 'spec_helper'

describe Tugboat::CLI do
include_context "spec"

describe "passwordreset" do
it "resets the root password given a fuzzy name" do
stub_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => fixture("show_droplets"))
stub_request(:post, "https://api.digitalocean.com/droplets/100823/password_reset?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => '{"status":"OK","event_id":456}')

@cli.password_reset("foo")

expect($stdout.string).to eq <<-eos
Droplet fuzzy name provided. Finding droplet ID...done\e[0m, 100823 (foo)
Queuing password reset for 100823 (foo)...done
Your new root password will be emailed to you
eos

expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).
to have_been_made
expect(a_request(:post, "https://api.digitalocean.com/droplets/100823/password_reset?api_key=#{api_key}&client_id=#{client_key}")).
to have_been_made
end

it "resets the root password given an id" do
stub_request(:get, "https://api.digitalocean.com/droplets/100823?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => fixture("show_droplet"))
stub_request(:post, "https://api.digitalocean.com/droplets/100823/password_reset?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => '{"status":"OK","event_id":456}')

@cli.options = @cli.options.merge(:id => 100823)
@cli.password_reset

expect($stdout.string).to eq <<-eos
Droplet id provided. Finding Droplet...done\e[0m, 100823 (foo)
Queuing password reset for 100823 (foo)...done
Your new root password will be emailed to you
eos

expect(a_request(:get, "https://api.digitalocean.com/droplets/100823?api_key=#{api_key}&client_id=#{client_key}")).
to have_been_made
expect(a_request(:post, "https://api.digitalocean.com/droplets/100823/password_reset?api_key=#{api_key}&client_id=#{client_key}")).
to have_been_made
end

it "resets the root password given a name" do
stub_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => fixture("show_droplets"))
stub_request(:post, "https://api.digitalocean.com/droplets/100823/password_reset?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => '{"status":"OK","event_id":456}')

@cli.options = @cli.options.merge(:name => "foo")
@cli.password_reset

expect($stdout.string).to eq <<-eos
Droplet name provided. Finding droplet ID...done\e[0m, 100823 (foo)
Queuing password reset for 100823 (foo)...done
Your new root password will be emailed to you
eos

expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).
to have_been_made
expect(a_request(:post, "https://api.digitalocean.com/droplets/100823/password_reset?api_key=#{api_key}&client_id=#{client_key}")).
to have_been_made
end

it "raises SystemExit when a request fails" do
stub_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => fixture("show_droplets"))
stub_request(:post, "https://api.digitalocean.com/droplets/100823/password_reset?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 500, :body => '{"status":"ERROR","message":"Some error"}')

expect { @cli.password_reset("foo") }.to raise_error(SystemExit)

expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).
to have_been_made
expect(a_request(:post, "https://api.digitalocean.com/droplets/100823/password_reset?api_key=#{api_key}&client_id=#{client_key}")).
to have_been_made
end
end
end
66 changes: 66 additions & 0 deletions spec/cli/wait_cli_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
require 'spec_helper'

describe Tugboat::CLI do
include_context "spec"

describe "wait" do
it "waits for a droplet with a fuzzy name" do
stub_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => fixture("show_droplets"))

stub_request(:get, "https://api.digitalocean.com/droplets/100823?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => fixture("show_droplet"))

@cli.options = @cli.options.merge(:state => "active")
@cli.wait("foo")

expect($stdout.string).to eq <<-eos
Droplet fuzzy name provided. Finding droplet ID...done\e[0m, 100823 (foo)
Waiting for droplet to become active..done\e[0m (0s)
eos

expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
expect(a_request(:get, "https://api.digitalocean.com/droplets/100823?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
end

it "waits for a droplet with an id" do
stub_request(:get, "https://api.digitalocean.com/droplets/#{droplet_id}?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => fixture("show_droplet"))

stub_request(:get, "https://api.digitalocean.com/droplets/100823?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => fixture("show_droplet"))

@cli.options = @cli.options.merge(:id => droplet_id, :state => "active")
@cli.wait

expect($stdout.string).to eq <<-eos
Droplet id provided. Finding Droplet...done\e[0m, 100823 (foo)
Waiting for droplet to become active..done\e[0m (0s)
eos

expect(a_request(:get, "https://api.digitalocean.com/droplets/100823?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
expect(a_request(:get, "https://api.digitalocean.com/droplets/#{droplet_id}?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
end

it "waits for a droplet with a name" do
stub_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => fixture("show_droplets"))

stub_request(:get, "https://api.digitalocean.com/droplets/100823?api_key=#{api_key}&client_id=#{client_key}").
to_return(:status => 200, :body => fixture("show_droplet"))

@cli.options = @cli.options.merge(:name => droplet_name, :state => "active")
@cli.wait

expect($stdout.string).to eq <<-eos
Droplet name provided. Finding droplet ID...done\e[0m, 100823 (foo)
Waiting for droplet to become active..done\e[0m (0s)
eos

expect(a_request(:get, "https://api.digitalocean.com/droplets/100823?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
expect(a_request(:get, "https://api.digitalocean.com/droplets?api_key=#{api_key}&client_id=#{client_key}")).to have_been_made
end

end

end