1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

Cleanup and refactor digitalocean integration

* Handle case where droplet is locked pending events, DO support says
they are planning to expose something in the api to show these events.
Until then this is the best we have.
* Whitespace cleanup
* Refactor test helpers
* Use the collection helper for the digitalocean servers collection
This commit is contained in:
Trae Robrock 2013-07-10 17:41:12 -07:00
parent a23d615ad5
commit dc6e78d6bd
7 changed files with 80 additions and 67 deletions

View file

@ -90,17 +90,46 @@ module Fog
params[:query].merge!(:api_key => @digitalocean_api_key) params[:query].merge!(:api_key => @digitalocean_api_key)
params[:query].merge!(:client_id => @digitalocean_client_id) params[:query].merge!(:client_id => @digitalocean_client_id)
response = @connection.request(params) response = retry_event_lock { parse @connection.request(params) }
unless response.body.empty? unless response.body.empty?
response.body = Fog::JSON.decode(response.body)
if response.body['status'] != 'OK' if response.body['status'] != 'OK'
raise Fog::Errors::Error.new response.body.to_s case response.body['error_message']
when /No Droplets Found/
raise Fog::Errors::NotFound.new
else
raise Fog::Errors::Error.new response.body.to_s
end
end end
end end
response response
end end
private
def parse(response)
return response if response.body.empty?
response.body = Fog::JSON.decode(response.body)
response
end
def retry_event_lock
count = 0
reponse = nil
while count < 5
response = yield
if response.body && response.body['error_message'] =~ /There is already a pending event for the droplet/
count += 1
sleep count ** 3
else
break
end
end
response
end
end end
end end
end end

View file

@ -7,13 +7,13 @@ module Fog
# A DigitalOcean Droplet # A DigitalOcean Droplet
# #
class Server < Fog::Compute::Server class Server < Fog::Compute::Server
identity :id identity :id
attribute :name attribute :name
attribute :state, :aliases => 'status' attribute :state, :aliases => 'status'
attribute :image_id attribute :image_id
attribute :region_id attribute :region_id
attribute :flavor_id, :aliases => 'size_id' attribute :flavor_id, :aliases => 'size_id'
# Not documented in their API, but # Not documented in their API, but
# available nevertheless # available nevertheless
attribute :ip_address attribute :ip_address
@ -52,7 +52,7 @@ module Fog
# Works as a power switch. # Works as a power switch.
# The server consumes resources while powered off # The server consumes resources while powered off
# so you are still charged. # so you are still charged.
# #
# @see https://www.digitalocean.com/community/questions/am-i-charged-while-my-droplet-is-in-a-powered-off-state # @see https://www.digitalocean.com/community/questions/am-i-charged-while-my-droplet-is-in-a-powered-off-state
def stop def stop
requires :id requires :id
@ -64,7 +64,7 @@ module Fog
# The server consumes resources while powered on # The server consumes resources while powered on
# so you will be charged. # so you will be charged.
# #
# Each time a server is spun up, even if for a few seconds, # Each time a server is spun up, even if for a few seconds,
# it is charged for an hour. # it is charged for an hour.
# #
def start def start
@ -85,7 +85,7 @@ module Fog
# :image_id => image_id_here, # :image_id => image_id_here,
# :flavor_id => flavor_id_here, # :flavor_id => flavor_id_here,
# :region_id => region_id_here # :region_id => region_id_here
# #
# @return [Boolean] # @return [Boolean]
def save def save
raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted? raise Fog::Errors::Error.new('Resaving an existing object may create a duplicate') if persisted?
@ -93,11 +93,11 @@ module Fog
options = {} options = {}
if attributes[:ssh_key_ids] if attributes[:ssh_key_ids]
options[:ssh_key_ids] = attributes[:ssh_key_ids] options[:ssh_key_ids] = attributes[:ssh_key_ids]
end end
data = service.create_server name, data = service.create_server name,
flavor_id, flavor_id,
image_id, image_id,
region_id, region_id,
options options
merge_attributes(data.body['droplet']) merge_attributes(data.body['droplet'])
@ -105,7 +105,7 @@ module Fog
end end
# Destroy the server, freeing up the resources. # Destroy the server, freeing up the resources.
# #
# DigitalOcean will stop charging you for the resources # DigitalOcean will stop charging you for the resources
# the server was using. # the server was using.
# #
@ -115,9 +115,9 @@ module Fog
# IMPORTANT: As of 2013/01/31, you should wait some time to # IMPORTANT: As of 2013/01/31, you should wait some time to
# destroy the server after creating it. If you try to destroy # destroy the server after creating it. If you try to destroy
# the server too fast, the destroy event may be lost and the # the server too fast, the destroy event may be lost and the
# server will remain running and consuming resources, so # server will remain running and consuming resources, so
# DigitalOcean will keep charging you. # DigitalOcean will keep charging you.
# Double checked this with DigitalOcean staff and confirmed # Double checked this with DigitalOcean staff and confirmed
# that it's the way it works right now. # that it's the way it works right now.
# #
# Double check the server has been destroyed! # Double check the server has been destroyed!

View file

