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

Refactor Terremark into Vcloud

Purpose is to better abstract individual services
This commit is contained in:
Edward Muller 2010-05-02 21:46:43 -07:00 committed by geemus
parent 013b2c3ead
commit d48db03314
35 changed files with 1725 additions and 9 deletions

View file

@ -10,3 +10,4 @@ gem 'nokogiri', ">= 0"
gem 'ruby-hmac', ">= 0"
gem 'rspec', '>= 0'
gem 'shindo', '>= 0'
gem 'builder', '>= 0'

View file

@ -8,7 +8,7 @@ dependencies:
group:
- :default
version: ">= 0"
ruby-hmac:
rspec:
group:
- :default
version: ">= 0"
@ -16,11 +16,7 @@ dependencies:
group:
- :default
version: ">= 0"
rspec:
group:
- :default
version: ">= 0"
net-ssh:
ruby-hmac:
group:
- :default
version: ">= 0"
@ -28,10 +24,18 @@ dependencies:
group:
- :default
version: ">= 0"
net-ssh:
group:
- :default
version: ">= 0"
excon:
group:
- :default
version: ">= 0.0.24"
builder:
group:
- :default
version: ">= 0"
shindo:
group:
- :default
@ -43,6 +47,8 @@ dependencies:
specs:
- rake:
version: 0.8.7
- builder:
version: 2.1.2
- excon:
version: 0.0.24
- formatador:
@ -63,7 +69,7 @@ specs:
version: 0.4.0
- shindo:
version: 0.0.18
hash: f7c60e9940d07b3b405ee2ac71eda00f018df121
hash: 9a6ccfd107913e3f8ca98af1fe437f5d2b7b112a
sources:
- Rubygems:
uri: http://gemcutter.org

View file

@ -15,6 +15,7 @@ require 'fog/local/bin'
require 'fog/rackspace/bin'
require 'fog/slicehost/bin'
require 'fog/terremark/bin'
require 'fog/vcloud/bin'
if ARGV.length > 1
print(instance_eval(ARGV[1..-1].join(' ')).to_json)
@ -37,6 +38,11 @@ else
end
print "Welcome to fog interactive!\n"
print "Your '#{Fog.credential.to_s}' configuration provides access to #{available_services}.\n"
Fog.services.each do |service|
if service.respond_to?(:startup_notice)
service.send(:startup_notice)
end
end
catch(:IRB_EXIT) { @irb.eval_input }

View file

@ -30,6 +30,7 @@ require 'fog/local'
require 'fog/rackspace'
require 'fog/slicehost'
require 'fog/terremark'
require 'fog/vcloud'
module Fog

View file

@ -5,7 +5,7 @@ module Fog
def services
services = []
[::AWS, ::Local, ::Rackspace, ::Slicehost, ::Terremark].each do |service|
[::AWS, ::Local, ::Rackspace, ::Slicehost, ::Terremark, ::Vcloud].each do |service|
if service.initialized?
services << service
end

288
lib/fog/vcloud.rb Normal file
View file

