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

1312 lines
36 KiB
Ruby
Raw Normal View History

require 'fog/core'
require 'ipaddr'
class IPAddr
def mask
_to_string(@mask_addr)
end
end
module Fog
module Ecloud
class Collection < Fog::Collection
def load(objects)
objects = [ objects ] if objects.is_a?(Hash)
super
end
def check_href!(opts = {})
unless href
if opts.is_a?(String)
t = Hash.new
t[:parent] = opts
opts = t
end
msg = ":href missing, call with a :href pointing to #{if opts[:message]
opts[:message]
elsif opts[:parent]
"the #{opts[:parent]} whos #{self.class.to_s.split('::').last.downcase} you want to enumerate"
else
"the resource"
end}"
raise Fog::Errors::Error.new(msg)
end
end
end
end
end
module Fog
module Ecloud
module MockDataClasses
class Base < Hash
def self.base_url=(url)
@base_url = url
end
self.base_url = "http://vcloud.example.com"
def self.base_url
@base_url
end
def first
raise "Don't do this"
end
def last
raise "Don't do this"
end
def initialize(data = {}, parent = nil)
@parent = parent
replace(data)
end
def _parent
@parent
end
def base_url
Base.base_url
end
def href
[base_url, self.class.name.split("::").last, object_id].join("/")
end
def inspect
"<#{self.class.name} #{object_id} data=#{super}>"
end
end
class MockData < Base
def versions
@versions ||= []
end
def organizations
@organizations ||= []
end
def organization_from_href(href)
find_href_in(href, organizations)
end
def all_vdcs
organizations.map(&:vdcs).flatten
end
def vdc_from_href(href)
find_href_in(href, all_vdcs)
end
def all_catalogs
all_vdcs.map(&:catalog).flatten
end
def catalog_from_href(href)
find_href_in(href, all_catalogs)
end
def all_catalog_items
all_catalogs.map(&:items).flatten
end
def catalog_item_from_href(href)
find_href_in(href, all_catalog_items)
end
def all_virtual_machines
all_vdcs.map(&:virtual_machines).flatten
end
def virtual_machine_from_href(href)
find_href_prefixed_in(href, all_virtual_machines)
end
def all_networks
all_vdcs.map(&:networks).flatten
end
def network_from_href(href)
find_href_in(href, all_networks)
end
def all_network_extensions
all_networks.map(&:extensions).flatten
end
def network_extension_from_href(href)
find_href_in(href, all_network_extensions)
end
def all_vdc_internet_service_collections
all_vdcs.map(&:internet_service_collection).flatten
end
def vdc_internet_service_collection_from_href(href)
find_href_in(href, all_vdc_internet_service_collections)
end
def all_backup_internet_services
all_vdc_internet_service_collections.map(&:backup_internet_services).flatten
end
def backup_internet_service_from_href(href)
find_href_in(href, all_backup_internet_services)
end
def all_public_ip_collections
all_vdcs.map {|v| v.public_ip_collection }.flatten
end
def public_ip_collection_from_href(href)
find_href_in(href, all_public_ip_collections)
end
def all_public_ips
all_public_ip_collections.map(&:items).flatten
end
def public_ip_from_href(href)
find_href_in(href, all_public_ips)
end
def all_public_ip_internet_service_collections
all_public_ips.map(&:internet_service_collection).flatten
end
def public_ip_internet_service_collection_from_href(href)
find_href_in(href, all_public_ip_internet_service_collections)
end
def all_public_ip_internet_services
all_public_ip_internet_service_collections.map(&:items).flatten
end
def public_ip_internet_service_from_href(href)
find_href_in(href, all_public_ip_internet_services)
end
def all_public_ip_internet_service_node_collections
all_public_ip_internet_services.map(&:node_collection).flatten
end
def public_ip_internet_service_node_collection_from_href(href)
find_href_in(href, all_public_ip_internet_service_node_collections)
end
def all_public_ip_internet_service_nodes
all_public_ip_internet_service_node_collections.map(&:items).flatten
end
def public_ip_internet_service_node_from_href(href)
find_href_in(href, all_public_ip_internet_service_nodes)
end
def all_network_ip_collections
all_networks.map(&:ip_collection)
end
def network_ip_collection_from_href(href)
find_href_in(href, all_network_ip_collections)
end
def all_network_ips
all_network_ip_collections.map {|c| c.items.values }.flatten
end
def network_ip_from_href(href)
find_href_in(href, all_network_ips)
end
private
def find_href_in(href, objects)
objects.detect {|o| o.href == href }
end
def find_href_prefixed_in(href, objects)
objects.detect {|o| href =~ %r{^#{o.href}($|/)} }
end
end
class MockVersion < Base
def version
self[:version]
end
def supported
!!self[:supported]
end
def login_url
href
end
end
class MockOrganization < Base
def name
self[:name]
end
def vdcs
@vdcs ||= []
end
end
class MockVdc < Base
def name
self[:name]
end
def storage_allocated
self[:storage_allocated] || 200
end
def storage_used
self[:storage_used] || 105
end
def cpu_allocated
self[:cpu_allocated] || 10000
end
def memory_allocated
self[:memory_allocated] || 20480
end
def catalog
@catalog ||= MockCatalog.new({}, self)
end
def networks
@networks ||= []
end
def virtual_machines
@virtual_machines ||= []
end
def task_list
@task_list ||= MockTaskList.new({}, self)
end
# for TM eCloud, should probably be subclassed
def public_ip_collection
@public_ip_collection ||= MockPublicIps.new({}, self)
end
def internet_service_collection
@internet_service_collection ||= MockVdcInternetServices.new({}, self)
end
def firewall_acls
@firewall_acls ||= MockFirewallAcls.new({}, self)
end
end
class MockTaskList < Base
def name
self[:name] || "Tasks List"
end
end
class MockCatalog < Base
def name
self[:name] || "Catalog"
end
def items
@items ||= []
end
end
class MockCatalogItem < Base
def name
self[:name]
end
def disks
@disks ||= MockVirtualMachineDisks.new(self)
end
def customization
@customization ||= MockCatalogItemCustomization.new({}, self)
end
def vapp_template
@vapp_template ||= MockCatalogItemVappTemplate.new({ :name => name }, self)
end
end
class MockCatalogItemCustomization < Base
def name
self[:name] || "Customization Options"
end
end
class MockCatalogItemVappTemplate < Base
def name
self[:name]
end
end
class MockNetwork < Base
def name
self[:name] || subnet
end
def subnet
self[:subnet]
end
def gateway
self[:gateway] || subnet_ips[1]
end
def netmask
self[:netmask] || subnet_ipaddr.mask
end
def dns
"8.8.8.8"
end
def features
[
{ :type => :FenceMode, :value => "isolated" }
]
end
def ip_collection
@ip_collection ||= MockNetworkIps.new({}, self)
end
def extensions
@extensions ||= MockNetworkExtensions.new({}, self)
end
def random_ip
usable_subnet_ips[rand(usable_subnet_ips.length)]
end
# for TM eCloud. should probably be a subclass
def rnat
self[:rnat]
end
def usable_subnet_ips
subnet_ips[3..-2]
end
def address
subnet_ips.first
end
def broadcast
subnet_ips.last
end
private
def subnet_ipaddr
@ipaddr ||= IPAddr.new(subnet)
end
def subnet_ips
subnet_ipaddr.to_range.to_a.map(&:to_s)
end
end
class MockNetworkIps < Base
def items
@items ||= _parent.usable_subnet_ips.inject({}) do |out, subnet_ip|
out.update(subnet_ip => MockNetworkIp.new({ :ip => subnet_ip }, self))
end
end
def ordered_ips
items.values.sort_by {|i| i.ip.split(".").map(&:to_i) }
end
def name
"IP Addresses"
end
end
class MockNetworkIp < Base
def name
self[:name] || ip
end
def ip
self[:ip]
end
def used_by
self[:used_by] || _parent._parent._parent.virtual_machines.detect {|v| v.ip == ip }
end
def status
if used_by
"Assigned"
else
"Available"
end
end
def rnat
self[:rnat] || _parent._parent.rnat
end
def rnat_set?
!!self[:rnat]
end
end
class MockNetworkExtensions < Base
def name
_parent.name
end
def gateway
_parent.gateway
end
def broadcast
_parent.broadcast
end
def address
_parent.address
end
def rnat
_parent.rnat
end
def type
self[:type] || "DMZ"
end
def vlan
object_id.to_s
end
def friendly_name
"#{name} (#{type}_#{object_id})"
end
end
class MockVirtualMachine < Base
def name
self[:name]
end
def ip
self[:ip]
end
def cpus
self[:cpus] || 1
end
def memory
self[:memory] || 1024
end
def disks
@disks ||= MockVirtualMachineDisks.new(self)
end
def status
self[:status] || 2
end
def power_off!
self[:status] = 2
end
def power_on!
self[:status] = 4
end
def size
disks.inject(0) {|s, d| s + d.vcloud_size }
end
def network_ip
if network = _parent.networks.detect {|n| n.ip_collection.items[ip] }
network.ip_collection.items[ip]
end
end
# from fog ecloud server's _compose_vapp_data
def to_configure_vapp_hash
{
:name => name,
:cpus => cpus,
:memory => memory,
:disks => disks.map {|d| { :number => d.address.to_s, :size => d.vcloud_size, :resource => d.vcloud_size.to_s } }
}
end
def href(purpose = :base)
case purpose
when :base
super()
when :power_on
super() + "/power/action/powerOn"
when :power_off
super() + "/power/action/powerOff"
end
end
end
class MockVirtualMachineDisks < Array
def initialize(parent = nil)
@parent = parent
end
def _parent
@parent
end
def <<(disk)
next_address = 0
disk_with_max_address = max {|a, b| a[:address] <=> b[:address] }
disk_with_max_address && next_address = disk_with_max_address.address + 1
disk[:address] ||= next_address
super(disk)
if (addresses = map {|d| d.address }).uniq.size != size
raise "Duplicate disk address in: #{addresses.inspect} (#{size})"
end
sort! {|a, b| a.address <=> b.address }
self
end
def at_address(address)
detect {|d| d.address == address }
end
end
class MockVirtualMachineDisk < Base
def size
self[:size].to_i
end
def vcloud_size
# kilobytes
size * 1024
end
def address
self[:address].to_i
end
end
# for Terremark eCloud
class MockVdcInternetServices < Base
def href
_parent.href + "/internetServices"
end
def name
"Internet Services"
end
def items
public_ip_internet_services + backup_internet_services
end
def public_ip_internet_services
_parent.public_ip_collection.items.inject([]) do |services, public_ip|
services + public_ip.internet_service_collection.items
end
end
def backup_internet_services
@backup_internet_services ||= []
end
end
class MockBackupInternetService < Base
def name
self[:name] || "Backup Internet Service #{object_id}"
end
def protocol
self[:protocol]
end
def port
0
end
def enabled
self[:enabled].to_s.downcase != "false"
end
def timeout
self[:timeout] || 2
end
def description
self[:description] || "Description for Backup Service #{name}"
end
def redirect_url
nil
end
def node_collection
@node_collection ||= MockPublicIpInternetServiceNodes.new({}, self)
end
end
class MockFirewallAcls < Base
def name
"Firewall Access List"
end
end
class MockPublicIps < Base
def name
self[:name] || "Public IPs"
end
def items
@items ||= []
end
end
class MockPublicIp < Base
def name
self[:name]
end
def internet_service_collection
@internet_service_collection ||= MockPublicIpInternetServices.new({}, self)
end
end
class MockPublicIpInternetServices < Base
def href
_parent.href + "/internetServices"
end
def items
@items ||= []
end
end
class MockPublicIpInternetService < Base
def name
self[:name] || "Public IP Service #{object_id}"
end
def description
self[:description] || "Description for Public IP Service #{name}"
end
def protocol
self[:protocol]
end
def port
self[:port]
end
def enabled
!!self[:enabled]
end
def redirect_url
self[:redirect_url]
end
def timeout
self[:timeout] || 2
end
def node_collection
@node_collection ||= MockPublicIpInternetServiceNodes.new({}, self)
end
def monitor
nil
end
def backup_service
self[:backup_service]
end
end
class MockPublicIpInternetServiceNodes < Base
def href
_parent.href + "/nodeServices"
end
def items
@items ||= [].tap do |node_array|
node_array.instance_variable_set("@default_port", _parent.port)
def node_array.<<(node)
node[:port] ||= @default_port
super
end
end
end
end
class MockPublicIpInternetServiceNode < Base
def ip_address
self[:ip_address]
end
def name
self[:name] || "Public IP Service Node #{object_id}"
end
def description
self[:description] || "Description for Public IP Service Node #{name}"
end
def port
self[:port]
end
def enabled
self[:enabled].to_s.downcase != "false"
end
def enabled=(new_value)
self[:enabled] = new_value
end
end
end
end
end
module Fog
module Ecloud
class Model < Fog::Model
attr_accessor :loaded
alias_method :loaded?, :loaded
def reload
instance = super
@loaded = true
instance
end
def load_unless_loaded!
unless @loaded
reload
end
end
end
end
end
module Fog
module Ecloud
class Compute < Fog::Service
class UnsupportedVersion < Exception ; end
requires :ecloud_username, :ecloud_password, :ecloud_versions_uri
recognizes :ecloud_version
recognizes :provider # remove post deprecation
model_path 'fog/compute/models/ecloud'
model :catalog_item
model :catalog
model :firewall_acl
collection :firewall_acls
model :internet_service
collection :internet_services
model :backup_internet_service
collection :backup_internet_services
model :ip
collection :ips
model :network
collection :networks
model :node
collection :nodes
model :public_ip
collection :public_ips
model :server
collection :servers
model :task
collection :tasks
model :vdc
collection :vdcs
request_path 'fog/compute/requests/ecloud'
request :add_internet_service
request :add_backup_internet_service
request :add_node
request :clone_vapp
request :configure_internet_service
request :configure_network
request :configure_network_ip
request :configure_node
request :configure_vapp
request :delete_internet_service
request :delete_node
request :delete_vapp
request :get_catalog
request :get_catalog_item
request :get_customization_options
request :get_firewall_acls
request :get_firewall_acl
request :get_internet_services
request :get_network
request :get_network_ip
request :get_network_ips
request :get_network_extensions
request :get_organization
request :get_node
request :get_nodes
request :get_public_ip
request :get_public_ips
request :get_task
request :get_task_list
request :get_vapp
request :get_vapp_template
request :get_vdc
request :get_versions
request :instantiate_vapp_template
request :login
request :power_off
request :power_on
request :power_reset
request :power_shutdown
module Shared
attr_reader :versions_uri
def default_organization_uri
@default_organization_uri ||= begin
unless @login_results
do_login
2011-02-16 20:17:21 -05:00
end
case @login_results.body[:Org]
when Array
@login_results.body[:Org].first[:href]
when Hash
@login_results.body[:Org][:href]
2011-02-16 20:17:21 -05:00
else
nil
2011-02-16 20:17:21 -05:00
end
end
end
2011-02-16 20:17:21 -05:00
# login handles the auth, but we just need the Set-Cookie
# header from that call.
def do_login
@login_results = login
@cookie = @login_results.headers['Set-Cookie']
end
def ecloud_xmlns
{
"xmlns" => "urn:tmrk:eCloudExtensions-2.6",
"xmlns:i" => "http://www.w3.org/2001/XMLSchema-instance"
}
end
def ensure_unparsed(uri)
if uri.is_a?(String)
uri
else
uri.to_s
end
end
def supported_versions
@supported_versions ||= get_versions(@versions_uri).body[:VersionInfo]
2011-02-16 20:17:21 -05:00
end
def xmlns
{ "xmlns" => "http://www.vmware.com/vcloud/v0.8",
"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
"xmlns:xsd" => "http://www.w3.org/2001/XMLSchema" }
end
2011-02-16 20:17:21 -05:00
end
class Mock
include Shared
include MockDataClasses
def self.base_url
"https://fakey.com/api/v0.8b-ext2.6"
end
def self.data( base_url = self.base_url )
@mock_data ||= MockData.new.tap do |vcloud_mock_data|
vcloud_mock_data.versions.clear
vcloud_mock_data.versions << MockVersion.new(:version => "v0.8b-ext2.6", :supported => true)
2011-02-16 20:17:21 -05:00
vcloud_mock_data.organizations << MockOrganization.new(:name => "Boom Inc.").tap do |mock_organization|
mock_organization.vdcs << MockVdc.new(:name => "Boomstick").tap do |mock_vdc|
mock_vdc.catalog.items << MockCatalogItem.new(:name => "Item 0").tap do |mock_catalog_item|
mock_catalog_item.disks << MockVirtualMachineDisk.new(:size => 25 * 1024)
end
mock_vdc.catalog.items << MockCatalogItem.new(:name => "Item 1").tap do |mock_catalog_item|
mock_catalog_item.disks << MockVirtualMachineDisk.new(:size => 25 * 1024)
end
mock_vdc.catalog.items << MockCatalogItem.new(:name => "Item 2").tap do |mock_catalog_item|
mock_catalog_item.disks << MockVirtualMachineDisk.new(:size => 25 * 1024)
2011-02-16 20:17:21 -05:00
end
mock_vdc.networks << MockNetwork.new({ :subnet => "1.2.3.0/24" }, mock_vdc)
mock_vdc.networks << MockNetwork.new({ :subnet => "4.5.6.0/24" }, mock_vdc)
2011-02-16 20:17:21 -05:00
mock_vdc.virtual_machines << MockVirtualMachine.new({ :name => "Broom 1", :ip => "1.2.3.3" }, mock_vdc)
mock_vdc.virtual_machines << MockVirtualMachine.new({ :name => "Broom 2", :ip => "1.2.3.4" }, mock_vdc)
mock_vdc.virtual_machines << MockVirtualMachine.new({ :name => "Email!", :ip => "1.2.3.10" }, mock_vdc)
2011-02-16 20:17:21 -05:00
end
mock_organization.vdcs << MockVdc.new(:name => "Rock-n-Roll", :storage_allocated => 150, :storage_used => 40, :cpu_allocated => 1000, :memory_allocated => 2048).tap do |mock_vdc|
mock_vdc.networks << MockNetwork.new({ :subnet => "7.8.9.0/24" }, mock_vdc)
mock_vdc.virtual_machines << MockVirtualMachine.new({ :name => "Master Blaster", :ip => "7.8.9.10" }, mock_vdc)
end
end
vcloud_mock_data.organizations.detect {|o| o.name == "Boom Inc." }.tap do |mock_organization|
mock_organization.vdcs.detect {|v| v.name == "Boomstick" }.tap do |mock_vdc|
mock_vdc.public_ip_collection.items << MockPublicIp.new(:name => "99.1.2.3").tap do |mock_public_ip|
mock_public_ip.internet_service_collection.items << MockPublicIpInternetService.new({
:protocol => "HTTP",
:port => 80,
:name => "Web Site",
:description => "Web Servers",
:redirect_url => "http://fakey.com"
}, mock_public_ip.internet_service_collection
).tap do |mock_public_ip_service|
mock_public_ip_service.node_collection.items << MockPublicIpInternetServiceNode.new({:ip_address => "1.2.3.5", :name => "Test Node 1", :description => "web 1"}, mock_public_ip_service.node_collection)
mock_public_ip_service.node_collection.items << MockPublicIpInternetServiceNode.new({:ip_address => "1.2.3.6", :name => "Test Node 2", :description => "web 2"}, mock_public_ip_service.node_collection)
mock_public_ip_service.node_collection.items << MockPublicIpInternetServiceNode.new({:ip_address => "1.2.3.7", :name => "Test Node 3", :description => "web 3"}, mock_public_ip_service.node_collection)
end
mock_public_ip.internet_service_collection.items << MockPublicIpInternetService.new({
:protocol => "TCP",
:port => 7000,
:name => "An SSH Map",
:description => "SSH 1"
}, mock_public_ip.internet_service_collection
).tap do |mock_public_ip_service|
mock_public_ip_service.node_collection.items << MockPublicIpInternetServiceNode.new({ :ip_address => "1.2.3.5", :port => 22, :name => "SSH", :description => "web ssh" }, mock_public_ip_service.node_collection)
end
end
mock_vdc.public_ip_collection.items << MockPublicIp.new(:name => "99.1.2.4").tap do |mock_public_ip|
mock_public_ip.internet_service_collection.items << MockPublicIpInternetService.new({
:protocol => "HTTP",
:port => 80,
:name => "Web Site",
:description => "Web Servers",
:redirect_url => "http://fakey.com"
}, mock_public_ip.internet_service_collection
)
mock_public_ip.internet_service_collection.items << MockPublicIpInternetService.new({
:protocol => "TCP",
:port => 7000,
:name => "An SSH Map",
:description => "SSH 2"
}, mock_public_ip.internet_service_collection
)
end
mock_vdc.public_ip_collection.items << MockPublicIp.new(:name => "99.1.9.7")
mock_vdc.internet_service_collection.backup_internet_services << MockBackupInternetService.new({ :port => 10000, :protocol => "TCP"}, self)
end
mock_organization.vdcs.detect {|v| v.name == "Rock-n-Roll" }.tap do |mock_vdc|
mock_vdc.public_ip_collection.items << MockPublicIp.new(:name => "99.99.99.99")
end
end
vcloud_mock_data.organizations.each do |organization|
organization.vdcs.each do |vdc|
vdc.networks.each do |network|
network[:rnat] = vdc.public_ip_collection.items.first.name
end
vdc.virtual_machines.each do |virtual_machine|
virtual_machine.disks << MockVirtualMachineDisk.new(:size => 25 * 1024)
virtual_machine.disks << MockVirtualMachineDisk.new(:size => 50 * 1024)
end
2010-06-30 00:15:36 -04:00
end
end
end
end
2010-06-30 00:15:36 -04:00
def self.reset
@mock_data = nil
end
2011-05-19 18:35:33 -04:00
def self.data_reset
Formatador.display_line("[yellow][WARN] #{self} => #data_reset is deprecated, use #reset instead[/] [light_black](#{caller.first})[/]")
self.reset
end
def initialize(options = {})
require 'builder'
require 'fog/core/parser'
2011-02-16 20:17:21 -05:00
@versions_uri = URI.parse('https://vcloud.fakey.com/api/versions')
end
2011-02-16 20:17:21 -05:00
def mock_data
Fog::Ecloud::Compute::Mock.data
end
2011-02-16 20:17:21 -05:00
def mock_error(expected, status, body='', headers={})
raise Excon::Errors::Unauthorized.new("Expected(#{expected}) <=> Actual(#{status})")
end
2011-02-16 20:17:21 -05:00
def mock_it(status, mock_data, mock_headers = {})
response = Excon::Response.new
2011-02-16 20:17:21 -05:00
#Parse the response body into a hash
if mock_data.empty?
response.body = mock_data
else
document = Fog::ToHashDocument.new
parser = Nokogiri::XML::SAX::PushParser.new(document)
parser << mock_data
parser.finish
response.body = document.body
2011-02-16 20:17:21 -05:00
end
response.status = status
response.headers = mock_headers
response
end
end
2011-02-16 20:17:21 -05:00
class Real
include Shared
class << self
def basic_request(*args)
self.class_eval <<-EOS, __FILE__,__LINE__
def #{args[0]}(uri)
request({
:expects => #{args[1] || 200},
:method => '#{args[2] || 'GET'}',
:headers => #{args[3] ? args[3].inspect : '{}'},
:body => '#{args[4] ? args[4] : ''}',
:parse => true,
:uri => uri })
end
EOS
2011-02-16 20:17:21 -05:00
end
def unauthenticated_basic_request(*args)
self.class_eval <<-EOS, __FILE__,__LINE__
def #{args[0]}(uri)
unauthenticated_request({
:expects => #{args[1] || 200},
:method => '#{args[2] || 'GET'}',
:headers => #{args[3] ? args[3].inspect : '{}'},
:parse => true,
:uri => uri })
2011-02-16 20:17:21 -05:00
end
EOS
2011-02-16 20:17:21 -05:00
end
end
def initialize(options = {})
require 'builder'
require 'fog/core/parser'
@connections = {}
@versions_uri = URI.parse(options[:ecloud_versions_uri])
@version = options[:ecloud_version]
@username = options[:ecloud_username]
@password = options[:ecloud_password]
@persistent = options[:persistent]
end
2011-02-16 20:17:21 -05:00
def default_organization_uri
@default_organization_uri ||= begin
unless @login_results
2011-02-16 20:17:21 -05:00
do_login
end
case @login_results.body[:Org]
when Array
@login_results.body[:Org].first[:href]
when Hash
@login_results.body[:Org][:href]
else
nil
2011-02-16 20:17:21 -05:00
end
end
end
def reload
@connections.each_value { |k,v| v.reset if v }
end
2011-02-16 20:17:21 -05:00
# If the cookie isn't set, do a get_organizations call to set it
# and try the request.
# If we get an Unauthorized error, we assume the token expired, re-auth and try again
def request(params)
unless @cookie
do_login
end
begin
do_request(params)
rescue Excon::Errors::Unauthorized => e
do_login
do_request(params)
end
end
def supporting_versions
["v0.8b-ext2.6", "0.8b-ext2.6"]
end
private
2011-02-16 20:17:21 -05:00
def ensure_parsed(uri)
if uri.is_a?(String)
URI.parse(uri)
else
uri
2011-02-16 20:17:21 -05:00
end
end
2011-02-16 20:17:21 -05:00
def supported_version_numbers
case supported_versions
when Array
supported_versions.map { |version| version[:Version] }
when Hash
[ supported_versions[:Version] ]
2011-02-16 20:17:21 -05:00
end
end
2011-02-16 20:17:21 -05:00
def get_login_uri
check_versions
URI.parse case supported_versions
when Array
supported_versions.detect {|version| version[:Version] == @version }[:LoginUrl]
when Hash
supported_versions[:LoginUrl]
2011-02-16 20:17:21 -05:00
end
end
2011-02-16 20:17:21 -05:00
# If we don't support any versions the service does, then raise an error.
# If the @version that super selected isn't in our supported list, then select one that is.
def check_versions
if @version
unless supported_version_numbers.include?(@version.to_s)
raise UnsupportedVersion.new("#{@version} is not supported by the server.")
end
unless supporting_versions.include?(@version.to_s)
raise UnsupportedVersion.new("#{@version} is not supported by #{self.class}")
end
else
unless @version = (supported_version_numbers & supporting_versions).sort.first
raise UnsupportedVersion.new("\nService @ #{@versions_uri} supports: #{supported_version_numbers.join(', ')}\n" +
"#{self.class} supports: #{supporting_versions.join(', ')}")
2011-02-16 20:17:21 -05:00
end
end
end
2011-02-16 20:17:21 -05:00
# Don't need to set the cookie for these or retry them if the cookie timed out
def unauthenticated_request(params)
do_request(params)
end
2011-02-16 20:17:21 -05:00
# Use this to set the Authorization header for login
def authorization_header
"Basic #{Base64.encode64("#{@username}:#{@password}").chomp!}"
end
2011-02-16 20:17:21 -05:00
def login_uri
@login_uri ||= get_login_uri
end
2011-02-16 20:17:21 -05:00
# login handles the auth, but we just need the Set-Cookie
# header from that call.
def do_login
@login_results = login
@cookie = @login_results.headers['Set-Cookie']
end
# Actually do the request
def do_request(params)
# Convert the uri to a URI if it's a string.
if params[:uri].is_a?(String)
params[:uri] = URI.parse(params[:uri])
2011-02-16 20:17:21 -05:00
end
host_url = "#{params[:uri].scheme}://#{params[:uri].host}#{params[:uri].port ? ":#{params[:uri].port}" : ''}"
2011-02-16 20:17:21 -05:00
# Hash connections on the host_url ... There's nothing to say we won't get URI's that go to
# different hosts.
@connections[host_url] ||= Fog::Connection.new(host_url, @persistent)
2011-02-16 20:17:21 -05:00
# Set headers to an empty hash if none are set.
headers = params[:headers] || {}
2011-02-16 20:17:21 -05:00
# Add our auth cookie to the headers
if @cookie
headers.merge!('Cookie' => @cookie)
end
2011-02-16 20:17:21 -05:00
# Make the request
response = @connections[host_url].request({
:body => params[:body] || '',
:expects => params[:expects] || 200,
:headers => headers,
:method => params[:method] || 'GET',
:path => params[:uri].path
})
# Parse the response body into a hash
#puts response.body
unless response.body.empty?
if params[:parse]
document = Fog::ToHashDocument.new
parser = Nokogiri::XML::SAX::PushParser.new(document)
parser << response.body
parser.finish
2011-02-16 20:17:21 -05:00
response.body = document.body
2011-02-16 20:17:21 -05:00
end
end
response
end
end
end
end
end