[cloudsigma] Add CloudSigma compute provider

This commit is contained in:
Kaloyan Kanev 2013-01-18 17:34:08 +02:00
parent 22a3cc36ab
commit e61b81bf49
73 changed files with 2501 additions and 1 deletions

View File

@ -42,3 +42,5 @@ require 'fog/vsphere'
require 'fog/voxel'
require 'fog/xenserver'
require 'fog/zerigo'
require 'fog/cloudsigma'

View File

@ -94,3 +94,4 @@ require 'fog/bin/vsphere'
require 'fog/bin/voxel'
require 'fog/bin/xenserver'
require 'fog/bin/zerigo'
require 'fog/bin/cloudsigma'

29
lib/fog/bin/cloudsigma.rb Normal file
View File

@ -0,0 +1,29 @@
class CloudSigma < Fog::Bin
class << self
def class_for(key)
case key
when :compute
Fog::Compute::CloudSigma
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 => 'CloudSigma')
else
raise ArgumentError, "Unrecognized service: #{key.inspect}"
end
end
@@connections[service]
end
def services
Fog::CloudSigma.services
end
end
end

9
lib/fog/cloudsigma.rb Normal file
View File

@ -0,0 +1,9 @@
require 'fog/core'
module Fog
module CloudSigma
extend Fog::Provider
service(:compute, 'cloudsigma/compute', 'Compute')
end
end

View File

@ -0,0 +1,221 @@
require 'fog/compute'
require 'fog/cloudsigma/connection'
module Fog
module Compute
class CloudSigma < Fog::Service
requires :cloudsigma_password, :cloudsigma_username
recognizes :cloudsigma_password, :cloudsigma_username
model_path 'fog/cloudsigma/models'
request_path 'fog/cloudsigma/requests'
model :volume
collection :volumes
request :create_volume
request :get_volume
request :list_volumes
request :update_volume
request :delete_volume
request :clone_volume
model :lib_volume
collection :lib_volumes
request :get_lib_volume
request :list_lib_volumes
model :ipconf
model :nic
model :mountpoint
model :server
collection :servers
request :create_server
request :get_server
request :list_servers
request :update_server
request :delete_server
request :start_server
request :stop_server
request :open_vnc
request :close_vnc
request :clone_server
model :ip
collection :ips
request :list_ips
request :get_ip
model :vlan
collection :vlans
request :list_vlans
request :get_vlan
request :update_vlan
model :subscription
collection :subscriptions
request :list_subscriptions
request :get_subscription
request :create_subscription
request :extend_subscription
model :price_calculation
request :calculate_subscription_price
model :profile
request :get_profile
request :update_profile
model :balance
request :get_balance
model :current_usage
request :get_current_usage
model :pricing
request :get_pricing
module CommonMockAndReal
def initialize(options={})
@init_options = options
setup_connection(options)
end
def profile
response = get_profile
Profile.new(response.body)
end
def balance
response = get_balance
Balance.new(response.body)
end
def current_usage
response = get_current_usage
CurrentUsage.new(response.body['usage'])
end
def currency
# Cache since currency does not change
@currency ||= profile.currency
end
def pricing
resp = get_princing(currency)
resp.body['objects']
end
def current_pricing_levels
resp = get_pricing(currency)
resp.body['current']
end
def next_pricing_levels
resp = get_pricing(currency)
resp.body['next']
end
def subscription_pricing
resp = get_pricing(currency, true)
current_levels = resp.body['current']
current_prices = resp.body['objects']
current_pricing_pairs = current_levels.map do |resource, level|
price_for_resource_and_level = current_prices.detect do |price|
price['resource'] == resource
end
price_for_resource_and_level ||= {}
[resource, price_for_resource_and_level]
end
Pricing.new(Hash[current_pricing_pairs])
end
def current_pricing
resp = get_pricing(currency)
current_levels = resp.body['current']
current_prices = resp.body['objects']
current_pricing_pairs = current_levels.map do |resource, level|
price_for_resource_and_level = current_prices.detect do |price|
price['level'] == level && price['resource'] == resource
end
price_for_resource_and_level ||= {}
[resource, price_for_resource_and_level]
end
Pricing.new(Hash[current_pricing_pairs])
end
def next_pricing
resp = get_pricing(currency)
current_levels = resp.body['next']
current_prices = resp.body['objects']
current_pricing_pairs = current_levels.map do |resource, level|
price_for_resource_and_level = current_prices.detect do |price|
price['level'] == level && price['resource'] == resource
end
price_for_resource_and_level ||= {}
[resource, price_for_resource_and_level]
end
Pricing.new(Hash[current_pricing_pairs])
end
end
class Mock
include Collections
include CommonMockAndReal
include Fog::CloudSigma::CloudSigmaConnection::Mock
require 'fog/cloudsigma/mock_data'
def self.data
@data ||= Hash.new do |hash, key|
hash[key] = mock_data
end
end
def self.random_uuid
# Insert '4' at 13th position and 'a' at 17th as per uuid4 spec
hex = Fog::Mock.random_hex(30).insert(12,'4').insert(16, 'a')
# Add dashes
"#{hex[0...8]}-#{hex[8...12]}-#{hex[12...16]}-#{hex[16...20]}-#{hex[20..32]}"
end
def self.random_mac
(0..5).map{Fog::Mock.random_hex(2)}.join(':')
end
def data
self.class.data[:test]
end
end
class Real
include Collections
include CommonMockAndReal
include Fog::CloudSigma::CloudSigmaConnection::Real
end
end
end
end

View File

