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

Merge remote-tracking branch 'fog/master' into ssh-agent

Conflicts:
	lib/fog/joyent/compute.rb
This commit is contained in:
Kevin Chan 2013-06-02 17:34:59 +08:00
commit 815b5dbbd8
108 changed files with 3005 additions and 136 deletions

View file

@ -41,7 +41,7 @@ Gem::Specification.new do |s|
## List your runtime dependencies here. Runtime dependencies are those
## that are needed for an end user to actually USE your code.
s.add_dependency('builder')
s.add_dependency('excon', '~>0.20')
s.add_dependency('excon', '~>0.22.1')
s.add_dependency('formatador', '~>0.2.0')
s.add_dependency('multi_json', '~>1.0')
s.add_dependency('mime-types')

View file

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

View file

@ -8,46 +8,52 @@ module Fog
extend Fog::Deprecation
deprecate :ip_address, :public_ip_address
identity :id, :aliases => 'instanceId'
identity :id, :aliases => 'instanceId'
attr_accessor :architecture
attribute :ami_launch_index, :aliases => 'amiLaunchIndex'
attribute :availability_zone, :aliases => 'availabilityZone'
attribute :block_device_mapping, :aliases => 'blockDeviceMapping'
attribute :network_interfaces, :aliases => 'networkInterfaces'
attribute :client_token, :aliases => 'clientToken'
attribute :dns_name, :aliases => 'dnsName'
attribute :ebs_optimized, :aliases => 'ebsOptimized'
attribute :ami_launch_index, :aliases => 'amiLaunchIndex'
attribute :availability_zone, :aliases => 'availabilityZone'
attribute :block_device_mapping, :aliases => 'blockDeviceMapping'
attribute :network_interfaces, :aliases => 'networkInterfaces'
attribute :client_token, :aliases => 'clientToken'
attribute :dns_name, :aliases => 'dnsName'
attribute :ebs_optimized, :aliases => 'ebsOptimized'
attribute :groups
attribute :flavor_id, :aliases => 'instanceType'
attribute :iam_instance_profile, :aliases => 'iamInstanceProfile'
attribute :image_id, :aliases => 'imageId'
attribute :flavor_id, :aliases => 'instanceType'
attribute :hypervisor
attribute :iam_instance_profile, :aliases => 'iamInstanceProfile'
attribute :image_id, :aliases => 'imageId'
attr_accessor :instance_initiated_shutdown_behavior
attribute :kernel_id, :aliases => 'kernelId'
attribute :key_name, :aliases => 'keyName'
attribute :created_at, :aliases => 'launchTime'
attribute :monitoring, :squash => 'state'
attribute :placement_group, :aliases => 'groupName'
attribute :platform, :aliases => 'platform'
attribute :product_codes, :aliases => 'productCodes'
attribute :private_dns_name, :aliases => 'privateDnsName'
attribute :private_ip_address, :aliases => 'privateIpAddress'
attribute :public_ip_address, :aliases => 'ipAddress'
attribute :ramdisk_id, :aliases => 'ramdiskId'
attribute :kernel_id, :aliases => 'kernelId'
attribute :key_name, :aliases => 'keyName'
attribute :created_at, :aliases => 'launchTime'
attribute :lifecycle, :aliases => 'instanceLifecycle'
attribute :monitoring, :squash => 'state'
attribute :placement_group, :aliases => 'groupName'
attribute :platform, :aliases => 'platform'
attribute :product_codes, :aliases => 'productCodes'
attribute :private_dns_name, :aliases => 'privateDnsName'
attribute :private_ip_address, :aliases => 'privateIpAddress'
attribute :public_ip_address, :aliases => 'ipAddress'
attribute :ramdisk_id, :aliases => 'ramdiskId'
attribute :reason
attribute :root_device_name, :aliases => 'rootDeviceName'
attribute :root_device_type, :aliases => 'rootDeviceType'
attribute :security_group_ids, :aliases => 'securityGroupIds'
attribute :state, :aliases => 'instanceState', :squash => 'name'
attribute :state_reason, :aliases => 'stateReason'
attribute :subnet_id, :aliases => 'subnetId'
attribute :requester_id, :aliases => 'requesterId'
attribute :root_device_name, :aliases => 'rootDeviceName'
attribute :root_device_type, :aliases => 'rootDeviceType'
attribute :security_group_ids, :aliases => 'securityGroupIds'
attribute :source_dest_check, :aliases => 'sourceDestCheck'
attribute :spot_instance_request_id, :aliases => 'spotInstanceRequestId'
attribute :state, :aliases => 'instanceState', :squash => 'name'
attribute :state_reason, :aliases => 'stateReason'
attribute :subnet_id, :aliases => 'subnetId'
attribute :tenancy
attribute :tags, :aliases => 'tagSet'
attribute :tags, :aliases => 'tagSet'
attribute :user_data
attribute :vpc_id, :aliases => 'vpcId'
attribute :virtualization_type, :aliases => 'virtualizationType'
attribute :vpc_id, :aliases => 'vpcId'
attr_accessor :password
attr_writer :iam_instance_profile_name, :iam_instance_profile_arn
attr_accessor :password
attr_writer :iam_instance_profile_name, :iam_instance_profile_arn
def initialize(attributes={})

