[vcloud|compute] duplicate ecloud code for vcloud, remove obvious terremark specific code.
This commit is contained in:
parent
f7e4797834
commit
7e351ff91d
|
@ -69,6 +69,7 @@ require 'fog/bin/rackspace'
|
|||
require 'fog/bin/slicehost'
|
||||
require 'fog/bin/stormondemand'
|
||||
require 'fog/bin/terremark'
|
||||
require 'fog/bin/vcloud'
|
||||
require 'fog/bin/virtual_box'
|
||||
require 'fog/bin/voxel'
|
||||
require 'fog/bin/zerigo'
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
class Vcloud < Fog::Bin
|
||||
class << self
|
||||
|
||||
def class_for(key)
|
||||
case key
|
||||
when :compute
|
||||
Fog::Vcloud::Compute
|
||||
else
|
||||
raise ArgumentError, "Unrecognized service: #{key}"
|
||||
end
|
||||
end
|
||||
|
||||
def [](service)
|
||||
@@connections ||= Hash.new do |hash, key|
|
||||
hash[key] = case key
|
||||
when :compute
|
||||
Fog::Compute.new(:provider => 'Vcloud')
|
||||
else
|
||||
raise ArgumentError, "Unrecognized service: #{key.inspect}"
|
||||
end
|
||||
end
|
||||
@@connections[service]
|
||||
end
|
||||
|
||||
def services
|
||||
Fog::Vcloud.services
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -40,8 +40,11 @@ module Fog
|
|||
Fog::Compute::Slicehost.new(attributes)
|
||||
when :stormondemand
|
||||
require 'fog/compute/storm_on_demand'
|
||||
Fog::Compute::StormOnDemand.new(attributes)
|
||||
when :virtualbox
|
||||
Fog::StormOnDemand::Compute.new(attributes)
|
||||
when 'Vcloud'
|
||||
require 'fog/compute/vcloud'
|
||||
Fog::Vcloud::Compute.new(attributes)
|
||||
when 'VirtualBox'
|
||||
require 'fog/compute/virtual_box'
|
||||
Fog::Compute::VirtualBox.new(attributes)
|
||||
when :voxel
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
class Catalog < Fog::Vcloud::Collection
|
||||
|
||||
model Fog::Vcloud::Compute::CatalogItem
|
||||
|
||||
attribute :href, :aliases => :Href
|
||||
|
||||
def all
|
||||
check_href!
|
||||
if data = connection.get_catalog(href).body[:CatalogItems][:CatalogItem]
|
||||
load(data)
|
||||
end
|
||||
end
|
||||
|
||||
def get(uri)
|
||||
if data = connection.get_catalog_item(uri)
|
||||
new(data.body)
|
||||
end
|
||||
rescue Fog::Errors::NotFound
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
class CatalogItem < Fog::Vcloud::Model
|
||||
|
||||
identity :href, :aliases => :Href
|
||||
|
||||
ignore_attributes :xmlns, :xmlns_i, :xmlns_xsi, :xmlns_xsd
|
||||
|
||||
attribute :type
|
||||
attribute :name
|
||||
attribute :entity, :aliases => :Entity
|
||||
attribute :link, :aliases => :Link
|
||||
attribute :property, :aliases => :Property
|
||||
|
||||
def customization_options
|
||||
load_unless_loaded!
|
||||
if data = connection.get_customization_options( link[:href] ).body
|
||||
data.delete_if { |key, value| [:xmlns_i, :xmlns].include?(key) }
|
||||
data
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
class Ip < Fog::Vcloud::Model
|
||||
|
||||
ignore_attributes :xmlns_i, :xmlns
|
||||
|
||||
identity :href, :aliases => :Href
|
||||
|
||||
attribute :name, :aliases => :Name
|
||||
attribute :status, :aliases => :Status
|
||||
attribute :server, :aliases => :Server
|
||||
attribute :id, :aliases => :Id, :type => :integer
|
||||
|
||||
def save
|
||||
if @changed
|
||||
connection.configure_network_ip( href, _compose_network_ip_data )
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def reload
|
||||
super
|
||||
@changed = false
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
def _compose_network_ip_data
|
||||
{
|
||||
:id => id,
|
||||
:href => href,
|
||||
:name => name,
|
||||
:status => status,
|
||||
:server => server
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
require 'fog/compute/models/vcloud/ip'
|
||||
|
||||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
class Ips < Fog::Vcloud::Collection
|
||||
|
||||
model Fog::Vcloud::Compute::Ip
|
||||
|
||||
undef_method :create
|
||||
|
||||
attribute :href
|
||||
|
||||
def all
|
||||
check_href!( :messages => "Ips href of a Network you want to enumerate" )
|
||||
if data = connection.get_network_ips(href).body[:IpAddress]
|
||||
load(data)
|
||||
end
|
||||
end
|
||||
|
||||
def get(uri)
|
||||
if data = connection.get_network_ip(uri).body
|
||||
new(data)
|
||||
end
|
||||
rescue Fog::Errors::NotFound
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,65 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
class Network < Fog::Vcloud::Model
|
||||
|
||||
identity :href
|
||||
|
||||
ignore_attributes :xmlns, :xmlns_xsi, :xmlns_xsd, :xmlns_i, :Configuration, :Id
|
||||
|
||||
attribute :name, :aliases => :Name
|
||||
#attribute :id, :aliases => :Id
|
||||
attribute :features, :aliases => :Features, :type => :array
|
||||
attribute :links, :aliases => :Link, :type => :array
|
||||
attribute :type
|
||||
attribute :gateway, :aliases => :GatewayAddress
|
||||
attribute :broadcast, :aliases => :BroadcastAddress
|
||||
attribute :address, :aliases => :Address
|
||||
attribute :extension_href, :aliases => :Href
|
||||
attribute :network_type, :aliases => :NetworkType
|
||||
attribute :vlan, :aliases => :Vlan
|
||||
attribute :friendly_name, :aliases => :FriendlyName
|
||||
|
||||
def ips
|
||||
load_unless_loaded!
|
||||
Fog::Vcloud::Compute::Ips.new( :connection => connection,
|
||||
:href => links.detect { |link| link[:name] == "IP Addresses" }[:href] )
|
||||
end
|
||||
|
||||
def save
|
||||
if @changed
|
||||
connection.configure_network( extension_href, _compose_network_data )
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def reload
|
||||
super
|
||||
merge_attributes(extension_data.body)
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def extension_data
|
||||
connection.get_network_extensions( extensions_link[:href] )
|
||||
end
|
||||
|
||||
def extensions_link
|
||||
links.detect { |link| link[:name] == name }
|
||||
end
|
||||
|
||||
def _compose_network_data
|
||||
{
|
||||
:id => id,
|
||||
:href => extension_href,
|
||||
:name => name,
|
||||
:address => address,
|
||||
:broadcast => broadcast,
|
||||
:gateway => gateway
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
require 'fog/compute/models/vcloud/network'
|
||||
|
||||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Networks < Fog::Vcloud::Collection
|
||||
|
||||
undef_method :create
|
||||
|
||||
model Fog::Vcloud::Compute::Network
|
||||
|
||||
attribute :href
|
||||
|
||||
def all
|
||||
check_href!("Vdc")
|
||||
if data = connection.get_vdc(href).body[:AvailableNetworks][:Network]
|
||||
load(data)
|
||||
end
|
||||
end
|
||||
|
||||
def get(uri)
|
||||
if data = connection.get_network(uri)
|
||||
new(data.body)
|
||||
end
|
||||
rescue Fog::Errors::NotFound
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,209 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
class Server < Fog::Vcloud::Model
|
||||
|
||||
identity :href, :aliases => :Href
|
||||
|
||||
ignore_attributes :xmlns, :xmlns_i, :xmlns_xsi, :xmlns_xsd
|
||||
|
||||
attribute :type
|
||||
attribute :name
|
||||
attribute :status
|
||||
attribute :network_connections, :aliases => :NetworkConnectionSection, :squash => :NetworkConnection
|
||||
attribute :os, :aliases => :OperatingSystemSection
|
||||
attribute :virtual_hardware, :aliases => :VirtualHardwareSection
|
||||
attribute :storage_size, :aliases => :size
|
||||
attribute :links, :aliases => :Link, :type => :array
|
||||
|
||||
def friendly_status
|
||||
load_unless_loaded!
|
||||
case status
|
||||
when '0'
|
||||
'creating'
|
||||
when '2'
|
||||
'off'
|
||||
when '4'
|
||||
'on'
|
||||
else
|
||||
'unkown'
|
||||
end
|
||||
end
|
||||
|
||||
def ready?
|
||||
load_unless_loaded!
|
||||
status == '2'
|
||||
end
|
||||
|
||||
def on?
|
||||
load_unless_loaded!
|
||||
status == '4'
|
||||
end
|
||||
|
||||
def off?
|
||||
load_unless_loaded!
|
||||
status == '2'
|
||||
end
|
||||
|
||||
def power_on
|
||||
power_operation( :power_on => :powerOn )
|
||||
end
|
||||
|
||||
def power_off
|
||||
power_operation( :power_off => :powerOff )
|
||||
end
|
||||
|
||||
def shutdown
|
||||
power_operation( :power_shutdown => :shutdown )
|
||||
end
|
||||
|
||||
def power_reset
|
||||
power_operation( :power_reset => :reset )
|
||||
end
|
||||
|
||||
def graceful_restart
|
||||
requires :href
|
||||
shutdown
|
||||
wait_for { off? }
|
||||
power_on
|
||||
end
|
||||
|
||||
def delete
|
||||
requires :href
|
||||
connection.delete_vapp( href)
|
||||
end
|
||||
|
||||
def name=(new_name)
|
||||
attributes[:name] = new_name
|
||||
@changed = true
|
||||
end
|
||||
|
||||
def cpus
|
||||
if cpu_mess
|
||||
{ :count => cpu_mess[:VirtualQuantity].to_i,
|
||||
:units => cpu_mess[:AllocationUnits] }
|
||||
end
|
||||
end
|
||||
|
||||
def cpus=(qty)
|
||||
@changed = true
|
||||
cpu_mess[:VirtualQuantity] = qty.to_s
|
||||
end
|
||||
|
||||
def memory
|
||||
if memory_mess
|
||||
{ :amount => memory_mess[:VirtualQuantity].to_i,
|
||||
:units => memory_mess[:AllocationUnits] }
|
||||
end
|
||||
end
|
||||
|
||||
def memory=(amount)
|
||||
@changed = true
|
||||
memory_mess[:VirtualQuantity] = amount.to_s
|
||||
end
|
||||
|
||||
def disks
|
||||
disk_mess.map do |dm|
|
||||
{ :number => dm[:AddressOnParent], :size => dm[:VirtualQuantity].to_i, :resource => dm[:HostResource] }
|
||||
end
|
||||
end
|
||||
|
||||
def add_disk(size)
|
||||
if @disk_change == :deleted
|
||||
raise RuntimeError, "Can't add a disk w/o saving changes or reloading"
|
||||
else
|
||||
@disk_change = :added
|
||||
load_unless_loaded!
|
||||
virtual_hardware[:Item] << { :ResourceType => '17',
|
||||
:AddressOnParent => (disk_mess.map { |dm| dm[:AddressOnParent] }.sort.last.to_i + 1).to_s,
|
||||
:VirtualQuantity => size.to_s }
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def delete_disk(number)
|
||||
if @disk_change == :added
|
||||
raise RuntimeError, "Can't delete a disk w/o saving changes or reloading"
|
||||
else
|
||||
@disk_change = :deleted
|
||||
load_unless_loaded!
|
||||
unless number == 0
|
||||
virtual_hardware[:Item].delete_if { |vh| vh[:ResourceType] == '17' && vh[:AddressOnParent].to_i == number }
|
||||
end
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def reload
|
||||
reset_tracking
|
||||
super
|
||||
end
|
||||
|
||||
def save
|
||||
if new_record?
|
||||
#Lame ...
|
||||
raise RuntimeError, "Should not be here"
|
||||
else
|
||||
if on?
|
||||
if @changed
|
||||
raise RuntimeError, "Can't save cpu, name or memory changes while the VM is on."
|
||||
end
|
||||
end
|
||||
connection.configure_vapp( href, _compose_vapp_data )
|
||||
end
|
||||
reset_tracking
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def reset_tracking
|
||||
@disk_change = false
|
||||
@changed = false
|
||||
end
|
||||
|
||||
def _compose_vapp_data
|
||||
{ :name => name,
|
||||
:cpus => cpus[:count],
|
||||
:memory => memory[:amount],
|
||||
:disks => disks
|
||||
}
|
||||
end
|
||||
|
||||
def memory_mess
|
||||
load_unless_loaded!
|
||||
if virtual_hardware && virtual_hardware[:Item]
|
||||
virtual_hardware[:Item].detect { |item| item[:ResourceType] == "4" }
|
||||
end
|
||||
end
|
||||
|
||||
def cpu_mess
|
||||
load_unless_loaded!
|
||||
if virtual_hardware && virtual_hardware[:Item]
|
||||
virtual_hardware[:Item].detect { |item| item[:ResourceType] == "3" }
|
||||
end
|
||||
end
|
||||
|
||||
def disk_mess
|
||||
load_unless_loaded!
|
||||
if virtual_hardware && virtual_hardware[:Item]
|
||||
virtual_hardware[:Item].select { |item| item[:ResourceType] == "17" }
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def power_operation(op)
|
||||
requires :href
|
||||
begin
|
||||
connection.send(op.keys.first, href + "/power/action/#{op.values.first}" )
|
||||
rescue Excon::Errors::InternalServerError => e
|
||||
#Frankly we shouldn't get here ...
|
||||
raise e unless e.to_s =~ /because it is already powered o(n|ff)/
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
require 'fog/compute/models/vcloud/server'
|
||||
|
||||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Servers < Fog::Vcloud::Collection
|
||||
|
||||
undef_method :create
|
||||
|
||||
model Fog::Vcloud::Compute::Server
|
||||
|
||||
attribute :href, :aliases => :Href
|
||||
|
||||
def all
|
||||
check_href!(:parent => "Vdc")
|
||||
load(_vapps)
|
||||
end
|
||||
|
||||
def get(uri)
|
||||
if data = connection.get_vapp(uri)
|
||||
new(data.body)
|
||||
end
|
||||
rescue Fog::Errors::NotFound
|
||||
nil
|
||||
end
|
||||
|
||||
def create( catalog_item_uri, options )
|
||||
options[:vdc_uri] = href
|
||||
options[:cpus] ||= 1
|
||||
options[:memory] ||= 512
|
||||
data = connection.instantiate_vapp_template( catalog_item_uri, options ).body
|
||||
object = new(data)
|
||||
object
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _resource_entities
|
||||
if Hash === resource_entities = connection.get_vdc(href).body[:ResourceEntities]
|
||||
resource_entities[:ResourceEntity]
|
||||
end
|
||||
end
|
||||
|
||||
def _vapps
|
||||
resource_entities = _resource_entities
|
||||
if resource_entities.nil?
|
||||
[]
|
||||
else
|
||||
resource_entities
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
class Task < Fog::Vcloud::Model
|
||||
|
||||
identity :href, :aliases => :Href
|
||||
|
||||
ignore_attributes :xmlns, :xmlns_i, :xmlns_xsi, :xmlns_xsd
|
||||
|
||||
attribute :status
|
||||
attribute :type
|
||||
attribute :result, :aliases => :Result
|
||||
attribute :owner, :aliases => :Owner
|
||||
attribute :start_time, :aliases => :startTime, :type => :time
|
||||
attribute :end_time, :aliases => :endTime, :type => :time
|
||||
attribute :error, :aliases => :Error
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
require 'fog/compute/models/vcloud/task'
|
||||
|
||||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Tasks < Fog::Vcloud::Collection
|
||||
|
||||
model Fog::Vcloud::Compute::Task
|
||||
|
||||
attribute :href, :aliases => :Href
|
||||
|
||||
def all
|
||||
check_href!
|
||||
if data = connection.get_task_list(href).body[:Task]
|
||||
load(data)
|
||||
end
|
||||
end
|
||||
|
||||
def get(uri)
|
||||
if data = connection.get_task(uri)
|
||||
new(data.body)
|
||||
end
|
||||
rescue Fog::Errors::NotFound
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,60 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
class Vdc < Fog::Vcloud::Model
|
||||
|
||||
identity :href
|
||||
|
||||
ignore_attributes :xmlns, :xmlns_xsi, :xmlns_xsd
|
||||
|
||||
attribute :name
|
||||
attribute :type
|
||||
attribute :description, :aliases => :Description
|
||||
attribute :other_links, :aliases => :Link
|
||||
attribute :compute_capacity, :aliases => :ComputeCapacity
|
||||
attribute :storage_capacity, :aliases => :StorageCapacity
|
||||
attribute :available_networks, :aliases => :AvailableNetworks, :squash => :Network
|
||||
attribute :resource_entities, :aliases => :ResourceEntities, :squash => :ResourceEntity
|
||||
attribute :deployed_vm_quota
|
||||
attribute :instantiated_vm_quota
|
||||
|
||||
def networks
|
||||
@networks ||= Fog::Vcloud::Compute::Networks.
|
||||
new( :connection => connection,
|
||||
:href => href )
|
||||
end
|
||||
|
||||
def servers
|
||||
@servers ||= Fog::Vcloud::Compute::Servers.
|
||||
new( :connection => connection,
|
||||
:href => href )
|
||||
end
|
||||
|
||||
def tasks
|
||||
@tasks ||= Fog::Vcloud::Compute::Tasks.
|
||||
new( :connection => connection,
|
||||
:href => href + "/tasksList" )
|
||||
end
|
||||
|
||||
def catalog
|
||||
@catalog ||= collection_based_on_type("application/vnd.vmware.vcloud.catalog+xml")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def collection_based_on_type(type, klass = nil)
|
||||
load_unless_loaded!
|
||||
test_links = other_links.kind_of?(Array) ? other_links : [other_links]
|
||||
if link = test_links.detect { |link| link[:type] == type }
|
||||
case type
|
||||
when "application/vnd.vmware.vcloud.catalog+xml"
|
||||
Fog::Vcloud::Compute::Catalog
|
||||
end.new( :connection => connection, :href => link[:href] )
|
||||
else
|
||||
[ ]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
require 'fog/compute/models/vcloud/vdc'
|
||||
|
||||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Vdcs < Collection
|
||||
|
||||
model Fog::Vcloud::Compute::Vdc
|
||||
|
||||
undef_method :create
|
||||
|
||||
def all
|
||||
data = connection.get_organization(organization_uri).body[:Link].select { |link| link[:type] == "application/vnd.vmware.vcloud.vdc+xml" }
|
||||
data.each { |link| link.delete_if { |key, value| [:rel].include?(key) } }
|
||||
load(data)
|
||||
end
|
||||
|
||||
def get(uri)
|
||||
if data = connection.get_vdc(uri)
|
||||
new(data.body)
|
||||
end
|
||||
rescue Fog::Errors::NotFound
|
||||
nil
|
||||
end
|
||||
|
||||
def organization_uri
|
||||
@organization_uri ||= connection.default_organization_uri
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def organization_uri=(new_organization_uri)
|
||||
@organization_uri = new_organization_uri
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
class Real
|
||||
|
||||
def validate_clone_vapp_options(options)
|
||||
valid_opts = [:name, :poweron]
|
||||
unless valid_opts.all? { |opt| options.keys.include?(opt) }
|
||||
raise ArgumentError.new("Required data missing: #{(valid_opts - options.keys).map(&:inspect).join(", ")}")
|
||||
end
|
||||
end
|
||||
|
||||
def generate_clone_vapp_request(uri, options)
|
||||
xml = Builder::XmlMarkup.new
|
||||
xml.CloneVAppParams(xmlns.merge!(:name => options[:name], :deploy => "true", :powerOn => options[:poweron])) {
|
||||
xml.VApp( :href => uri, :type => "application/vnd.vmware.vcloud.vApp+xml",
|
||||
:xmlns => "http://www.vmware.com/vcloud/v0.8")
|
||||
}
|
||||
end
|
||||
|
||||
def clone_vapp(vdc_uri, vapp_uri, options = {})
|
||||
unless options.has_key?(:poweron)
|
||||
options[:poweron] = "false"
|
||||
end
|
||||
|
||||
validate_clone_vapp_options(options)
|
||||
|
||||
request(
|
||||
:body => generate_clone_vapp_request(vapp_uri, options),
|
||||
:expects => 202,
|
||||
:headers => {'Content-Type' => 'application/vnd.vmware.vcloud.cloneVAppParams+xml'},
|
||||
:method => 'POST',
|
||||
:uri => vdc_uri + '/action/clonevapp',
|
||||
:parse => true
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,43 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
class Real
|
||||
|
||||
def validate_network_data(network_data, configure=false)
|
||||
valid_opts = [:id, :href, :name, :address, :broadcast, :gateway]
|
||||
unless valid_opts.all? { |opt| network_data.keys.include?(opt) }
|
||||
raise ArgumentError.new("Required data missing: #{(valid_opts - network_data.keys).map(&:inspect).join(", ")}")
|
||||
end
|
||||
end
|
||||
|
||||
def configure_network(network_uri, network_data)
|
||||
validate_network_data(network_data)
|
||||
|
||||
request(
|
||||
:body => generate_configure_network_request(network_data),
|
||||
:expects => 200,
|
||||
:headers => {'Content-Type' => 'application/vnd.vmware.vcloud.networkService+xml'},
|
||||
:method => 'PUT',
|
||||
:uri => network_uri,
|
||||
:parse => true
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_configure_network_request(network_data)
|
||||
builder = Builder::XmlMarkup.new
|
||||
builder.Network(xmlns) {
|
||||
builder.Id(network_data[:id])
|
||||
builder.Href(network_data[:href])
|
||||
builder.Name(network_data[:name])
|
||||
builder.Address(network_data[:address])
|
||||
builder.BroadcastAddress(network_data[:broadcast])
|
||||
builder.GatewayAddress(network_data[:gateway])
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,64 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
module Shared
|
||||
private
|
||||
|
||||
def validate_network_ip_data(network_ip_data)
|
||||
valid_opts = [:id, :href, :name, :status, :server]
|
||||
unless valid_opts.all? { |opt| network_ip_data.keys.include?(opt) }
|
||||
raise ArgumentError.new("Required data missing: #{(valid_opts - network_ip_data.keys).map(&:inspect).join(", ")}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
include Shared
|
||||
|
||||
def configure_network_ip(network_ip_uri, network_ip_data)
|
||||
validate_network_ip_data(network_ip_data)
|
||||
|
||||
request(
|
||||
:body => generate_configure_network_ip_request(network_ip_data),
|
||||
:expects => 200,
|
||||
:headers => {'Content-Type' => 'application/vnd.vmware.vcloud.ip+xml' },
|
||||
:method => 'PUT',
|
||||
:uri => network_ip_uri,
|
||||
:parse => true
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_configure_network_ip_request(network_ip_data)
|
||||
builder = Builder::XmlMarkup.new
|
||||
builder.IpAddress(xmlns) {
|
||||
builder.Id(network_ip_data[:id])
|
||||
builder.Href(network_ip_data[:href])
|
||||
builder.Name(network_ip_data[:name])
|
||||
builder.Status(network_ip_data[:status])
|
||||
builder.Server(network_ip_data[:server])
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
include Shared
|
||||
|
||||
def configure_network_ip(network_ip_uri, network_ip_data)
|
||||
validate_network_ip_data(network_ip_data)
|
||||
|
||||
if network_ip = mock_data.network_ip_from_href(network_ip_uri)
|
||||
|
||||
builder = Builder::XmlMarkup.new
|
||||
xml = network_ip_response(builder, network_ip, xmlns)
|
||||
|
||||
mock_it 200, xml, { 'Content-Type' => 'application/vnd.vmware.vcloud.ip+xml' }
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,56 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
module Shared
|
||||
private
|
||||
|
||||
def generate_configure_node_request(node_data)
|
||||
builder = Builder::XmlMarkup.new
|
||||
builder.NodeService(:"xmlns:i" => "http://www.w3.org/2001/XMLSchema-instance",
|
||||
:xmlns => "urn:tmrk:eCloudExtensions-2.0") {
|
||||
builder.Name(node_data[:name])
|
||||
builder.Enabled(node_data[:enabled].to_s)
|
||||
builder.Description(node_data[:description])
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Real
|
||||
include Shared
|
||||
|
||||
def configure_node(node_uri, node_data)
|
||||
validate_node_data(node_data, true)
|
||||
|
||||
request(
|
||||
:body => generate_configure_node_request(node_data),
|
||||
:expects => 200,
|
||||
:headers => {'Content-Type' => 'application/vnd.vmware.vcloud.nodeService+xml'},
|
||||
:method => 'PUT',
|
||||
:uri => node_uri,
|
||||
:parse => true
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
include Shared
|
||||
|
||||
def configure_node(node_uri, node_data)
|
||||
validate_node_data(node_data, true)
|
||||
|
||||
if node = mock_data.public_ip_internet_service_node_from_href(ensure_unparsed(node_uri))
|
||||
node.update(node_data)
|
||||
#if node_data[:enabled]
|
||||
# node.enabled = (node_data[:enabled] == "true") ? true : false
|
||||
#end
|
||||
mock_it 200, mock_node_service_response(node), { 'Content-Type' => 'application/vnd.vmware.vcloud.nodeService+xml' }
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,144 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
module Shared
|
||||
private
|
||||
|
||||
def validate_vapp_data(vapp_data)
|
||||
valid_opts = [:name, :cpus, :memory, :disks]
|
||||
unless valid_opts.all? { |opt| vapp_data.keys.include?(opt) }
|
||||
raise ArgumentError.new("Required Vapp data missing: #{(valid_opts - vapp_data.keys).map(&:inspect).join(", ")}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
include Shared
|
||||
|
||||
def generate_configure_vapp_request(vapp_uri, vapp_data)
|
||||
rasd_xmlns = { "xmlns" => "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" }
|
||||
|
||||
xml = Nokogiri::XML(request( :uri => vapp_uri).body)
|
||||
xml.root['name'] = vapp_data[:name]
|
||||
|
||||
#cpu
|
||||
xml.at("//xmlns:ResourceType[.='3']/..", rasd_xmlns).at('.//xmlns:VirtualQuantity', rasd_xmlns).content = vapp_data[:cpus]
|
||||
|
||||
#memory
|
||||
xml.at("//xmlns:ResourceType[.='4']/..", rasd_xmlns).at('.//xmlns:VirtualQuantity', rasd_xmlns).content = vapp_data[:memory]
|
||||
|
||||
#disks
|
||||
real_disks = xml.xpath("//xmlns:ResourceType[ .='17']/..", rasd_xmlns)
|
||||
real_disk_numbers = real_disks.map { |disk| disk.at('.//xmlns:AddressOnParent', rasd_xmlns).content }
|
||||
disk_numbers = vapp_data[:disks].map { |vdisk| vdisk[:number].to_s }
|
||||
|
||||
if vapp_data[:disks].length < real_disks.length
|
||||
#Assume we're removing a disk
|
||||
remove_disk_numbers = real_disk_numbers - disk_numbers
|
||||
remove_disk_numbers.each do |number|
|
||||
if result = xml.at("//xmlns:ResourceType[ .='17']/../xmlns:AddressOnParent[.='#{number}']/..", rasd_xmlns)
|
||||
result.remove
|
||||
end
|
||||
end
|
||||
elsif vapp_data[:disks].length > real_disks.length
|
||||
add_disk_numbers = disk_numbers - real_disk_numbers
|
||||
|
||||
add_disk_numbers.each do |number|
|
||||
new_disk = real_disks.first.dup
|
||||
new_disk.at('.//xmlns:AddressOnParent', rasd_xmlns).content = -1
|
||||
new_disk.at('.//xmlns:VirtualQuantity', rasd_xmlns).content = vapp_data[:disks].detect { |disk| disk[:number].to_s == number.to_s }[:size]
|
||||
real_disks.first.parent << new_disk
|
||||
end
|
||||
end
|
||||
|
||||
#puts xml.root.to_s
|
||||
xml.root.to_s
|
||||
|
||||
#builder = Builder::XmlMarkup.new
|
||||
#builder.Vapp(:href => vapp_uri.to_s,
|
||||
# :type => 'application/vnd.vmware.vcloud.vApp+xml',
|
||||
# :name => vapp_data[:name],
|
||||
# :status => 2,
|
||||
# :size => 0,
|
||||
# :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') {
|
||||
# #builder.VirtualHardwareSection(:xmlns => 'http://schemas.dmtf.org/ovf/envelope/1') {
|
||||
# builder.Section(:"xsi:type" => "q2:VirtualHardwareSection_Type", :xmlns => "http://schemas.dmtf.org/ovf/envelope/1", :"xmlns:q2" => "http://www.vmware.com/vcloud/v0.8") {
|
||||
# builder.Info('Virtual Hardware')
|
||||
# builder.Item(:xmlns => 'http://schemas.dmtf.org/ovf/envelope/1') {
|
||||
# #builder.Item {
|
||||
# builder.InstanceID(1, :xmlns => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData')
|
||||
# builder.ResourceType(3, :xmlns => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData')
|
||||
# builder.VirtualQuantity(vapp_data[:cpus], :xmlns => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData')
|
||||
# }
|
||||
# builder.Item(:xmlns => 'http://schemas.dmtf.org/ovf/envelope/1') {
|
||||
# #builder.Item {
|
||||
# builder.InstanceID(2, :xmlns => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData')
|
||||
# builder.ResourceType(4, :xmlns => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData')
|
||||
# builder.VirtualQuantity(vapp_data[:memory], :xmlns => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData')
|
||||
# }
|
||||
# vapp_data[:disks].each do |disk_data|
|
||||
# #builder.Item(:xmlns => 'http://schemas.dmtf.org/ovf/envelope/1') {
|
||||
# builder.Item {
|
||||
# builder.AddressOnParent(disk_data[:number], :xmlns => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData')
|
||||
# builder.HostResource(disk_data[:resource], :xmlns => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData')
|
||||
# builder.InstanceID(9, :xmlns => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData')
|
||||
# builder.ResourceType(17, :xmlns => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData')
|
||||
# builder.VirtualQuantity(disk_data[:size], :xmlns => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData')
|
||||
# }
|
||||
# end
|
||||
#
|
||||
# }
|
||||
#}
|
||||
end
|
||||
|
||||
def configure_vapp(vapp_uri, vapp_data)
|
||||
validate_vapp_data(vapp_data)
|
||||
|
||||
request(
|
||||
:body => generate_configure_vapp_request(vapp_uri, vapp_data),
|
||||
:expects => 202,
|
||||
:headers => {'Content-Type' => 'application/vnd.vmware.vcloud.vApp+xml' },
|
||||
:method => 'PUT',
|
||||
:uri => vapp_uri,
|
||||
:parse => true
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
include Shared
|
||||
|
||||
def configure_vapp(vapp_uri, vapp_data)
|
||||
validate_vapp_data(vapp_data)
|
||||
|
||||
if vapp = mock_data.virtual_machine_from_href(vapp_uri)
|
||||
vapp_data.each do |key, value|
|
||||
case key
|
||||
when :cpus, :memory
|
||||
vapp[key] = value
|
||||
when :disks
|
||||
addresses_to_delete = vapp.disks.map {|d| d.address } - value.map {|d| d[:number] }
|
||||
addresses_to_delete.each do |address_to_delete|
|
||||
vapp.disks.delete(vapp.disks.at_address(address_to_delete))
|
||||
end
|
||||
|
||||
current_addresses = vapp.disks.map {|d| d.address }
|
||||
disks_to_add = value.find_all {|d| !current_addresses.include?(d[:number]) }
|
||||
disks_to_add.each do |disk_to_add|
|
||||
vapp.disks << MockVirtualMachineDisk.new(:size => disk_to_add[:size] / 1024, :address => disk_to_add[:number])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mock_it 200, '', { "Location" => mock_data.base_url + "/some_tasks/1234" }
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :delete_node, 200, 'DELETE', {}, ""
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def delete_node(node_uri)
|
||||
if node = mock_data.public_ip_internet_service_node_from_href(ensure_unparsed(node_uri))
|
||||
node._parent.items.delete(node)
|
||||
mock_it 200, '', {}
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,27 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :delete_vapp, 202, "DELETE"
|
||||
end
|
||||
|
||||
class Mock
|
||||
def delete_vapp(vapp_uri)
|
||||
if virtual_machine = mock_data.virtual_machine_from_href(vapp_uri)
|
||||
vdc = virtual_machine._parent
|
||||
|
||||
if virtual_machine.status != 2
|
||||
mock_it 202, '', {}
|
||||
else
|
||||
vdc.virtual_machines.delete(virtual_machine)
|
||||
mock_it 202, '', { "Location" => mock_data.base_url + "/some_tasks/1234" }
|
||||
end
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_catalog
|
||||
end
|
||||
|
||||
class Mock
|
||||
def get_catalog(catalog_uri)
|
||||
catalog_uri = ensure_unparsed(catalog_uri)
|
||||
xml = nil
|
||||
|
||||
if catalog = mock_data.catalog_from_href(catalog_uri)
|
||||
builder = Builder::XmlMarkup.new
|
||||
|
||||
xml = builder.Catalog(xmlns.merge(
|
||||
:type => "application/vnd.vmware.vcloud.catalog+xml",
|
||||
:href => catalog.href,
|
||||
:name => catalog.name
|
||||
)) do |xml|
|
||||
xml.CatalogItems do |xml|
|
||||
catalog.items.each do |catalog_item|
|
||||
xml.CatalogItem(
|
||||
:type => "application/vnd.vmware.vcloud.catalogItem+xml",
|
||||
:href => catalog_item.href,
|
||||
:name => catalog_item.name
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if xml
|
||||
mock_it 200,
|
||||
xml, { 'Content-Type' => 'application/vnd.vmware.vcloud.catalog+xml' }
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_catalog_item
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def get_catalog_item(catalog_item_uri)
|
||||
if catalog_item = mock_data.catalog_item_from_href(catalog_item_uri)
|
||||
builder = Builder::XmlMarkup.new
|
||||
|
||||
xml = builder.CatalogItem(xmlns.merge(:href => catalog_item.href, :name => catalog_item.name)) do
|
||||
builder.Link(
|
||||
:rel => "down",
|
||||
:href => catalog_item.customization.href,
|
||||
:type => "application/vnd.vmware.vcloud.catalogItemCustomizationParameters+xml",
|
||||
:name => catalog_item.customization.name
|
||||
)
|
||||
|
||||
builder.Entity(
|
||||
:href => catalog_item.vapp_template.href,
|
||||
:type => "application/vnd.vmware.vcloud.vAppTemplate+xml",
|
||||
:name => catalog_item.vapp_template.name
|
||||
)
|
||||
|
||||
builder.Property(0, :key => "LicensingCost")
|
||||
end
|
||||
end
|
||||
|
||||
if xml
|
||||
mock_it 200, xml, {'Content-Type' => 'application/vnd.vmware.vcloud.catalogItem+xml'}
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_customization_options
|
||||
end
|
||||
|
||||
class Mock
|
||||
def get_customization_options(options_uri)
|
||||
builder = Builder::XmlMarkup.new
|
||||
xml = builder.CustomizationParameters(xmlns) do
|
||||
builder.CustomizeNetwork "true"
|
||||
builder.CustomizePassword "false"
|
||||
end
|
||||
|
||||
mock_it 200, xml, "Content-Type" => "application/vnd.vmware.vcloud.catalogItemCustomizationParameters+xml"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_network
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
|
||||
def get_network(network_uri)
|
||||
network_uri = ensure_unparsed(network_uri)
|
||||
|
||||
if network = mock_data.network_from_href(network_uri)
|
||||
builder = Builder::XmlMarkup.new
|
||||
xml = builder.Network(xmlns.merge(:href => network.href, :name => network.name, :type => "application/vnd.vmware.vcloud.network+xml")) {
|
||||
builder.Link(:rel => "down", :href => network.ip_collection.href, :type => "application/xml", :name => network.ip_collection.name)
|
||||
builder.Link(:rel => "down", :href => network.extensions.href, :type => "application/xml", :name => network.name)
|
||||
builder.Configuration {
|
||||
builder.Gateway(network.gateway)
|
||||
builder.Netmask(network.netmask)
|
||||
}
|
||||
if network.features
|
||||
builder.Features {
|
||||
network.features.each do |feature|
|
||||
builder.tag!(feature[:type], feature[:value])
|
||||
end
|
||||
}
|
||||
end
|
||||
}
|
||||
|
||||
mock_it 200, xml, { "Content-Type" => "application/vnd.vmware.vcloud.network+xml" }
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_network_extensions
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def get_network_extensions(network_extension_uri)
|
||||
if network_extension = mock_data.network_extension_from_href(ensure_unparsed(network_extension_uri))
|
||||
xml = Builder::XmlMarkup.new
|
||||
mock_it 200, xml.Network(xmlns) {
|
||||
xml.Address network_extension.address
|
||||
xml.Href network_extension.href
|
||||
xml.Id network_extension.object_id
|
||||
xml.Name network_extension.name
|
||||
xml.GatewayAddress network_extension.gateway
|
||||
xml.BroadcastAddress network_extension.broadcast
|
||||
xml.NetworkType network_extension.type
|
||||
xml.Vlan network_extension.vlan
|
||||
xml.FriendlyName network_extension.friendly_name
|
||||
}, { 'Content-Type' => "application/vnd.vmware.vcloud.network+xml" }
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
#
|
||||
# AFAICT this is basically undocumented ATM - 6/18/2010 - freeformz
|
||||
#
|
||||
|
||||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_network_ip
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def get_network_ip(network_ip_uri)
|
||||
if network_ip = mock_data.network_ip_from_href(network_ip_uri)
|
||||
builder = Builder::XmlMarkup.new
|
||||
xml = network_ip_response(builder, network_ip, xmlns)
|
||||
|
||||
mock_it 200, xml, { 'Content-Type' => 'application/vnd.vmware.vcloud.ip+xml' }
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
|
||||
def network_ip_response(builder, network_ip, xmlns = {})
|
||||
builder.IpAddress(xmlns) do
|
||||
builder.Id network_ip.object_id
|
||||
builder.Href network_ip.href
|
||||
builder.Name network_ip.name
|
||||
|
||||
builder.Status network_ip.status
|
||||
if network_ip.used_by
|
||||
builder.Server network_ip.used_by.name
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
#
|
||||
# AFAICT - This is basically undocumented - 6/18/2010 - freeformz
|
||||
#
|
||||
|
||||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_network_ips
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def get_network_ips(network_ips_uri)
|
||||
network_ips_uri = ensure_unparsed(network_ips_uri)
|
||||
|
||||
if network_ip_collection = mock_data.network_ip_collection_from_href(network_ips_uri)
|
||||
builder = Builder::XmlMarkup.new
|
||||
xml = builder.IpAddresses do
|
||||
network_ip_collection.ordered_ips.each do |network_ip|
|
||||
network_ip_response(builder, network_ip)
|
||||
end
|
||||
end
|
||||
|
||||
mock_it 200, xml, { 'Content-Type' => 'application/vnd.vmware.vcloud.ipAddressesList+xml' }
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,43 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_organization
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def get_organization(organization_uri)
|
||||
organization_uri = ensure_unparsed(organization_uri)
|
||||
if organization = mock_data.organization_from_href(organization_uri)
|
||||
xml = Builder::XmlMarkup.new
|
||||
|
||||
mock_it 200,
|
||||
xml.Org(xmlns.merge(:href => organization.href, :name => organization.name)) {
|
||||
|
||||
organization.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.catalog.href,
|
||||
:type => "application/vnd.vmware.vcloud.catalog+xml",
|
||||
:name => vdc.catalog.name)
|
||||
xml.Link(:rel => "down",
|
||||
:href => vdc.task_list.href,
|
||||
:type => "application/vnd.vmware.vcloud.tasksList+xml",
|
||||
:name => vdc.task_list.name)
|
||||
end
|
||||
},
|
||||
{'Content-Type' => "application/vnd.vmware.vcloud.org+xml" }
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_task
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_task_list
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,99 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_vapp
|
||||
end
|
||||
|
||||
class Mock
|
||||
def return_vapp_as_creating!(name)
|
||||
vapps_to_return_as_creating[name] = true
|
||||
end
|
||||
|
||||
def vapps_to_return_as_creating
|
||||
@vapps_to_return_as_creating ||= {}
|
||||
end
|
||||
|
||||
def get_vapp(vapp_uri)
|
||||
xml = nil
|
||||
|
||||
if vapp = mock_data.virtual_machine_from_href(vapp_uri)
|
||||
if vapps_to_return_as_creating[vapp.name]
|
||||
xml = generate_instantiate_vapp_template_response(vapp)
|
||||
else
|
||||
xml = generate_get_vapp_response(vapp)
|
||||
end
|
||||
end
|
||||
|
||||
if xml
|
||||
mock_it 200, xml, "Content-Type" => "application/vnd.vmware.vcloud.vApp+xml"
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_get_vapp_response(vapp)
|
||||
builder = Builder::XmlMarkup.new
|
||||
builder.VApp(xmlns.merge(
|
||||
:href => vapp.href,
|
||||
:type => "application/vnd.vmware.vcloud.vApp+xml",
|
||||
:name => vapp.name,
|
||||
:status => vapp.status,
|
||||
:size => vapp.size
|
||||
)) do
|
||||
builder.Link(:rel => "up", :href => vapp._parent.href, :type => "application/vnd.vmware.vcloud.vdc+xml")
|
||||
|
||||
builder.NetworkConnectionSection(:xmlns => "http://schemas.dmtf.org/ovf/envelope/1") do
|
||||
builder.NetworkConnection(:Network => "Internal", :xmlns => "http://www.vmware.com/vcloud/v0.8") do
|
||||
builder.IpAddress vapp.ip
|
||||
end
|
||||
end
|
||||
|
||||
builder.OperatingSystemSection(
|
||||
"d2p1:id" => 4,
|
||||
:xmlns => "http://schemas.dmtf.org/ovf/envelope/1",
|
||||
"xmlns:d2p1" => "http://schemas.dmtf.org/ovf/envelope/1") do
|
||||
builder.Info "The kind of installed guest operating system"
|
||||
builder.Description "Red Hat Enterprise Linux 5 (64-bit)"
|
||||
end
|
||||
|
||||
builder.VirtualHardwareSection(:xmlns => "http://schemas.dmtf.org/ovf/envelope/1") do
|
||||
builder.Info
|
||||
builder.System
|
||||
builder.Item do
|
||||
# CPUs
|
||||
builder.VirtualQuantity vapp.cpus
|
||||
builder.ResourceType 3
|
||||
end
|
||||
builder.Item do
|
||||
# memory
|
||||
builder.VirtualQuantity vapp.memory
|
||||
builder.ResourceType 4
|
||||
end
|
||||
builder.Item do
|
||||
# SCSI controller
|
||||
builder.Address 0
|
||||
builder.ResourceType 6
|
||||
builder.InstanceId 3
|
||||
end
|
||||
|
||||
# Hard Disks
|
||||
vapp.disks.each do |disk|
|
||||
builder.Item do
|
||||
builder.Parent 3
|
||||
builder.VirtualQuantity disk.vcloud_size
|
||||
builder.HostResource disk.vcloud_size
|
||||
builder.ResourceType 17
|
||||
builder.AddressOnParent disk.address
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_vapp_template
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,72 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :get_vdc
|
||||
end
|
||||
|
||||
class Mock
|
||||
def get_vdc(vdc_uri)
|
||||
vdc_uri = ensure_unparsed(vdc_uri)
|
||||
|
||||
if vdc = mock_data.vdc_from_href(vdc_uri)
|
||||
xml = Builder::XmlMarkup.new
|
||||
mock_it 200,
|
||||
xml.Vdc(xmlns.merge(:href => vdc.href, :name => vdc.name)) {
|
||||
xml.Link(:rel => "down",
|
||||
:href => vdc.catalog.href,
|
||||
:type => "application/vnd.vmware.vcloud.catalog+xml",
|
||||
:name => vdc.catalog.name)
|
||||
# xml.Link(:rel => "down",
|
||||
# :href => 'vdc.public_ip_collection.href',
|
||||
# :type => "application/vnd.tmrk.ecloud.publicIpsList+xml",
|
||||
# :name => 'vdc.public_ip_collection.name')
|
||||
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.virtual_machines.each do |virtual_machine|
|
||||
xml.ResourceEntity(:href => virtual_machine.href,
|
||||
:type => "application/vnd.vmware.vcloud.vApp+xml",
|
||||
:name => virtual_machine.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
|
|
@ -0,0 +1,137 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
module Shared
|
||||
private
|
||||
|
||||
def validate_instantiate_vapp_template_options(catalog_item_uri, options)
|
||||
valid_opts = [:name, :vdc_uri, :network_uri, :cpus, :memory, :row, :group]
|
||||
unless valid_opts.all? { |opt| options.keys.include?(opt) }
|
||||
raise ArgumentError.new("Required data missing: #{(valid_opts - options.keys).map(&:inspect).join(", ")}")
|
||||
end
|
||||
|
||||
# Figure out the template_uri
|
||||
catalog_item = get_catalog_item( catalog_item_uri ).body
|
||||
catalog_item[:Entity] = [ catalog_item[:Entity] ] if catalog_item[:Entity].is_a?(Hash)
|
||||
catalog_item[:Link] = [ catalog_item[:Link] ] if catalog_item[:Link].is_a?(Hash)
|
||||
|
||||
options[:template_uri] = begin
|
||||
catalog_item[:Entity].detect { |entity| entity[:type] == "application/vnd.vmware.vcloud.vAppTemplate+xml" }[:href]
|
||||
rescue
|
||||
raise RuntimeError.new("Unable to locate template uri for #{catalog_item_uri}")
|
||||
end
|
||||
|
||||
customization_options = begin
|
||||
customization_href = catalog_item[:Link].detect { |link| link[:type] == "application/vnd.vmware.vcloud.catalogItemCustomizationParameters+xml" }[:href]
|
||||
get_customization_options( customization_href ).body
|
||||
rescue
|
||||
raise RuntimeError.new("Unable to get customization options for #{catalog_item_uri}")
|
||||
end
|
||||
|
||||
# Check to see if we can set the password
|
||||
if options[:password] and customization_options[:CustomizePassword] == "false"
|
||||
raise ArgumentError.new("This catalog item (#{catalog_item_uri}) does not allow setting a password.")
|
||||
end
|
||||
|
||||
# According to the docs if CustomizePassword is "true" then we NEED to set a password
|
||||
if customization_options[:CustomizePassword] == "true" and ( options[:password].nil? or options[:password].empty? )
|
||||
raise ArgumentError.new("This catalog item (#{catalog_item_uri}) requires a :password to instantiate.")
|
||||
end
|
||||
end
|
||||
|
||||
def generate_instantiate_vapp_template_request(options)
|
||||
xml = Builder::XmlMarkup.new
|
||||
xml.InstantiateVAppTemplateParams(xmlns.merge!(:name => options[:name], :"xml:lang" => "en")) {
|
||||
xml.VAppTemplate(:href => options[:template_uri])
|
||||
xml.InstantiationParams {
|
||||
xml.ProductSection( :"xmlns:q1" => "http://www.vmware.com/vcloud/v0.8", :"xmlns:ovf" => "http://schemas.dmtf.org/ovf/envelope/1") {
|
||||
if options[:password]
|
||||
xml.Property( :xmlns => "http://schemas.dmtf.org/ovf/envelope/1", :"ovf:key" => "password", :"ovf:value" => options[:password] )
|
||||
end
|
||||
xml.Property( :xmlns => "http://schemas.dmtf.org/ovf/envelope/1", :"ovf:key" => "row", :"ovf:value" => options[:row] )
|
||||
xml.Property( :xmlns => "http://schemas.dmtf.org/ovf/envelope/1", :"ovf:key" => "group", :"ovf:value" => options[:group] )
|
||||
}
|
||||
xml.VirtualHardwareSection( :"xmlns:q1" => "http://www.vmware.com/vcloud/v0.8" ) {
|
||||
# # of CPUS
|
||||
xml.Item( :xmlns => "http://schemas.dmtf.org/ovf/envelope/1" ) {
|
||||
xml.InstanceID(1, :xmlns => "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData")
|
||||
xml.ResourceType(3, :xmlns => "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData")
|
||||
xml.VirtualQuantity(options[:cpus], :xmlns => "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData")
|
||||
}
|
||||
# Memory
|
||||
xml.Item( :xmlns => "http://schemas.dmtf.org/ovf/envelope/1" ) {
|
||||
xml.InstanceID(2, :xmlns => "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData")
|
||||
xml.ResourceType(4, :xmlns => "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData")
|
||||
xml.VirtualQuantity(options[:memory], :xmlns => "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData")
|
||||
}
|
||||
}
|
||||
xml.NetworkConfigSection {
|
||||
xml.NetworkConfig {
|
||||
xml.NetworkAssociation( :href => options[:network_uri] )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
class Real
|
||||
include Shared
|
||||
|
||||
def instantiate_vapp_template(catalog_item_uri, options = {})
|
||||
validate_instantiate_vapp_template_options(catalog_item_uri, options)
|
||||
|
||||
request(
|
||||
:body => generate_instantiate_vapp_template_request(options),
|
||||
:expects => 200,
|
||||
:headers => {'Content-Type' => 'application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml'},
|
||||
:method => 'POST',
|
||||
:uri => options[:vdc_uri] + '/action/instantiatevAppTemplate',
|
||||
:parse => true
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
class Mock
|
||||
include Shared
|
||||
|
||||
def instantiate_vapp_template(catalog_item_uri, options = {})
|
||||
validate_instantiate_vapp_template_options(catalog_item_uri, options)
|
||||
catalog_item = mock_data.catalog_item_from_href(catalog_item_uri)
|
||||
|
||||
xml = nil
|
||||
if vdc = mock_data.vdc_from_href(options[:vdc_uri])
|
||||
if network = mock_data.network_from_href(options[:network_uri])
|
||||
new_vm = MockVirtualMachine.new({ :name => options[:name], :ip => network.random_ip, :cpus => options[:cpus], :memory => options[:memory] }, vdc)
|
||||
new_vm.disks.push(*catalog_item.disks.dup)
|
||||
vdc.virtual_machines << new_vm
|
||||
|
||||
xml = generate_instantiate_vapp_template_response(new_vm)
|
||||
end
|
||||
end
|
||||
|
||||
if xml
|
||||
mock_it 200, xml, {'Content-Type' => 'application/xml'}
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_instantiate_vapp_template_response(vapp)
|
||||
builder = Builder::XmlMarkup.new
|
||||
builder.VApp(xmlns.merge(
|
||||
:href => vapp.href,
|
||||
:type => "application/vnd.vmware.vcloud.vApp+xml",
|
||||
:name => vapp.name,
|
||||
:status => 0,
|
||||
:size => 4
|
||||
)) {
|
||||
builder.Link(:rel => "up", :href => vapp._parent.href, :type => "application/vnd.vmware.vcloud.vdc+xml")
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
|
||||
|
||||
def login
|
||||
unauthenticated_request({
|
||||
:expects => 200,
|
||||
:headers => {
|
||||
'Authorization' => authorization_header
|
||||
},
|
||||
:method => 'POST',
|
||||
:parse => true,
|
||||
:uri => login_uri
|
||||
})
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
|
||||
def login
|
||||
xml = Builder::XmlMarkup.new
|
||||
|
||||
mock_it 200,
|
||||
xml.OrgList(xmlns) {
|
||||
mock_data.organizations.each do |organization|
|
||||
xml.Org( :type => "application/vnd.vmware.vcloud.org+xml", :href => organization.href, :name => organization.name )
|
||||
end
|
||||
},
|
||||
{ 'Set-Cookie' => 'vcloud-token=fc020a05-21d7-4f33-9b2a-25d8cd05a44e; path=/',
|
||||
'Content-Type' => 'application/vnd.vmware.vcloud.orgslist+xml' }
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :power_off, 202, 'POST'
|
||||
end
|
||||
|
||||
class Mock
|
||||
def power_off(vapp_uri)
|
||||
if vapp = mock_data.virtual_machine_from_href(vapp_uri)
|
||||
vapp.power_off!
|
||||
|
||||
builder = Builder::XmlMarkup.new
|
||||
mock_it 200, builder.Task(xmlns)
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :power_on, 202, 'POST'
|
||||
end
|
||||
|
||||
class Mock
|
||||
def power_on(vapp_uri)
|
||||
if vapp = mock_data.virtual_machine_from_href(vapp_uri)
|
||||
vapp.power_on!
|
||||
|
||||
builder = Builder::XmlMarkup.new
|
||||
mock_it 200, builder.Task(xmlns)
|
||||
else
|
||||
mock_error 200, "401 Unauthorized"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :power_reset, 202, 'POST'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
module Fog
|
||||
module Vcloud
|
||||
class Compute
|
||||
|
||||
class Real
|
||||
basic_request :power_shutdown, 204, 'POST'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,867 @@
|
|||
require 'fog/core'
|
||||
|
||||
module Fog
|
||||
module Vcloud
|
||||
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 Vcloud
|
||||
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 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_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 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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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 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 vcloud 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
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
module Fog
|
||||
module Vcloud
|
||||
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 Vcloud
|
||||
class Compute < Fog::Service
|
||||
|
||||
PATH = '/api/v1.0'
|
||||
PORT = 443
|
||||
SCHEME = 'https'
|
||||
|
||||
requires :vcloud_username, :vcloud_password, :vcloud_host
|
||||
recognizes :vcloud_port, :vcloud_scheme, :vcloud_path
|
||||
recognizes :provider # remove post deprecation
|
||||
|
||||
model_path 'fog/compute/models/vcloud'
|
||||
model :catalog_item
|
||||
model :catalog
|
||||
model :ip
|
||||
collection :ips
|
||||
model :network
|
||||
collection :networks
|
||||
model :server
|
||||
collection :servers
|
||||
model :task
|
||||
collection :tasks
|
||||
model :vdc
|
||||
collection :vdcs
|
||||
|
||||
request_path 'fog/compute/requests/vcloud'
|
||||
request :clone_vapp
|
||||
request :configure_network
|
||||
request :configure_network_ip
|
||||
request :configure_vapp
|
||||
request :delete_vapp
|
||||
request :get_catalog
|
||||
request :get_catalog_item
|
||||
request :get_customization_options
|
||||
request :get_network
|
||||
request :get_network_ip
|
||||
request :get_network_ips
|
||||
request :get_network_extensions
|
||||
request :get_organization
|
||||
request :get_task
|
||||
request :get_task_list
|
||||
request :get_vapp
|
||||
request :get_vapp_template
|
||||
request :get_vdc
|
||||
request :instantiate_vapp_template
|
||||
request :login
|
||||
request :power_off
|
||||
request :power_on
|
||||
request :power_reset
|
||||
request :power_shutdown
|
||||
|
||||
module Shared
|
||||
|
||||
|
||||
def default_organization_uri
|
||||
@default_organization_uri ||= begin
|
||||
unless @login_results
|
||||
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
|
||||
end
|
||||
end
|
||||
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
|
||||
|
||||
def ensure_unparsed(uri)
|
||||
if uri.is_a?(String)
|
||||
uri
|
||||
else
|
||||
uri.to_s
|
||||
end
|
||||
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
|
||||
|
||||
end
|
||||
|
||||
class Mock
|
||||
include Shared
|
||||
include MockDataClasses
|
||||
|
||||
def self.base_url
|
||||
"https://fakey.com/api/v0.8b-ext2.6"
|
||||
end
|
||||
|
||||
def self.data_reset
|
||||
@mock_data = nil
|
||||
end
|
||||
|
||||
def self.data( base_url = self.base_url )
|
||||
@mock_data ||= MockData.new.tap do |vcloud_mock_data|
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
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.each do |organization|
|
||||
organization.vdcs.each do |vdc|
|
||||
vdc.virtual_machines.each do |virtual_machine|
|
||||
virtual_machine.disks << MockVirtualMachineDisk.new(:size => 25 * 1024)
|
||||
virtual_machine.disks << MockVirtualMachineDisk.new(:size => 50 * 1024)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(options = {})
|
||||
require 'builder'
|
||||
require 'fog/core/parser'
|
||||
|
||||
end
|
||||
|
||||
def mock_data
|
||||
Fog::Vcloud::Compute::Mock.data
|
||||
end
|
||||
|
||||
def mock_error(expected, status, body='', headers={})
|
||||
raise Excon::Errors::Unauthorized.new("Expected(#{expected}) <=> Actual(#{status})")
|
||||
end
|
||||
|
||||
def mock_it(status, mock_data, mock_headers = {})
|
||||
response = Excon::Response.new
|
||||
|
||||
#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
|
||||
end
|
||||
|
||||
response.status = status
|
||||
response.headers = mock_headers
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
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
|
||||
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 })
|
||||
end
|
||||
EOS
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def initialize(options = {})
|
||||
require 'builder'
|
||||
require 'fog/core/parser'
|
||||
|
||||
@connections = {}
|
||||
@persistent = options[:persistent]
|
||||
|
||||
@host = options[:vcloud_host] || Fog::Vcloud::Compute::HOST
|
||||
@path = options[:vcloud_path] || Fog::Vcloud::Compute::PATH
|
||||
@port = options[:vcloud_port] || Fog::Vcloud::Compute::PORT
|
||||
@scheme = options[:vcloud_scheme] || Fog::Vcloud::Compute::SCHEME
|
||||
end
|
||||
|
||||
def default_organization_uri
|
||||
@default_organization_uri ||= begin
|
||||
unless @login_results
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def reload
|
||||
@connections.each_value { |k,v| v.reset if v }
|
||||
end
|
||||
|
||||
# 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
|
||||
|
||||
private
|
||||
|
||||
def ensure_parsed(uri)
|
||||
if uri.is_a?(String)
|
||||
URI.parse(uri)
|
||||
else
|
||||
uri
|
||||
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
|
||||
|
||||
# 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])
|
||||
end
|
||||
host_url = "#{params[:uri].scheme}://#{params[:uri].host}#{params[:uri].port ? ":#{params[:uri].port}" : ''}"
|
||||
|
||||
# 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)
|
||||
|
||||
# Set headers to an empty hash if none are set.
|
||||
headers = params[:headers] || {}
|
||||
|
||||
# Add our auth cookie to the headers
|
||||
if @cookie
|
||||
headers.merge!('Cookie' => @cookie)
|
||||
end
|
||||
|
||||
# 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
|
||||
|
||||
response.body = document.body
|
||||
end
|
||||
end
|
||||
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -21,6 +21,7 @@ require 'fog/providers/ninefold'
|
|||
require 'fog/providers/rackspace'
|
||||
require 'fog/providers/slicehost'
|
||||
require 'fog/providers/storm_on_demand'
|
||||
require 'fog/providers/vcloud'
|
||||
require 'fog/providers/virtual_box'
|
||||
require 'fog/providers/voxel'
|
||||
require 'fog/providers/zerigo'
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
require 'fog/core'
|
||||
|
||||
module Fog
|
||||
module Vcloud
|
||||
|
||||
extend Fog::Provider
|
||||
|
||||
service(:compute, 'compute/vcloud')
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
describe 'Vcloud' do
|
||||
it { Vcloud.should be_available }
|
||||
|
||||
it { Vcloud.should have_at_least(1).services }
|
||||
|
||||
describe "when indexing it like an array" do
|
||||
describe "with a service that exists" do
|
||||
it "should return something when indexed with a configured service" do
|
||||
Vcloud[:compute].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
|
|
@ -0,0 +1,33 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud::Compute::Ip", :type => :mock_vcloud_model do
|
||||
subject { @vcloud }
|
||||
|
||||
describe :class do
|
||||
subject { Fog::Vcloud::Compute::Ip }
|
||||
|
||||
it { should have_identity(:href) }
|
||||
it { should have_only_these_attributes([:href, :name, :status, :server, :id]) }
|
||||
end
|
||||
|
||||
context "with no uri" do
|
||||
subject { Fog::Vcloud::Compute::Ip.new() }
|
||||
|
||||
it { should have_all_attributes_be_nil }
|
||||
end
|
||||
|
||||
context "as a collection member" do
|
||||
subject { @ip = @vcloud.vdcs[0].networks[0].ips[0] }
|
||||
|
||||
it { should be_an_instance_of(Fog::Vcloud::Compute::Ip) }
|
||||
|
||||
its(:name) { should == @mock_data.network_ip_from_href(@ip.href).name }
|
||||
its(:status) { should == @mock_data.network_ip_from_href(@ip.href).status }
|
||||
its(:server) { should == @mock_data.network_ip_from_href(@ip.href).used_by.name }
|
||||
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud::Compute::Ips", :type => :mock_vcloud_model do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:ips) }
|
||||
|
||||
describe :class do
|
||||
subject { @vcloud.vdcs[0].networks[0].ips.class }
|
||||
its(:model) { should == Fog::Vcloud::Compute::Ip }
|
||||
end
|
||||
|
||||
describe :ips do
|
||||
subject { @vcloud.vdcs[0].networks[0].ips.reload }
|
||||
it { should_not respond_to(:create) }
|
||||
|
||||
it { should be_an_instance_of(Fog::Vcloud::Compute::Ips) }
|
||||
|
||||
its(:length) { should == 252 }
|
||||
|
||||
it { should have_members_of_the_right_model }
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud::Compute::Network", :type => :mock_vcloud_model do
|
||||
subject { @vcloud }
|
||||
|
||||
describe :class do
|
||||
subject { Fog::Vcloud::Compute::Network }
|
||||
|
||||
it { should have_identity(:href) }
|
||||
it { should have_only_these_attributes([:href, :name, :features, :links, :type, :gateway, :broadcast, :address, :extension_href, :network_type, :vlan, :friendly_name]) }
|
||||
end
|
||||
|
||||
context "with no uri" do
|
||||
|
||||
subject { Fog::Vcloud::Compute::Network.new() }
|
||||
|
||||
it { should have_all_attributes_be_nil }
|
||||
end
|
||||
|
||||
context "as a collection member" do
|
||||
subject { @vcloud.vdcs[0].networks[0].reload }
|
||||
|
||||
it { should be_an_instance_of(Fog::Vcloud::Compute::Network) }
|
||||
|
||||
its(:href) { should == @mock_network.href }
|
||||
its(:identity) { should == @mock_network.href }
|
||||
its(:name) { should == @mock_network.name }
|
||||
its(:type) { should == "application/vnd.vmware.vcloud.network+xml" }
|
||||
its(:gateway) { should == @mock_network.gateway }
|
||||
its(:broadcast) { should == @mock_network.broadcast }
|
||||
its(:address) { should == @mock_network.address }
|
||||
its(:extension_href) { should == @mock_network.extensions.href }
|
||||
its(:network_type) { should == @mock_network.extensions.type }
|
||||
its(:vlan) { should == @mock_network.extensions.vlan }
|
||||
its(:friendly_name) { should == @mock_network.extensions.friendly_name }
|
||||
|
||||
it { should have(1).features }
|
||||
|
||||
describe :features do
|
||||
let(:feature) { subject.features.first }
|
||||
specify { feature.should be_an_instance_of(Array) }
|
||||
specify { feature.last.should == @mock_network.features[0][:value] }
|
||||
end
|
||||
|
||||
it { should have(2).links }
|
||||
|
||||
describe :links do
|
||||
context "[0]" do
|
||||
let(:link) { subject.links[0] }
|
||||
specify { link[:rel].should == "down" }
|
||||
specify { link[:href].should == @mock_network_ip_collection.href }
|
||||
specify { link[:type].should == "application/xml" }
|
||||
specify { link[:name].should == @mock_network_ip_collection.name }
|
||||
end
|
||||
|
||||
context "[1]" do
|
||||
let(:link) { subject.links[1] }
|
||||
specify { link[:rel].should == "down" }
|
||||
specify { link[:href].should == @mock_network.extensions.href }
|
||||
specify { link[:type].should == "application/xml" }
|
||||
specify { link[:name].should == @mock_network.name }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud::Compute::Networks", :type => :mock_vcloud_model do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:networks) }
|
||||
|
||||
describe :class do
|
||||
subject { @vcloud.networks.class }
|
||||
its(:model) { should == Fog::Vcloud::Compute::Network }
|
||||
end
|
||||
|
||||
describe :networks do
|
||||
subject { @vcloud.vdcs[0].networks }
|
||||
it { should_not respond_to(:create) }
|
||||
|
||||
it { should be_an_instance_of(Fog::Vcloud::Compute::Networks) }
|
||||
|
||||
its(:length) { should == 2 }
|
||||
|
||||
it { should have_members_of_the_right_model }
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud::Compute::Vdc", :type => :mock_vcloud_model do
|
||||
subject { @vcloud }
|
||||
|
||||
describe :class do
|
||||
subject { Fog::Vcloud::Compute::Server }
|
||||
|
||||
it { should have_identity(:href) }
|
||||
it { should have_only_these_attributes([:href, :type, :name, :status, :network_connections, :os, :virtual_hardware, :storage_size, :links]) }
|
||||
end
|
||||
|
||||
context "with no uri" do
|
||||
subject { Fog::Vcloud::Compute::Server.new() }
|
||||
|
||||
it { should have_all_attributes_be_nil }
|
||||
end
|
||||
|
||||
context "as a collection member" do
|
||||
subject { @vcloud.vdcs[0].servers.first }
|
||||
|
||||
its(:href) { should == @mock_vm.href }
|
||||
its(:identity) { should == @mock_vm.href }
|
||||
its(:name) { should == @mock_vm.name }
|
||||
its(:cpus) { should == { :count => @mock_vm.cpus, :units => nil } }
|
||||
its(:memory) { should == { :amount => @mock_vm.memory, :units => nil } }
|
||||
its(:disks) { should == @mock_vm.to_configure_vapp_hash[:disks] }
|
||||
|
||||
describe "question methods" do
|
||||
describe "#ready?" do
|
||||
before { subject.power_off }
|
||||
|
||||
it { should be_ready }
|
||||
end
|
||||
|
||||
describe "#on?" do
|
||||
before { subject.power_on }
|
||||
|
||||
it { should be_on }
|
||||
end
|
||||
|
||||
describe "#off?" do
|
||||
before { subject.power_off }
|
||||
|
||||
it { should be_off }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "as a new server without all info" do
|
||||
before { @vcloud.return_vapp_as_creating! "test123" }
|
||||
|
||||
subject { @vcloud.vdcs[0].servers.create(@mock_catalog_item.href, { :name => "test123", :row => "foo", :group => "bar", :network_uri => @mock_network.href }) }
|
||||
|
||||
its(:cpus) { should be_nil }
|
||||
its(:memory) { should be_nil }
|
||||
its(:disks) { should == [] }
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
|
@ -0,0 +1,60 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud::Compute::Vdc", :type => :mock_vcloud_model do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:get_vdc) }
|
||||
|
||||
describe :class do
|
||||
subject { Fog::Vcloud::Compute::Vdc }
|
||||
|
||||
it { should have_identity(:href) }
|
||||
it { should have_only_these_attributes([:href, :name, :type, :description, :other_links, :compute_capacity, :storage_capacity, :available_networks,
|
||||
:resource_entities, :deployed_vm_quota, :instantiated_vm_quota]) }
|
||||
end
|
||||
|
||||
context "with no uri" do
|
||||
|
||||
subject { Fog::Vcloud::Compute::Vdc.new() }
|
||||
|
||||
it { should have_all_attributes_be_nil }
|
||||
end
|
||||
|
||||
context "as a collection member" do
|
||||
subject { @vcloud.vdcs[0].reload }
|
||||
|
||||
its(:href) { should == @mock_vdc.href }
|
||||
its(:identity) { should == @mock_vdc.href }
|
||||
its(:name) { should == @mock_vdc.name }
|
||||
its(:other_links) { should have(4).items }
|
||||
its(:resource_entities) { should have(3).items }
|
||||
its(:available_networks) { should have(2).items }
|
||||
|
||||
its(:compute_capacity) { should == {:Memory =>
|
||||
{:Allocated => @mock_vdc.memory_allocated.to_s, :Units => "bytes * 2^20"},
|
||||
:DeployedVmsQuota =>
|
||||
{:Limit => "-1", :Used => "-1"},
|
||||
:InstantiatedVmsQuota =>
|
||||
{:Limit => "-1", :Used => "-1"},
|
||||
:Cpu =>
|
||||
{:Allocated => @mock_vdc.cpu_allocated.to_s, :Units => "hz * 10^6"}} }
|
||||
|
||||
its(:storage_capacity) { should == {:Allocated => @mock_vdc.storage_allocated.to_s, :Used => @mock_vdc.storage_used.to_s, :Units => "bytes * 10^9"} }
|
||||
|
||||
its(:deployed_vm_quota) { should == nil }
|
||||
its(:instantiated_vm_quota) { should == nil }
|
||||
|
||||
its(:networks) { should have(2).networks }
|
||||
its(:servers) { should have(3).servers }
|
||||
|
||||
#FIXME: need to mock tasks related requests first
|
||||
#its(:tasks) { should have(0).tasks }
|
||||
|
||||
#FIXME: need to mock catalog related requests first
|
||||
#its(:catalog) { should have(0).entries }
|
||||
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud::Compute::Vdcs", :type => :mock_vcloud_model do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:vdcs) }
|
||||
|
||||
describe :class do
|
||||
subject { @vcloud.vdcs.class }
|
||||
its(:model) { should == Fog::Vcloud::Compute::Vdc }
|
||||
end
|
||||
|
||||
describe :vdcs do
|
||||
subject { @vcloud.vdcs }
|
||||
it { should_not respond_to(:create) }
|
||||
|
||||
it { should be_an_instance_of(Fog::Vcloud::Compute::Vdcs) }
|
||||
|
||||
its(:length) { should == 2 }
|
||||
|
||||
it { should have_members_of_the_right_model }
|
||||
|
||||
its(:organization_uri) { should == @mock_organization.href }
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:configure_network_ip) }
|
||||
|
||||
describe "#configure_network_ip" do
|
||||
let(:original_network_ip) { @vcloud.get_network_ip(@mock_network_ip.href).body }
|
||||
let(:network_ip_data) do
|
||||
{
|
||||
:id => original_network_ip[:Id],
|
||||
:href => original_network_ip[:Href],
|
||||
:name => original_network_ip[:Name],
|
||||
:status => original_network_ip[:Status],
|
||||
:server => original_network_ip[:Server]
|
||||
}
|
||||
end
|
||||
|
||||
context "with a valid network ip uri" do
|
||||
subject { @vcloud.configure_network_ip(@mock_network_ip.href, network_ip_data) }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
|
||||
describe "#body" do
|
||||
subject { @vcloud.configure_network_ip(@mock_network_ip.href, network_ip_data).body }
|
||||
|
||||
#Stuff that shouldn't change
|
||||
its(:Href) { should == @mock_network_ip.href }
|
||||
its(:Id) { should == @mock_network_ip.object_id.to_s }
|
||||
its(:Name) { should == @mock_network_ip.ip }
|
||||
its(:Status) { should == @mock_network_ip.status }
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "with a nodes uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.configure_network_ip(URI.parse('https://www.fakey.c/piv8vc99'), network_ip_data) } }
|
||||
|
||||
it_should_behave_like "a request for a resource that doesn't exist"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
|
@ -0,0 +1,71 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
shared_examples_for "a successful configure vapp" do
|
||||
specify { after_vapp_data.should == new_vapp_data }
|
||||
|
||||
describe "#body" do
|
||||
its(:body) { should == '' }
|
||||
end
|
||||
|
||||
describe "#headers" do
|
||||
its(:headers) { should include("Location") }
|
||||
end
|
||||
end
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:configure_vapp) }
|
||||
|
||||
let(:original_vapp_data) { vapp_data.dup }
|
||||
let(:vapp_data) { @mock_vm.to_configure_vapp_hash }
|
||||
let(:changed_vapp_data) { {} }
|
||||
let(:new_vapp_data) { vapp_data.update(changed_vapp_data) }
|
||||
let(:after_vapp_data) { @mock_vm.to_configure_vapp_hash }
|
||||
|
||||
describe "#configure_vapp" do
|
||||
context "with a valid vapp uri" do
|
||||
before { original_vapp_data; subject }
|
||||
|
||||
subject { @vcloud.configure_vapp(@mock_vm.href, new_vapp_data) }
|
||||
|
||||
context "when changing nothing" do
|
||||
it_should_behave_like "a successful configure vapp"
|
||||
end
|
||||
|
||||
context "when changing CPUs" do
|
||||
let(:changed_vapp_data) { { :cpus => @mock_vm.cpus * 2 } }
|
||||
|
||||
it_should_behave_like "a successful configure vapp"
|
||||
end
|
||||
|
||||
context "when changing memory" do
|
||||
let(:changed_vapp_data) { { :memory => @mock_vm.memory * 2 } }
|
||||
|
||||
it_should_behave_like "a successful configure vapp"
|
||||
end
|
||||
|
||||
context "when removing a disk" do
|
||||
let(:changed_vapp_data) { { :disks => original_vapp_data[:disks][0...1] } }
|
||||
|
||||
it_should_behave_like "a successful configure vapp"
|
||||
end
|
||||
|
||||
context "when adding a disk" do
|
||||
let(:changed_vapp_data) { { :disks => original_vapp_data[:disks] + [{ :number => "5", :size => 10 * 1024 * 1024, :resource => (10 * 1024 * 1024).to_s }] } }
|
||||
|
||||
it_should_behave_like "a successful configure vapp"
|
||||
end
|
||||
end
|
||||
|
||||
context "with an internet_services_uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.configure_vapp(URI.parse('https://www.fakey.c/piv8vc99'), new_vapp_data) } }
|
||||
|
||||
it_should_behave_like "a request for a resource that doesn't exist"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
shared_examples_for "a failed vapp deletion" do
|
||||
it "should not change the mock data" do
|
||||
expect { subject }.to change { @mock_vdc.virtual_machines.count }.by(0)
|
||||
end
|
||||
|
||||
it "should not change the model data" do
|
||||
expect { subject }.to change { vdc.reload.servers.reload.count }.by(0)
|
||||
end
|
||||
|
||||
describe "#body" do
|
||||
its(:body) { should == '' }
|
||||
end
|
||||
|
||||
describe "#headers" do
|
||||
its(:headers) { should_not include("Location") }
|
||||
end
|
||||
end
|
||||
|
||||
#FIXME: Make this more sane with rspec2
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:delete_vapp) }
|
||||
|
||||
describe "#delete_vapp" do
|
||||
context "with a valid vapp uri" do
|
||||
subject { @vcloud.delete_vapp(@mock_vm.href) }
|
||||
let(:vdc) { @vcloud.vdcs.first }
|
||||
|
||||
context "when there are no internet service nodes attached" do
|
||||
it_should_behave_like("all delete responses")
|
||||
|
||||
it "should change the mock data" do
|
||||
expect { subject }.to change { @mock_vdc.virtual_machines.count }.by(-1)
|
||||
end
|
||||
|
||||
it "should change the model data" do
|
||||
expect { subject }.to change { vdc.reload.servers.reload.count }.by(-1)
|
||||
end
|
||||
|
||||
describe "#body" do
|
||||
its(:body) { should == '' }
|
||||
end
|
||||
|
||||
describe "#headers" do
|
||||
its(:headers) { should include("Location") }
|
||||
end
|
||||
end
|
||||
|
||||
context "when the VM is powered on" do
|
||||
before do
|
||||
@mock_vm.power_on!
|
||||
end
|
||||
|
||||
it_should_behave_like "all delete responses"
|
||||
it_should_behave_like "a failed vapp deletion"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "with a vapp uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.delete_vapp(URI.parse('https://www.fakey.c/piv8vc99')) } }
|
||||
|
||||
it_should_behave_like "a request for a resource that doesn't exist"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:get_catalog_item) }
|
||||
|
||||
describe "#get_catalog_item" do
|
||||
context "with a valid catalog_item_uri" do
|
||||
before { @catalog_item = @vcloud.get_catalog_item(@vcloud.vdcs.first.catalog.first.href) }
|
||||
subject { @catalog_item }
|
||||
let(:mock_data_catalog_item) { @mock_data.catalog_item_from_href(@catalog_item.body[:href]) }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
it { should have_headers_denoting_a_content_type_of("application/vnd.vmware.vcloud.catalogItem+xml") }
|
||||
|
||||
describe "#body" do
|
||||
subject { @catalog_item.body }
|
||||
|
||||
it { should have(8).items }
|
||||
|
||||
it_should_behave_like("it has the standard vcloud v0.8 xmlns attributes") # 3 keys
|
||||
|
||||
its(:name) { should == "Item 0" }
|
||||
|
||||
it { should include(:Entity) }
|
||||
it { should include(:Link) }
|
||||
it { should include(:Property) }
|
||||
|
||||
describe "Entity" do
|
||||
subject { @catalog_item.body[:Entity] }
|
||||
let(:mock_data_catalog_item) { @mock_data.catalog_item_from_href(@catalog_item.body[:href]) }
|
||||
|
||||
it { should have(3).items }
|
||||
|
||||
its(:name) { should == mock_data_catalog_item.name }
|
||||
its(:type) { should == "application/vnd.vmware.vcloud.vAppTemplate+xml" }
|
||||
its(:href) { should == mock_data_catalog_item.vapp_template.href }
|
||||
end
|
||||
|
||||
describe "Link" do
|
||||
subject { @catalog_item.body[:Link] }
|
||||
|
||||
it { should have(4).items }
|
||||
|
||||
its(:rel) { should == "down" }
|
||||
its(:href) { should == mock_data_catalog_item.customization.href }
|
||||
its(:name) { should == mock_data_catalog_item.customization.name }
|
||||
its(:type) { should == "application/vnd.vmware.vcloud.catalogItemCustomizationParameters+xml" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a catalog uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.get_catalog(URI.parse('https://www.fakey.com/api/v0.8/vdc/999/catalog')) } }
|
||||
|
||||
it_should_behave_like("a request for a resource that doesn't exist")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:get_catalog) }
|
||||
|
||||
describe "#get_catalog" do
|
||||
context "with a valid vdc catalog_uri" do
|
||||
before { @catalog = @vcloud.get_catalog(@mock_vdc.catalog.href) }
|
||||
subject { @catalog }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
it { should have_headers_denoting_a_content_type_of("application/vnd.vmware.vcloud.catalog+xml") }
|
||||
|
||||
describe "#body" do
|
||||
subject { @catalog.body }
|
||||
|
||||
it { should have(7).items }
|
||||
|
||||
it_should_behave_like "it has the standard vcloud v0.8 xmlns attributes" # 3 keys
|
||||
|
||||
its(:name) { should == @mock_vdc.catalog.name }
|
||||
|
||||
it { should include(:CatalogItems) }
|
||||
|
||||
describe "CatalogItems" do
|
||||
subject { @catalog.body[:CatalogItems] }
|
||||
|
||||
it { should have(1).items }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a catalog uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.get_catalog(URI.parse('https://www.fakey.com/api/v0.8/vdc/999/catalog')) } }
|
||||
|
||||
it_should_behave_like "a request for a resource that doesn't exist"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
|
@ -0,0 +1,39 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:get_customization_options) }
|
||||
|
||||
describe "#get_customization_options" do
|
||||
context "with a valid catalog_item customizations uri" do
|
||||
let(:catalog_item) { @vcloud.get_catalog_item(@vcloud.vdcs.first.catalog.first.href) }
|
||||
|
||||
before { @customization_options = @vcloud.get_customization_options(catalog_item.body[:Link][:href]) }
|
||||
subject { @customization_options }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
it { should have_headers_denoting_a_content_type_of("application/vnd.vmware.vcloud.catalogItemCustomizationParameters+xml") }
|
||||
|
||||
describe "#body" do
|
||||
subject { @customization_options.body }
|
||||
|
||||
it { should have(5).items }
|
||||
|
||||
it_should_behave_like "it has the standard vcloud v0.8 xmlns attributes" # 3 keys
|
||||
|
||||
specify { subject[:CustomizeNetwork].should == "true" }
|
||||
specify { subject[:CustomizePassword].should == "false" }
|
||||
end
|
||||
end
|
||||
|
||||
context "with a catalog uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.get_catalog(URI.parse('https://www.fakey.com/api/v0.8/vdc/999/catalog')) } }
|
||||
|
||||
it_should_behave_like "a request for a resource that doesn't exist"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
|
@ -0,0 +1,39 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:get_network_ip) }
|
||||
|
||||
describe "#get_network_ip" do
|
||||
context "with a valid ip_uri" do
|
||||
before do
|
||||
@ip = @vcloud.get_network_ip(@mock_network_ip.href)
|
||||
end
|
||||
|
||||
subject { @ip }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
it { should have_headers_denoting_a_content_type_of("application/vnd.vmware.vcloud.ip+xml") }
|
||||
|
||||
describe "#body" do
|
||||
subject { @ip.body }
|
||||
|
||||
its(:Name) { should == @mock_network_ip.name }
|
||||
its(:Href) { should == @mock_network_ip.href }
|
||||
its(:Id) { should == @mock_network_ip.object_id.to_s }
|
||||
its(:Status) { should == @mock_network_ip.status }
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
context "with an ip_uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.get_network_ip('https://www.fakey.c/piv89') } }
|
||||
|
||||
it_should_behave_like "a request for a resource that doesn't exist"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
|
@ -0,0 +1,56 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:get_network_ips) }
|
||||
|
||||
describe "#get_network_ips" do
|
||||
context "with a valid VDC network ips_uri" do
|
||||
before { @ips = @vcloud.get_network_ips(@mock_network_ip_collection.href) }
|
||||
subject { @ips }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
it { should have_headers_denoting_a_content_type_of("application/vnd.vmware.vcloud.ipAddressesList+xml") }
|
||||
|
||||
describe "#body" do
|
||||
subject { @ips.body }
|
||||
|
||||
it { should have(1).item }
|
||||
|
||||
context "[:IpAddress]" do
|
||||
subject { @ips.body[:IpAddress] }
|
||||
|
||||
# Note the real TMRK API returns only "assigned" ips currently
|
||||
# This is a bug they've slated to fix in the next release.
|
||||
it { should have(252).addresses }
|
||||
|
||||
end
|
||||
|
||||
context "one we know is assigned" do
|
||||
let(:address) { @ips.body[:IpAddress][0] }
|
||||
specify { address.should have(5).keys }
|
||||
specify { address[:Status].should == "Assigned" }
|
||||
specify { address[:Server].should == "Broom 1" }
|
||||
specify { address[:Name].should == "1.2.3.3" }
|
||||
end
|
||||
|
||||
context "one we know is not assigned" do
|
||||
let(:address) { @ips.body[:IpAddress][100] }
|
||||
specify { address.should have(4).keys }
|
||||
specify { address[:Status].should == "Available" }
|
||||
specify { address.has_key?(:Server).should be_false }
|
||||
specify { address[:Name].should == "1.2.3.103" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a network ips uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.get_network_ips(URI.parse('https://www.fakey.c/piv8vc99')) } }
|
||||
|
||||
it_should_behave_like("a request for a resource that doesn't exist")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,49 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:get_network) }
|
||||
|
||||
describe "#get_network" do
|
||||
context "with a valid network uri" do
|
||||
before { @network = @vcloud.get_network(@mock_network.href) }
|
||||
subject { @network }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
it { should have_headers_denoting_a_content_type_of("application/vnd.vmware.vcloud.network+xml") }
|
||||
|
||||
describe "#body" do
|
||||
subject { @network.body }
|
||||
|
||||
it { should have(9).keys }
|
||||
|
||||
it_should_behave_like "it has the standard vcloud v0.8 xmlns attributes" # 3 keys
|
||||
|
||||
its(:type) { should == "application/vnd.vmware.vcloud.network+xml" }
|
||||
its(:Features) { should == @mock_network.features.map {|f| { f[:type] => f[:value] } }.first }
|
||||
its(:href) { should == @mock_network.href }
|
||||
its(:name) { should == @mock_network.name }
|
||||
its(:Configuration) { should == { :Gateway => @mock_network.gateway, :Netmask => @mock_network.netmask } }
|
||||
its(:Link) { should ==
|
||||
[{:type => "application/xml",
|
||||
:rel => "down",
|
||||
:href => @mock_network_ip_collection.href,
|
||||
:name => "IP Addresses"},
|
||||
{:type => "application/xml",
|
||||
:rel => "down",
|
||||
:href => @mock_network_extensions.href,
|
||||
:name => @mock_network_extensions.name}]}
|
||||
end
|
||||
end
|
||||
|
||||
context "with a network uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.get_network(URI.parse('https://www.fakey.com/api/v0.8/network/999')) } }
|
||||
it_should_behave_like "a request for a resource that doesn't exist"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe Fog::Vcloud, :type => :mock_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 responses"
|
||||
it { should have_headers_denoting_a_content_type_of("application/vnd.vmware.vcloud.org+xml") }
|
||||
|
||||
describe "#body" do
|
||||
subject { @organization.body }
|
||||
|
||||
|
||||
let(:links) { subject[:Link] }
|
||||
|
||||
it { should have(6).keys }
|
||||
|
||||
it_should_behave_like "it has the standard vcloud v0.8 xmlns attributes" # 3 keys
|
||||
it { should have_key_with_value(:href, @mock_organization.href)}
|
||||
it { should have_key_with_value(:name, @mock_organization.name) }
|
||||
it { should have_key_with_array(:Link, @mock_organization.vdcs.map { |vdc|
|
||||
[{ :type => "application/vnd.vmware.vcloud.vdc+xml",
|
||||
:href => vdc.href,
|
||||
:name => vdc.name,
|
||||
:rel => "down" },
|
||||
{ :type => "application/vnd.vmware.vcloud.catalog+xml",
|
||||
:href => vdc.catalog.href,
|
||||
:name => vdc.catalog.name,
|
||||
:rel => "down" },
|
||||
{ :type => "application/vnd.vmware.vcloud.tasksList+xml",
|
||||
:href => vdc.task_list.href,
|
||||
:name => vdc.task_list.name,
|
||||
:rel => "down" }]
|
||||
}.flatten) }
|
||||
|
||||
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
|
||||
end
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:get_vapp) }
|
||||
|
||||
describe "#get_vapp" do
|
||||
context "with a valid vapp_uri" do
|
||||
before { @vapp = @vcloud.get_vapp(@mock_vm.href) }
|
||||
subject { @vapp }
|
||||
let(:vapp_id) { @vapp.body[:href].split("/").last }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
it { should have_headers_denoting_a_content_type_of("application/vnd.vmware.vcloud.vApp+xml") }
|
||||
|
||||
describe "#body" do
|
||||
subject { @vapp.body }
|
||||
|
||||
specify { subject.keys.sort_by(&:to_s).should == [:Link, :NetworkConnectionSection,
|
||||
:OperatingSystemSection, :VirtualHardwareSection,
|
||||
:href, :name,
|
||||
:size, :status,
|
||||
:type, :xmlns,
|
||||
:xmlns_xsd, :xmlns_xsi] }
|
||||
|
||||
it_should_behave_like("it has the standard vcloud v0.8 xmlns attributes") # 3 keys
|
||||
|
||||
its(:href) { should == @mock_vm.href }
|
||||
its(:name) { should == @mock_vm.name }
|
||||
its(:status) { should == @mock_vm.status.to_s }
|
||||
its(:size) { should == (@mock_vm.disks.inject(0) {|s, d| s += d[:size].to_i } * 1024).to_s }
|
||||
|
||||
describe "Link" do
|
||||
subject { @vapp.body[:Link] }
|
||||
|
||||
its(:rel) { should == "up" }
|
||||
its(:type) { should == "application/vnd.vmware.vcloud.vdc+xml" }
|
||||
its(:href) { should == @mock_vdc.href }
|
||||
end
|
||||
|
||||
describe "NetworkConnectionSection" do
|
||||
subject { @vapp.body[:NetworkConnectionSection] }
|
||||
|
||||
it { should include(:NetworkConnection) }
|
||||
|
||||
describe "NetworkConnection" do
|
||||
subject { @vapp.body[:NetworkConnectionSection][:NetworkConnection] }
|
||||
|
||||
its(:IpAddress) { should == @mock_vm.ip }
|
||||
end
|
||||
end
|
||||
|
||||
describe "OperatingSystemSection" do
|
||||
subject { @vapp.body[:OperatingSystemSection] }
|
||||
|
||||
its(:Info) { should == "The kind of installed guest operating system" }
|
||||
its(:Description) { should == "Red Hat Enterprise Linux 5 (64-bit)" }
|
||||
end
|
||||
|
||||
describe "VirtualHardwareSection" do
|
||||
subject { @vapp.body[:VirtualHardwareSection] }
|
||||
|
||||
specify { subject.keys.sort_by(&:to_s).should == [:Info, :Item, :System, :xmlns] }
|
||||
|
||||
describe "Item" do
|
||||
subject { @vapp.body[:VirtualHardwareSection][:Item] }
|
||||
|
||||
it { should have(5).items }
|
||||
|
||||
specify { subject.map {|i| i[:ResourceType] }.uniq.sort.should == %w(3 4 6 17).sort }
|
||||
|
||||
describe "CPU" do
|
||||
subject { @vapp.body[:VirtualHardwareSection][:Item].detect {|i| i[:ResourceType] == "3" } }
|
||||
|
||||
its(:VirtualQuantity) { should == @mock_vm.cpus.to_s }
|
||||
end
|
||||
|
||||
describe "memory" do
|
||||
subject { @vapp.body[:VirtualHardwareSection][:Item].detect {|i| i[:ResourceType] == "4" } }
|
||||
|
||||
its(:VirtualQuantity) { should == @mock_vm.memory.to_s }
|
||||
end
|
||||
|
||||
describe "SCSI controller" do
|
||||
subject { @vapp.body[:VirtualHardwareSection][:Item].detect {|i| i[:ResourceType] == "6" } }
|
||||
|
||||
its(:Address) { should == "0" }
|
||||
end
|
||||
|
||||
describe "Hard Disks" do
|
||||
subject { @vapp.body[:VirtualHardwareSection][:Item].find_all {|i| i[:ResourceType] == "17" } }
|
||||
|
||||
it { should have(2).disks }
|
||||
|
||||
describe "#1" do
|
||||
subject { @vapp.body[:VirtualHardwareSection][:Item].find_all {|i| i[:ResourceType] == "17" }[0] }
|
||||
|
||||
its(:AddressOnParent) { should == "0" }
|
||||
its(:VirtualQuantity) { should == (1024 * @mock_vm.disks[0][:size].to_i).to_s }
|
||||
its(:HostResource) { should == (1024 * @mock_vm.disks[0][:size].to_i).to_s }
|
||||
end
|
||||
|
||||
describe "#2" do
|
||||
subject { @vapp.body[:VirtualHardwareSection][:Item].find_all {|i| i[:ResourceType] == "17" }[1] }
|
||||
|
||||
its(:AddressOnParent) { should == "1" }
|
||||
its(:VirtualQuantity) { should == (1024 * @mock_vm.disks[1][:size].to_i).to_s }
|
||||
its(:HostResource) { should == (1024 * @mock_vm.disks[1][:size].to_i).to_s }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a vapp uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.get_vapp(URI.parse('https://www.fakey.com/api/v0.8/vApp/99999')) } }
|
||||
|
||||
it_should_behave_like("a request for a resource that doesn't exist")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,86 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_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(URI.parse(@mock_vdc.href)) }
|
||||
subject { @vdc }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
it { should have_headers_denoting_a_content_type_of("application/vnd.vmware.vcloud.vdc+xml") }
|
||||
|
||||
describe "#body" do
|
||||
subject { @vdc.body }
|
||||
|
||||
it { should have(11).items }
|
||||
|
||||
it_should_behave_like("it has the standard vcloud v0.8 xmlns attributes") # 3 keys
|
||||
|
||||
its(:href) { should == @mock_vdc.href }
|
||||
its(:name) { should == @mock_vdc.name }
|
||||
|
||||
its(:Description) { should == "" }
|
||||
its(:StorageCapacity) { should == {:Units => "bytes * 10^9", :Allocated => @mock_vdc.storage_allocated.to_s, :Used => @mock_vdc.storage_used.to_s } }
|
||||
its(:ComputeCapacity) { should == {:InstantiatedVmsQuota => { :Limit => "-1", :Used => "-1" },
|
||||
:Memory => { :Units => "bytes * 2^20", :Allocated => @mock_vdc.memory_allocated.to_s },
|
||||
:Cpu => { :Units => "hz * 10^6", :Allocated => @mock_vdc.cpu_allocated.to_s },
|
||||
:DeployedVmsQuota => { :Limit => "-1", :Used => "-1" } } }
|
||||
|
||||
describe "link 0" do
|
||||
subject { @vdc.body[:Link] }
|
||||
it { should have(4).attributes }
|
||||
its(:type) { should == "application/vnd.vmware.vcloud.catalog+xml" }
|
||||
its(:rel) { should == "down" }
|
||||
its(:href) { should == @mock_vdc.catalog.href }
|
||||
its(:name) { should == @mock_vdc.catalog.name }
|
||||
end
|
||||
|
||||
let(:resource_entities) { subject[:ResourceEntities][:ResourceEntity] }
|
||||
specify { resource_entities.should have(@mock_vdc.virtual_machines.length).vapps }
|
||||
|
||||
describe "[:ResourceEntities][:ResourceEntity]" do
|
||||
context "[0]" do
|
||||
subject { @vdc.body[:ResourceEntities][:ResourceEntity][0] }
|
||||
it { should be_a_vapp_link_to(@mock_vdc.virtual_machines[0]) }
|
||||
end
|
||||
context "[1]" do
|
||||
subject { @vdc.body[:ResourceEntities][:ResourceEntity][1] }
|
||||
it { should be_a_vapp_link_to(@mock_vdc.virtual_machines[1]) }
|
||||
end
|
||||
context "[2]" do
|
||||
subject { @vdc.body[:ResourceEntities][:ResourceEntity][2] }
|
||||
it { should be_a_vapp_link_to(@mock_vdc.virtual_machines[2]) }
|
||||
end
|
||||
end
|
||||
|
||||
its(:name) { should == @mock_vdc[:name] }
|
||||
|
||||
let(:available_networks) { subject[:AvailableNetworks][:Network] }
|
||||
specify { available_networks.should have(2).networks }
|
||||
|
||||
describe "[:AvailableNetworks][:Network]" do
|
||||
context "[0]" do
|
||||
subject { @vdc.body[:AvailableNetworks][:Network][0] }
|
||||
it { should be_a_network_link_to(@mock_vdc.networks[0]) }
|
||||
end
|
||||
context "[1]" do
|
||||
subject { @vdc.body[:AvailableNetworks][:Network][1] }
|
||||
it { should be_a_network_link_to(@mock_vdc.networks[1]) }
|
||||
end
|
||||
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
|
||||
end
|
|
@ -0,0 +1,95 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe "Fog::Vcloud", :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:instantiate_vapp_template) }
|
||||
|
||||
describe "#instantiate_vapp_template" do
|
||||
let(:vdc) { @vcloud.vdcs.first }
|
||||
let(:mock_vdc) { @mock_vdc }
|
||||
|
||||
let(:catalog_item) { vdc.catalog.first }
|
||||
let(:mock_catalog_item) { @vcloud.mock_data.catalog_item_from_href(catalog_item.href) }
|
||||
|
||||
let(:new_vapp_data) do
|
||||
{
|
||||
:name => "foobar",
|
||||
:network_uri => @mock_network.href,
|
||||
:row => "test row",
|
||||
:group => "test group",
|
||||
:memory => 1024,
|
||||
:cpus => 2,
|
||||
:vdc_uri => @mock_vdc.href
|
||||
}
|
||||
end
|
||||
|
||||
let(:added_mock_data) { mock_vdc.virtual_machines.last }
|
||||
|
||||
context "with a valid data" do
|
||||
let(:template_instantiation) { @vcloud.instantiate_vapp_template(catalog_item.href, new_vapp_data) }
|
||||
subject { template_instantiation }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
it { should have_headers_denoting_a_content_type_of("application/xml") }
|
||||
|
||||
it "updates the mock data properly" do
|
||||
expect { subject }.to change { mock_vdc.virtual_machines.size }.by(1)
|
||||
end
|
||||
|
||||
describe "added mock data" do
|
||||
before { template_instantiation }
|
||||
subject { added_mock_data }
|
||||
|
||||
it { should be_an_instance_of(Fog::Vcloud::MockDataClasses::MockVirtualMachine) }
|
||||
|
||||
its(:name) { should == new_vapp_data[:name] }
|
||||
its(:memory) { should == new_vapp_data[:memory] }
|
||||
its(:cpus) { should == new_vapp_data[:cpus] }
|
||||
# WHAT
|
||||
specify { subject._parent.should == mock_vdc }
|
||||
specify { subject.status.should == 2 }
|
||||
specify { subject.disks.should == mock_catalog_item.disks }
|
||||
# its(:_parent) { should == mock_vdc }
|
||||
#its(:status) { should == 2 }
|
||||
#its(:disks) { should == mock_catalog_item.disks }
|
||||
end
|
||||
|
||||
describe "server based on added mock data" do
|
||||
before { template_instantiation }
|
||||
subject { vdc.servers.reload.detect {|s| s.href == added_mock_data.href }.reload }
|
||||
|
||||
its(:name) { should == new_vapp_data[:name] }
|
||||
end
|
||||
|
||||
describe "#body" do
|
||||
subject { template_instantiation.body }
|
||||
|
||||
it { should have(9).items }
|
||||
|
||||
it_should_behave_like("it has the standard vcloud v0.8 xmlns attributes") # 3 keys
|
||||
|
||||
its(:href) { should == added_mock_data.href }
|
||||
its(:type) { should == "application/vnd.vmware.vcloud.vApp+xml" }
|
||||
its(:name) { should == new_vapp_data[:name] }
|
||||
its(:status) { should == "0" }
|
||||
its(:size) { should == "4" }
|
||||
|
||||
it { should include(:Link) }
|
||||
|
||||
describe "Link" do
|
||||
subject { template_instantiation.body[:Link] }
|
||||
|
||||
it { should have(3).keys }
|
||||
|
||||
its(:rel) { should == "up" }
|
||||
its(:type) { should == "application/vnd.vmware.vcloud.vdc+xml" }
|
||||
# WHAT
|
||||
its(:href) { blah = vdc.href; should == blah }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe Fog::Vcloud, :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it_should_behave_like "all login requests"
|
||||
end
|
||||
else
|
||||
end
|
|
@ -0,0 +1,34 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe Fog::Vcloud, :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:power_off) }
|
||||
|
||||
describe :power_off, :type => :vcloud_request do
|
||||
context "with a valid vapp uri" do
|
||||
before { @mock_vm.power_on!; @power_off = @vcloud.power_off(@mock_vm.href(:power_off)) }
|
||||
subject { @power_off }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
#it { should have_headers_denoting_a_content_type_of "application/vnd.vmware.vcloud.network+xml" }
|
||||
|
||||
specify { @mock_vm.status.should == 2 }
|
||||
|
||||
describe :body do
|
||||
subject { @power_off.body }
|
||||
|
||||
it_should_behave_like "it has the standard vcloud v0.8 xmlns attributes" # 3 keys
|
||||
end
|
||||
end
|
||||
|
||||
context "with a vapp uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.power_off(URI.parse('https://www.fakey.com/api/v0.8/vapp/9999')) } }
|
||||
it_should_behave_like "a request for a resource that doesn't exist"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe Fog::Vcloud, :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should respond_to(:power_on) }
|
||||
|
||||
describe :power_on, :type => :vcloud_request do
|
||||
context "with a valid vapp uri" do
|
||||
before { @mock_vm.power_off!; @power_on = @vcloud.power_on(@mock_vm.href(:power_on)) }
|
||||
subject { @power_on }
|
||||
|
||||
it_should_behave_like "all responses"
|
||||
#it { should have_headers_denoting_a_content_type_of "application/vnd.vmware.vcloud.network+xml" }
|
||||
|
||||
specify { @mock_vm.status.should == 4 }
|
||||
|
||||
describe :body do
|
||||
subject { @power_on.body }
|
||||
|
||||
it_should_behave_like "it has the standard vcloud v0.8 xmlns attributes" # 3 keys
|
||||
end
|
||||
end
|
||||
|
||||
context "with a vapp uri that doesn't exist" do
|
||||
subject { lambda { @vcloud.power_on(URI.parse('https://www.fakey.com/api/v0.8/vapp/9999')) } }
|
||||
it_should_behave_like "a request for a resource that doesn't exist"
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
|
@ -0,0 +1,362 @@
|
|||
require 'spec'
|
||||
require 'pp'
|
||||
|
||||
require 'fog'
|
||||
require 'fog/bin'
|
||||
require 'fog/bin/vcloud'
|
||||
|
||||
module Spec
|
||||
module Example
|
||||
module Subject
|
||||
module ExampleGroupMethods
|
||||
def its(attribute, &block)
|
||||
describe(attribute) do
|
||||
define_method(:subject) { s = super(); s.is_a?(Hash) ? s[attribute] : s.send(attribute) }
|
||||
it(&block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#Initialize this to a known seed
|
||||
srand 1234
|
||||
|
||||
Fog.mock! if ENV['FOG_MOCK']
|
||||
|
||||
def arrayify(item)
|
||||
item.is_a?(Array) ? item : [ item ]
|
||||
end
|
||||
|
||||
def vcloud_disabled_default_monitor
|
||||
{:url_send_string=>nil, :receive_string=>nil, :response_timeout=>2, :retries=>3, :is_enabled=>"true", :down_time=>30, :type=>"Disabled", :http_headers=>nil, :interval=>5, :downtime=>nil}
|
||||
end
|
||||
|
||||
shared_examples_for "all responses" do
|
||||
it { should be_an_instance_of(Excon::Response) }
|
||||
it { should respond_to(:body) }
|
||||
it { should respond_to(:headers) }
|
||||
it { should have_at_least(1).body }
|
||||
it { should have_at_least(0).headers }
|
||||
its(:body) { should be_an_instance_of(Hash) }
|
||||
its(:headers) { should be_an_instance_of(Hash) }
|
||||
end
|
||||
|
||||
shared_examples_for "all delete responses" do
|
||||
it { should be_an_instance_of(Excon::Response) }
|
||||
it { should respond_to(:body) }
|
||||
it { should respond_to(:headers) }
|
||||
its(:headers) { should be_an_instance_of(Hash) }
|
||||
end
|
||||
|
||||
shared_examples_for "it has a Content-Type header" do
|
||||
its(:headers) { should include("Content-Type") }
|
||||
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 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 responses")
|
||||
|
||||
its(:headers) { should include("Set-Cookie") }
|
||||
|
||||
describe "#body" do
|
||||
subject { @login.body }
|
||||
|
||||
it { should have(4).items }
|
||||
it_should_behave_like("it has the standard vcloud v0.8 xmlns attributes") # 3 keys
|
||||
it { should include(:Org) }
|
||||
|
||||
describe ":Org" do
|
||||
subject { arrayify(@login.body[:Org]) }
|
||||
|
||||
specify do
|
||||
subject.each do |org|
|
||||
org.should include(:type)
|
||||
org[:type].should be_of_type("application/vnd.vmware.vcloud.org+xml")
|
||||
org.should include(:name)
|
||||
org[:name].should be_an_instance_of(String)
|
||||
org.should include(:href)
|
||||
org[:href].should(be_a_url)
|
||||
end
|
||||
end
|
||||
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 "it has the proper xmlns_xsi" do
|
||||
its(:xmlns_xsi) { should == "http://www.w3.org/2001/XMLSchema-instance" }
|
||||
end
|
||||
|
||||
shared_examples_for "it has the proper xmlns_xsd" do
|
||||
its(:xmlns_xsd) { should == "http://www.w3.org/2001/XMLSchema" }
|
||||
end
|
||||
|
||||
shared_examples_for "it has the standard xmlns attributes" do
|
||||
it_should_behave_like("it has the proper xmlns_xsi")
|
||||
it_should_behave_like("it has the proper xmlns_xsd")
|
||||
end
|
||||
|
||||
shared_examples_for "it has the standard vcloud v0.8 xmlns attributes" do
|
||||
it_should_behave_like("it has a vcloud v0.8 xmlns")
|
||||
it_should_behave_like("it has the standard xmlns attributes")
|
||||
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 == URI.parse(@mock_vdc[:href] + "/catalog") }
|
||||
end
|
||||
|
||||
shared_examples_for "a 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 network links" do
|
||||
it { should have(2).networks }
|
||||
|
||||
describe "[0]" do
|
||||
subject { @vdc.body.networks[0] }
|
||||
it_should_behave_like "a network link"
|
||||
its(:href) { should == URI.parse(@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 network link"
|
||||
its(:href) { should == URI.parse(@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 == URI.parse(@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 == URI.parse(@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 == URI.parse(@mock_vdc[:vms][2][:href]) }
|
||||
its(:name) { should == @mock_vdc[:vms][2][:name] }
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Example::ExampleGroupFactory.register(:mock_vcloud_request, Class.new(Spec::Example::ExampleGroup))
|
||||
Spec::Example::ExampleGroupFactory.register(:mock_vcloud_model, Class.new(Spec::Example::ExampleGroup))
|
||||
Spec::Example::ExampleGroupFactory.register(:mock_vcloud_request, Class.new(Spec::Example::ExampleGroup))
|
||||
Spec::Example::ExampleGroupFactory.register(:mock_vcloud_model, Class.new(Spec::Example::ExampleGroup))
|
||||
Spec::Example::ExampleGroupFactory.register(:vcloud_request, Class.new(Spec::Example::ExampleGroup))
|
||||
Spec::Example::ExampleGroupFactory.register(:vcloud_request, Class.new(Spec::Example::ExampleGroup))
|
||||
|
||||
def setup_generic_mock_data
|
||||
@mock_organization = @mock_data.organizations.first
|
||||
@mock_vdc = @mock_organization.vdcs.first
|
||||
@mock_vm = @mock_vdc.virtual_machines.first
|
||||
@mock_network = @mock_vdc.networks.first
|
||||
end
|
||||
|
||||
def setup_vcloud_mock_data
|
||||
@base_url = Fog::Vcloud::Compute::Mock.base_url
|
||||
@mock_data = Fog::Vcloud::Compute::Mock.data
|
||||
setup_generic_mock_data
|
||||
# @mock_service = @mock_service_collection.items.first
|
||||
@mock_catalog = @mock_vdc.catalog
|
||||
@mock_catalog_item = @mock_catalog.items.first
|
||||
@mock_network_ip_collection = @mock_network.ip_collection
|
||||
@mock_network_ip = @mock_network_ip_collection.items.values.first
|
||||
@mock_network_extensions = @mock_network.extensions
|
||||
@base_url = Fog::Vcloud::Compute::Mock.base_url
|
||||
@mock_data = Fog::Vcloud::Compute::Mock.data
|
||||
end
|
||||
|
||||
Spec::Runner.configure do |config|
|
||||
config.after(:all) do
|
||||
Fog::Vcloud::Compute::Mock.data_reset
|
||||
end
|
||||
|
||||
config.before(:each, :type => :vcloud_request) do
|
||||
@vcloud = Fog::Vcloud::Compute.new(Fog.credentials[:vcloud][:vcloud])
|
||||
end
|
||||
|
||||
config.before(:each, :type => :mock_vcloud_request) do
|
||||
Fog::Vcloud::Compute::Mock.data_reset
|
||||
setup_vcloud_mock_data
|
||||
@vcloud = Fog::Vcloud::Compute.new(:vcloud_username => "foo", :vcloud_password => "bar", :vcloud_host => "fakey.com")
|
||||
end
|
||||
config.before(:each, :type => :mock_vcloud_model) do
|
||||
Fog::Vcloud::Compute::Mock.data_reset
|
||||
setup_vcloud_mock_data
|
||||
@vcloud = Fog::Vcloud::Compute.new(:vcloud_username => "foo", :vcloud_password => "bar", :vcloud_host => "fakey.com")
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :have_only_these_attributes do |expected|
|
||||
match do |actual|
|
||||
attributes = actual.instance_variable_get('@attributes')
|
||||
attributes.all? { |attribute| expected.include?(attribute) } && ( expected.length == attributes.length )
|
||||
end
|
||||
|
||||
failure_message_for_should do |actual|
|
||||
msg = "Expected: [#{expected.map{|e| ":#{e}"}.join(", ")}]\n"
|
||||
msg += "Got: [#{actual.instance_variable_get('@attributes').map{|a| ":#{a}"}.join(", ")}]"
|
||||
msg
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :have_identity do |expected|
|
||||
match do |actual|
|
||||
actual.instance_variable_get('@identity').should == expected
|
||||
end
|
||||
|
||||
failure_message_for_should do |actual|
|
||||
"Expected: '#{expected}', but got: '#{actual.instance_variable_get('@identity')}'"
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :have_members_of_the_right_model do
|
||||
match do |actual|
|
||||
actual.all? { |member| member.is_a?(actual.model) }
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :have_key_with_value do |expected_key, expected_value|
|
||||
match do |actual|
|
||||
actual.has_key?(expected_key) && actual[expected_key] == expected_value
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :have_key_with_array do |expected_key, expected_array|
|
||||
match do |actual|
|
||||
actual[expected_key].all? { |item| expected_array.include?(item) } && actual[expected_key].length == expected_array.length
|
||||
end
|
||||
failure_message_for_should do |actual|
|
||||
"Items not found in array:\n#{expected_array.select { |expected_item| !actual[expected_key].include?(expected_item) }.map { |item| item.inspect }.join("\n")}\n" +
|
||||
"Original items:\n#{actual[expected_key].map { |item| item.inspect }.join("\n") }\n"+
|
||||
"Length Difference: #{expected_array.length - actual[expected_key].length}"
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :have_headers_denoting_a_content_type_of do |expected|
|
||||
match do |actual|
|
||||
actual.headers["Content-Type"] == expected
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :have_keys_with_values do |expected|
|
||||
match do |actual|
|
||||
actual.each_pair.all? do |key, value|
|
||||
expected.keys.include?(key) && expected[key] == value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :be_a_vapp_link_to do |expected|
|
||||
match do |actual|
|
||||
actual.is_a?(Hash) and
|
||||
actual[:type] == "application/vnd.vmware.vcloud.vApp+xml" and
|
||||
actual[:href] == expected.href and
|
||||
actual[:name] == expected.name
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :be_a_network_link_to do |expected|
|
||||
match do |actual|
|
||||
actual.is_a?(Hash) and
|
||||
actual[:type] == "application/vnd.vmware.vcloud.network+xml" and
|
||||
actual[:href] == expected.href and
|
||||
actual[:name] == expected.name
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :have_all_attributes_be_nil do
|
||||
match do |actual|
|
||||
actual.class.attributes.all? { |attribute| actual.send(attribute.to_sym) == nil }
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :be_a_url do
|
||||
match do |actual|
|
||||
actual.match(/^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/ix)
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :be_either_a_hash_or_array do
|
||||
match do |actual|
|
||||
actual.is_a?(Hash) || actual.is_a?(Array)
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :be_a_known_vmware_type do
|
||||
match do |actual|
|
||||
["application/vnd.vmware.vcloud.org+xml"].include?(actual)
|
||||
end
|
||||
end
|
||||
|
||||
Spec::Matchers.define :be_of_type do |type|
|
||||
match do |actual|
|
||||
actual == type ||
|
||||
if actual.is_a?(Hash) && actual[:type]
|
||||
actual[:type] == type
|
||||
end ||
|
||||
if actual.respond_to(:type)
|
||||
actual.type == type
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
require 'vcloud/spec_helper'
|
||||
|
||||
if Fog.mocking?
|
||||
describe Fog::Vcloud, :type => :mock_vcloud_request do
|
||||
subject { @vcloud }
|
||||
|
||||
it { should be_an_instance_of(Fog::Vcloud::Compute::Mock) }
|
||||
|
||||
it { should respond_to(:default_organization_uri) }
|
||||
|
||||
its(:default_organization_uri) { should == @mock_organization.href }
|
||||
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue