1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00
fog--fog/lib/fog/vcloud_director/compute.rb
2013-10-02 02:58:20 +01:00

443 lines
14 KiB
Ruby

require 'fog/vcloud_director'
require 'fog/compute'
require 'fog/vcloud_director/requests/compute/helper'
class VcloudDirectorParser < Fog::Parsers::Base
def extract_attributes(attributes_xml)
attributes = {}
until attributes_xml.empty?
if attributes_xml.first.is_a?(Array)
until attributes_xml.first.empty?
attribute = attributes_xml.first.shift
attributes[attribute.localname.to_sym] = attribute.value
end
else
attribute = attributes_xml.shift
attributes[attribute.localname.to_sym] = attribute.value
end
end
attributes
end
end
class NonLoaded
end
module Fog
module Compute
class VcloudDirector < Fog::Service
module Defaults
PATH = '/api'
PORT = 443
SCHEME = 'https'
API_VERSION = '5.1'
end
module Errors
class ServiceError < Fog::Errors::Error; end
class Task < ServiceError; end
end
requires :vcloud_director_username, :vcloud_director_password, :vcloud_director_host
recognizes :vcloud_director_api_version
secrets :vcloud_director_password
model_path 'fog/vcloud_director/models/compute'
model :catalog
collection :catalogs
model :organization
collection :organizations
model :catalog_item
collection :catalog_items
model :vdc
collection :vdcs
model :vapp
collection :vapps
model :task
collection :tasks
model :vm
collection :vms
model :vm_customization
collection :vm_customizations
model :network
collection :networks
model :disk
collection :disks
model :vm_network
collection :vm_networks
model :tag # this is called metadata in vcloud
collection :tags
model :media
collection :medias # sic
request_path 'fog/vcloud_director/requests/compute'
request :delete_media
request :delete_vapp
request :delete_vapp_metadata_item_metadata
request :get_catalog
request :get_catalog_item
request :get_cpu_rasd_item
request :get_current_session
request :get_disks_rasd_items_list
request :get_guest_customization_system_section_vapp
request :get_href # this is used for manual testing
request :get_media
request :get_media_owner
request :get_memory_rasd_item
request :get_metadata
request :get_network
request :get_network_connection_system_section_vapp
request :get_organization
request :get_organizations
request :get_request # this is used for manual testing
request :get_supported_systems_info
request :get_supported_versions
request :get_task
request :get_task_list
request :get_vapp
request :get_vapp_metadata
request :get_vapp_ovf_descriptor
request :get_vapp_template
request :get_vapp_template_ovf_descriptor
request :get_vdc
request :get_vm
request :get_vm_customization
request :get_vm_disks
request :get_vm_network
request :get_vms
request :get_vms_by_metadata
request :instantiate_vapp_template
request :post_cancel_task
request :post_capture_vapp
request :post_power_off_vapp
request :post_power_on_vapp
request :post_reboot_vapp
request :post_reset_vapp
request :post_shutdown_vapp
request :post_suspend_vapp
request :post_undeploy_vapp
request :post_upload_media
request :post_vapp_metadata_item_metadata
request :put_cpu
request :put_disks
request :put_guest_customization_section_vapp
request :put_memory
request :put_network_connection_system_section_vapp
request :put_vapp_metadata_item_metadata
class Model < Fog::Model
def initialize(attrs={})
super(attrs)
lazy_load_attrs.each do |attr|
attributes[attr]= NonLoaded if attributes[attr].nil?
make_lazy_load_method(attr)
end
self.class.attributes.each {|attr| make_attr_loaded_method(attr)}
end
def lazy_load_attrs
@lazy_load_attrs ||= self.class.attributes - attributes.keys
end
def make_lazy_load_method(attr)
self.class.instance_eval do
define_method(attr) do
reload if attributes[attr] == NonLoaded and !@inspecting
attributes[attr]
end
end
end
# it adds an attr_loaded? method to know if the value has been loaded
# yet or not: ie description_loaded?
def make_attr_loaded_method(attr)
self.class.instance_eval do
define_method("#{attr}_loaded?") do
attributes[attr] != NonLoaded
end
end
end
def inspect
@inspecting = true
out = super
@inspecting = false
out
end
end
class Collection < Fog::Collection
def all(lazy_load=true)
lazy_load ? index : get_everyone
end
def get(item_id)
item = get_by_id(item_id)
return nil unless item
new(item)
end
def get_by_name(item_name)
item_found = item_list.detect {|item| item[:name] == item_name}
return nil unless item_found
get(item_found[:id])
end
def index
load(item_list)
end
def get_everyone
items = item_list.map {|item| get_by_id(item[:id])}
load(items)
end
def ensure_list(items)
items.is_a?(Hash) ? [items] : items
end
end
class Real
include Fog::Compute::Helper
attr_reader :end_point, :api_version
def initialize(options={})
@vcloud_director_password = options[:vcloud_director_password]
@vcloud_director_username = options[:vcloud_director_username]
@connection_options = options[:connection_options] || {}
@host = options[:vcloud_director_host]
@path = options[:path] || Fog::Compute::VcloudDirector::Defaults::PATH
@persistent = options[:persistent] || false
@port = options[:port] || Fog::Compute::VcloudDirector::Defaults::PORT
@scheme = options[:scheme] || Fog::Compute::VcloudDirector::Defaults::SCHEME
@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
@end_point = "#{@scheme}://#{@host}#{@path}/"
@api_version = options[:vcloud_director_api_version] || Fog::Compute::VcloudDirector::Defaults::API_VERSION
end
def auth_token
login if @auth_token.nil?
@auth_token
end
def org_name
login if @org_name.nil?
@org_name
end
def reload
@cookie = nil # verify that this makes the connection to be restored, if so use Excon::Errors::Forbidden instead of Excon::Errors::Unauthorized
@connection.reset
end
def request(params)
unless @cookie
@cookie = auth_token
end
begin
do_request(params)
# this is to know if Excon::Errors::Unauthorized really happens
#rescue Excon::Errors::Unauthorized
# @cookie = auth_token
# do_request(params)
end
end
# @api private
def do_request(params)
headers = { 'Accept' => 'application/*+xml;version=' + @api_version }
if @cookie
headers.merge!('Cookie' => @cookie)
end
if params[:path]
if params[:override_path] == true
path = params[:path]
else
path = "#{@path}/#{params[:path]}"
end
else
path = "#{@path}"
end
@connection.request({
:body => params[:body],
:expects => params[:expects],
:headers => headers.merge!(params[:headers] || {}),
:host => @host,
:method => params[:method],
:parser => params[:parser],
:path => path
})
rescue => @e
raise @e unless @e.class.to_s =~ /^Excon::Errors/
if @e.respond_to?(:response)
puts @e.response.status
puts CGI::unescapeHTML(@e.response.body)
end
raise @e
end
def process_task(response_body)
task = make_task_object(response_body)
wait_and_raise_unless_success(task)
true
end
def make_task_object(task_response)
task_response[:id] = task_response[:href].split('/').last
tasks.new(task_response)
end
def wait_and_raise_unless_success(task)
task.wait_for { non_running? }
raise Errors::Task.new "status: #{task.status}, error: #{task.error}" unless task.success?
end
def add_id_from_href!(data={})
data[:id] = data[:href].split('/').last
end
private
def login
headers = {
'Authorization' => "Basic #{Base64.encode64("#{@vcloud_director_username}:#{@vcloud_director_password}").delete("\r\n")}",
'Accept' => 'application/*+xml;version=' + @api_version
}
response = @connection.request({
:expects => 200,
:headers => headers,
:host => @host,
:method => 'POST',
:parser => Fog::ToHashDocument.new,
:path => '/api/sessions' # curl http://example.com/api/versions | grep LoginUrl
})
@auth_token = response.headers['Set-Cookie'] || response.headers['set-cookie']
@org_name = response.body[:org]
end
end
class Mock
attr_reader :end_point, :api_version
def data
@@data ||= Hash.new do |hash, key|
hash[key] = {
:catalogs => {
uuid => {
:name => 'Default Catalog'
}
},
:catalog_items => {
uuid => {
:type => 'vAppTemplate',
:name => 'vAppTemplate 1'
}
},
:medias => {},
:networks => {
uuid => {
:Description => 'Network for mocking',
:Dns1 => '8.8.8.8',
:Dns2 => '8.8.4.4',
:DnsSuffix => 'example.com',
:Gateway => '192.168.1.1',
:IpRanges => [{
:StartAddress=>'192.168.1.2',
:EndAddress=>'192.168.1.254'
}],
:IsInherited => false,
:Netmask => '255.255.255.0',
:name => 'Default Network'
}
},
:org => {
:description => 'Organization for mocking',
:full_name => 'Mock Organization',
:name => org_name,
:uuid => uuid
},
:tasks => {},
:vdcs => {
uuid => {
:description => 'vDC for mocking',
:name => 'MockVDC'
}
}
}
end[@vcloud_director_username]
end
def initialize(options={})
@vcloud_director_password = options[:vcloud_director_password]
@vcloud_director_username = options[:vcloud_director_username]
#@connection_options = options[:connection_options] || {}
@host = options[:vcloud_director_host]
@path = options[:path] || Fog::Compute::VcloudDirector::Defaults::PATH
@persistent = options[:persistent] || false
@port = options[:port] || Fog::Compute::VcloudDirector::Defaults::PORT
@scheme = options[:scheme] || Fog::Compute::VcloudDirector::Defaults::SCHEME
#@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
@end_point = "#{@scheme}://#{@host}#{@path}/"
@api_version = options[:vcloud_director_api_version] || Fog::Compute::VcloudDirector::Defaults::API_VERSION
end
def auth_token
@auth_token || Fog::Mock.random_base64(32)
end
def org_name
@org_name ||=
begin
username = @vcloud_director_username.split('@')
unless username.size == 2
Fog::Logger.warning('vcloud_director_username should be in the form user@org_name')
end
username.last || 'vcd_org_name'
end
end
def user_name
@user_name ||= @vcloud_director_username.split('@').first
end
def user_uuid
@user_uuid ||= uuid
end
def uuid
[8,4,4,4,12].map {|i| Fog::Mock.random_hex(i)}.join('-')
end
def add_id_from_href!(data={})
data[:id] = data[:href].split('/').last
end
private
def make_href(path)
"#{@end_point}#{path}"
end
def valid_uuid?(uuid)
/^[\da-f]{8}(?:-[\da-f]{4}){3}-[\da-f]{12}$/.match(uuid.downcase)
end
def xmlns
'http://www.vmware.com/vcloud/v1.5'
end
def xmlns_xsi
'http://www.w3.org/2001/XMLSchema-instance'
end
def xsi_schema_location
"http://www.vmware.com/vcloud/v1.5 http://#{@host}#{@path}/v1.5/schema/master.xsd"
end
end
end
end
end