View file

@ -21,10 +21,26 @@ module Fog
super
end
# This will return a single page based on the current or provided filters,
# updating the filters with the marker for the next page. Calling this repeatedly
# will iterate through pages.
def all(filters = filters)
self.filters = filters
data = service.describe_db_snapshots(filters).body['DescribeDBSnapshotsResult']['DBSnapshots']
load(data) # data is an array of attribute hashes
self.filters.merge!(filters)
snapshots = service.describe_db_snapshots(filters)
self.filters[:marker] = snapshots.body['DescribeDBSnapshotsResult']['Marker']
data = snapshots.body['DescribeDBSnapshotsResult']['DBSnapshots']
load(data)
end
# This will execute a block for each snapshot, fetching new pages of snapshots as required.
def each(filters = filters)
begin
page = self.all(filters)
# We need to explicitly use the base 'each' method here on the page, otherwise we get infinite recursion
base_each = Fog::Collection.instance_method(:each)
base_each.bind(page).call {|snapshot| yield snapshot}
end while self.filters[:marker]
end
def get(identity)

View file

@ -68,7 +68,7 @@ module Fog
})
new(file_data)
rescue Excon::Errors::NotFound => error
case error.message
case error.response.body
when /<Code>NoSuchKey<\/Code>/
nil
when /<Code>NoSuchBucket<\/Code>/

View file

@ -31,10 +31,11 @@ module Fog
@instance[@context.last][name] = value
when 'availabilityZone', 'tenancy'
@instance['placement'][name] = value
when 'architecture', 'clientToken', 'dnsName', 'imageId',
'instanceId', 'instanceType', 'ipAddress', 'kernelId',
'keyName', 'platform', 'privateDnsName', 'privateIpAddress', 'ramdiskId',
'reason', 'rootDeviceType', 'virtualizationType'
when 'architecture', 'clientToken', 'dnsName', 'hypervisor', 'imageId',
'instanceId', 'instanceType', 'ipAddress', 'kernelId', 'keyName',
'instanceLifecycle', 'platform', 'privateDnsName', 'privateIpAddress', 'ramdiskId',
'reason', 'requesterId', 'rootDeviceType',
'spotInstanceRequestId', 'virtualizationType'
@instance[name] = value
when 'attachTime'
@block_device_mapping[name] = Time.parse(value)
@ -103,6 +104,12 @@ module Fog
@instance['monitoring'][name] = (value == 'enabled')
when 'ebsOptimized'
@instance['ebsOptimized'] = (value == 'true')
when 'sourceDestCheck'
if value == 'true'
@instance[name] = true
else
@instance[name] = false
end
# Eucalyptus passes status in schema non conforming way
when 'stateCode'
@instance['instanceState']['code'] = value

View file

