From e61b81bf49e8bef359a4946341f6d007b6bc7113 Mon Sep 17 00:00:00 2001 From: Kaloyan Kanev Date: Fri, 18 Jan 2013 17:34:08 +0200 Subject: [PATCH 1/4] [cloudsigma] Add CloudSigma compute provider --- lib/fog.rb | 2 + lib/fog/bin.rb | 1 + lib/fog/bin/cloudsigma.rb | 29 +++ lib/fog/cloudsigma.rb | 9 + lib/fog/cloudsigma/compute.rb | 221 ++++++++++++++++++ lib/fog/cloudsigma/connection.rb | 197 ++++++++++++++++ lib/fog/cloudsigma/error.rb | 45 ++++ lib/fog/cloudsigma/mock_data.rb | 46 ++++ lib/fog/cloudsigma/models/balance.rb | 12 + lib/fog/cloudsigma/models/current_usage.rb | 19 ++ lib/fog/cloudsigma/models/ip.rb | 22 ++ lib/fog/cloudsigma/models/ipconf.rb | 12 + lib/fog/cloudsigma/models/ips.rb | 27 +++ lib/fog/cloudsigma/models/lib_volume.rb | 50 ++++ lib/fog/cloudsigma/models/lib_volumes.rb | 27 +++ lib/fog/cloudsigma/models/mountpoint.rb | 25 ++ lib/fog/cloudsigma/models/nic.rb | 22 ++ lib/fog/cloudsigma/models/obj_ref.rb | 12 + .../cloudsigma/models/price_calculation.rb | 13 ++ lib/fog/cloudsigma/models/price_record.rb | 38 +++ lib/fog/cloudsigma/models/pricing.rb | 20 ++ lib/fog/cloudsigma/models/profile.rb | 50 ++++ lib/fog/cloudsigma/models/server.rb | 208 +++++++++++++++++ lib/fog/cloudsigma/models/servers.rb | 27 +++ lib/fog/cloudsigma/models/subscription.rb | 53 +++++ lib/fog/cloudsigma/models/subscriptions.rb | 41 ++++ lib/fog/cloudsigma/models/usage_record.rb | 13 ++ lib/fog/cloudsigma/models/vlan.rb | 29 +++ lib/fog/cloudsigma/models/vlans.rb | 27 +++ lib/fog/cloudsigma/models/volume.rb | 71 ++++++ lib/fog/cloudsigma/models/volumes.rb | 27 +++ lib/fog/cloudsigma/nested_model.rb | 60 +++++ .../requests/calculate_subscription_price.rb | 18 ++ .../cloudsigma/requests/clone_libvolume.rb | 32 +++ lib/fog/cloudsigma/requests/clone_server.rb | 32 +++ lib/fog/cloudsigma/requests/clone_volume.rb | 32 +++ lib/fog/cloudsigma/requests/close_vnc.rb | 30 +++ lib/fog/cloudsigma/requests/create_server.rb | 33 +++ .../requests/create_subscription.rb | 40 ++++ lib/fog/cloudsigma/requests/create_volume.rb | 30 +++ lib/fog/cloudsigma/requests/delete_server.rb | 18 ++ lib/fog/cloudsigma/requests/delete_volume.rb | 18 ++ .../requests/extend_subscription.rb | 22 ++ lib/fog/cloudsigma/requests/get_balance.rb | 18 ++ .../cloudsigma/requests/get_current_usage.rb | 18 ++ lib/fog/cloudsigma/requests/get_ip.rb | 18 ++ lib/fog/cloudsigma/requests/get_lib_volume.rb | 18 ++ lib/fog/cloudsigma/requests/get_pricing.rb | 28 +++ lib/fog/cloudsigma/requests/get_profile.rb | 18 ++ lib/fog/cloudsigma/requests/get_server.rb | 18 ++ .../cloudsigma/requests/get_subscription.rb | 18 ++ lib/fog/cloudsigma/requests/get_vlan.rb | 18 ++ lib/fog/cloudsigma/requests/get_volume.rb | 18 ++ lib/fog/cloudsigma/requests/list_ips.rb | 18 ++ .../cloudsigma/requests/list_lib_volumes.rb | 18 ++ lib/fog/cloudsigma/requests/list_servers.rb | 18 ++ .../cloudsigma/requests/list_subscriptions.rb | 18 ++ lib/fog/cloudsigma/requests/list_vlans.rb | 18 ++ lib/fog/cloudsigma/requests/list_volumes.rb | 18 ++ lib/fog/cloudsigma/requests/open_vnc.rb | 34 +++ lib/fog/cloudsigma/requests/start_server.rb | 32 +++ lib/fog/cloudsigma/requests/stop_server.rb | 33 +++ lib/fog/cloudsigma/requests/update_profile.rb | 18 ++ lib/fog/cloudsigma/requests/update_server.rb | 40 ++++ lib/fog/cloudsigma/requests/update_vlan.rb | 20 ++ lib/fog/cloudsigma/requests/update_volume.rb | 18 ++ tests/cloudsigma/models/server_tests.rb | 72 ++++++ tests/cloudsigma/models/servers_tests.rb | 7 + tests/cloudsigma/models/volume_tests.rb | 21 ++ tests/cloudsigma/models/volumes_tests.rb | 9 + tests/cloudsigma/requests/server_tests.rb | 81 +++++++ tests/cloudsigma/requests/volumes_tests.rb | 55 +++++ tests/helpers/mock_helper.rb | 4 +- 73 files changed, 2501 insertions(+), 1 deletion(-) create mode 100644 lib/fog/bin/cloudsigma.rb create mode 100644 lib/fog/cloudsigma.rb create mode 100644 lib/fog/cloudsigma/compute.rb create mode 100644 lib/fog/cloudsigma/connection.rb create mode 100644 lib/fog/cloudsigma/error.rb create mode 100644 lib/fog/cloudsigma/mock_data.rb create mode 100644 lib/fog/cloudsigma/models/balance.rb create mode 100644 lib/fog/cloudsigma/models/current_usage.rb create mode 100644 lib/fog/cloudsigma/models/ip.rb create mode 100644 lib/fog/cloudsigma/models/ipconf.rb create mode 100644 lib/fog/cloudsigma/models/ips.rb create mode 100644 lib/fog/cloudsigma/models/lib_volume.rb create mode 100644 lib/fog/cloudsigma/models/lib_volumes.rb create mode 100644 lib/fog/cloudsigma/models/mountpoint.rb create mode 100644 lib/fog/cloudsigma/models/nic.rb create mode 100644 lib/fog/cloudsigma/models/obj_ref.rb create mode 100644 lib/fog/cloudsigma/models/price_calculation.rb create mode 100644 lib/fog/cloudsigma/models/price_record.rb create mode 100644 lib/fog/cloudsigma/models/pricing.rb create mode 100644 lib/fog/cloudsigma/models/profile.rb create mode 100644 lib/fog/cloudsigma/models/server.rb create mode 100644 lib/fog/cloudsigma/models/servers.rb create mode 100644 lib/fog/cloudsigma/models/subscription.rb create mode 100644 lib/fog/cloudsigma/models/subscriptions.rb create mode 100644 lib/fog/cloudsigma/models/usage_record.rb create mode 100644 lib/fog/cloudsigma/models/vlan.rb create mode 100644 lib/fog/cloudsigma/models/vlans.rb create mode 100644 lib/fog/cloudsigma/models/volume.rb create mode 100644 lib/fog/cloudsigma/models/volumes.rb create mode 100644 lib/fog/cloudsigma/nested_model.rb create mode 100644 lib/fog/cloudsigma/requests/calculate_subscription_price.rb create mode 100644 lib/fog/cloudsigma/requests/clone_libvolume.rb create mode 100644 lib/fog/cloudsigma/requests/clone_server.rb create mode 100644 lib/fog/cloudsigma/requests/clone_volume.rb create mode 100644 lib/fog/cloudsigma/requests/close_vnc.rb create mode 100644 lib/fog/cloudsigma/requests/create_server.rb create mode 100644 lib/fog/cloudsigma/requests/create_subscription.rb create mode 100644 lib/fog/cloudsigma/requests/create_volume.rb create mode 100644 lib/fog/cloudsigma/requests/delete_server.rb create mode 100644 lib/fog/cloudsigma/requests/delete_volume.rb create mode 100644 lib/fog/cloudsigma/requests/extend_subscription.rb create mode 100644 lib/fog/cloudsigma/requests/get_balance.rb create mode 100644 lib/fog/cloudsigma/requests/get_current_usage.rb create mode 100644 lib/fog/cloudsigma/requests/get_ip.rb create mode 100644 lib/fog/cloudsigma/requests/get_lib_volume.rb create mode 100644 lib/fog/cloudsigma/requests/get_pricing.rb create mode 100644 lib/fog/cloudsigma/requests/get_profile.rb create mode 100644 lib/fog/cloudsigma/requests/get_server.rb create mode 100644 lib/fog/cloudsigma/requests/get_subscription.rb create mode 100644 lib/fog/cloudsigma/requests/get_vlan.rb create mode 100644 lib/fog/cloudsigma/requests/get_volume.rb create mode 100644 lib/fog/cloudsigma/requests/list_ips.rb create mode 100644 lib/fog/cloudsigma/requests/list_lib_volumes.rb create mode 100644 lib/fog/cloudsigma/requests/list_servers.rb create mode 100644 lib/fog/cloudsigma/requests/list_subscriptions.rb create mode 100644 lib/fog/cloudsigma/requests/list_vlans.rb create mode 100644 lib/fog/cloudsigma/requests/list_volumes.rb create mode 100644 lib/fog/cloudsigma/requests/open_vnc.rb create mode 100644 lib/fog/cloudsigma/requests/start_server.rb create mode 100644 lib/fog/cloudsigma/requests/stop_server.rb create mode 100644 lib/fog/cloudsigma/requests/update_profile.rb create mode 100644 lib/fog/cloudsigma/requests/update_server.rb create mode 100644 lib/fog/cloudsigma/requests/update_vlan.rb create mode 100644 lib/fog/cloudsigma/requests/update_volume.rb create mode 100644 tests/cloudsigma/models/server_tests.rb create mode 100644 tests/cloudsigma/models/servers_tests.rb create mode 100644 tests/cloudsigma/models/volume_tests.rb create mode 100644 tests/cloudsigma/models/volumes_tests.rb create mode 100644 tests/cloudsigma/requests/server_tests.rb create mode 100644 tests/cloudsigma/requests/volumes_tests.rb diff --git a/lib/fog.rb b/lib/fog.rb index 3185281b8..d53baf9cd 100644 --- a/lib/fog.rb +++ b/lib/fog.rb @@ -42,3 +42,5 @@ require 'fog/vsphere' require 'fog/voxel' require 'fog/xenserver' require 'fog/zerigo' +require 'fog/cloudsigma' + diff --git a/lib/fog/bin.rb b/lib/fog/bin.rb index c7a3650ef..8cf85fcf0 100644 --- a/lib/fog/bin.rb +++ b/lib/fog/bin.rb @@ -94,3 +94,4 @@ require 'fog/bin/vsphere' require 'fog/bin/voxel' require 'fog/bin/xenserver' require 'fog/bin/zerigo' +require 'fog/bin/cloudsigma' diff --git a/lib/fog/bin/cloudsigma.rb b/lib/fog/bin/cloudsigma.rb new file mode 100644 index 000000000..9f572c289 --- /dev/null +++ b/lib/fog/bin/cloudsigma.rb @@ -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 \ No newline at end of file diff --git a/lib/fog/cloudsigma.rb b/lib/fog/cloudsigma.rb new file mode 100644 index 000000000..201ea2c07 --- /dev/null +++ b/lib/fog/cloudsigma.rb @@ -0,0 +1,9 @@ +require 'fog/core' + +module Fog + module CloudSigma + extend Fog::Provider + + service(:compute, 'cloudsigma/compute', 'Compute') + end +end diff --git a/lib/fog/cloudsigma/compute.rb b/lib/fog/cloudsigma/compute.rb new file mode 100644 index 000000000..9dd0a5e6e --- /dev/null +++ b/lib/fog/cloudsigma/compute.rb @@ -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 diff --git a/lib/fog/cloudsigma/connection.rb b/lib/fog/cloudsigma/connection.rb new file mode 100644 index 000000000..2c6009884 --- /dev/null +++ b/lib/fog/cloudsigma/connection.rb @@ -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 \ No newline at end of file diff --git a/lib/fog/cloudsigma/error.rb b/lib/fog/cloudsigma/error.rb new file mode 100644 index 000000000..bba86fb58 --- /dev/null +++ b/lib/fog/cloudsigma/error.rb @@ -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 \ No newline at end of file diff --git a/lib/fog/cloudsigma/mock_data.rb b/lib/fog/cloudsigma/mock_data.rb new file mode 100644 index 000000000..dd85aa912 --- /dev/null +++ b/lib/fog/cloudsigma/mock_data.rb @@ -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 \ No newline at end of file diff --git a/lib/fog/cloudsigma/models/balance.rb b/lib/fog/cloudsigma/models/balance.rb new file mode 100644 index 000000000..d6e9e74cb --- /dev/null +++ b/lib/fog/cloudsigma/models/balance.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/current_usage.rb b/lib/fog/cloudsigma/models/current_usage.rb new file mode 100644 index 000000000..875744f6e --- /dev/null +++ b/lib/fog/cloudsigma/models/current_usage.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/ip.rb b/lib/fog/cloudsigma/models/ip.rb new file mode 100644 index 000000000..a50053dea --- /dev/null +++ b/lib/fog/cloudsigma/models/ip.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/ipconf.rb b/lib/fog/cloudsigma/models/ipconf.rb new file mode 100644 index 000000000..73c3898f3 --- /dev/null +++ b/lib/fog/cloudsigma/models/ipconf.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/ips.rb b/lib/fog/cloudsigma/models/ips.rb new file mode 100644 index 000000000..cfb7906d1 --- /dev/null +++ b/lib/fog/cloudsigma/models/ips.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/lib_volume.rb b/lib/fog/cloudsigma/models/lib_volume.rb new file mode 100644 index 000000000..e5d285018 --- /dev/null +++ b/lib/fog/cloudsigma/models/lib_volume.rb @@ -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 \ No newline at end of file diff --git a/lib/fog/cloudsigma/models/lib_volumes.rb b/lib/fog/cloudsigma/models/lib_volumes.rb new file mode 100644 index 000000000..7578ab9f8 --- /dev/null +++ b/lib/fog/cloudsigma/models/lib_volumes.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/mountpoint.rb b/lib/fog/cloudsigma/models/mountpoint.rb new file mode 100644 index 000000000..3718cd4ec --- /dev/null +++ b/lib/fog/cloudsigma/models/mountpoint.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/nic.rb b/lib/fog/cloudsigma/models/nic.rb new file mode 100644 index 000000000..a552e0da1 --- /dev/null +++ b/lib/fog/cloudsigma/models/nic.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/obj_ref.rb b/lib/fog/cloudsigma/models/obj_ref.rb new file mode 100644 index 000000000..bb6468b38 --- /dev/null +++ b/lib/fog/cloudsigma/models/obj_ref.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/price_calculation.rb b/lib/fog/cloudsigma/models/price_calculation.rb new file mode 100644 index 000000000..d1fa4b2f6 --- /dev/null +++ b/lib/fog/cloudsigma/models/price_calculation.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/price_record.rb b/lib/fog/cloudsigma/models/price_record.rb new file mode 100644 index 000000000..27816a209 --- /dev/null +++ b/lib/fog/cloudsigma/models/price_record.rb @@ -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 \ No newline at end of file diff --git a/lib/fog/cloudsigma/models/pricing.rb b/lib/fog/cloudsigma/models/pricing.rb new file mode 100644 index 000000000..be81d1bf9 --- /dev/null +++ b/lib/fog/cloudsigma/models/pricing.rb @@ -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 \ No newline at end of file diff --git a/lib/fog/cloudsigma/models/profile.rb b/lib/fog/cloudsigma/models/profile.rb new file mode 100644 index 000000000..ea4639ec3 --- /dev/null +++ b/lib/fog/cloudsigma/models/profile.rb @@ -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 \ No newline at end of file diff --git a/lib/fog/cloudsigma/models/server.rb b/lib/fog/cloudsigma/models/server.rb new file mode 100644 index 000000000..3afbe1233 --- /dev/null +++ b/lib/fog/cloudsigma/models/server.rb @@ -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 \ No newline at end of file diff --git a/lib/fog/cloudsigma/models/servers.rb b/lib/fog/cloudsigma/models/servers.rb new file mode 100644 index 000000000..eb68fac6f --- /dev/null +++ b/lib/fog/cloudsigma/models/servers.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/subscription.rb b/lib/fog/cloudsigma/models/subscription.rb new file mode 100644 index 000000000..60865270a --- /dev/null +++ b/lib/fog/cloudsigma/models/subscription.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/subscriptions.rb b/lib/fog/cloudsigma/models/subscriptions.rb new file mode 100644 index 000000000..637cbfedc --- /dev/null +++ b/lib/fog/cloudsigma/models/subscriptions.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/usage_record.rb b/lib/fog/cloudsigma/models/usage_record.rb new file mode 100644 index 000000000..fd1f064d0 --- /dev/null +++ b/lib/fog/cloudsigma/models/usage_record.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/vlan.rb b/lib/fog/cloudsigma/models/vlan.rb new file mode 100644 index 000000000..19290ef7b --- /dev/null +++ b/lib/fog/cloudsigma/models/vlan.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/vlans.rb b/lib/fog/cloudsigma/models/vlans.rb new file mode 100644 index 000000000..b5f67aa03 --- /dev/null +++ b/lib/fog/cloudsigma/models/vlans.rb @@ -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 diff --git a/lib/fog/cloudsigma/models/volume.rb b/lib/fog/cloudsigma/models/volume.rb new file mode 100644 index 000000000..fee03fba2 --- /dev/null +++ b/lib/fog/cloudsigma/models/volume.rb @@ -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 \ No newline at end of file diff --git a/lib/fog/cloudsigma/models/volumes.rb b/lib/fog/cloudsigma/models/volumes.rb new file mode 100644 index 000000000..40881e41e --- /dev/null +++ b/lib/fog/cloudsigma/models/volumes.rb @@ -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 diff --git a/lib/fog/cloudsigma/nested_model.rb b/lib/fog/cloudsigma/nested_model.rb new file mode 100644 index 000000000..1b0ce2118 --- /dev/null +++ b/lib/fog/cloudsigma/nested_model.rb @@ -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 \ No newline at end of file diff --git a/lib/fog/cloudsigma/requests/calculate_subscription_price.rb b/lib/fog/cloudsigma/requests/calculate_subscription_price.rb new file mode 100644 index 000000000..bd2cfccfa --- /dev/null +++ b/lib/fog/cloudsigma/requests/calculate_subscription_price.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/clone_libvolume.rb b/lib/fog/cloudsigma/requests/clone_libvolume.rb new file mode 100644 index 000000000..40d66227d --- /dev/null +++ b/lib/fog/cloudsigma/requests/clone_libvolume.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/clone_server.rb b/lib/fog/cloudsigma/requests/clone_server.rb new file mode 100644 index 000000000..da985f764 --- /dev/null +++ b/lib/fog/cloudsigma/requests/clone_server.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/clone_volume.rb b/lib/fog/cloudsigma/requests/clone_volume.rb new file mode 100644 index 000000000..3a647b914 --- /dev/null +++ b/lib/fog/cloudsigma/requests/clone_volume.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/close_vnc.rb b/lib/fog/cloudsigma/requests/close_vnc.rb new file mode 100644 index 000000000..e98e58a65 --- /dev/null +++ b/lib/fog/cloudsigma/requests/close_vnc.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/create_server.rb b/lib/fog/cloudsigma/requests/create_server.rb new file mode 100644 index 000000000..2e8ac5a72 --- /dev/null +++ b/lib/fog/cloudsigma/requests/create_server.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/create_subscription.rb b/lib/fog/cloudsigma/requests/create_subscription.rb new file mode 100644 index 000000000..80223506a --- /dev/null +++ b/lib/fog/cloudsigma/requests/create_subscription.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/create_volume.rb b/lib/fog/cloudsigma/requests/create_volume.rb new file mode 100644 index 000000000..185d5b719 --- /dev/null +++ b/lib/fog/cloudsigma/requests/create_volume.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/delete_server.rb b/lib/fog/cloudsigma/requests/delete_server.rb new file mode 100644 index 000000000..c6e3a39b5 --- /dev/null +++ b/lib/fog/cloudsigma/requests/delete_server.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/delete_volume.rb b/lib/fog/cloudsigma/requests/delete_volume.rb new file mode 100644 index 000000000..f54f8f092 --- /dev/null +++ b/lib/fog/cloudsigma/requests/delete_volume.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/extend_subscription.rb b/lib/fog/cloudsigma/requests/extend_subscription.rb new file mode 100644 index 000000000..87c7d4376 --- /dev/null +++ b/lib/fog/cloudsigma/requests/extend_subscription.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/get_balance.rb b/lib/fog/cloudsigma/requests/get_balance.rb new file mode 100644 index 000000000..0ffa2afc8 --- /dev/null +++ b/lib/fog/cloudsigma/requests/get_balance.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/get_current_usage.rb b/lib/fog/cloudsigma/requests/get_current_usage.rb new file mode 100644 index 000000000..31c78e78f --- /dev/null +++ b/lib/fog/cloudsigma/requests/get_current_usage.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/get_ip.rb b/lib/fog/cloudsigma/requests/get_ip.rb new file mode 100644 index 000000000..58d065baa --- /dev/null +++ b/lib/fog/cloudsigma/requests/get_ip.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/get_lib_volume.rb b/lib/fog/cloudsigma/requests/get_lib_volume.rb new file mode 100644 index 000000000..6d0878729 --- /dev/null +++ b/lib/fog/cloudsigma/requests/get_lib_volume.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/get_pricing.rb b/lib/fog/cloudsigma/requests/get_pricing.rb new file mode 100644 index 000000000..20e1e9b83 --- /dev/null +++ b/lib/fog/cloudsigma/requests/get_pricing.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/get_profile.rb b/lib/fog/cloudsigma/requests/get_profile.rb new file mode 100644 index 000000000..5b6bf67d4 --- /dev/null +++ b/lib/fog/cloudsigma/requests/get_profile.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/get_server.rb b/lib/fog/cloudsigma/requests/get_server.rb new file mode 100644 index 000000000..39b502674 --- /dev/null +++ b/lib/fog/cloudsigma/requests/get_server.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/get_subscription.rb b/lib/fog/cloudsigma/requests/get_subscription.rb new file mode 100644 index 000000000..bd4ff454e --- /dev/null +++ b/lib/fog/cloudsigma/requests/get_subscription.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/get_vlan.rb b/lib/fog/cloudsigma/requests/get_vlan.rb new file mode 100644 index 000000000..93d7e2439 --- /dev/null +++ b/lib/fog/cloudsigma/requests/get_vlan.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/get_volume.rb b/lib/fog/cloudsigma/requests/get_volume.rb new file mode 100644 index 000000000..deeefeb4d --- /dev/null +++ b/lib/fog/cloudsigma/requests/get_volume.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/list_ips.rb b/lib/fog/cloudsigma/requests/list_ips.rb new file mode 100644 index 000000000..a03f119ca --- /dev/null +++ b/lib/fog/cloudsigma/requests/list_ips.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/list_lib_volumes.rb b/lib/fog/cloudsigma/requests/list_lib_volumes.rb new file mode 100644 index 000000000..d782ace47 --- /dev/null +++ b/lib/fog/cloudsigma/requests/list_lib_volumes.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/list_servers.rb b/lib/fog/cloudsigma/requests/list_servers.rb new file mode 100644 index 000000000..942ec7d0c --- /dev/null +++ b/lib/fog/cloudsigma/requests/list_servers.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/list_subscriptions.rb b/lib/fog/cloudsigma/requests/list_subscriptions.rb new file mode 100644 index 000000000..ccb5355ae --- /dev/null +++ b/lib/fog/cloudsigma/requests/list_subscriptions.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/list_vlans.rb b/lib/fog/cloudsigma/requests/list_vlans.rb new file mode 100644 index 000000000..f49b7884d --- /dev/null +++ b/lib/fog/cloudsigma/requests/list_vlans.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/list_volumes.rb b/lib/fog/cloudsigma/requests/list_volumes.rb new file mode 100644 index 000000000..b26998b2b --- /dev/null +++ b/lib/fog/cloudsigma/requests/list_volumes.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/open_vnc.rb b/lib/fog/cloudsigma/requests/open_vnc.rb new file mode 100644 index 000000000..831d9b4ae --- /dev/null +++ b/lib/fog/cloudsigma/requests/open_vnc.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/start_server.rb b/lib/fog/cloudsigma/requests/start_server.rb new file mode 100644 index 000000000..740502d76 --- /dev/null +++ b/lib/fog/cloudsigma/requests/start_server.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/stop_server.rb b/lib/fog/cloudsigma/requests/stop_server.rb new file mode 100644 index 000000000..e13f4c58b --- /dev/null +++ b/lib/fog/cloudsigma/requests/stop_server.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/update_profile.rb b/lib/fog/cloudsigma/requests/update_profile.rb new file mode 100644 index 000000000..dc4fd2745 --- /dev/null +++ b/lib/fog/cloudsigma/requests/update_profile.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/update_server.rb b/lib/fog/cloudsigma/requests/update_server.rb new file mode 100644 index 000000000..d485f4337 --- /dev/null +++ b/lib/fog/cloudsigma/requests/update_server.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/update_vlan.rb b/lib/fog/cloudsigma/requests/update_vlan.rb new file mode 100644 index 000000000..223832fba --- /dev/null +++ b/lib/fog/cloudsigma/requests/update_vlan.rb @@ -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 diff --git a/lib/fog/cloudsigma/requests/update_volume.rb b/lib/fog/cloudsigma/requests/update_volume.rb new file mode 100644 index 000000000..a1bf30c0c --- /dev/null +++ b/lib/fog/cloudsigma/requests/update_volume.rb @@ -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 diff --git a/tests/cloudsigma/models/server_tests.rb b/tests/cloudsigma/models/server_tests.rb new file mode 100644 index 000000000..cf9150509 --- /dev/null +++ b/tests/cloudsigma/models/server_tests.rb @@ -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 \ No newline at end of file diff --git a/tests/cloudsigma/models/servers_tests.rb b/tests/cloudsigma/models/servers_tests.rb new file mode 100644 index 000000000..f8811d92a --- /dev/null +++ b/tests/cloudsigma/models/servers_tests.rb @@ -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 \ No newline at end of file diff --git a/tests/cloudsigma/models/volume_tests.rb b/tests/cloudsigma/models/volume_tests.rb new file mode 100644 index 000000000..8f970ddda --- /dev/null +++ b/tests/cloudsigma/models/volume_tests.rb @@ -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 \ No newline at end of file diff --git a/tests/cloudsigma/models/volumes_tests.rb b/tests/cloudsigma/models/volumes_tests.rb new file mode 100644 index 000000000..35903ff3b --- /dev/null +++ b/tests/cloudsigma/models/volumes_tests.rb @@ -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 \ No newline at end of file diff --git a/tests/cloudsigma/requests/server_tests.rb b/tests/cloudsigma/requests/server_tests.rb new file mode 100644 index 000000000..7b803c098 --- /dev/null +++ b/tests/cloudsigma/requests/server_tests.rb @@ -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 diff --git a/tests/cloudsigma/requests/volumes_tests.rb b/tests/cloudsigma/requests/volumes_tests.rb new file mode 100644 index 000000000..c9e6df14d --- /dev/null +++ b/tests/cloudsigma/requests/volumes_tests.rb @@ -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 \ No newline at end of file diff --git a/tests/helpers/mock_helper.rb b/tests/helpers/mock_helper.rb index 6a0582585..285f32e67 100644 --- a/tests/helpers/mock_helper.rb +++ b/tests/helpers/mock_helper.rb @@ -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 From a77ccfbd1d5e11c76e2b992ce46ba52df5f4da04 Mon Sep 17 00:00:00 2001 From: Kaloyan Kanev Date: Wed, 27 Mar 2013 15:57:20 +0200 Subject: [PATCH 2/4] [cloudsigma] Fix create request not expecting status 201 --- lib/fog/cloudsigma/connection.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fog/cloudsigma/connection.rb b/lib/fog/cloudsigma/connection.rb index 2c6009884..cd24d2c3e 100644 --- a/lib/fog/cloudsigma/connection.rb +++ b/lib/fog/cloudsigma/connection.rb @@ -89,7 +89,7 @@ module Fog end def create_request(path, data, override_params={}) - default_params = {:method => 'POST', :expects => [200, 202]} + default_params = {:method => 'POST', :expects => [200, 201, 202]} override_params[:path] = path override_params[:body] = data From 8f664c1ffc031c87c1b08eefdae55dd9122492b9 Mon Sep 17 00:00:00 2001 From: Kaloyan Kanev Date: Wed, 27 Mar 2013 15:58:54 +0200 Subject: [PATCH 3/4] [cloudsigma] Make api location as an option (:cloudsigma_host) --- lib/fog/cloudsigma/compute.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fog/cloudsigma/compute.rb b/lib/fog/cloudsigma/compute.rb index 9dd0a5e6e..38bbe2e0e 100644 --- a/lib/fog/cloudsigma/compute.rb +++ b/lib/fog/cloudsigma/compute.rb @@ -6,7 +6,7 @@ module Fog module Compute class CloudSigma < Fog::Service requires :cloudsigma_password, :cloudsigma_username - recognizes :cloudsigma_password, :cloudsigma_username + recognizes :cloudsigma_password, :cloudsigma_username, :cloudsigma_host model_path 'fog/cloudsigma/models' request_path 'fog/cloudsigma/requests' From b1bb07e48d614e71f9577c1112848c5d989e4e9c Mon Sep 17 00:00:00 2001 From: Kaloyan Kanev Date: Wed, 27 Mar 2013 17:00:46 +0200 Subject: [PATCH 4/4] [cloudsigma] Fix excon HTTPStatusError#response not having []= and failing on assignment of json decoded body --- lib/fog/cloudsigma/connection.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fog/cloudsigma/connection.rb b/lib/fog/cloudsigma/connection.rb index cd24d2c3e..7cb4f59a6 100644 --- a/lib/fog/cloudsigma/connection.rb +++ b/lib/fog/cloudsigma/connection.rb @@ -54,7 +54,7 @@ module Fog response = @connection.request(params) rescue Excon::Errors::HTTPStatusError => e - e.response[:body] = Fog::JSON.decode(e.response[:body]) unless e.response[:body].empty? + 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