@ -4,36 +4,43 @@ def service
Fog::Compute[:digitalocean] Fog::Compute[:digitalocean]
end end
def fog_test_server_attributes
image = service.images.find { |i| i.name == 'Ubuntu 12.04 x64' }
region = service.regions.find { |r| r.name == 'New York 1' }
flavor = service.flavors.find { |r| r.name == '512MB' }
{
:image_id => image.id,
:region_id => region.id,
:flavor_id => flavor.id
}
end
def fog_server_name
"fog-server-test"
end
# Create a long lived server for the tests # Create a long lived server for the tests
def fog_test_server def fog_test_server
server = service.servers.find { |s| s.name == 'fog-test-server' } server = service.servers.find { |s| s.name == fog_server_name }
unless server unless server
image = service.images.find { |i| i.name == 'Ubuntu 12.04 x64 Server' } server = service.servers.create({
region = service.regions.find { |r| r.name == 'New York 1' } :name => fog_server_name
flavor = service.flavors.find { |r| r.name == '512MB' } }.merge(fog_test_server_attributes))
server = service.servers.create :name => 'fog-test-server', server.wait_for { ready? }
:image_id => image.id,
:region_id => region.id,
:flavor_id => flavor.id
# Wait for the server to come up
begin
server.wait_for(120) { server.reload rescue nil; server.ready? }
rescue Fog::Errors::TimeoutError
# Server bootstrap took more than 120 secs!
end
end end
server server
end end
# Destroy the long lived server # Destroy the long lived server
def fog_test_server_destroy def fog_test_server_destroy
server = service.servers.find { |s| s.name == 'fog-test-server' } server = service.servers.find { |s| s.name == fog_server_name }
server.destroy if server server.destroy if server
end end
at_exit do at_exit do
unless Fog.mocking? || Fog.credentials[:digitalocean_api_key].nil? unless Fog.mocking? || Fog.credentials[:digitalocean_api_key].nil?
server = service.servers.find { |s| s.name == 'fog-test-server' } server = service.servers.find { |s| s.name == fog_server_name }
if server if server
server.wait_for(120) do server.wait_for(120) do
reload rescue nil; ready? reload rescue nil; ready?

View file

@ -1,35 +1,12 @@
Shindo.tests('Fog::Compute[:digitalocean] | servers collection', ['digitalocean']) do Shindo.tests('Fog::Compute[:digitalocean] | servers collection', ['digitalocean']) do
service = Fog::Compute[:digitalocean]
service = Fog::Compute[:digitalocean] options = {
:name => "#{fog_server_name}-#{Time.now.to_i.to_s}"
tests('The servers collection') do }.merge fog_test_server_attributes
servers = service.servers.all
server = fog_test_server
test('should NOT be empty') do
servers.reload
!servers.empty?
end
test('should be a kind of Fog::Compute::DigitalOcean::Servers') do
servers.kind_of? Fog::Compute::DigitalOcean::Servers
end
tests('should have Fog::Compute::DigitalOcean::Servers inside') do
servers.each do |s|
test { s.kind_of? Fog::Compute::DigitalOcean::Server }
end
end
tests('should be able to reload itself').succeeds { servers.reload }
tests('should be able to get a model') do
test('by instance id') do
servers.get(server.id).kind_of? Fog::Compute::DigitalOcean::Server
end
end
collection_tests(service.servers, options, true) do
@instance.wait_for { ready? }
end end
end end

View file

@ -15,7 +15,7 @@ Shindo.tests('Fog::Compute[:digitalocean] | create_server request', ['digitaloce
tests('#create_server').formats({'status' => 'OK', 'droplet' => @server_format}) do tests('#create_server').formats({'status' => 'OK', 'droplet' => @server_format}) do
image = service.images.find { |img| img.name == 'Ubuntu 12.04 x64 Server' } image = service.images.find { |img| img.name == 'Ubuntu 12.04 x64 Server' }
flavor = service.flavors.find { |f| f.name == '512MB' } flavor = service.flavors.find { |f| f.name == '512MB' }
data = Fog::Compute[:digitalocean].create_server 'fog-test-server', data = Fog::Compute[:digitalocean].create_server fog_server_name,
flavor.id, flavor.id,
image.id, image.id,
service.regions.first.id service.regions.first.id

View file

@ -5,7 +5,7 @@ Shindo.tests('Fog::Compute[:digitalocean] | get_server_details request', ['digit
test('#get_server_details') do test('#get_server_details') do
server = fog_test_server server = fog_test_server
body = Fog::Compute[:digitalocean].get_server_details(server.id).body body = Fog::Compute[:digitalocean].get_server_details(server.id).body
body['droplet']['name'] == 'fog-test-server' body['droplet']['name'] == fog_server_name
end end
end end

View file

@ -21,8 +21,8 @@ def collection_tests(collection, params = {}, mocks_implemented = true)
pending if Fog.mocking? && !mocks_implemented pending if Fog.mocking? && !mocks_implemented
collection.all collection.all
end end
if !Fog.mocking? || mocks_implemented if !Fog.mocking? || mocks_implemented
@identity = @instance.identity @identity = @instance.identity
@ -37,7 +37,7 @@ def collection_tests(collection, params = {}, mocks_implemented = true)
pending if Fog.mocking? && !mocks_implemented pending if Fog.mocking? && !mocks_implemented
[ [
'all?', 'any?', 'find', 'detect', 'collect', 'map', 'all?', 'any?', 'find', 'detect', 'collect', 'map',
'find_index', 'flat_map', 'collect_concat', 'group_by', 'find_index', 'flat_map', 'collect_concat', 'group_by',
'none?', 'one?' 'none?', 'one?'
].each do |enum_method| ].each do |enum_method|
@ -74,7 +74,7 @@ def collection_tests(collection, params = {}, mocks_implemented = true)
@instance.destroy @instance.destroy
end end
end end
tests('failure') do tests('failure') do
if !Fog.mocking? || mocks_implemented if !Fog.mocking? || mocks_implemented