@ -24,10 +24,11 @@ module Fog
case name
when 'amiLaunchIndex'
@instance[name] = value.to_i
when 'architecture', 'clientToken', 'dnsName', 'imageId',
'instanceId', 'instanceType', 'ipAddress', 'kernelId',
'keyName', 'privateDnsName', 'privateIpAddress', 'ramdiskId',
'reason', 'rootDeviceType'
when 'architecture', 'clientToken', 'dnsName', 'hypervisor', 'imageId',
'instanceId', 'instanceType', 'ipAddress', 'kernelId', 'keyName',
'instanceLifecycle', 'privateDnsName', 'privateIpAddress', 'ramdiskId',
'reason', 'requesterId', 'rootDeviceType', 'sourceDestCheck',
'spotInstanceRequestId', 'virtualizationType'
@instance[name] = value
when 'availabilityZone', 'tenancy'
@instance['placement'][name] = value

View file

@ -23,6 +23,8 @@ module Fog
@response['HostedZone'] = @hosted_zone
@hosted_zone = {}
@section = :name_servers
when 'ResourceRecordSetCount'
@response['ResourceRecordSetCount'] = value.to_i
end
elsif @section == :name_servers
case name

View file

@ -212,7 +212,7 @@ module Fog
'ownerId' => instance['ownerId'],
'reservationId' => instance['reservationId']
}
reservation_set[instance['reservationId']]['instancesSet'] << instance.reject{|key,value| !['amiLaunchIndex', 'architecture', 'blockDeviceMapping', 'clientToken', 'dnsName', 'ebsOptimized', 'iamInstanceProfile', 'imageId', 'instanceId', 'instanceState', 'instanceType', 'ipAddress', 'kernelId', 'keyName', 'launchTime', 'monitoring', 'networkInterfaces', 'ownerId', 'placement', 'platform', 'privateDnsName', 'privateIpAddress', 'productCodes', 'ramdiskId', 'reason', 'rootDeviceType', 'stateReason'].include?(key)}.merge('tagSet' => self.data[:tag_sets][instance['instanceId']])
reservation_set[instance['reservationId']]['instancesSet'] << instance.reject{|key,value| !['amiLaunchIndex', 'architecture', 'blockDeviceMapping', 'clientToken', 'dnsName', 'ebsOptimized', 'hypervisor', 'iamInstanceProfile', 'imageId', 'instanceId', 'instanceState', 'instanceType', 'ipAddress', 'kernelId', 'keyName', 'launchTime', 'monitoring', 'networkInterfaces', 'ownerId', 'placement', 'platform', 'privateDnsName', 'privateIpAddress', 'productCodes', 'ramdiskId', 'reason', 'rootDeviceType', 'stateReason', 'virtualizationType'].include?(key)}.merge('tagSet' => self.data[:tag_sets][instance['instanceId']])
end
end

View file