@ -0,0 +1,288 @@
module URI
class Generic
def host_url
@host_url ||= "#{self.scheme}://#{self.host}#{self.port ? ":#{self.port}" : ''}"
end
end
end
module Fog
module Vcloud
class UnsupportedVersion < Exception ; end
module Options
REQUIRED = [:versions_uri, :username, :password]
OPTIONAL = [:module, :version]
ALL = REQUIRED + OPTIONAL
end
class Real
attr_accessor :login_uri
attr_reader :supported_versions
def initialize(options = {})
@connections = {}
@versions_uri = URI.parse(options[:versions_uri])
@module = options[:module]
@version = options[:version]
@username = options[:username]
@password = options[:password]
@login_uri = get_login_uri
end
def default_organization_uri
@default_organization_uri ||= begin
unless @login_results
do_login
end
org_list = @login_results.body.organizations
if organization = @login_results.body.organizations.first
URI.parse(organization[:href])
else
nil
end
end
end
private
def supported_version_ids
@supported_versions.map { |version| version.version }
end
def get_login_uri
check_versions
URI.parse(@supported_versions.detect {|version| version.version == @version }.login_url)
end
# Load up @all_versions and @supported_versions from the provided :versions_uri
# If there are no supported versions raise an error
# And choose a default version is none is specified
def check_versions
@all_versions = get_versions.body
@supported_versions = @all_versions.select { |version| version.supported == true }
if @supported_versions.empty?
raise UnsupportedVersion.new("No supported versions found @ #{@version_uri}")
end
unless @version
@version = supported_version_ids.sort.first
end
end
# 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
# Use this to set the Authorization header for login
def authorization_header
"Basic #{Base64.encode64("#{@username}:#{@password}").chomp!}"
end
# 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
# If the cookie isn't set, do a get_organizations call to set it
# and try the request.
# If we get an Unauthoried 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
# Actually do the request
def do_request(params)
if params[:uri].is_a?(String)
params[:uri] = URI.parse(params[:uri])
end
@connections[params[:uri].host_url] ||= Fog::Connection.new(params[:uri].host_url)
headers = params[:headers] || {}
if @cookie
headers.merge!('Cookie' => @cookie)
end
@connections[params[:uri].host_url].request({
:body => params[:body],
:expects => params[:expects],
:headers => headers,
:method => params[:method],
:parser => params[:parser],
:path => params[:uri].path
})
end
end
class Mock < Real
DATA =
{
:versions => [
{ :version => "v0.8", :login_url => "https://fakey.com/api/v0.8/login", :supported => true }
],
:organizations =>
[
{
:info => {
:href => "https://fakey.com/api/v0.8/org/1",
:name => "Boom Inc.",
},
:vdcs => [
{ :href => "https://fakey.com/api/v0.8/vdc/21",
:name => "Boomstick",
:storage => { :used => 105, :allocated => 200 },
:cpu => { :allocated => 10000 },
:memory => { :allocated => 20480 },
:networks => [
{ :href => "https://fakey.com/api/v0.8/network/31",
:name => "1.2.3.0/24",
:subnet => "1.2.3.0/24",
:gateway => "1.2.3.1",
:netmask => "255.255.255.0",
:fencemode => "isolated"
},
{ :href => "https://fakey.com/api/v0.8/network/32",
:name => "4.5.6.0/24",
:subnet => "4.5.6.0/24",
:gateway => "4.5.6.1",
:netmask => "255.255.255.0",
:fencemode => "isolated"
},
],
:vms => [
{ :href => "https://fakey.com/api/v0.8/vap/41",
:name => "Broom 1"
},
{ :href => "https://fakey.com/api/v0.8/vap/42",
:name => "Broom 2"
},
{ :href => "https://fakey.com/api/v0.8/vap/43",
:name => "Email!"
}
],
:public_ips => [
{ :id => 51,
:name => "99.1.2.3"
},
{ :id => 52,
:name => "99.1.2.4"
},
{ :id => 53,
:name => "99.1.9.7"
}
]
},
{ :href => "https://fakey.com/api/v0.8/vdc/22",
:storage => { :used => 40, :allocated => 150 },
:cpu => { :allocated => 1000 },
:memory => { :allocated => 2048 },
:name => "Rock-n-Roll",
:networks => [
{ :href => "https://fakey.com/api/v0.8/network/33",
:name => "7.8.9.0/24",
:subnet => "7.8.9.0/24",
:gateway => "7.8.9.1",
:netmask => "255.255.255.0",
:fencemode => "isolated"
}
],
:vms => [
{ :href => "https://fakey.com/api/v0.8/vap/44",
:name => "Master Blaster"
}
],
:public_ips => [
{ :id => 54,
:name => "99.99.99.99"
}
]
}
]
}
]
}
def initialize(credentials = {})
require 'builder'
@versions_uri = URI.parse('https://vcloud.fakey.com/api/versions')
@login_uri = get_login_uri
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
def mock_it(parser, status, mock_data, mock_headers = {})
body = Nokogiri::XML::SAX::PushParser.new(parser)
body << mock_data
body.finish
response = Excon::Response.new
response.status = status
response.body = parser.response
response.headers = mock_headers
response
end
def mock_error(expected, status, body='', headers={})
raise Excon::Errors::Unauthorized.new("Expected(#{expected}) <=> Actual(#{status})")
end
def mock_data
DATA
end
end
class <<self
def new(credentials = {})
unless @required
require 'fog/vcloud/parser'
require 'fog/vcloud/terremark/vcloud'
require 'fog/vcloud/terremark/ecloud'
require 'fog/vcloud/requests/get_organization'
require 'fog/vcloud/requests/get_vdc'
require 'fog/vcloud/requests/get_versions'
require 'fog/vcloud/requests/login'
require 'fog/vcloud/parsers/get_organization'
require 'fog/vcloud/parsers/get_vdc'
require 'fog/vcloud/parsers/get_versions'
require 'fog/vcloud/parsers/login'
Struct.new("VcloudLink", :rel, :href, :type, :name)
Struct.new("VcloudVdc", :links, :href, :type, :name, :xmlns, :allocation_model, :description)
Struct.new("VcloudOrganization", :links, :name, :href, :type, :xmlns, :description)
Struct.new("VcloudVersion", :version, :login_url, :supported)
Struct.new("VcloudOrgList", :organizations, :xmlns)
Struct.new("VcloudOrgLink", :name, :href, :type)
@required = true
end
instance = if Fog.mocking?
Fog::Vcloud::Mock.new(credentials)
else
Fog::Vcloud::Real.new(credentials)
end
if mod = credentials[:module]
instance.extend eval "#{mod}"
end
instance
end
end
end
end

57
lib/fog/vcloud/bin.rb Normal file
View file

@ -0,0 +1,57 @@
module Vcloud
class << self
def services
if Fog.credentials.has_key?(:vcloud)
Fog.credentials[:vcloud].keys.sort { |a,b| a.to_s <=> b.to_s }
else
[]
end
end
def registered_services
Vcloud.services.map { |service| ":" << service.to_s }.join(", ")
end
def complete_service_options?(service)
if Fog.credentials.has_key?(:vcloud)
if Fog.credentials[:vcloud].has_key?(service)
service = Fog.credentials[:vcloud][service]
if Fog::Vcloud::Options::REQUIRED.all? { |option| service.has_key?(option) }
return true
end
end
end
false
end
if Vcloud.services.all? { |service| Vcloud.complete_service_options?(service) }
def initialized?
true
end
def startup_notice
puts "You have acess to the following Vcloud services: #{Vcloud.registered_services}."
end
def [](service)
@@connections ||= Hash.new do |hash, key|
if credentials = Fog.credentials[:vcloud][key]
hash[key] = Fog::Vcloud.new(credentials.reject { |k,value| Fog::Vcloud::Options::ALL.include?(value) })
else
raise ArgumentError.new("Unregistered service: :#{key}. Registered services are: #{Vcloud.registered_services}")
end
end
@@connections[service]
end
else
def initialized?
false
end
end
end
end

34
lib/fog/vcloud/parser.rb Normal file
View file

@ -0,0 +1,34 @@
module Fog
module Parsers
module Vcloud
class Base < Fog::Parsers::Base
private
def generate_link(attributes)
link = Struct::VcloudLink.new
until attributes.empty?
link[attributes.shift.downcase] = attributes.shift
end
link
end
def handle_root(attributes)
root = {}
until attributes.empty?
if attributes.first.is_a?(Array)
attribute = attributes.shift
root[attribute.first.downcase] = attribute.last
else
root[attributes.shift.downcase] = attributes.shift
end
end
@response.href = root['href']
@response.name = root['name']
@response.type = root['type']
@response.xmlns = root['xmlns']
end
end
end
end
end

View file

@ -0,0 +1,37 @@
module Fog
module Parsers
module Vcloud
class GetOrganization < Fog::Parsers::Vcloud::Base
#
# Based off of:
# http://support.theenterprisecloud.com/kb/default.asp?id=540&Lang=1&SID=
#
# vCloud API Guide v0.9 - Page 26
#
def reset
@response = Struct::VcloudOrganization.new([])
end
def start_element(name, attributes)
@value = ''
case name
when 'Link'
@response.links << generate_link(attributes)
when 'Org'
handle_root(attributes)
end
end
def end_element(name)
if name == 'Description'
@response.description = @value
end
end
end
end
end
end

View file