@ -0,0 +1,197 @@
require 'fog/cloudsigma/error'
module Fog
module CloudSigma
module CloudSigmaConnection
module Real
def auth_header(type = :basic)
case type
when :basic
unless @username and @password
raise ArgumentError, 'Username and password required for basic auth'
end
{'Authorization' => 'Basic ' << Base64.encode64("#{@username}:#{@password}").gsub("\n", '')}
else
unless @username and @password
raise ArgumentError, 'Username and password required for basic auth'
end
{'Authorization' => 'Basic ' << Base64.encode64("#{@username}:#{@password}").gsub("\n", '')}
end
end
def setup_connection(options)
@persistent = options[:persistent] || false
@connection_options = options[:connection_options] || {}
@connection_options[:ssl_verify_peer] = false
@auth_type = options[:cloudsigma_auth_type] || :basic
@username = options[:cloudsigma_username]
@password = options[:cloudsigma_password]
@scheme = options[:cloudsigma_scheme] || 'https'
@host = options[:cloudsigma_host] || 'lvs.cloudsigma.com'
@port = options[:cloudsigma_port] || '443'
@api_path_prefix = options[:cloudsigma_api_path_prefix] || 'api'
@api_version = options[:cloudsigma_api_version] || '2.0'
@path_prefix = "#{@api_path_prefix}/#{@api_version}/"
@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
end
def request(params)
params[:headers] = params.fetch(:headers, {}).merge(auth_header(@auth_type))
params[:headers]['Content-Type'] = 'application/json; charset=utf-8'
req_path = params[:path]
params[:path] = "#{@path_prefix}#{req_path}"
params[:body] = Fog::JSON.encode(params[:body]) if params[:body]
begin
response = @connection.request(params)
rescue Excon::Errors::HTTPStatusError => e
e.response[:body] = Fog::JSON.decode(e.response[:body]) unless e.response[:body].empty?
err = Fog::CloudSigma::Errors.slurp_http_status_error(e)
raise err
end
response.body = Fog::JSON.decode(response.body) unless response.body.empty?
response
end
def list_request(path, override_params={})
default_params = {:method => 'GET', :expects => 200, :query => {:limit => 0}}
override_params[:path] = path
params = default_params.merge(override_params)
request(params)
end
def get_request(path, override_params={})
default_params = {:method => 'GET', :expects => 200}
override_params[:path] = path
params = default_params.merge(override_params)
request(params)
end
def delete_request(path, override_params={})
default_params = {:method => 'DELETE', :expects => 204}
override_params[:path] = path
params = default_params.merge(override_params)
request(params)
end
def create_request(path, data, override_params={})
default_params = {:method => 'POST', :expects => [200, 202]}
override_params[:path] = path
override_params[:body] = data
params = default_params.merge(override_params)
request(params)
end
def update_request(path, data, override_params={})
default_params = {:method => 'PUT', :expects => [200, 202]}
override_params[:path] = path
override_params[:body] = data
params = default_params.merge(override_params)
request(params)
end
end
module Mock
def setup_connection(options)
@username = options[:cloudsigma_username]
@password = options[:cloudsigma_password]
end
def mock_get(obj_or_collection, status, key=nil)
data = self.data[obj_or_collection]
if key
data = data[key]
unless data
raise Fog::CloudSigma::Errors::NotFound.new("Object with uuid #{key} does not exist", 'notexist')
end
end
Excon::Response.new(:body => Fog::JSON.decode(Fog::JSON.encode(data)), :status => status)
end
def mock_list(collection, status)
data_array = self.data[collection].values
Excon::Response.new(:body => {'objects' => data_array}, :status => status)
end
def mock_update(data, obj_or_collection, status, key, &clean_before_update)
data = Fog::JSON.decode(Fog::JSON.encode(data))
if key
unless self.data[obj_or_collection][key]
raise Fog::CloudSigma::Errors::NotFound.new("Object with uuid #{key} does not exist", 'notexist')
end
if clean_before_update
new_data = clean_before_update.call(self.data[obj_or_collection][key], data)
else
new_data = self.data[obj_or_collection][key].merge(data)
end
self.data[obj_or_collection][key] = new_data
else
if clean_before_update
new_data = clean_before_update.call(self.data[obj_or_collection], data)
else
new_data = self.data[obj_or_collection].merge(data)
end
self.data[obj_or_collection] = new_data
end
Excon::Response.new(:body => Fog::JSON.decode(Fog::JSON.encode(new_data)), :status => status)
end
def mock_delete(collection, status, key)
self.data[collection].delete(key)
Excon::Response.new(:body => '', :status => status)
end
def mock_create(collection, status, data, key, defaults={}, &clean_before_store)
data_with_defaults = data.merge(defaults) {|k, oldval, newval| oldval == nil ? newval: oldval}
if clean_before_store
cleaned_data = clean_before_store.call(data_with_defaults)
else
cleaned_data = data_with_defaults
end
# Encode and decode into JSON so that the result is the same as the one returned and parsed from the API
final_data = Fog::JSON.decode(Fog::JSON.encode(cleaned_data))
self.data[collection][key] = final_data
# dup so that stored data is different instance from response data
response_data = final_data.dup
response = Excon::Response.new
response.body = {'objects' => [response_data]}
response.status = status
response
end
end
end
end
end

View File

@ -0,0 +1,45 @@
module Fog
module CloudSigma
module Errors
class Error < Fog::Errors::Error
attr_accessor :type, :error_point
def initialize(message, type='n/a', error_point=nil)
@type = type
@error_point = error_point
super(message)
end
end
class NotFound < Error; end
class RequestError < Error; end
class ServerError < Error; end
def self.slurp_http_status_error(error)
error_class = case error.response[:status]
when 404
NotFound
when 500..599
ServerError
when 400..499
RequestError
else
Error
end
new_error = error_class.new(error.response[:body].first['error_message'],
error.response[:body].first['error_type'],
error.response[:body].first['error_point'])
new_error.set_backtrace(error.backtrace)
new_error.verbose = error.message
new_error
end
end
end
end

View File

@ -0,0 +1,46 @@
module Fog
module Compute
class CloudSigma
class Mock
def self.mock_data
{
:volumes => {},
:servers => {},
:vlans => {},
:ips => {},
:profile => {:login_sms=>false,
:town=>"",
:postcode=>"",
:reseller=>"",
:has_autotopup=>false,
:currency=>"CHF",
:state=>"REGULAR",
:uuid=>"6c2203a1-a2e6-433f-aeab-b976b8cd3d18",
:company=>"",
:api_https_only=>false,
:my_notes=>"",
:key_auth=>false,
:email=>"MyFirstName.MyLasttName@MyCompany.com",
:bank_reference=>"mmlastname278",
:first_name=>"MyFirstName",
:meta =>"",
:phone=>"",
:language=>"EN",
:vat=>"",
:last_name=>"MyLasttName",
:title=>"",
:mailing_list=>true,
:autotopup_amount=>0.0,
:country=>"",
:address=>""},
:subscriptions => {},
:current_usage => {},
:balance => {:balance => 100, :currency => 'CHF'},
}
end
end
end
end
end

View File

@ -0,0 +1,12 @@
require 'fog/cloudsigma/nested_model'
module Fog
module Compute
class CloudSigma
class Balance < Fog::CloudSigma::CloudsigmaModel
attribute :balance, :type => :float
attribute :currency, :type => :string
end
end
end
end

View File

@ -0,0 +1,19 @@
require 'fog/cloudsigma/nested_model'
require 'fog/cloudsigma/models/usage_record'
module Fog
module Compute
class CloudSigma
class CurrentUsage < Fog::CloudSigma::CloudsigmaModel
model_attribute :cpu, UsageRecord
model_attribute :hdd, UsageRecord
model_attribute :ip, UsageRecord
model_attribute :mem, UsageRecord
model_attribute :sms, UsageRecord
model_attribute :ssd, UsageRecord
model_attribute :tx, UsageRecord
model_attribute :vlan, UsageRecord
end
end
end
end

View File

@ -0,0 +1,22 @@
require 'fog/cloudsigma/nested_model'
module Fog
module Compute
class CloudSigma
class IP < Fog::CloudSigma::CloudsigmaModel
identity :uuid
attribute :tags, :type => :array
attribute :nameservers, :type => :array
attribute :server, :type => :string
attribute :netmask, :type => :integer
attribute :meta
attribute :owner
attribute :subscription
attribute :gateway, :type => :string
attribute :resource_uri, :type => :string
end
end
end
end

View File

@ -0,0 +1,12 @@
require 'fog/cloudsigma/nested_model'
module Fog
module Compute
class CloudSigma
class IPConf < Fog::CloudSigma::CloudsigmaModel
attribute :ip
attribute :conf, :type => :string
end
end
end
end

View File

@ -0,0 +1,27 @@
require 'fog/core/collection'
require 'fog/cloudsigma/models/ip'
module Fog
module Compute
class CloudSigma
class Ips < Fog::Collection
model Fog::Compute::CloudSigma::IP
def all
resp = service.list_ips
data = resp.body['objects']
load(data)
end
def get(ip)
resp = service.get_ip(ip)
data = resp.body
new(data)
rescue Fog::CloudSigma::Errors::NotFound
return nil
end
end
end
end
end

View File

@ -0,0 +1,50 @@
require 'fog/core/model'
module Fog
module Compute
class CloudSigma
class LibVolume < Fog::Model
identity :uuid
attribute :mounted_on, :type => :related
attribute :licenses
attribute :meta
attribute :owner
attribute :affinities
attribute :image_format, :type => :string
attribute :size, :type => :integer
attribute :category
attribute :image_type, :type => :string
attribute :media, :type => :string
attribute :state, :type => :string
attribute :status, :type => :string
attribute :jobs
attribute :description, :type => :string
attribute :tags
attribute :favourite, :type => :boolean
attribute :paid, :type => :boolean
attribute :allow_multimount, :type => :boolean
attribute :install_notes, :type => :string
attribute :arch, :type => :string
attribute :name, :type => :string
attribute :url, :type => :string
attribute :os, :type => :string
attribute :resource_uri, :type => :string
def reload
requires :identity
collection.get(identity)
end
def clone(clone_params={})
requires :identity
response = service.clone_volume(identity, clone_params)
self.class.new(response.body['objects'].first)
end
end
end
end
end

View File

@ -0,0 +1,27 @@
require 'fog/core/collection'
require 'fog/cloudsigma/models/lib_volume'
module Fog
module Compute
class CloudSigma
class LibVolumes < Fog::Collection
model Fog::Compute::CloudSigma::LibVolume
def all
resp = service.list_lib_volumes
data = resp.body['objects']
load(data)
end
def get(vol_id)
resp = service.get_lib_volume(vol_id)
data = resp.body
new(data)
rescue Fog::CloudSigma::Errors::NotFound
return nil
end
end
end
end
end

View File

@ -0,0 +1,25 @@
require 'fog/core/model'
module Fog
module Compute
class CloudSigma
class MountPoint < Fog::Model
attribute :device, :type => 'string'
attribute :dev_channel, :type => 'string'
attribute :drive
attribute :boot_order, :type => 'integer'
def drive
drive = attributes[:drive]
drive.kind_of?(Hash) ? drive['uuid'] : drive
end
def drive=(new_drive)
attributes[:drive] = new_drive
end
alias :volume :drive
end
end
end
end

View File

@ -0,0 +1,22 @@
require 'fog/core/model'
require 'fog/cloudsigma/nested_model'
require 'fog/cloudsigma/models/ipconf'
module Fog
module Compute
class CloudSigma
class Nic < Fog::CloudSigma::CloudsigmaModel
attribute :boot_order
attribute :mac, :type => :string
attribute :model, :type => :string
attribute :vlan
model_attribute :ip_v4_conf, IPConf
model_attribute :ip_v6_conf, IPConf
end
end
end
end

View File

@ -0,0 +1,12 @@
require 'fog/core/model'
module Fog
module Compute
class CloudSigma
class ObjRef < Fog::Model
attribute :uuid, :type => :string
attribute :resource_uri, :type => :string
end
end
end
end

View File

@ -0,0 +1,13 @@
require 'fog/cloudsigma/nested_model'
require 'fog/cloudsigma/models/subscriptions'
module Fog
module Compute
class CloudSigma
class PriceCalculation < Fog::CloudSigma::CloudsigmaModel
attribute :price, :type => :float
model_attribute_array :subscriptions, Subscription, :aliases => 'objects'
end
end
end
end

View File

@ -0,0 +1,38 @@
require 'fog/cloudsigma/nested_model'
require 'bigdecimal'
module Fog
module Compute
class CloudSigma
class PriceRecord < Fog::CloudSigma::CloudsigmaModel
attribute :resource, :type => :string
attribute :multiplier, :type => :integer
attribute :price, :type => :string
attribute :level, :type => :integer
attribute :currency, :type => :string
attribute :unit, :type => :string
def price
if attributes[:price]
BigDecimal(attributes[:price])
else
nil
end
end
def price=(new_price)
attributes[:price] = new_price.kind_of?(String) ? new_price : new_price.to_s('F')
end
# The base price of the resource.
# This is the price for the base API unit which is byte for memory, data, etc. and MHz for CPU.
# Also the price is per second for time based resource (basically everything except data transfer which is not
# limited in time)
def base_price
price / multiplier
end
end
end
end
end

View File

@ -0,0 +1,20 @@
require 'fog/cloudsigma/nested_model'
require 'fog/cloudsigma/models/price_record'
module Fog
module Compute
class CloudSigma
class Pricing < Fog::CloudSigma::CloudsigmaModel
model_attribute :cpu, PriceRecord
model_attribute :hdd, PriceRecord
model_attribute :ip, PriceRecord
model_attribute :mem, PriceRecord
model_attribute :sms, PriceRecord
model_attribute :ssd, PriceRecord
model_attribute :tx, PriceRecord
model_attribute :vlan, PriceRecord
end
end
end
end

View File

