fog--fog/lib/fog/cloudstack/compute.rb

255 lines
8.3 KiB
Ruby

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'cloudstack'))
require 'fog/compute'
require 'digest/md5'
module Fog
module Compute
class Cloudstack < Fog::Service
class BadRequest < Fog::Compute::Cloudstack::Error; end
class Unauthorized < Fog::Compute::Cloudstack::Error; end
requires :cloudstack_host
recognizes :cloudstack_api_key, :cloudstack_secret_access_key, :cloudstack_session_key, :cloudstack_session_id,
:cloudstack_port, :cloudstack_path, :cloudstack_scheme, :cloudstack_persistent
request_path 'fog/cloudstack/requests/compute'
request :acquire_ip_address
request :assign_to_load_balancer_rule
request :attach_volume
request :authorize_security_group_ingress
request :change_service_for_virtual_machine
request :create_account
request :create_domain
request :create_load_balancer_rule
request :create_network
request :create_port_forwarding_rule
request :create_security_group
request :create_ssh_key_pair
request :create_snapshot
request :create_snapshot_policy
request :create_user
request :create_volume
request :delete_account
request :delete_domain
request :delete_load_balancer_rule
request :delete_port_forwarding_rule
request :delete_security_group
request :delete_ssh_key_pair
request :delete_snapshot
request :delete_snapshot_policies
request :delete_user
request :delete_volume
request :detach_volume
request :deploy_virtual_machine
request :destroy_virtual_machine
request :disable_user
request :enable_user
request :generate_usage_records
request :get_vm_password
request :list_accounts
request :list_alerts
request :list_async_jobs
request :list_capacity
request :list_capabilities
request :list_clusters
request :list_configurations
request :list_disk_offerings
request :list_capacity
request :list_domains
request :list_domain_children
request :list_events
request :list_external_firewalls
request :list_external_load_balancers
request :list_hosts
request :list_hypervisors
request :list_instance_groups
request :list_isos
request :list_load_balancer_rules
request :list_load_balancer_rule_instances
request :list_network_offerings
request :list_networks
request :list_os_categories
request :list_os_types
request :list_pods
request :list_port_forwarding_rules
request :list_public_ip_addresses
request :list_resource_limits
request :list_security_groups
request :list_service_offerings
request :list_snapshots
request :list_snapshot_policies
request :list_ssh_key_pairs
request :list_storage_pools
request :list_templates
request :list_usage_records
request :list_users
request :list_virtual_machines
request :list_volumes
request :list_zones
request :migrate_virtual_machine
request :query_async_job_result
request :reboot_virtual_machine
request :recover_virtual_machine
request :register_ssh_key_pair
request :register_user_keys
request :remove_from_load_balancer_rule
request :reset_password_for_virtual_machine
request :revoke_security_group_ingress
request :start_virtual_machine
request :stop_virtual_machine
request :update_account
request :update_domain
request :update_user
request :update_resource_count
request :update_virtual_machine
class Mock
def self.data
@data ||= Hash.new do |hash, key|
hash[key] = {}
end
end
def self.reset
@data = nil
end
def initialize(options={})
@cloudstack_api_key = options[:cloudstack_api_key]
end
def data
self.class.data[@cloudstack_api_key]
end
def reset_data
self.class.data.delete(@cloudstack_api_key)
end
end
class Real
def initialize(options={})
require 'multi_json'
@cloudstack_api_key = options[:cloudstack_api_key]
@cloudstack_secret_access_key = options[:cloudstack_secret_access_key]
@cloudstack_session_id = options[:cloudstack_session_id]
@cloudstack_session_key = options[:cloudstack_session_key]
@host = options[:cloudstack_host]
@path = options[:cloudstack_path] || '/client/api'
@port = options[:cloudstack_port] || 443
@scheme = options[:cloudstack_scheme] || 'https'
@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}#{@path}", options[:cloudstack_persistent], {:ssl_verify_peer => false})
end
def reload
@connection.reset
end
def login(username,password,domain)
response = issue_request({
'response' => 'json',
'command' => 'login',
'username' => username,
'password' => Digest::MD5.hexdigest(password),
'domain' => domain
})
# Parse response cookies to retrive JSESSIONID token
cookies = CGI::Cookie.parse(response.headers['Set-Cookie'])
sessionid = cookies['JSESSIONID'].first
# Decode the login response
response = MultiJson.decode(response.body)
user = response['loginresponse']
user.merge!('sessionid' => sessionid)
@cloudstack_session_id = user['sessionid']
@cloudstack_session_key = user['sessionkey']
user
end
def request(params)
params.reject!{|k,v| v.nil?}
params.merge!('response' => 'json')
if has_session?
params, headers = authorize_session(params)
elsif has_keys?
params, headers = authorize_api_keys(params)
end
response = issue_request(params,headers)
response = MultiJson.decode(response.body) unless response.body.empty?
response
end
private
def has_session?
@cloudstack_session_id && @cloudstack_session_key
end
def has_keys?
@cloudstack_api_key && @cloudstack_secret_access_key
end
def authorize_session(params)
# set the session id cookie for the request
headers = {'Cookie' => "JSESSIONID=#{@cloudstack_session_id};"}
# set the sesion key for the request, params are not signed using session auth
params.merge!('sessionkey' => @cloudstack_session_key)
return params, headers
end
def authorize_api_keys(params)
headers = {}
# merge the api key into the params
params.merge!('apiKey' => @cloudstack_api_key)
# sign the request parameters
signature = Fog::Cloudstack.signed_params(@cloudstack_secret_access_key,params)
# merge signature into request param
params.merge!({'signature' => signature})
return params, headers
end
def issue_request(params={},headers={},method='GET',expects=200)
begin
response = @connection.request({
:query => params,
:headers => headers,
:method => method,
:expects => expects
})
rescue Excon::Errors::HTTPStatusError => error
error_response = MultiJson.decode(error.response.body)
error_code = error_response.values.first['errorcode']
error_text = error_response.values.first['errortext']
case error_code
when 401
raise Fog::Compute::Cloudstack::Unauthorized, error_text
when 431
raise Fog::Compute::Cloudstack::BadRequest, error_text
else
raise Fog::Compute::Cloudstack::Error, error_text
end
end
end
end
end
end
end