@ -0,0 +1,37 @@
module Fog
module Parsers
module Vcloud
class GetVdc < Fog::Parsers::Vcloud::Base
#WARNING: Incomplete
#Based off of:
#vCloud API Guide v0.9 - Page 27
def reset
@response = Struct::VcloudVdc.new([])
end
def start_element(name, attributes)
@value = ''
case name
when 'Link'
@response.links << generate_link(attributes)
when 'Vdc'
handle_root(attributes)
end
end
def end_element(name)
case name
when "AllocationModel"
@response.allocation_model = @value
when "Description"
@response.description = @value
end
end
end
end
end
end

View file

@ -0,0 +1,46 @@
module Fog
module Parsers
module Vcloud
class GetVersions < Fog::Parsers::Base
#
# Based off of:
# http://support.theenterprisecloud.com/kb/default.asp?id=535&Lang=1&SID=
# https://community.vcloudexpress.terremark.com/en-us/product_docs/w/wiki/02-get-versions.aspx
# vCloud API Guide v0.9 - Page 89
#
def reset
@response = []
@supported = false
end
def start_element(name, attributes = {})
@value = ''
case name
when "Version"
@version = Struct::VcloudVersion.new
when "SupportedVersions"
@supported = true
end
end
def end_element(name)
case name
when "Version"
@version.version = @value
@version.supported = @supported
when "LoginUrl"
@version.login_url = @value
when "VersionInfo"
@response << @version
when "SupportedVersions"
@supported = false
end
end
end
end
end
end

View file

@ -0,0 +1,40 @@
module Fog
module Parsers
module Vcloud
class Login < Fog::Parsers::Base
#
# Based off of:
# http://support.theenterprisecloud.com/kb/default.asp?id=536&Lang=1&SID=
# https://community.vcloudexpress.terremark.com/en-us/product_docs/w/wiki/01-get-login-token.aspx
# vCloud API Guide v0.9 - Page 17
#
def reset
@response = Struct::VcloudOrgList.new([])
end
def start_element(name, attributes)
@value = ''
case name
when 'OrgList'
until attributes.empty?
if at = attributes.shift
if at[0] == "xmlns"
@response.xmlns = at[1]
end
end
end
when 'Org'
organization = Struct::VcloudOrgLink.new
until attributes.empty?
organization[attributes.shift.downcase.to_sym] = attributes.shift
end
@response.organizations << organization
end
end
end
end
end
end

View file

@ -0,0 +1,55 @@
module Fog
module Vcloud
class Real
def get_organization(organization_uri)
response = request(
:expects => 200,
:method => 'GET',
:parser => Fog::Parsers::Vcloud::GetOrganization.new,
:uri => organization_uri
)
response
end
end
class Mock
def get_organization(organization_uri)
#
# Based off of:
# http://support.theenterprisecloud.com/kb/default.asp?id=540&Lang=1&SID=
#
# vCloud API Guide v0.9 - Page 26
#
if org = DATA[:organizations].detect { |org| org[:info][:href] == organization_uri.to_s }
xml = Builder::XmlMarkup.new
mock_it Fog::Parsers::Vcloud::GetOrganization.new, 200,
xml.Org(xmlns.merge(:href => org[:info][:href], :name => org[:info][:name])) {
org[:vdcs].each do |vdc|
xml.Link(:rel => "down",
:href => vdc[:href],
:type => "application/vnd.vmware.vcloud.vdc+xml",
:name => vdc[:name])
xml.Link(:rel => "down",
:href => "#{vdc[:href]}/catalog",
:type => "application/vnd.vmware.vcloud.catalog+xml",
:name => "#{vdc[:name]} Catalog")
xml.Link(:rel => "down",
:href => "#{vdc[:href]}/tasksList",
:type => "application/vnd.vmware.vcloud.tasksList+xml",
:name => "#{vdc[:name]} Tasks List")
end
},
{'Content-Type' => "application/vnd.vmware.vcloud.org+xml" }
else
mock_error 200, "401 Unauthorized"
end
end
end
end
end

View file

@ -0,0 +1,59 @@
module Fog
module Vcloud
class Real
# Get details of a vdc
def get_vdc(vdc_uri)
request(
:expects => 200,
:method => 'GET',
:parser => Fog::Parsers::Vcloud::GetVdc.new,
:uri => vdc_uri
)
end
end
class Mock
# WARNING: Incomplete
#Based off of:
#vCloud API Guide v0.9 - Page 27
def get_vdc(vdc_uri)
if vdc = DATA[:organizations].map { |org| org[:vdcs] }.flatten.detect { |vdc| vdc[:href] == vdc_uri }
xml = Builder::XmlMarkup.new
mock_it Fog::Parsers::Vcloud::GetVdc.new, 200,
xml.Vdc(xmlns.merge(:href => vdc[:href], :name => vdc[:name])) {
xml.Link(:rel => "up",
:href => DATA[:organizations].detect { |org| org[:vdcs].detect { |_vdc| vdc[:href] == _vdc[:href] }[:href] == vdc[:href] }[:info][:href],
:type => "application/vnd.vmware.vcloud.org+xml")
xml.Link(:rel => "add",
:href => vdc[:href] + "/action/uploadVAppTemplate",
:type => "application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml")
xml.Link(:rel => "add",
:href => vdc[:href] + "/media",
:type => "application/vnd.vmware.vcloud.media+xml")
xml.Link(:rel => "add",
:href => vdc[:href] + "/action/instantiateVAppTemplate",
:type => "application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml")
xml.Link(:rel => "add",
:type => "application/vnd.vmware.vcloud.cloneVAppParams+xml",
:href => vdc[:href] + "/action/cloneVApp")
xml.Link(:rel => "add",
:type => "application/vnd.vmware.vcloud.captureVAppParams+xml",
:href => vdc[:href] + "/action/captureVApp")
xml.Link(:rel => "add",
:type => "application/vnd.vmware.vcloud.composeVAppParams+xml",
:href => vdc[:href] + "/action/composeVApp")
xml.AllocationModel("AllocationPool")
xml.Description(vdc[:name] + " VDC")
#FIXME: Incomplete
}, { 'Content-Type' => 'application/vnd.vmware.vcloud.vdc+xml' }
else
mock_error 200, "401 Unauthorized"
end
end
end
end
end

View file