@ -0,0 +1,50 @@
require 'fog/cloudsigma/nested_model'
module Fog
module Compute
class CloudSigma
class Profile < Fog::CloudSigma::CloudsigmaModel
identity :uuid
attribute :last_name, :type => :string
attribute :login_sms, :type => :boolean
attribute :currency, :type => :string
attribute :meta
attribute :api_https_only, :type => :boolean
attribute :first_name, :type => :string
attribute :uuid, :type => :string
attribute :title, :type => :string
attribute :state, :type => :string
attribute :email, :type => :string
attribute :vat, :type => :string
attribute :autotopup_amount, :type => :float
attribute :reseller, :type => :string
attribute :company, :type => :string
attribute :key_auth, :type => :boolean
attribute :phone, :type => :string
attribute :address, :type => :string
attribute :mailing_list, :type => :boolean
attribute :town, :type => :string
attribute :has_autotopup, :type => :boolean
attribute :my_notes, :type => :string
attribute :bank_reference, :type => :string
attribute :language, :type => :string
attribute :country, :type => :string
attribute :postcode, :type => :string
def save
update
end
def update
response = service.update_profile(attributes)
self.attribute.merge!(response.body)
self
end
end
end
end
end

View File

@ -0,0 +1,208 @@
require 'fog/cloudsigma/nested_model'
require 'fog/cloudsigma/models/mountpoint'
require 'fog/cloudsigma/models/nic'
module Fog
module Compute
class CloudSigma
class Server < Fog::CloudSigma::CloudsigmaModel
identity :uuid
attribute :status, :type => :string
attribute :vnc_password, :type => :string
attribute :name, :type => :string
attribute :cpus_instead_of_cores, :type => :boolean
attribute :tags
attribute :mem, :type => :integer
attribute :enable_numa, :type => :boolean
attribute :smp
attribute :hv_relaxed, :type => :boolean
attribute :hv_tsc, :type => :boolean
attribute :meta
attribute :owner
attribute :runtime
attribute :cpu, :type => :integer
attribute :resource_uri, :type => :string
model_attribute_array :volumes, MountPoint, :aliases => 'drives'
model_attribute_array :nics, Nic
def save
if persisted?
update
else
create
end
end
def create
requires :name, :cpu, :mem, :vnc_password
data = attributes
response = service.create_server(data)
new_attributes = response.body['objects'].first
merge_attributes(new_attributes)
end
def update
requires :identity, :name, :cpu, :mem, :vnc_password
data = attributes
response = service.update_server(identity, data)
new_attributes = response.body
merge_attributes(new_attributes)
end
def destroy
requires :identity
service.delete_server(identity)
true
end
alias :delete :destroy
def start(start_params={})
requires :identity
service.start_server(identity, start_params)
end
def stop
requires :identity
service.stop_server(identity)
end
def open_vnc
requires :identity
service.open_vnc(identity)
end
def close_vnc
requires :identity
service.close_vnc(identity)
end
def clone(clone_params={})
requires :identity
response = service.clone_server(identity, clone_params)
self.class.new(response.body)
end
def mount_volume(volume, device = 'virtio', dev_channel = nil, boot_order = nil)
unless dev_channel
specified_channels = self.volumes.map { |v| v.dev_channel }.sort
if specified_channels
controller, controller_channel = 0, 0
max_ctlr, max_chnl = case device
when 'ide'
[4, 2]
else
[1024, 5]
end
dev_channel = "#{controller}:#{controller_channel}"
while specified_channels.include? dev_channel
controller_channel += 1
if controller_channel >= max_chnl
controller_channel = 0
controller += 1
if controller >= max_ctlr
raise Fog::CloudSigma::Errors::Error.new("Max channel reached, cannot attach more")
end
end
dev_channel = "#{controller}:#{controller_channel}"
end
else # no other channels specified
dev_channel = '0:0'
end
end
vol_id = volume.kind_of?(String) ? volume : volume.identity
mountpoint_data = {
'drive' => vol_id,
'device' => device,
'dev_channel' => dev_channel,
}
if boot_order
mountpoint_data['boot_order'] = boot_order
end
self.volumes = self.volumes << MountPoint.new(mountpoint_data)
end
def unmount_volume(volume_or_position)
if volume_or_position.kind_of? Fixnum
self.volumes.delete_at(volume_or_position)
# assign to update attributes
return self.volumes = self.volumes
end
vol_id = volume_or_position.kind_of?(String) ? volume_or_position : volume_or_position.identity
self.volumes = self.volumes.reject do |v|
if v.volume.kind_of? Hash
v.volume['uuid'] == vol_id
else
v.volume == vol_id
end
end
end
def unmount_all_volumes
self.volumes = []
end
def add_nic(vlan=nil, ip_v4_conf=nil, ip_v6_conf=nil, model='virtio', boot_order=nil)
nic_data = {
'model' => model,
'vlan' => vlan,
'ip_v4_conf' => ip_v4_conf,
'ip_v6_conf' => ip_v6_conf
}
if boot_order
nic_data['boot_order'] = boot_order
end
self.nics = self.nics << Nic.new(nic_data)
end
def add_public_nic(ip_or_conf=:dhcp, model='virtio', boot_order=nil)
case ip_or_conf
when :dhcp
add_nic(nil, {:conf => :dhcp}, nil, model, boot_order)
when :manual
add_nic(nil, {:conf => :manual}, nil, model, boot_order)
else
ip = ip_or_conf.kind_of?(String) ? ip_or_conf : ip_or_conf.identity
add_nic(nil, {:conf => :static, :ip => ip}, nil, model, boot_order)
end
end
def add_private_nic(vlan, model='virtio', boot_order=nil)
vlan = vlan.kind_of?(String) ? vlan : vlan.identity
add_nic(vlan, nil, nil, model, boot_order)
end
def remove_nic(mac_or_position)
if mac_or_position.kind_of? Fixnum
self.nics.delete_at(mac_or_position)
# assign to update attributes
return self.nics = self.nics
end
self.nics = self.nics.reject { |n| n.mac == mac_or_position }
end
def remove_all_nics
self.nics = []
end
end
end
end
end

View File

@ -0,0 +1,27 @@
require 'fog/core/collection'
require 'fog/cloudsigma/models/server'
module Fog
module Compute
class CloudSigma
class Servers < Fog::Collection
model Fog::Compute::CloudSigma::Server
def all
resp = service.list_servers
data = resp.body['objects']
load(data)
end
def get(server_id)
resp = service.get_server(server_id)
data = resp.body
new(data)
rescue Fog::CloudSigma::Errors::NotFound
return nil
end
end
end
end
end

View File

