From 61155040e1f8ac52865d69831b5c7e15282870f7 Mon Sep 17 00:00:00 2001 From: Edward Muller Date: Tue, 8 Jun 2010 00:18:06 +0800 Subject: [PATCH] Internet Services and tweaks to Vcloud collection/model. configure internet service flesh out internet services a bit more more tweaks to vcloud collection/model related stuff remove debugging --- lib/fog/vcloud/collection.rb | 27 ++++- lib/fog/vcloud/model.rb | 4 + lib/fog/vcloud/terremark/ecloud.rb | 1 + .../ecloud/models/internet_service.rb | 40 ++++++++ .../ecloud/models/internet_services.rb | 15 +-- .../terremark/ecloud/models/public_ip.rb | 4 +- .../terremark/ecloud/models/public_ips.rb | 2 +- lib/fog/vcloud/terremark/ecloud/models/vdc.rb | 3 + .../vcloud/terremark/ecloud/models/vdcs.rb | 2 + .../ecloud/requests/add_internet_service.rb | 17 ++-- .../requests/configure_internet_service.rb | 99 +++++++++++++++++++ .../ecloud/models/internet_service_spec.rb | 15 +++ .../configure_internet_service_spec.rb | 44 +++++++++ 13 files changed, 250 insertions(+), 23 deletions(-) create mode 100644 lib/fog/vcloud/terremark/ecloud/requests/configure_internet_service.rb create mode 100644 spec/vcloud/terremark/ecloud/requests/configure_internet_service_spec.rb diff --git a/lib/fog/vcloud/collection.rb b/lib/fog/vcloud/collection.rb index 6c47190d8..d45aeaa44 100644 --- a/lib/fog/vcloud/collection.rb +++ b/lib/fog/vcloud/collection.rb @@ -53,14 +53,33 @@ module Fog end end - def [](index) - self.slice(index).reload + attr_accessor :href + + def create(attributes = {}) + attributes.merge!(:new => true) + obj = super(attributes) + self << obj + obj end - def reload - self.all + def each + super do |item| + item.reload + yield(item) + end end + def [](index) + if obj = super + obj.reload unless obj.loaded? + end + obj + end + + #def reload + # self.all + #end + end end end diff --git a/lib/fog/vcloud/model.rb b/lib/fog/vcloud/model.rb index cc1451689..db6ed6854 100644 --- a/lib/fog/vcloud/model.rb +++ b/lib/fog/vcloud/model.rb @@ -27,9 +27,13 @@ module Fog end end + attr_accessor :loaded + alias_method :loaded?, :loaded + def reload if data = collection.get_raw(identity) merge_get_raw_result(data) + @loaded = true self end end diff --git a/lib/fog/vcloud/terremark/ecloud.rb b/lib/fog/vcloud/terremark/ecloud.rb index ceccee7df..571cdedfc 100644 --- a/lib/fog/vcloud/terremark/ecloud.rb +++ b/lib/fog/vcloud/terremark/ecloud.rb @@ -41,6 +41,7 @@ module Fog require 'fog/vcloud/terremark/ecloud/parsers/get_vdc' require 'fog/vcloud/terremark/ecloud/parsers/internet_service' require 'fog/vcloud/terremark/ecloud/requests/add_internet_service' + require 'fog/vcloud/terremark/ecloud/requests/configure_internet_service' require 'fog/vcloud/terremark/ecloud/requests/delete_internet_service' require 'fog/vcloud/terremark/ecloud/requests/get_internet_services' require 'fog/vcloud/terremark/ecloud/requests/get_public_ip' diff --git a/lib/fog/vcloud/terremark/ecloud/models/internet_service.rb b/lib/fog/vcloud/terremark/ecloud/models/internet_service.rb index 05c32381d..bd03db7da 100644 --- a/lib/fog/vcloud/terremark/ecloud/models/internet_service.rb +++ b/lib/fog/vcloud/terremark/ecloud/models/internet_service.rb @@ -20,6 +20,46 @@ module Fog attribute :url_send_string attribute :http_header + attr_accessor :new + + def delete + requires :href + + connection.delete_internet_service( self.href ) + collection.reload + end + + def save + if new? + result = connection.add_internet_service( collection.href, _compose_service_data ) + self.href = result.body.href + self.reload + @new = false + else + connection.configure_internet_service( self.href, _compose_service_data, _compose_ip_data ) + end + end + + def new? + @new ||= false + end + + private + + def _compose_service_data + service_data = {} + self.class.attributes.select{ |attribute| !attribute.nil? }.each { |attribute| service_data[attribute] = send(attribute).to_s } + service_data + end + + def _compose_ip_data + if public_ip.nil? + {} + else + { :id => self.public_ip.id, :href => self.public_ip.href.to_s, :name => self.public_ip.name } + end + end + end end end diff --git a/lib/fog/vcloud/terremark/ecloud/models/internet_services.rb b/lib/fog/vcloud/terremark/ecloud/models/internet_services.rb index 6ec725584..336e393f3 100644 --- a/lib/fog/vcloud/terremark/ecloud/models/internet_services.rb +++ b/lib/fog/vcloud/terremark/ecloud/models/internet_services.rb @@ -17,12 +17,10 @@ module Fog class InternetServices < Fog::Vcloud::Collection - attr_accessor :href - model Fog::Vcloud::Terremark::Ecloud::InternetService vcloud_type "application/vnd.tmrk.ecloud.internetService+xml" - all_request lambda { |internet_services| internet_services.raw_results } + all_request lambda { |internet_services| internet_services.send(:raw_results) } def get(uri) if internet_service = get_raw(uri) @@ -32,18 +30,15 @@ module Fog end def get_raw(uri) - raw_results.body.links.detect { |link| link.href == uri } + raw_results.body.links.detect { |link| link.href.to_s == uri.to_s } end + private + def raw_results - @raw_results ||= connection.get_internet_services(self.href) + connection.get_internet_services(self.href) end - #def reload - # super - # @raw_results = nil - #end - end end end diff --git a/lib/fog/vcloud/terremark/ecloud/models/public_ip.rb b/lib/fog/vcloud/terremark/ecloud/models/public_ip.rb index 21ac9eb0d..8be879986 100644 --- a/lib/fog/vcloud/terremark/ecloud/models/public_ip.rb +++ b/lib/fog/vcloud/terremark/ecloud/models/public_ip.rb @@ -13,11 +13,13 @@ module Fog attribute :id def internet_services + unless @loaded + reload + end @internet_services ||= Fog::Vcloud::Terremark::Ecloud::InternetServices. new( :connection => connection, :href => href.to_s + "/internetServices" ) end - end end end diff --git a/lib/fog/vcloud/terremark/ecloud/models/public_ips.rb b/lib/fog/vcloud/terremark/ecloud/models/public_ips.rb index 8a796c940..291bb2afd 100644 --- a/lib/fog/vcloud/terremark/ecloud/models/public_ips.rb +++ b/lib/fog/vcloud/terremark/ecloud/models/public_ips.rb @@ -17,7 +17,7 @@ module Fog class PublicIps < Fog::Vcloud::Collection - attr_accessor :href + undef_method :create model Fog::Vcloud::Terremark::Ecloud::PublicIp diff --git a/lib/fog/vcloud/terremark/ecloud/models/vdc.rb b/lib/fog/vcloud/terremark/ecloud/models/vdc.rb index eae152e54..0a2f1de51 100644 --- a/lib/fog/vcloud/terremark/ecloud/models/vdc.rb +++ b/lib/fog/vcloud/terremark/ecloud/models/vdc.rb @@ -14,6 +14,9 @@ module Fog attribute :instantiated_vm_quota def public_ips + unless @loaded + reload + end @public_ips ||= Fog::Vcloud::Terremark::Ecloud::PublicIps.new( :connection => connection, :href => other_links.detect { |link| link.type == "application/vnd.tmrk.ecloud.publicIpsList+xml" }.href ) end diff --git a/lib/fog/vcloud/terremark/ecloud/models/vdcs.rb b/lib/fog/vcloud/terremark/ecloud/models/vdcs.rb index 70fdfd801..84c17239f 100644 --- a/lib/fog/vcloud/terremark/ecloud/models/vdcs.rb +++ b/lib/fog/vcloud/terremark/ecloud/models/vdcs.rb @@ -16,6 +16,8 @@ module Fog class Vdcs < Fog::Vcloud::Vdcs + undef_method :create + model Fog::Vcloud::Terremark::Ecloud::Vdc #get_request :get_vdc diff --git a/lib/fog/vcloud/terremark/ecloud/requests/add_internet_service.rb b/lib/fog/vcloud/terremark/ecloud/requests/add_internet_service.rb index c1af7ef5c..17b936d32 100644 --- a/lib/fog/vcloud/terremark/ecloud/requests/add_internet_service.rb +++ b/lib/fog/vcloud/terremark/ecloud/requests/add_internet_service.rb @@ -17,15 +17,18 @@ module Fog } end - def self.validate_internet_service_request_data(service_data) + def self.validate_internet_service_data(service_data, configure=false) valid_opts = [:name, :protocol, :port, :description, :enabled, :description] + if configure + valid_opts + [ :id, :href, :timeout ] + end unless valid_opts.all? { |opt| service_data.keys.include?(opt) } raise ArgumentError.new("Required Internet Service data missing: #{(valid_opts - service_data.keys).map(&:inspect).join(", ")}") end end - def add_internet_service(internet_service_uri, service_data) - Fog::Vcloud::Terremark::Ecloud::Real.validate_internet_service_request_data(service_data) + def add_internet_service(internet_services_uri, service_data) + Fog::Vcloud::Terremark::Ecloud::Real.validate_internet_service_data(service_data) request( :body => Fog::Vcloud::Terremark::Ecloud::Real.generate_internet_service_request(service_data), @@ -33,7 +36,7 @@ module Fog :headers => {'Content-Type' => 'application/vnd.tmrk.ecloud.internetService+xml'}, :method => 'POST', :parser => Fog::Parsers::Vcloud::Terremark::Ecloud::InternetService.new, - :uri => internet_service_uri + :uri => internet_services_uri ) end @@ -45,10 +48,10 @@ module Fog # http://support.theenterprisecloud.com/kb/default.asp?id=561&Lang=1&SID= # - def add_internet_service(internet_service_uri, service_data) - Fog::Vcloud::Terremark::Ecloud::Real.validate_internet_service_request_data(service_data) + def add_internet_service(internet_services_uri, service_data) + Fog::Vcloud::Terremark::Ecloud::Real.validate_internet_service_data(service_data) - if ip = Fog::Vcloud::Mock.ip_from_uri(internet_service_uri.to_s) + if ip = Fog::Vcloud::Mock.ip_from_uri(internet_services_uri.to_s) new_service = service_data.merge!( { :id => rand(1000), :timeout => 2 } ) ip[:services] << new_service builder = Builder::XmlMarkup.new diff --git a/lib/fog/vcloud/terremark/ecloud/requests/configure_internet_service.rb b/lib/fog/vcloud/terremark/ecloud/requests/configure_internet_service.rb new file mode 100644 index 000000000..ef3bd689d --- /dev/null +++ b/lib/fog/vcloud/terremark/ecloud/requests/configure_internet_service.rb @@ -0,0 +1,99 @@ +module Fog + module Vcloud + module Terremark + module Ecloud + module Real + + def self.generate_configure_internet_service_request(service_data,ip_address_data) + builder = Builder::XmlMarkup.new + builder.InternetService(:"xmlns:i" => "http://www.w3.org/2001/XMLSchema-instance", + :xmlns => "urn:tmrk:eCloudExtensions-2.0") { + builder.Id(service_data[:id]) + builder.Href(service_data[:href].to_s) + builder.Name(service_data[:name]) + builder.Protocol(service_data[:protocol]) + builder.Port(service_data[:port]) + builder.Enabled(service_data[:enabled]) + builder.Description(service_data[:description]) + builder.Timeout(service_data[:timeout]) + builder.PublicIpAddress { + builder.Id(ip_address_data[:id]) + builder.Href(ip_address_data[:href].to_s) + builder.Name(ip_address_data[:name]) + } + } + end + + def self.validate_public_ip_address_data(ip_address_data) + valid_opts = [:name, :href, :id] + unless valid_opts.all? { |opt| ip_address_data.keys.include?(opt) } + raise ArgumentError.new("Required Internet Service data missing: #{(valid_opts - ip_address_data.keys).map(&:inspect).join(", ")}") + end + end + + def configure_internet_service(internet_service_uri, service_data, ip_address_data) + Fog::Vcloud::Terremark::Ecloud::Real.validate_internet_service_data(service_data, true) + + Fog::Vcloud::Terremark::Ecloud::Real.validate_public_ip_address_data(ip_address_data) + + request( + :body => Fog::Vcloud::Terremark::Ecloud::Real.generate_configure_internet_service_request(service_data, ip_address_data), + :expects => 200, + :headers => {'Content-Type' => 'application/vnd.tmrk.ecloud.internetService+xml'}, + :method => 'PUT', + :parser => Fog::Parsers::Vcloud::Terremark::Ecloud::InternetService.new, + :uri => internet_service_uri + ) + end + + end + + module Mock + # + # Based on + # http://support.theenterprisecloud.com/kb/default.asp?id=583&Lang=1&SID= + # + + def configure_internet_service(internet_service_uri, service_data, ip_address_data) + Fog::Vcloud::Terremark::Ecloud::Real.validate_internet_service_data(service_data, true) + + Fog::Vcloud::Terremark::Ecloud::Real.validate_public_ip_address_data(ip_address_data) + + found = false + xml = nil + if ip = Fog::Vcloud::Mock.ip_from_uri(ip_address_data[:href]) + if service = ip[:services].detect { |service| service[:id] == internet_service_uri.to_s.split('/')[-1].to_i } + found = true + ip[:services][ip[:services].index(service)] = service_data + + builder = Builder::XmlMarkup.new + xml = builder.InternetService(:xmlns => "urn:tmrk:eCloudExtensions-2.0", + :"xmlns:i" => "http://www.w3.org/2001/XMLSchema-instance") { + builder.Id(service_data[:id]) + builder.Href(Fog::Vcloud::Terremark::Ecloud::Mock.internet_service_href(service_data)) + builder.Name(service_data[:name]) + builder.PublicIpAddress { + builder.Id(ip[:id]) + builder.Href(Fog::Vcloud::Terremark::Ecloud::Mock.public_ip_href(ip)) + builder.Name(ip[:name]) + } + builder.Protocol(service_data[:protocol]) + builder.Port(service_data[:port]) + builder.Enabled(service_data[:enabled]) + builder.Description(service_data[:description]) + builder.Timeout(service_data[:timeout]) + } + end + end + if found + mock_it Fog::Parsers::Vcloud::Terremark::Ecloud::InternetService.new, 200, xml, {'Content-Type' => 'application/vnd.tmrk.ecloud.internetService+xml'} + else + mock_error 200, "401 Unauthorized" + end + end + end + end + end + end +end + diff --git a/spec/vcloud/terremark/ecloud/models/internet_service_spec.rb b/spec/vcloud/terremark/ecloud/models/internet_service_spec.rb index 420e1419b..eac6d1086 100644 --- a/spec/vcloud/terremark/ecloud/models/internet_service_spec.rb +++ b/spec/vcloud/terremark/ecloud/models/internet_service_spec.rb @@ -38,6 +38,8 @@ describe "Fog::Vcloud::Terremark::Ecloud::InternetService", :type => :tmrk_eclou context "as a collection member" do subject { @vcloud.vdcs[0].public_ips[0].internet_services[0] } let(:public_ip) { @vcloud.get_public_ip(@vcloud.vdcs[0].public_ips[0].internet_services[0].public_ip.href).body } + let(:composed_public_ip_data) { @vcloud.vdcs[0].public_ips[0].internet_services[0].send(:_compose_ip_data) } + let(:composed_service_data) { @vcloud.vdcs[0].public_ips[0].internet_services[0].send(:_compose_service_data) } it { should be_an_instance_of Fog::Vcloud::Terremark::Ecloud::InternetService } @@ -54,5 +56,18 @@ describe "Fog::Vcloud::Terremark::Ecloud::InternetService", :type => :tmrk_eclou its(:timeout) { should == 2 } its(:url_send_string) { should == nil } its(:http_header) { should == nil } + + specify { composed_public_ip_data[:href].should == public_ip.href.to_s } + specify { composed_public_ip_data[:name].should == public_ip.name } + specify { composed_public_ip_data[:id].should == public_ip.id } + + specify { composed_service_data[:href].should == subject.href.to_s } + specify { composed_service_data[:name].should == subject.name } + specify { composed_service_data[:id].should == subject.id.to_s } + specify { composed_service_data[:protocol].should == subject.protocol } + specify { composed_service_data[:port].should == subject.port.to_s } + specify { composed_service_data[:enabled].should == subject.enabled.to_s } + specify { composed_service_data[:description].should == subject.description } + specify { composed_service_data[:timeout].should == subject.timeout.to_s } end end diff --git a/spec/vcloud/terremark/ecloud/requests/configure_internet_service_spec.rb b/spec/vcloud/terremark/ecloud/requests/configure_internet_service_spec.rb new file mode 100644 index 000000000..bddc1f675 --- /dev/null +++ b/spec/vcloud/terremark/ecloud/requests/configure_internet_service_spec.rb @@ -0,0 +1,44 @@ +require "spec_helper" + +describe "Fog::Vcloud, initialized w/ the TMRK Ecloud module", :type => :tmrk_ecloud_request do + subject { @vcloud } + + it { should respond_to :configure_internet_service } + + describe "#configure_internet_service" do + before do + @public_ip = @vcloud.vdcs[0].public_ips[0] + @original_service = @vcloud.get_internet_services(@public_ip.href).body.links.first + @service_data = {} + @original_service.each_pair { |sym, data| @service_data[sym] = data } + @ip_data = { :id => @public_ip.id, :name => @public_ip.name, :href => @public_ip.href.to_s } + end + + context "with a valid Internet Service uri and valid data" do + + subject { @vcloud.configure_internet_service(@original_service.href, @service_data, @ip_data) } + + it_should_behave_like "all requests" + + context "with some changed data" do + before do + @service_data[:description] = "TEST BOOM" + end + it "should change data" do + @original_service.description.should == "Web Servers" + result = subject + result.body.description.should == "TEST BOOM" + @vcloud.get_internet_services(@public_ip.href).body.links.first.description.should == "TEST BOOM" + end + end + + end + + context "with an internet_services_uri that doesn't exist" do + subject { lambda { @vcloud.configure_internet_service(URI.parse('https://www.fakey.c/piv8vc99'), @service_data, @ip_data ) } } + + it_should_behave_like "a request for a resource that doesn't exist" + end + end +end +