@ -0,0 +1,43 @@
module Fog
module Vcloud
class Real
def get_versions
unauthenticated_request({
:expects => 200,
:method => 'GET',
:parser => Fog::Parsers::Vcloud::GetVersions.new,
:uri => @versions_uri
})
end
end
class Mock
def get_versions
#
# Based off of:
# http://support.theenterprisecloud.com/kb/default.asp?id=535&Lang=1&SID=
# https://community.vcloudexpress.terremark.com/en-us/product_docs/w/wiki/02-get-versions.aspx
# vCloud API Guide v0.9 - Page 89
#
xml = Builder::XmlMarkup.new
mock_it Fog::Parsers::Vcloud::GetVersions.new, 200,
xml.SupportedVersions( xmlns.merge("xmlns" => "http://www.vmware.com/vcloud/versions")) {
DATA[:versions].select {|version| version[:supported] }.each do |version|
xml.VersionInfo {
xml.Version(version[:version])
xml.LoginUrl(version[:login_url])
}
end
}
end
end
end
end

View file

@ -0,0 +1,46 @@
module Fog
module Vcloud
class Real
def login
unauthenticated_request({
:expects => 200,
:headers => {
'Authorization' => authorization_header
},
:method => 'POST',
:parser => Fog::Parsers::Vcloud::Login.new,
:uri => @login_uri
})
end
end
class Mock
def login
#
# Based off of:
# http://support.theenterprisecloud.com/kb/default.asp?id=536&Lang=1&SID=
# https://community.vcloudexpress.terremark.com/en-us/product_docs/w/wiki/01-get-login-token.aspx
# vCloud API Guide v0.9 - Page 17
#
xml = Builder::XmlMarkup.new
mock_it Fog::Parsers::Vcloud::Login.new, 200,
xml.OrgList(xmlns) {
DATA[:organizations].each do |org|
xml.Org( org[:info].merge( "type" => "application/vnd.vmware.vcloud.org+xml" ) ) {}
end
},
{ 'Set-Cookie' => 'vcloud-token=fc020a05-21d7-4f33-9b2a-25d8cd05a44e; path=/',
'Content-Type' => 'application/vnd.vmware.vcloud.orgslist+xml' }
end
end
end
end

View file

@ -0,0 +1,9 @@
module Fog
module Vcloud
module Terremark
unless @required
@required = true
end
end
end
end

View file

@ -0,0 +1,47 @@
module Fog
module Vcloud
module Terremark
module Ecloud
module Versions
SUPPORTED = ["v0.8", "v0.8a-ext2.0"]
end
def self.extended(klass)
#Do anything we need to do here that's specific to ecloud
unless @required
require 'fog/vcloud/terremark/all'
require 'fog/vcloud/terremark/ecloud/parsers/get_vdc'
require 'fog/vcloud/terremark/ecloud/requests/login'
require 'fog/vcloud/terremark/ecloud/requests/get_vdc'
Struct.new("TmrkEcloudVdc", :links, :resource_entities, :networks,
:cpu_capacity, :storage_capacity, :memory_capacity, :deployed_vm_quota, :instantiated_vm_quota,
:href, :type, :name, :xmlns, :description)
Struct.new("TmrkEcloudXCapacity", :units, :allocated, :used, :limit)
@required = true
end
if Fog.mocking?
klass.extend Fog::Vcloud::Terremark::Ecloud::Mock
else
klass.extend Fog::Vcloud::Terremark::Ecloud::Real
end
end
private
# 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
super
unless (supported_version_ids & Versions::SUPPORTED).length > 0
raise UnsupportedVersion.new("\nService @ #{@versions_uri} supports: #{supported_version_ids.join(', ')}\n" +
"Fog::Vcloud::Terremark::Ecloud supports: #{Versions::SUPPORTED.join(', ')}")
end
unless supported_version_ids.include?(@version)
@version = (supported_version_ids & Versions::SUPPORTED).sort.first
end
end
end
end
end
end

View file

@ -0,0 +1,59 @@
module Fog
module Parsers
module Vcloud
module Terremark
module Ecloud
class GetVdc < Fog::Parsers::Vcloud::Base
def reset
@target = nil
@response = Struct::TmrkEcloudVdc.new([],[],[],Struct::TmrkEcloudXCapacity.new,Struct::TmrkEcloudXCapacity.new,
Struct::TmrkEcloudXCapacity.new,Struct::TmrkEcloudXCapacity.new,
Struct::TmrkEcloudXCapacity.new)
end
def start_element(name, attributes)
@value = ''
case name
when 'Cpu'
@target = :cpu_capacity
when 'DeployedVmsQuota'
@target = :deployed_vm_quota
when 'InstantiatedVmsQuota'
@target = :instantiated_vm_quota
when 'Memory'
@target = :memory_capacity
when 'StorageCapacity'
@target = :storage_capacity
when 'Link'
@response.links << generate_link(attributes)
when 'Network'
@response.networks << generate_link(attributes)
when 'ResourceEntity'
@response.resource_entities << generate_link(attributes)
when 'Vdc'
handle_root(attributes)
end
end
def end_element(name)
case name
when 'Allocated', 'Limit', 'Used'
@response[@target][name.downcase] = @value.to_i
when 'Units'
@response[@target][name.downcase] = @value
when 'Cpu', 'DeployedVmsQuota', 'InstantiatedVmsQuota', 'Memory', 'StorageCapacity'
@target = nil
when 'Description'
@response.description = @value
end
end
end
end
end
end
end
end

View file