@ -0,0 +1,53 @@
require 'fog/cloudsigma/nested_model'
module Fog
module Compute
class CloudSigma
class Subscription < Fog::CloudSigma::CloudsigmaModel
identity :id
attribute :status, :type => :string
attribute :uuid, :type => :string
attribute :resource, :type => :string
attribute :auto_renew, :type => :boolean
attribute :descendants
attribute :start_time, :type => :time
attribute :price, :type => :float
attribute :period, :type => :string
attribute :remaining, :type => :string
attribute :amount, :type => :integer
attribute :end_time, :type => :time
attribute :discount_percent, :type => :float
attribute :subscribed_object, :type => :string
attribute :discount_amount, :type => :float
def save
create
end
def create
requires :resource, :amount
data = attributes
response = service.create_subscription(data)
new_attributes = response.body['objects'].first
merge_attributes(new_attributes)
end
def extend(period=nil, end_time=nil)
requires :identity
data = {}
if period
data[:period] = period
elsif end_time
data[:end_time] = end_time
end
response = service.extend_subscription(identity, data)
self.class.new(response.body)
end
end
end
end
end

View File

@ -0,0 +1,41 @@
require 'fog/core/collection'
require 'fog/cloudsigma/models/subscription'
module Fog
module Compute
class CloudSigma
class Subscriptions < Fog::Collection
model Fog::Compute::CloudSigma::Subscription
def all
resp = service.list_subscriptions
data = resp.body['objects']
load(data)
end
def get(sub_id)
resp = service.get_subscription(sub_id)
data = resp.body
new(data)
rescue Fog::CloudSigma::Errors::NotFound
return nil
end
def check_price(subscriptions_list)
subscriptions_list = subscriptions_list.map {|s| s.kind_of?(Hash) ? s : s.attributes}
resp = service.calculate_subscription_price(subscriptions_list)
PriceCalculation.new(resp.body)
end
def create_multiple(subscriptions_list)
subscriptions_list = subscriptions_list.map { |s| s.kind_of?(Hash) ? s : s.attributes }
resp = service.create_subscription(subscriptions_list)
resp.body['objects'].map { |s| Subscription.new(s) }
end
end
end
end
end

View File

@ -0,0 +1,13 @@
require 'fog/cloudsigma/nested_model'
module Fog
module Compute
class CloudSigma
class UsageRecord < Fog::CloudSigma::CloudsigmaModel
attribute :burst, :type => :integer
attribute :subscribed, :type => :integer
attribute :using, :type => :integer
end
end
end
end

View File

@ -0,0 +1,29 @@
require 'fog/cloudsigma/nested_model'
module Fog
module Compute
class CloudSigma
class VLAN < Fog::CloudSigma::CloudsigmaModel
identity :uuid
attribute :tags
attribute :servers
attribute :meta
attribute :owner
attribute :resource_uri, :type => :string
attribute :subscription
def update
requires :identity
data = attributes
response = service.update_vlan(identity, data)
new_attributes = response.body
merge_attributes(new_attributes)
end
alias :save :update
end
end
end
end

View File

@ -0,0 +1,27 @@
require 'fog/core/collection'
require 'fog/cloudsigma/models/vlan'
module Fog
module Compute
class CloudSigma
class Vlans < Fog::Collection
model Fog::Compute::CloudSigma::VLAN
def all
resp = service.list_vlans
data = resp.body['objects']
load(data)
end
def get(vlan)
resp = service.get_vlan(vlan)
data = resp.body
new(data)
rescue Fog::CloudSigma::Errors::NotFound
return nil
end
end
end
end
end

View File

@ -0,0 +1,71 @@
require 'fog/cloudsigma/nested_model'
module Fog
module Compute
class CloudSigma
class Volume < Fog::CloudSigma::CloudsigmaModel
identity :uuid
attribute :status, :type => :string
attribute :jobs
attribute :name, :type => :string
attribute :tags
attribute :media, :type => :string
attribute :mounted_on
attribute :owner
attribute :meta
attribute :allow_multimount, :type => :boolean
attribute :licenses
attribute :affinities, :type => :array
attribute :size, :type => :integer
attribute :resource_uri, :type => :string
def save
if persisted?
update
else
create
end
end
def create
requires :name, :size, :media
data = attributes
response = service.create_volume(data)
new_attributes = response.body['objects'].first
merge_attributes(new_attributes)
end
def update
requires :identity, :name, :size, :media
data = attributes()
response = service.update_volume(identity, data)
new_attributes = response.body
merge_attributes(new_attributes)
end
def destroy
requires :identity
service.delete_volume(identity)
true
end
alias :delete :destroy
def clone(clone_params={})
requires :identity
response = service.clone_volume(identity, clone_params)
self.class.new(response.body['objects'].first)
end
end
end
end
end

View File

@ -0,0 +1,27 @@
require 'fog/core/collection'
require 'fog/cloudsigma/models/volume'
module Fog
module Compute
class CloudSigma
class Volumes < Fog::Collection
model Fog::Compute::CloudSigma::Volume
def all
resp = service.list_volumes
data = resp.body['objects']
load(data)
end
def get(vol_id)
resp = service.get_volume(vol_id)
data = resp.body
new(data)
rescue Fog::CloudSigma::Errors::NotFound
return nil
end
end
end
end
end

View File