@ -143,6 +143,8 @@ module Fog
'blockDeviceMapping' => [],
'clientToken' => options['clientToken'],
'dnsName' => nil,
'ebsOptimized' => options['EbsOptimized'] || false,
'hypervisor' => 'xen',
'imageId' => image_id,
'instanceId' => instance_id,
'instanceState' => { 'code' => 0, 'name' => 'pending' },
@ -156,7 +158,7 @@ module Fog
'productCodes' => [],
'reason' => nil,
'rootDeviceType' => 'instance-store',
'ebsOptimized' => options['EbsOptimized'] || false
'virtualizationType' => 'paravirtual'
}
instances_set << instance
self.data[:instances][instance_id] = instance.merge({

View file

@ -449,7 +449,7 @@ DATA
if VALID_QUERY_KEYS.include?(key)
value = params[:query][key]
if value
query_args << "#{key}=#{Fog::AWS.escape(value.to_s)}"
query_args << "#{key}=#{value}"
else
query_args << key
end

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, :cloudsigma_host
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.data[: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, 201, 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

@ -23,7 +23,7 @@ module Fog
def get(server_id)
servers = service.list_virtual_machines('id' => server_id)["listvirtualmachinesresponse"]["virtualmachine"]
unless servers.nil?
unless servers.empty? || servers.nil?
new(servers.first)
end
rescue Fog::Compute::Cloudstack::BadRequest

View file

@ -68,7 +68,7 @@ module Fog
})
new(file_data)
rescue Excon::Errors::NotFound => error
case error.message
case error.response.body
when /<Code>NoSuchKey<\/Code>/
nil
when /<Code>NoSuchBucket<\/Code>/

View file

@ -14,6 +14,7 @@ module Fog
recognizes :joyent_keyname
recognizes :joyent_keyfile
recognizes :joyent_keyphrase
recognizes :joyent_version
model_path 'fog/joyent/models/compute'
request_path 'fog/joyent/requests/compute'
@ -74,7 +75,10 @@ module Fog
request :delete_machine_tag
request :delete_all_machine_tags
# Networks
collection :networks
model :network
request :list_networks
class Mock
def self.data

View file

@ -0,0 +1,12 @@
module Fog
module Compute
class Joyent
class Network < Fog::Model
identity :id
attribute :name
end
end
end
end

View file

@ -0,0 +1,15 @@
require 'fog/joyent/models/compute/network'
module Fog
module Compute
class Joyent
class Networks < Fog::Collection
model Fog::Compute::Joyent::Network
def all
load(service.list_networks.body)
end
end
end
end
end

View file

@ -0,0 +1,26 @@
module Fog
module Compute
class Joyent
class Mock
def list_networks(options={})
res = Excon::Response.new
res.status = 200
res.body = self.data[:networks].values
res
end
end
class Real
def list_networks(options={})
request(
:path => "/my/networks",
:method => "GET",
:query => options,
:expects => 200
)
end
end
end
end
end

View file

@ -14,19 +14,19 @@ module Fog
def all
requires :directory
if directory.collection.get(directory.key)
pwd = Dir.pwd
Dir.chdir(service.path_to(directory.key))
data = Dir.glob('**/*').reject do |file|
::File.directory?(file)
end.map do |key|
path = file_path(key)
{
:content_length => ::File.size(path),
:key => key,
:last_modified => ::File.mtime(path)
}
end
Dir.chdir(pwd)
data = []
Dir.chdir(service.path_to(directory.key)) {
data = Dir.glob('**/*').reject do |file|
::File.directory?(file)
end.map do |key|
path = file_path(key)
{
:content_length => ::File.size(path),
:key => key,
:last_modified => ::File.mtime(path)
}
end
}
load(data)
else
nil

View file

@ -18,6 +18,7 @@ module Fog
def find_by_id(id)
self.find {|image| image.id == id}
end
alias_method :get, :find_by_id
def public
images = load(service.list_public_images_detailed.body['images'])

View file

@ -16,6 +16,16 @@ module Fog
class Mock
def list_address_pools
response = Excon::Response.new
response.status = 200
response.body = {
'floating_ip_pools' => [
{ 'name' => 'nova' }
]
}
response
end
end
end

View file

@ -278,7 +278,7 @@ This returns a `Fog::Storage::Rackspace::Directory` instance:
cdn_cname=nil
>
## Create Drectory
## Create Directory
To create a directory:
@ -335,6 +335,8 @@ To upload a file into a directory:
file = directory.files.create :key => 'space.jpg', :body => File.open "space.jpg"
**Note**: For files larger than 5 GB please refer to the [Upload Large Files](#upload_large_files) section.
### Additional Parameters
The `create` method also supports the following key values:
@ -366,6 +368,37 @@ The `create` method also supports the following key values:
</tr>
</table>
## Upload Large Files
Cloud Files requires files larger than 5 GB to be uploaded into segments along with an accompanying manifest file. All of the segments must be uploaded to the same container.
SEGMENT_LIMIT = 5368709119.0 # 5GB -1
BUFFER_SIZE = 1024 * 1024 # 1MB
File.open("large_file") do |f|
num_segments = (f.size / SEGMENT_LIMIT).round + 1
1.upto(num_segments) do |segment|
offset = 0
read = 0
# upload segment to cloud files
service.put_object("my_container", "large_file/#{segment}", nil, options = {}) do
if (offset < SEGMENT_LIMIT) && (read.zero? || read == BUFFER_SIZE)
buf = f.sysread(BUFFER_SIZE)
read = buf.size
offset += read
buf
else
""
end
end
end
end
# write manifest file
service.put_object_manifest("my_container", "large_file")
Segmented files are downloaded like ordinary files. See [Download Files](#download-files) section for more information.
## Download Files
The most efficient way to download files from a private or public directory is as follows:

View file

@ -0,0 +1,99 @@
#!/usr/bin/env ruby
# This example demonstrates uploading large files in segments
require 'rubygems' #required for Ruby 1.8.x
require 'fog'
# Size of segment. The Rackspace cloud currently requires files larger than 5GB to be segmented so we will choose 5GB -1 for a size
# http://docs.rackspace.com/files/api/v1/cf-devguide/content/Large_Object_Creation-d1e2019.html
SEGMENT_LIMIT = 5368709119.0
# Size of buffer to use for transfers. Use Excon's default chunk size and if that's not avaliable we will default to 1 MB
BUFFER_SIZE = Excon.defaults[:chunk_size] || 1024 * 1024
def get_user_input(prompt)
print "\n#{prompt}: "
gets.chomp
end
def select_directory(directories)
abort "\nThere are not any directories in the Chicago region. Try running create_private_directory.rb\n\n" if directories.empty?
puts "\nSelect Directory:\n\n"
directories.each_with_index do |dir, i|
puts "\t #{i}. #{dir.key} [#{dir.count} objects]"
end
select_str = get_user_input "Enter Directory Number"
directories[select_str.to_i]
end
# Use username defined in ~/.fog file, if absent prompt for username.
# For more details on ~/.fog refer to http://fog.io/about/getting_started.html
def rackspace_username
Fog.credentials[:rackspace_username] || get_user_input("Enter Rackspace Username")
end
# Use api key defined in ~/.fog file, if absent prompt for api key
# For more details on ~/.fog refer to http://fog.io/about/getting_started.html
def rackspace_api_key
Fog.credentials[:rackspace_api_key] || get_user_input("Enter Rackspace API key")
end
# create Cloud Files service
service = Fog::Storage.new({
:provider => 'Rackspace',
:rackspace_username => rackspace_username,
:rackspace_api_key => rackspace_api_key,
:rackspace_region => :ord
})
# retrieve directories with files
directories = service.directories
# prompt for directory
directory = select_directory(directories)
# prompt for file name
file_name = get_user_input "Enter full path of file to upload"
segment_name = File.basename(file_name)
File.open(file_name) do |f|
num_segments = (f.size / SEGMENT_LIMIT).round + 1
puts "\nThis upload of '#{file_name}' will require #{num_segments} segment(s) and 1 manifest file\n"
1.upto(num_segments) do |segment|
print "\n\tUploading segment #{segment} "
offset = 0
read = 0
service.put_object(directory.key, "#{segment_name}/#{segment}", nil, options = {}) do
if (offset < SEGMENT_LIMIT) && (read.zero? || read == BUFFER_SIZE)
print "."
buf = f.sysread(BUFFER_SIZE)
read = buf.size
offset += read
buf
else
""
end
end
end
end
puts "\n\n\tWriting manifest #{segment_name}\n\n"
service.put_object_manifest(directory.key, segment_name)
puts <<-NOTE
You should now be able to download #{segment_name} from the cloud control panel or using the following code:
directory = service.directories.get('#{directory.key}')
File.open('downloaded_#{segment_name}', 'w') do | f |
directory.files.get(#{segment_name}) do | data, remaining, content_length |
print "."
f.syswrite data
end
end
NOTE

View file

@ -26,6 +26,7 @@ module Fog
attribute :updated
attribute :name
attribute :state, :aliases => 'status'
attribute :timeout
attribute :nodes
def initialize(attributes)
@ -214,23 +215,22 @@ module Fog
def create
requires :name, :protocol, :port, :virtual_ips, :nodes
if algorithm
options = { :algorithm => algorithm }
else
options = {}
end
options = {}
options[:algorithm] = algorithm if algorithm
options[:timeout] = timeout if timeout
data = service.create_load_balancer(name, protocol, port, virtual_ips_hash, nodes_hash, options)
merge_attributes(data.body['loadBalancer'])
end
def update
requires :name, :protocol, :port, :algorithm
requires :name, :protocol, :port, :algorithm, :timeout
options = {
:name => name,
:algorithm => algorithm,
:protocol => protocol,
:port => port}
:port => port,
:timeout => timeout }
service.update_load_balancer(identity, options)
#TODO - Should this bubble down to nodes? Without tracking changes this would be very inefficient.

View file

@ -132,6 +132,24 @@ module Fog
end
end
# Set last modified
# @param [String, Fog::Time] timestamp
def last_modified=(obj)
if obj.nil? || obj == "" || obj.is_a?(Time)
attributes[:last_modified] = obj
return obj
end
# This is a work around for swift bug that has existed for 4+ years. The is that fixing the swift bug would cause more problems than its worth.
# For more information refer to https://github.com/fog/fog/pull/1811
d = Date._strptime(obj,"%Y-%m-%dT%H:%M:%S")
if d
attributes[:last_modified] = Time.utc(d[:year], d[:mon], d[:mday], d[:hour], d[:min], d[:sec], d[:leftover], d[:zone])
else
attributes[:last_modified] = Time.parse(obj)
end
end
# Is file published to CDN
# @return [Boolean] return true if published to CDN
# @raise [Fog::Storage::Rackspace::NotFound] - HTTP 404

View file

@ -8,7 +8,8 @@ module Fog
'name' => options[:name],
'port' => options[:port],
'protocol' => options[:protocol],
'algorithm' => options[:algorithm]
'algorithm' => options[:algorithm],
'timeout' => options[:timeout]
}
}
request(

View file

@ -14,19 +14,22 @@ module Fog
# @raise [Fog::Storage::Rackspace::BadRequest] - HTTP 400
# @raise [Fog::Storage::Rackspace::InternalServerError] - HTTP 500
# @raise [Fog::Storage::Rackspace::ServiceError]
def put_object(container, object, data, options = {})
def put_object(container, object, data, options = {}, &block)
data = Fog::Storage.parse_data(data)
headers = data[:headers].merge!(options)
request(
:body => data[:body],
params = block_given? ? { :request_block => block } : { :body => data[:body] }
params.merge!(
:expects => 201,
:idempotent => true,
:headers => headers,
:method => 'PUT',
:path => "#{Fog::Rackspace.escape(container)}/#{Fog::Rackspace.escape(object)}"
)
end
request(params)
end
end
end
end

View file

@ -31,7 +31,7 @@ module Fog
dc_root_folder = dc.vmFolder
# Filter the root path for this datacenter not to be used."
dc_root_folder_path=dc_root_folder.path.map { | id, name | name }.join("/")
paths = path.sub(/^\/?#{dc_root_folder_path}\/?/, '').split('/')
paths = path.sub(/^\/?#{Regex.quote(dc_root_folder_path)}\/?/, '').split('/')
return dc_root_folder if paths.empty?
# Walk the tree resetting the folder pointer as we go

View file

@ -3,7 +3,8 @@ Shindo.tests('Fog::Compute[:aws] | instance requests', ['aws']) do
@instance_format = {
'architecture' => String,
'amiLaunchIndex' => Integer,
'blockDeviceMapping' => [],
'attachmentId' => Fog::Nullable::String,
'blockDeviceMapping' => [Fog::Nullable::Hash],
'clientToken' => Fog::Nullable::String,
'dnsName' => NilClass,
'ebsOptimized' => Fog::Boolean,
@ -11,24 +12,24 @@ Shindo.tests('Fog::Compute[:aws] | instance requests', ['aws']) do
'instanceId' => String,
'instanceState' => {'code' => Integer, 'name' => String},
'instanceType' => String,
# 'ipAddress' => String,
'kernelId' => Fog::Nullable::String,
'keyName' => Fog::Nullable::String,
'launchTime' => Time,
'monitoring' => {'state' => Fog::Boolean},
'networkInterfaceId' => Fog::Nullable::String,
'placement' => {
'availabilityZone' => String,
'groupName' => Fog::Nullable::String,
'tenancy' => String
'groupName' => Fog::Nullable::String,
'tenancy' => String
},
'platform' => Fog::Nullable::String,
'privateDnsName' => NilClass,
# 'privateIpAddress' => String,
'productCodes' => [],
# 'ramdiskId' => Fog::Nullable::String,
'productCodes' => Array,
'reason' => Fog::Nullable::String,
# 'rootDeviceName' => String,
'rootDeviceType' => String,
'sourceDestCheck' => Fog::Nullable::Boolean,
'subnetId' => Fog::Nullable::String,
'vpcId' => Fog::Nullable::String
}
@run_instances_format = {
@ -44,16 +45,18 @@ Shindo.tests('Fog::Compute[:aws] | instance requests', ['aws']) do
'groupSet' => [String],
'groupIds' => [String],
'instancesSet' => [@instance_format.merge(
'architecture' => String,
'dnsName' => Fog::Nullable::String,
'iamInstanceProfile' => {},
'ipAddress' => Fog::Nullable::String,
'networkInterfaces' => [],
'ownerId' => String,
'privateDnsName' => Fog::Nullable::String,
'privateIpAddress' => Fog::Nullable::String,
'stateReason' => Hash,
'tagSet' => Hash
'architecture' => String,
'dnsName' => Fog::Nullable::String,
'hypervisor' => String,
'iamInstanceProfile' => Hash,
'ipAddress' => Fog::Nullable::String,
'networkInterfaces' => Array,
'ownerId' => String,
'privateDnsName' => Fog::Nullable::String,
'privateIpAddress' => Fog::Nullable::String,
'stateReason' => Hash,
'tagSet' => Hash,
'virtualizationType' => String
)],
'ownerId' => Fog::Nullable::String,
'reservationId' => String
@ -98,7 +101,7 @@ Shindo.tests('Fog::Compute[:aws] | instance requests', ['aws']) do
'instanceTenancy' => String,
'currencyCode' => String
}],
'requestId' => String
'requestId' => String
}
@purchase_reserved_instances_offering_format = {
@ -130,43 +133,36 @@ Shindo.tests('Fog::Compute[:aws] | instance requests', ['aws']) do
}
@describe_instance_status_format = {
'requestId' => String,
'requestId' => String,
'instanceStatusSet' => [{
'instanceId' => String,
'availabilityZone' => String,
'instanceState' => {
'code' => Integer,
'name' => String
},
'systemStatus' => {
'status' => String,
'details' => [{
'name' => String,
'status' => String
}]
},
'instanceStatus' => {
'status' => String,
'details' => [{
'name' => String,
'status' => String
}]
},
'eventsSet' => [{
'code' => String,
'description' => String,
'notBefore' => Time,
'notAfter' => Time
}]
}]
'instanceId' => String,
'availabilityZone' => String,
'instanceState' => {
'code' => Integer,
'name' => String
},
'systemStatus' => {
'status' => String,
'details' => [{
'name' => String,
'status' => String
}]
},
'instanceStatus' => {
'status' => String,
'details' => [{
'name' => String,
'status' => String
}]
},
'eventsSet' => [Fog::Nullable::Hash],
}]
}
tests('success') do
@instance_id = nil
@ami = if ENV['FASTER_TEST_PLEASE']
'ami-6bbb1302' # ubuntu 12.04 daily build 20120728
'ami-79c0ae10' # ubuntu 12.04 daily build 20120728
else
# Use a MS Windows AMI to test #get_password_data
'ami-71b50018' # Amazon Public Images - Windows_Server-2008-SP2-English-64Bit-Base-2012.07.11
@ -191,14 +187,14 @@ Shindo.tests('Fog::Compute[:aws] | instance requests', ['aws']) do
server.wait_for { ready? }
tests("#describe_instances").formats(@describe_instances_format) do
Fog::Compute[:aws].describe_instances('instance-state-name' => 'running').body
Fog::Compute[:aws].describe_instances('instance-state-name' => 'running').body
end
# Launch another instance to test filters
another_server = Fog::Compute[:aws].servers.create
tests("#describe_instances('instance-id' => '#{@instance_id}')").formats(@describe_instances_format) do
body = Fog::Compute[:aws].describe_instances('instance-id' => @instance_id).body
tests("#describe_instances('instance-id' => '#{@instance_id}'").formats(@describe_instances_format) do
body = Fog::Compute[:aws].describe_instances('instance-id' => "#{@instance_id}").body
tests("returns 1 instance").returns(1) { body['reservationSet'].size }
body
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

Some files were not shown because too many files have changed in this diff Show more