@ -0,0 +1,94 @@
module Fog
module Vcloud
module Terremark
module Ecloud
module Real
# Get details of a vdc
def get_vdc(vdc_uri)
request(
:expects => 200,
:method => 'GET',
:parser => Fog::Parsers::Vcloud::Terremark::Ecloud::GetVdc.new,
:uri => vdc_uri
)
end
end
module Mock
#
#Based off of:
#http://support.theenterprisecloud.com/kb/default.asp?id=545&Lang=1&SID=
def get_vdc(vdc_uri)
if vdc = mock_data[:organizations].map { |org| org[:vdcs] }.flatten.detect { |vdc| vdc[:href] == vdc_uri }
xml = Builder::XmlMarkup.new
mock_it Fog::Parsers::Vcloud::Terremark::Ecloud::GetVdc.new, 200,
xml.Vdc(xmlns.merge(:href => vdc[:href], :name => vdc[:name])) {
xml.Link(:rel => "down",
:href => vdc[:href] + "/catalog",
:type => "application/vnd.vmware.vcloud.catalog+xml",
:name => vdc[:name])
xml.Link(:rel => "down",
:href => vdc[:href].gsub('/vdc','/extensions/vdc') + "/publicIps",
:type => "application/vnd.tmrk.ecloud.publicIpsList+xml",
:name => "Public IPs")
xml.Link(:rel => "down",
:href => vdc[:href] + "/internetServices",
:type => "application/vnd.tmrk.ecloud.internetServicesList+xml",
:name => "Internet Services")
xml.Link(:rel => "down",
:href => vdc[:href].sub('/vdc','/extensions/vdc') + "/firewallAcls",
:type => "application/vnd.tmrk.ecloud.firewallAclsList+xml",
:name => "Firewall Access List")
xml.Description("")
xml.StorageCapacity {
xml.Units("bytes * 10^9")
xml.Allocated(vdc[:storage][:allocated])
xml.Used(vdc[:storage][:used])
}
xml.ComputeCapacity {
xml.Cpu {
xml.Units("hz * 10^6")
xml.Allocated(vdc[:cpu][:allocated])
}
xml.Memory {
xml.Units("bytes * 2^20")
xml.Allocated(vdc[:memory][:allocated])
}
xml.DeployedVmsQuota {
xml.Limit("-1")
xml.Used("-1")
}
xml.InstantiatedVmsQuota {
xml.Limit("-1")
xml.Used("-1")
}
}
xml.ResourceEntities {
vdc[:vms].each do |vm|
xml.ResourceEntity(:href => vm[:href],
:type => "application/vnd.vmware.vcloud.vApp+xml",
:name => vm[:name])
end
}
xml.AvailableNetworks {
vdc[:networks].each do |network|
xml.Network(:href => network[:href],
:type => "application/vnd.vmware.vcloud.network+xml",
:name => network[:name])
end
}
}, { 'Content-Type' => 'application/vnd.vmware.vcloud.vdc+xml'}
else
mock_error 200, "401 Unauthorized"
end
end
end
end
end
end
end

View file

@ -0,0 +1,27 @@
module Fog
module Vcloud
module Terremark
module Ecloud
module Real
# See /lib/fog/vcloud/requests/get_organizations.rb
def login
unauthenticated_request({
:expects => 200,
:headers => {
'Authorization' => authorization_header,
'Content-Type' => "application/vnd.vmware.vcloud.orgList+xml"
},
:method => 'POST',
:parser => Fog::Parsers::Vcloud::Login.new,
:uri => @login_uri
})
end
end
end
end
end
end

View file

@ -0,0 +1,43 @@
module Fog
module Vcloud
module Terremark
module Vcloud
module Versions
SUPPORTED = ["v0.8"]
end
def self.extended(klass)
#Do anything we need to do here that's specific to ecloud
unless @required
require 'fog/vcloud/terremark/all'
require 'fog/vcloud/terremark/vcloud/parsers/get_vdc'
require 'fog/vcloud/terremark/vcloud/requests/get_vdc'
Struct.new("TmrkVcloudVdc", :links, :resource_entities, :networks, :href, :type, :name, :xmlns)
@required = true
end
if Fog.mocking?
klass.extend Fog::Vcloud::Terremark::Vcloud::Mock
else
klass.extend Fog::Vcloud::Terremark::Vcloud::Real
end
end
private
# 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
super
unless (supported_version_ids & Versions::SUPPORTED).length > 0
raise UnsupportedVersion.new("\nService @ #{@versions_uri} supports: #{supported_version_ids.join(', ')}\n" +
"Fog::Vcloud::Terremark::Vcloud supports: #{Versions::SUPPORTED.join(', ')}")
end
unless supported_version_ids.include?(@version)
@version = (supported_version_ids & Versions::SUPPORTED).sort.first
end
end
end
end
end
end

View file

@ -0,0 +1,34 @@
module Fog
module Parsers
module Vcloud
module Terremark
module Vcloud
class GetVdc < Fog::Parsers::Vcloud::Base
def reset
@target = nil
@response = Struct::TmrkVcloudVdc.new([],[],[])
end
def start_element(name, attributes)
@value = ''
case name
when 'Link'
@response.links << generate_link(attributes)
when 'Network'
@response.networks << generate_link(attributes)
when 'ResourceEntity'
@response.resource_entities << generate_link(attributes)
when 'Vdc'
handle_root(attributes)
end
end
end
end
end
end
end
end

View file

@ -0,0 +1,65 @@
module Fog
module Vcloud
module Terremark
module Vcloud
module Real
# Get details of a vdc
def get_vdc(vdc_uri)
request(
:expects => 200,
:method => 'GET',
:parser => Fog::Parsers::Vcloud::Terremark::Vcloud::GetVdc.new,
:uri => vdc_uri
)
end
end
module Mock
#
#Based off of:
#https://community.vcloudexpress.terremark.com/en-us/product_docs/w/wiki/09-get-vdc.aspx
def get_vdc(vdc_uri)
if vdc = mock_data[:organizations].map { |org| org[:vdcs] }.flatten.detect { |vdc| vdc[:href] == vdc_uri }
xml = Builder::XmlMarkup.new
mock_it Fog::Parsers::Vcloud::Terremark::Vcloud::GetVdc.new, 200,
xml.Vdc(xmlns.merge(:href => vdc[:href], :name => vdc[:name])) {
xml.Link(:rel => "down",
:href => vdc[:href] + "/catalog",
:type => "application/vnd.vmware.vcloud.catalog+xml",
:name => vdc[:name])
xml.Link(:rel => "down",
:href => vdc[:href] + "/publicIps",
:type => "application/xml",
:name => "Public IPs")
xml.Link(:rel => "down",
:href => vdc[:href] + "/internetServices",
:type => "application/xml",
:name => "Internet Services")
xml.ResourceEntities {
vdc[:vms].each do |vm|
xml.ResourceEntity(:href => vm[:href],
:type => "application/vnd.vmware.vcloud.vApp+xml",
:name => vm[:name])
end
}
xml.AvailableNetworks {
vdc[:networks].each do |network|
xml.Network(:href => network[:href],
:type => "application/vnd.vmware.vcloud.network+xml",
:name => network[:name])
end
}
}, { 'Content-Type' => 'application/vnd.vmware.vcloud.vdc+xml'}
else
mock_error 200, "401 Unauthorized"
end
end
end
end
end
end
end