@ -0,0 +1,60 @@
module Fog
module CloudSigma
class CloudsigmaModel < Fog::Model
class << self
def model_attribute_array(name, model, options={})
attributes_key = options[:aliases] || name
class_eval <<-EOS, __FILE__, __LINE__
def #{name}
#{name}_attrs = attributes[:#{attributes_key}] || []
refreshed_#{name} = #{name}_attrs.map { |x| #{model}.new(x) }
attributes[:#{attributes_key}] = refreshed_#{name}.map { |x| x.attributes }
refreshed_#{name}
end
def #{name}=(new_#{name})
new_#{name} ||= []
attributes[:#{attributes_key}] = new_#{name}.map { |x| x.kind_of?(Hash) ? x : x.attributes}
end
EOS
@attributes ||= []
@attributes |= [name]
for new_alias in [*options[:aliases]]
aliases[new_alias] = name
end
end
def model_attribute(name, model, options={})
attributes_key = options[:aliases] || name
class_eval <<-EOS, __FILE__, __LINE__
def #{name}
#{name}_attrs = attributes[:#{attributes_key}]
if #{name}_attrs
refreshed_#{name} = #{name}_attrs ? #{model}.new(#{name}_attrs) : nil
attributes[:#{attributes_key}] = refreshed_#{name}.attributes
refreshed_#{name}
else
nil
end
end
def #{name}=(new_#{name})
if new_#{name}
attributes[:#{attributes_key}] = new_#{name}.kind_of?(Hash) ? new_#{name} : new_#{name}.attributes
else
nil
end
end
EOS
@attributes ||= []
@attributes |= [name]
for new_alias in [*options[:aliases]]
aliases[new_alias] = name
end
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def calculate_subscription_price(data)
create_request("subscriptioncalculator/", data)
end
end
class Mock
def calculate_subscription_price(data)
end
end
end
end
end

View File

@ -0,0 +1,32 @@
module Fog
module Compute
class CloudSigma
class Real
def clone_libvolume(vol_id, clone_params={})
request(:path => "libdrives/#{vol_id}/action/",
:method => 'POST',
:query => {:do => :clone},
:body => clone_params,
:expects => [200, 202])
end
end
class Mock
def clone_libvolume(vol_id, clone_params={})
volume = self.data[:libvolumes][vol_id].dup
uuid = self.class.random_uuid
volume['uuid'] = uuid
self.data[:volumes][uuid] = volume
response = Excon::Response.new
response.status = 200
response.body = volume
response
end
end
end
end
end

View File

@ -0,0 +1,32 @@
module Fog
module Compute
class CloudSigma
class Real
def clone_server(server_id, clone_params={})
request(:path => "servers/#{server_id}/action/",
:method => 'POST',
:query => {:do => :clone},
:body => clone_params,
:expects => [200, 202])
end
end
class Mock
def clone_server(server_id, clone_params={})
server = self.data[:servers][server_id].dup
uuid = self.class.random_uuid
server['uuid'] = uuid
self.data[:servers][uuid] = server
response = Excon::Response.new
response.status = 200
response.body = server
response
end
end
end
end
end

View File

@ -0,0 +1,32 @@
module Fog
module Compute
class CloudSigma
class Real
def clone_volume(vol_id, clone_params={})
request(:path => "drives/#{vol_id}/action/",
:method => 'POST',
:query => {:do => :clone},
:body => clone_params,
:expects => [200, 202])
end
end
class Mock
def clone_volume(vol_id, clone_params={})
volume = self.data[:volumes][vol_id].dup
uuid = self.class.random_uuid
volume['uuid'] = uuid
self.data[:volumes][uuid] = volume
response = Excon::Response.new
response.status = 200
response.body = volume
response
end
end
end
end
end

View File

@ -0,0 +1,30 @@
module Fog
module Compute
class CloudSigma
class Real
def close_vnc(server_id)
request(:path => "servers/#{server_id}/action/",
:method => 'POST',
:query => {:do => :close_vnc},
:expects => [200, 202])
end
end
class Mock
def close_vnc(server_id)
response = Excon::Response.new
response.status = 200
response.body = {
'action' => 'close_vnc',
'result' => 'success',
'uuid' => server_id,
}
response
end
end
end
end
end

View File

@ -0,0 +1,33 @@
module Fog
module Compute
class CloudSigma
class Real
def create_server(data)
create_request("servers/", data)
end
end
class Mock
def create_server(data)
uuid = self.class.random_uuid
defaults = {'uuid' => uuid,
'status' => 'stopped',
'smp' => 1,
'hv_relaxed' => false,
'hv_tsc' => false,
'enable_numa' => false,
'cpus_instead_of_cores' => false,
'drives' => [],
'nics' => [],
'tags' => []
}
mock_create(:servers, 202, data, uuid, defaults)
end
end
end
end
end

View File

@ -0,0 +1,40 @@
module Fog
module Compute
class CloudSigma
class Real
def create_subscription(data)
create_request("subscriptions/", data)
end
end
class Mock
def create_subscription(data)
if data[:period] != '1 month' || data[:start_time] || data[:end_time]
raise Fog::Errors::MockNotImplemented.new('Currently only mocks for subscriptions with period 1 month from now are implemented as mock')
end
id = Fog::Mock.random_numbers(3).to_i
defaults = {'id' => id,
'start_time' => DateTime.now,
'end_time' => DateTime.now + 30 * 24 * 60 *60,
'auto_renew' => false,
'amount' => 1.0}
if data[:resource] == 'vlan'
vlan_uuid = self.class.random_uuid
self.data[:vlans][vlan_uuid] = {'uuid' => vlan_uuid,
'subscription' => {'id' => id},
'servers' => [],
'meta' => {},
'tags' => []}
defaults['subscribed_object'] = vlan_uuid
end
mock_create(:subscriptions, 200, data, id, defaults)
end
end
end
end
end

View File

@ -0,0 +1,30 @@
module Fog
module Compute
class CloudSigma
class Real
def create_volume(data)
create_request("drives/", data)
end
end
class Mock
def create_volume(data)
uuid = self.class.random_uuid
defaults = {'uuid' => uuid,
'status' => 'unmounted',
'tags' => [],
'mounted_on' => [],
'affinities' => [],
'licenses' => [],
'jobs' => [],
'allow_multimount' => false,
}
mock_create(:volumes, 202, data, uuid, defaults)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def delete_server(server_id)
delete_request("servers/#{server_id}/")
end
end
class Mock
def delete_server(server_id)
mock_delete(:servers, 204, server_id)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def delete_volume(vol_id)
delete_request("drives/#{vol_id}/")
end
end
class Mock
def delete_volume(vol_id)
mock_delete(:volumes, 204, vol_id)
end
end
end
end
end

View File

@ -0,0 +1,22 @@
module Fog
module Compute
class CloudSigma
class Real
def extend_subscription(sub_id, data)
request(:path => "subscriptions/#{sub_id}/action/",
:method => 'POST',
:expects => [200, 202],
:query => {:do => :extend},
:body=>data)
end
end
class Mock
def extend_subscription(sub_id, data)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def get_balance
get_request("balance/")
end
end
class Mock
def get_balance
mock_get(:balance, 200)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def get_current_usage
get_request("currentusage/")
end
end
class Mock
def get_current_usage
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def get_ip(ip)
request("ips/#{ip}/")
end
end
class Mock
def get_ip(ip)
mock_get(:ips, 200, ip)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def get_lib_volume(vol_id)
get_request("libdrives/#{vol_id}/")
end
end
class Mock
def get_lib_volume(vol_id)
mock_get(:libvolumes, 200, vol_id)
end
end
end
end
end

View File

@ -0,0 +1,28 @@
module Fog
module Compute
class CloudSigma
class Real
def get_pricing(currency=nil, subscription=false)
query = {:limit => 0}
if currency
query[:currency] = currency
end
if subscription
query[:level] = 0
end
request(:path => "pricing/",
:method => 'GET',
:expects => 200,
:query => query)
end
end
class Mock
def get_pricing(currency=nil, subscription=false)
mock_get(:pricing, 200)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def get_profile
get_request("profile/")
end
end
class Mock
def get_profile
mock_get(:profile, 200)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def get_server(server_id)
get_request("servers/#{server_id}/")
end
end
class Mock
def get_server(server_id)
mock_get(:servers, 200, server_id)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def get_subscription(sub_id)
get_request("subscriptions/#{sub_id}/")
end
end
class Mock
def get_subscription(sub_id)
mock_get(:subscriptions, 200, sub_id)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def get_vlan(vlan)
get_request("vlans/#{vlan}/")
end
end
class Mock
def get_vlan(vlan)
mock_get(:vlans, 200, vlan)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def get_volume(vol_id)
get_request("drives/#{vol_id}/")
end
end
class Mock
def get_volume(vol_id)
mock_get(:volumes, 200, vol_id)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def list_ips
list_request('ips/detail/')
end
end
class Mock
def list_ips
mock_list(:ips, 200)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def list_lib_volumes
list_request('libdrives/')
end
end
class Mock
def list_lib_volumes
mock_list(:libvolumes, 200)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def list_servers
list_request('servers/detail/')
end
end
class Mock
def list_servers
mock_list(:servers, 200)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def list_subscriptions
list_request('subscriptions/')
end
end
class Mock
def list_subscriptions
mock_list(:subscriptions, 200)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def list_vlans
list_request('vlans/detail/')
end
end
class Mock
def list_vlans
mock_list(:vlans, 200)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def list_volumes
list_request('drives/detail/')
end
end
class Mock
def list_volumes
mock_list(:volumes, 200)
end
end
end
end
end

View File

@ -0,0 +1,34 @@
module Fog
module Compute
class CloudSigma
class Real
def open_vnc(server_id)
request(:path => "servers/#{server_id}/action/",
:method => 'POST',
:query => {:do => :open_vnc},
:expects => [200, 202])
end
end
class Mock
def open_vnc(server_id)
response = Excon::Response.new
response.status = 200
host = @init_options[:cloudsigma_host]
port = Fog::Mock.random_number(65000)
vnc_url = "vnc://#{host}:#{port}"
response.body = {
'action' => 'open_vnc',
'result' => 'success',
'uuid' => server_id,
'vnc_url' => vnc_url
}
response
end
end
end
end
end

View File

@ -0,0 +1,32 @@
module Fog
module Compute
class CloudSigma
class Real
def start_server(server_id, start_params={})
request(:path => "servers/#{server_id}/action/",
:method => 'POST',
:query => {:do => :start}.merge!(start_params),
:expects => [200, 202])
end
end
class Mock
def start_server(server_id, start_params={})
server = self.data[:servers][server_id]
server['status'] = 'running'
response = Excon::Response.new
response.status = 200
response.body = {
'action' => 'start',
'result' => 'success',
'uuid' => server_id
}
response
end
end
end
end
end

View File

@ -0,0 +1,33 @@
module Fog
module Compute
class CloudSigma
class Real
def stop_server(server_id)
request(:path => "servers/#{server_id}/action/",
:method => 'POST',
:query => {:do => :stop},
:expects => [200, 202])
end
end
class Mock
def stop_server(server_id)
server = self.data[:servers][server_id]
server['status'] = 'stopped'
response = Excon::Response.new
response.status = 200
response.body = {
'action' => 'stop',
'result' => 'success',
'uuid' => server_id
}
response
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def update_profile(data)
update_request("profile/", data)
end
end
class Mock
def update_profile(data)
mock_update(data, :profile, 200)
end
end
end
end
end

View File

@ -0,0 +1,40 @@
require 'set'
module Fog
module Compute
class CloudSigma
class Real
def update_server(server_id, data)
update_request("servers/#{server_id}/", data)
end
end
class Mock
def update_server(server_id, data)
mock_update(data, :servers, 200, server_id) do |old_data, new_data|
old_nics = old_data['nics']
new_nics = new_data['nics']
old_nics_macs = old_nics.map { |nic| nic['mac'] }.compact
new_nics_macs = new_nics.map { |nic| nic['mac'] }.compact
newly_created_macs = Set.new(new_nics_macs) - old_nics_macs
unless newly_created_macs.empty?
mac_err = <<-EOS
MAC(s) #{newly_created_macs.to_a} not specified on guest #{server_id}. Nic MACs are automatically assigned at
creation time and cannot be changed. Do not specify MAC to create a new NIC or specify existing MAC to
update existing NIC.
EOS
raise Fog::CloudSigma::Errors::RequestError.new(mac_err, 'permission')
end
new_nics.each { |nic| nic['mac'] ||= Fog::Compute::CloudSigma::Mock.random_mac }
old_data.merge(new_data)
end
end
end
end
end
end

View File

@ -0,0 +1,20 @@
require 'set'
module Fog
module Compute
class CloudSigma
class Real
def update_vlan(vlan_id, data)
update_request("vlans/#{vlan_id}/", data)
end
end
class Mock
def update_vlan(vlan_id, data)
mock_update(data, :vlans, 200, vlan_id)
end
end
end
end
end

View File

@ -0,0 +1,18 @@
module Fog
module Compute
class CloudSigma
class Real
def update_volume(vol_id, data)
update_request("drives/#{vol_id}/", data)
end
end
class Mock
def update_volume(vol_id, data)
mock_update(data, :volumes, 200, vol_id)
end
end
end
end
end

View File

@ -0,0 +1,72 @@
Shindo.tests('Fog::Compute[:cloudsigma] | server model', ['cloudsigma']) do
service = Fog::Compute[:cloudsigma]
servers = Fog::Compute[:cloudsigma].servers
server_create_args = {:name => 'fogtest', :cpu => 2000, :mem => 512*1024**2, :vnc_password => 'myrandompass'}
model_tests(servers, server_create_args, true) do
tests('start_stop').succeeds do
@instance.start
@instance.wait_for(timeout=60) { status == 'running' }
@instance.stop
@instance.wait_for(timeout=60) { status == 'stopped' }
end
tests('attach_dhcp_nic').succeeds do
@instance.add_public_nic()
@instance.save
@instance.reload
returns('dhcp') { @instance.nics.first.ip_v4_conf.conf }
succeeds {/^([0-9a-f]{2}[:]){5}([0-9a-f]{2})$/ === @instance.nics.first.mac}
end
tests('attach_vlan') do
if Fog.mocking?
# Do not buy subscription with real account
service.subscriptions.create({:period=>"1 month", :amount=>1, :resource=>"vlan"})
vlan = service.vlans.first
vlan.meta['name'] = 'fog-test'
vlan.save
end
vlan = service.vlans.find {|vlan| vlan.meta['name'] == 'fog-test'}
# Skip if there is no vlan marked for fog tests
pending unless vlan
@instance.add_private_nic(vlan)
@instance.save
@instance.reload
returns(vlan.uuid) { @instance.nics.last.vlan['uuid'] || @instance.nics.last.vlan}
succeeds {/^([0-9a-f]{2}[:]){5}([0-9a-f]{2})$/ === @instance.nics.last.mac}
end
tests('attach_volume') do
volume_create_args = {:name => 'fogservermodeltest', :size => 1000**3, :media => :cdrom}
v = service.volumes.create(volume_create_args)
volume_uuid = v.uuid
@instance.mount_volume(v)
@instance.save
@instance.reload
returns(volume_uuid) { @instance.volumes.first.volume }
@instance.unmount_volume(v)
@instance.save
@instance.reload
succeeds { @instance.volumes.empty? }
v.delete
end
end
end

View File

@ -0,0 +1,7 @@
Shindo.tests('Fog::Compute[:cloudsigma] | servers collection', ['cloudsigma']) do
servers = Fog::Compute[:cloudsigma].servers
server_create_args = {:name => 'fogtest', :cpu => 2000, :mem => 512*1024**2, :vnc_password => 'myrandompass'}
collection_tests(servers, server_create_args, true)
end

View File

@ -0,0 +1,21 @@
Shindo.tests('Fog::Compute[:cloudsigma] | volume model', ['cloudsigma']) do
volumes = Fog::Compute[:cloudsigma].volumes
volume_create_args = {:name => 'fogmodeltest', :size => 1000**3, :media => :cdrom}
model_tests(volumes, volume_create_args, true) do
@instance.wait_for(timeout=60) { status == 'unmounted' }
tests('#update').succeeds do
@instance.media = 'disk'
#@instance.size = 1024**3 # resizes disk
@instance.save
@instance.reload
@instance.wait_for(timeout=60) { status == 'unmounted' }
#returns(1024**3) { @instance.size }
returns('disk') { @instance.media }
end
end
end

View File

@ -0,0 +1,9 @@
Shindo.tests('Fog::Compute[:cloudsigma] | volumes collection', ['cloudsigma']) do
volumes = Fog::Compute[:cloudsigma].volumes
volume_create_args = {:name => 'fogtest', :size => 1024**3, :media => :cdrom}
collection_tests(volumes, volume_create_args, true) do
@instance.wait_for(timeout=60) { status == 'unmounted' }
end
end

View File

@ -0,0 +1,81 @@
Shindo.tests('Fog::Compute[:cloudsigma] | server requests', ['cloudsigma']) do
@server_format = {
'uuid' => String,
'status' => String,
'vnc_password' => String,
'name' => String,
'cpus_instead_of_cores' => Fog::Boolean,
'tags' => Array,
'mem' => Integer,
'enable_numa' => Fog::Boolean,
'smp' => Integer,
'hv_relaxed' => Fog::Boolean,
'hv_tsc' => Fog::Boolean,
'meta' => Fog::Nullable::Hash,
'owner' => Fog::Nullable::Hash,
'runtime' => Fog::Nullable::Hash,
'cpu' => Integer,
'resource_uri' => Fog::Nullable::String,
'drives' => Array,
'nics' => Array
}
@server_create_args = {:name => 'fogtest', :cpu => 2000, :mem => 512*1024**2, :vnc_password => 'myrandompass'}
tests('success') do
tests("#create_server(#@server_create_args)").formats(@server_format, false) do
server_def = Fog::Compute[:cloudsigma].create_server(@server_create_args).body['objects'].first
@server_uuid = server_def['uuid']
server_def
end
tests("#get_server(#@server_uuid)").formats(@server_format, false) do
@resp_server = Fog::Compute[:cloudsigma].get_server(@server_uuid).body
end
tests("#update_server(#@server_uuid)").formats(@server_format, false) do
@resp_server['cpu'] = 1000
@resp_server = Fog::Compute[:cloudsigma].update_server(@server_uuid, @resp_server).body
@resp_server
end
tests("#start_server(#@server_uuid)").succeeds do
response = Fog::Compute[:cloudsigma].start_server(@server_uuid)
response.body['result'] == "success"
end
server = Fog::Compute[:cloudsigma].servers.get(@server_uuid)
server.wait_for { status == 'running' }
tests("#stop_server(#@server_uuid)").succeeds do
response = Fog::Compute[:cloudsigma].stop_server(@server_uuid)
response.body['result'] == "success"
end
server = Fog::Compute[:cloudsigma].servers.get(@server_uuid)
server.wait_for { status == 'stopped' }
tests("#delete_server(#@server_uuid)").succeeds do
resp = Fog::Compute[:cloudsigma].delete_server(@server_uuid)
resp.body.empty? && resp.status == 204
end
end
tests('failure') do
tests("#get_server(#@server_uuid)|deleted|").raises(Fog::CloudSigma::Errors::NotFound) do
Fog::Compute[:cloudsigma].get_server(@server_uuid).body
end
end
end

View File

@ -0,0 +1,55 @@
Shindo.tests('Fog::Compute[:cloudsigma] | volume requests', ['cloudsigma']) do
@volume_format = {
'uuid' => String,
'size' => Integer,
'status' => String,
'name' => String,
'tags' => Array,
'meta' => Fog::Nullable::Hash,
'owner' => Fog::Nullable::Hash,
'resource_uri' => Fog::Nullable::String,
'licenses' => Array,
'jobs' => Array,
'affinities' => Array,
'mounted_on' => Array,
'media' => String,
'allow_multimount' => Fog::Boolean
}
@volume_create_args = {:name => 'fogtest', :size => 1024**3, :media => :cdrom}
tests('success') do
tests("#create_volume(#@volume_create_args)").formats(@volume_format, false) do
@resp_volume = Fog::Compute[:cloudsigma].create_volume(@volume_create_args).body['objects'].first
@volume_uuid = @resp_volume['uuid']
@resp_volume
end
volume = Fog::Compute[:cloudsigma].volumes.get(@volume_uuid)
volume.wait_for { status == 'unmounted' }
tests("#update_volume(#@volume_uuid)").formats(@volume_format, false) do
@resp_volume['media'] = 'disk'
@resp_volume = Fog::Compute[:cloudsigma].update_volume(@volume_uuid, @resp_volume).body
@resp_volume
end
tests("#delete_volume(#@volume_uuid)").succeeds do
resp = Fog::Compute[:cloudsigma].delete_volume(@volume_uuid)
resp.body.empty? && resp.status == 204
end
end
tests('failure') do
tests("#get_volume(#@server_uuid)|deleted|").raises(Fog::CloudSigma::Errors::NotFound) do
Fog::Compute[:cloudsigma].get_volume(@volume_uuid).body
end
end
end

View File

@ -93,6 +93,8 @@ if Fog.mock?
:vsphere_expected_pubkey_hash => 'abcdef1234567890',
:libvirt_uri => 'qemu:///system',
:libvirt_username => 'root',
:libvirt_password => 'password'
:libvirt_password => 'password',
:cloudsigma_username => 'csuname',
:cloudsigma_password => 'cspass'
}.merge(Fog.credentials)
end