View file

@ -9,6 +9,8 @@ if ENV["FOG_MOCK"] == "true"
Fog.mock!
end
require "#{current_directory}/../lib/fog/vcloud/bin"
module AWS
class << self
def [](service)
@ -100,4 +102,4 @@ end
def lorem_file
File.open(File.dirname(__FILE__) + '/lorem.txt', 'r')
end
end

31
spec/vcloud/bin_spec.rb Normal file
View file

@ -0,0 +1,31 @@
require 'spec_helper'
describe Vcloud do
it { should be_initialized }
it { should have(2).services }
describe "#registered_services" do
subject { Vcloud.registered_services }
it { should == ":ecloud, :vcloud" }
end
describe "when indexing it like an array" do
describe "with a service that exists" do
before do
Fog::Vcloud.should_receive(:new).and_return(true)
end
it "should return something when indexed with a configured service" do
Vcloud[:ecloud].should_not be_nil
end
end
describe "with a service that does not exist" do
it "should raise an ArgumentError" do
lambda {Vcloud[:foozle]}.should raise_error(ArgumentError)
end
end
end
end

View file

@ -0,0 +1,46 @@
require File.dirname(__FILE__) + '/../spec_helper'
describe Fog::Vcloud, :type => :vcloud_request do
subject { @vcloud }
it { should respond_to :get_organization }
describe "#get_organization" do
context "with a valid organization uri" do
before { @organization = @vcloud.get_organization(@vcloud.default_organization_uri) }
subject { @organization }
it_should_behave_like "all requests"
its(:headers) { should include "Content-Type" }
its(:body) { should be_an_instance_of Struct::VcloudOrganization }
describe :headers do
let(:header){ @organization.headers["Content-Type"] }
specify{ header.should == "application/vnd.vmware.vcloud.org+xml" }
end
describe "#body" do
subject { @organization.body }
it_should_behave_like "it has a vcloud v0.8 xmlns"
its(:links) { should have(@mock_organization[:vdcs].length * 3).links }
its(:name) { should == @mock_organization[:info][:name] }
its(:href) { should == @mock_organization[:info][:href] }
let(:link) { subject.links[0] }
specify { link.should be_an_instance_of Struct::VcloudLink }
specify { link.rel.should == "down" }
specify { link.href.should == @mock_vdc[:href] }
specify { link.type.should == "application/vnd.vmware.vcloud.vdc+xml" }
specify { link.name.should == @mock_vdc[:name] }
end
end
context "with an organization uri that doesn't exist" do
subject { lambda { @vcloud.get_organization(URI.parse('https://www.fakey.com/api/v0.8/org/999')) } }
it_should_behave_like "a request for a resource that doesn't exist"
end
end
end

View file

@ -0,0 +1,50 @@
require "spec_helper"
#
# WARNING: INCOMPLETE
#
describe Fog::Vcloud, :type => :vcloud_request do
subject { @vcloud }
it { should respond_to :get_vdc }
describe :get_vdc, :type => :vcloud_request do
context "with a valid vdc uri" do
before { @vdc = @vcloud.get_vdc(@mock_vdc[:href]) }
subject { @vdc }
it_should_behave_like "all requests"
its(:headers) { should include "Content-Type" }
its(:body) { should be_an_instance_of Struct::VcloudVdc }
describe :headers do
let(:header) { @vdc.headers["Content-Type"] }
specify { header.should == "application/vnd.vmware.vcloud.vdc+xml" }
end
describe :body do
subject { @vdc.body }
it_should_behave_like "it has a vcloud v0.8 xmlns"
its(:links) { should have(7).links }
its(:name) { should == @mock_vdc[:name] }
its(:href) { should == @mock_vdc[:href] }
let(:link) { subject.links[0] }
specify { link.should be_an_instance_of Struct::VcloudLink }
specify { link.rel.should == "up" }
specify { link.href.should == @mock_organization[:info][:href] }
specify { link.type.should == "application/vnd.vmware.vcloud.org+xml" }
end
end
context "with a vdc uri that doesn't exist" do
subject { lambda { @vcloud.get_vdc(URI.parse('https://www.fakey.com/api/v0.8/vdc/999')) } }
it_should_behave_like "a request for a resource that doesn't exist"
end
end
end

View file

@ -0,0 +1,28 @@
require 'spec_helper'
describe Fog::Vcloud, :type => :vcloud_request do
subject { @vcloud }
it { should respond_to :get_versions }
describe "#get_versions" do
before { @versions = @vcloud.get_versions }
subject { @versions }
it_should_behave_like "all requests"
its(:body) { should have(1).version }
describe "body.first" do
let(:version) { @versions.body.first }
subject { version }
its(:login_url) { should == @mock_version[:login_url] }
its(:version) { should == @mock_version[:version] }
its(:supported) { should == @mock_version[:supported] }
end
end
end

View file

@ -0,0 +1,8 @@
require 'spec_helper'
describe Fog::Vcloud, :type => :vcloud_request do
subject { @vcloud }
it_should_behave_like "all login requests"
end

184
spec/vcloud/spec_helper.rb Normal file
View file

@ -0,0 +1,184 @@
require 'spec'
require 'pp'
current_directory = File.dirname(__FILE__)
require "#{current_directory}/../../lib/fog"
require "#{current_directory}/../../lib/fog/bin"
Fog.mock!
require "#{current_directory}/../../lib/fog/vcloud/bin"
shared_examples_for "all requests" do
it { should respond_to :body }
it { should respond_to :headers }
it { should have_at_least(1).body }
it { should have_at_least(0).headers }
end
shared_examples_for "all rel=down vcloud links" do
it { should be_an_instance_of Struct::VcloudLink }
specify { subject.rel.should == "down" }
end
shared_examples_for "all vcloud links w/o a rel" do
it { should be_an_instance_of Struct::VcloudLink }
specify { subject.rel.should == nil }
end
shared_examples_for "all vcloud catalog links" do
specify { subject.type.should == "application/vnd.vmware.vcloud.catalog+xml" }
end
shared_examples_for "all tmrk ecloud publicIpList links" do
specify { subject.type.should == "application/vnd.tmrk.ecloud.publicIpsList+xml" }
end
shared_examples_for "all tmrk ecloud firewallAclList links" do
specify { subject.type.should == "application/vnd.tmrk.ecloud.firewallAclsList+xml" }
end
shared_examples_for "all tmrk ecloud internetServicesList links" do
specify { subject.type.should == "application/vnd.tmrk.ecloud.internetServicesList+xml" }
end
shared_examples_for "all vcloud application/xml types" do
specify { subject.type.should == "application/xml" }
end
shared_examples_for "a vapp type" do
specify { subject.type.should == "application/vnd.vmware.vcloud.vApp+xml" }
end
shared_examples_for "all vcloud network types" do
specify { subject.type.should == "application/vnd.vmware.vcloud.network+xml" }
end
shared_examples_for "all login requests" do
it { should respond_to :login }
describe "#login" do
before { @login = @vcloud.login }
subject { @login }
it_should_behave_like "all requests"
its(:headers) { should include "Set-Cookie" }
its(:headers) { should include "Content-Type" }
its(:body) { should be_an_instance_of Struct::VcloudOrgList }
describe "#body" do
before { @orglist = @login.body }
subject { @orglist }
its(:xmlns) { should == "http://www.vmware.com/vcloud/v0.8" }
it { should have(1).organizations }
describe "#first" do
before { @org = @orglist.organizations.first }
subject { @org }
it { should be_an_instance_of Struct::VcloudOrgLink }
its(:href) { should == @mock_organization[:info][:href] }
its(:name) { should == @mock_organization[:info][:name] }
its(:type) { should == "application/vnd.vmware.vcloud.org+xml" }
end
end
end
end
shared_examples_for "it has a vcloud v0.8 xmlns" do
its(:xmlns) { should == 'http://www.vmware.com/vcloud/v0.8' }
end
shared_examples_for "a request for a resource that doesn't exist" do
it { should raise_error Excon::Errors::Unauthorized }
end
shared_examples_for "a vdc catalog link" do
it_should_behave_like "all rel=down vcloud links"
it_should_behave_like "all vcloud catalog links"
its(:href) { should == @mock_vdc[:href] + "/catalog" }
end
shared_examples_for "a tmrk vdc" do
it { should respond_to :links }
it { should respond_to :networks }
it { should respond_to :resource_entities }
end
shared_examples_for "a tmrk network link" do
it_should_behave_like "all vcloud links w/o a rel"
it_should_behave_like "all vcloud network types"
end
shared_examples_for "the mocked tmrk network links" do
it { should have(2).networks }
describe "[0]" do
subject { @vdc.body.networks[0] }
it_should_behave_like "a tmrk network link"
its(:href) { should == @mock_vdc[:networks][0][:href] }
its(:name) { should == @mock_vdc[:networks][0][:name] }
end
describe "[1]" do
subject { @vdc.body.networks[1] }
it_should_behave_like "a tmrk network link"
its(:href) { should == @mock_vdc[:networks][1][:href] }
its(:name) { should == @mock_vdc[:networks][1][:name] }
end
end
shared_examples_for "the mocked tmrk resource entity links" do
it { should have(3).resource_entities }
describe "[0]" do
subject { @vdc.body.resource_entities[0] }
it_should_behave_like "a vapp type"
it_should_behave_like "all vcloud links w/o a rel"
its(:href) { should == @mock_vdc[:vms][0][:href] }
its(:name) { should == @mock_vdc[:vms][0][:name] }
end
describe "[1]" do
subject { @vdc.body.resource_entities[1] }
it_should_behave_like "a vapp type"
it_should_behave_like "all vcloud links w/o a rel"
its(:href) { should == @mock_vdc[:vms][1][:href] }
its(:name) { should == @mock_vdc[:vms][1][:name] }
end
describe "[2]" do
subject { @vdc.body.resource_entities[2] }
it_should_behave_like "a vapp type"
it_should_behave_like "all vcloud links w/o a rel"
its(:href) { should == @mock_vdc[:vms][2][:href] }
its(:name) { should == @mock_vdc[:vms][2][:name] }
end
end
Spec::Example::ExampleGroupFactory.register(:vcloud_request, Class.new(Spec::Example::ExampleGroup))
Spec::Example::ExampleGroupFactory.register(:tmrk_ecloud_request, Class.new(Spec::Example::ExampleGroup))
Spec::Example::ExampleGroupFactory.register(:tmrk_vcloud_request, Class.new(Spec::Example::ExampleGroup))
Spec::Runner.configure do |config|
config.before(:all) do
@mock_data = Fog::Vcloud::Mock::DATA
@mock_version = @mock_data[:versions][0]
@mock_organization = @mock_data[:organizations][0]
@mock_vdc = @mock_organization[:vdcs][0]
end
config.before(:each, :type => :vcloud_request) do
@vcloud = Fog::Vcloud.new
end
config.before(:each, :type => :tmrk_ecloud_request) do
@vcloud = Fog::Vcloud.new(:module => "Fog::Vcloud::Terremark::Ecloud")
end
config.before(:each, :type => :tmrk_vcloud_request) do
@vcloud = Fog::Vcloud.new(:module => "Fog::Vcloud::Terremark::Vcloud")
end
end

View file

@ -0,0 +1,135 @@
require "spec_helper"
describe "Fog::Vcloud, initialized w/ the TMRK Ecloud module", :type => :tmrk_ecloud_request do
subject { @vcloud }
it { should respond_to :get_vdc }
describe "#get_vdc" do
context "with a valid vdc uri" do
before { @vdc = @vcloud.get_vdc(@mock_vdc[:href]) }
subject { @vdc }
it_should_behave_like "all requests"
its(:headers) { should include "Content-Type" }
its(:body) { should be_an_instance_of Struct::TmrkEcloudVdc }
describe "#headers" do
let(:header) { @vdc.headers["Content-Type"] }
specify { header.should == "application/vnd.vmware.vcloud.vdc+xml" }
end
describe "#body" do
subject { @vdc.body }
it_should_behave_like "it has a vcloud v0.8 xmlns"
it_should_behave_like "a tmrk vdc"
it { should respond_to :storage_capacity }
it { should respond_to :cpu_capacity }
it { should respond_to :memory_capacity }
it { should respond_to :deployed_vm_quota }
it { should respond_to :instantiated_vm_quota }
its(:name) { should == @mock_vdc[:name] }
its(:href) { should == @mock_vdc[:href] }
its(:description) { should == '' }
describe "#links" do
subject { @vdc.body.links }
it { should have(4).links }
describe "[0]" do
subject { @vdc.body.links[0] }
it_should_behave_like "a vdc catalog link"
end
describe "[1]" do
subject { @vdc.body.links[1] }
it_should_behave_like "all rel=down vcloud links"
it_should_behave_like "all tmrk ecloud publicIpList links"
specify { subject.href.should == @mock_vdc[:href].sub('/vdc','/extensions/vdc') + "/publicIps" }
end
describe "[2]" do
subject { @vdc.body.links[2] }
it_should_behave_like "all rel=down vcloud links"
it_should_behave_like "all tmrk ecloud internetServicesList links"
specify { subject.href.should == @mock_vdc[:href] + "/internetServices" }
end
describe "[3]" do
subject { @vdc.body.links[3] }
it_should_behave_like "all rel=down vcloud links"
it_should_behave_like "all tmrk ecloud firewallAclList links"
specify { subject.href.should == @mock_vdc[:href].sub('/vdc','/extensions/vdc') + "/firewallAcls" }
end
end
describe "#networks" do
subject { @vdc.body.networks }
it_should_behave_like "the mocked tmrk network links"
end
describe "#storage_capacity" do
subject { @vdc.body.storage_capacity }
its(:units) { should == "bytes * 10^9" }
its(:allocated) { should == @mock_vdc[:storage][:allocated] }
its(:used) { should == @mock_vdc[:storage][:used] }
end
describe "#cpu_capacity" do
subject { @vdc.body.cpu_capacity }
its(:units) { should == "hz * 10^6" }
its(:allocated) { should == @mock_vdc[:cpu][:allocated] }
its(:used) { should == nil }
its(:limit) { should == nil }
end
describe "#memory_capacity" do
subject { @vdc.body.memory_capacity }
it { should be_an_instance_of Struct::TmrkEcloudXCapacity }
its(:units) { should == "bytes * 2^20" }
its(:allocated) { should == @mock_vdc[:memory][:allocated] }
its(:used) { should == nil }
its(:limit) { should == nil }
end
describe "#deployed_vm_quota" do
subject { @vdc.body.deployed_vm_quota }
it { should be_an_instance_of Struct::TmrkEcloudXCapacity }
its(:limit) { should == -1 }
its(:used) { should == -1 }
its(:units) { should == nil }
its(:allocated) { should == nil }
end
describe "#instantiated_vm_quota" do
subject { @vdc.body.instantiated_vm_quota }
it { should be_an_instance_of Struct::TmrkEcloudXCapacity }
its(:limit) { should == -1 }
its(:used) { should == -1 }
its(:units) { should == nil }
its(:allocated) { should == nil }
end
describe "#resource_entities" do
subject { @vdc.body.resource_entities }
it_should_behave_like "the mocked tmrk resource entity links"
end
end
end
context "with a vdc uri that doesn't exist" do
subject { lambda { @vcloud.get_vdc(URI.parse('https://www.fakey.com/api/v0.8/vdc/999')) } }
it_should_behave_like "a request for a resource that doesn't exist"
end
end
end

View file

@ -0,0 +1,7 @@
require 'spec_helper'
describe Fog::Vcloud, :type => :tmrk_ecloud_request do
subject { @vcloud }
it_should_behave_like "all login requests"
end

View file

@ -0,0 +1,74 @@
require "spec_helper"
describe "Fog::Vcloud, initialized w/ the TMRK Vcloud module", :type => :tmrk_vcloud_request do
subject { @vcloud }
it { should respond_to :get_vdc }
describe :get_vdc do
context "with a valid vdc uri" do
before { @vdc = @vcloud.get_vdc(@mock_vdc[:href]) }
subject { @vdc }
it_should_behave_like "all requests"
its(:headers) { should include "Content-Type" }
its(:body) { should be_an_instance_of Struct::TmrkVcloudVdc }
describe :headers do
let(:header) { @vdc.headers["Content-Type"] }
specify { header.should == "application/vnd.vmware.vcloud.vdc+xml" }
end
describe :body do
subject { @vdc.body }
it_should_behave_like "it has a vcloud v0.8 xmlns"
it_should_behave_like "a tmrk vdc"
its(:name) { should == @mock_vdc[:name] }
its(:href) { should == @mock_vdc[:href] }
describe "#links" do
subject { @vdc.body.links }
it { should have(3).links }
describe "#link[0]" do
subject { @vdc.body.links[0] }
it_should_behave_like "a vdc catalog link"
end
describe "#link[1]" do
subject { @vdc.body.links[1] }
it_should_behave_like "all rel=down vcloud links"
it_should_behave_like "all vcloud application/xml types"
specify { subject.href.should == @mock_vdc[:href] + "/publicIps" }
end
describe "#link[2]" do
subject { @vdc.body.links[2] }
it_should_behave_like "all rel=down vcloud links"
it_should_behave_like "all vcloud application/xml types"
specify { subject.href.should == @mock_vdc[:href] + "/internetServices" }
end
end
describe :networks do
subject { @vdc.body.networks }
it_should_behave_like "the mocked tmrk network links"
end
describe "#resource_entities" do
subject { @vdc.body.resource_entities }
it_should_behave_like "the mocked tmrk resource entity links"
end
end
end
context "with a vdc uri that doesn't exist" do
subject { lambda { @vcloud.get_vdc(URI.parse('https://www.fakey.com/api/v0.8/vdc/999')) } }
it_should_behave_like "a request for a resource that doesn't exist"
end
end
end

View file

@ -0,0 +1,17 @@
require 'spec_helper'
describe Fog::Vcloud do
subject { Fog::Vcloud.new() }
it { should be_an_instance_of Fog::Vcloud::Mock }
it { should respond_to :default_organization_uri }
it { should respond_to :supported_versions }
it { should have_at_least(1).supported_versions }
its(:default_organization_uri) { should == URI.parse(@mock_organization[:info][:href]) }
its(:default_organization_uri) { should be_an_instance_of URI::HTTPS }
end