From e8f1920cb1c6d1acc3c140149601835e3d8736c3 Mon Sep 17 00:00:00 2001 From: Kyle Rames Date: Fri, 1 Feb 2013 16:16:37 -0600 Subject: [PATCH] [rackspace|cdn] implemented purge object from CDN; added CDN tests and mocks. --- lib/fog/core/errors.rb | 2 + lib/fog/rackspace/cdn.rb | 17 ++++- lib/fog/rackspace/models/storage/directory.rb | 12 ++- lib/fog/rackspace/models/storage/file.rb | 12 +++ .../rackspace/requests/cdn/delete_object.rb | 37 +++++++++ .../rackspace/requests/cdn/get_containers.rb | 34 +++++++++ .../rackspace/requests/cdn/head_container.rb | 24 ++++++ .../rackspace/requests/cdn/post_container.rb | 21 +++++ .../rackspace/requests/cdn/put_container.rb | 21 +++++ tests/rackspace/requests/cdn/cdn_tests.rb | 76 +++++++++++++++++++ 10 files changed, 250 insertions(+), 6 deletions(-) create mode 100644 lib/fog/rackspace/requests/cdn/delete_object.rb create mode 100644 tests/rackspace/requests/cdn/cdn_tests.rb diff --git a/lib/fog/core/errors.rb b/lib/fog/core/errors.rb index 9e1c404d2..4f26bb076 100644 --- a/lib/fog/core/errors.rb +++ b/lib/fog/core/errors.rb @@ -19,6 +19,8 @@ module Fog class LoadError < LoadError; end class TimeoutError< Fog::Errors::Error; end + + class NotImplemented < Fog::Errors::Error; end # @return [String] The error message that will be raised, if credentials cannot be found def self.missing_credentials diff --git a/lib/fog/rackspace/cdn.rb b/lib/fog/rackspace/cdn.rb index d439dcb5d..4aa86360c 100644 --- a/lib/fog/rackspace/cdn.rb +++ b/lib/fog/rackspace/cdn.rb @@ -8,13 +8,12 @@ module Fog requires :rackspace_api_key, :rackspace_username recognizes :rackspace_auth_url, :persistent - model_path 'fog/rackspace/models/cdn' - request_path 'fog/rackspace/requests/cdn' request :get_containers request :head_container request :post_container request :put_container + request :delete_object class Mock @@ -39,6 +38,11 @@ module Fog def reset_data self.class.data.delete(@rackspace_username) end + + def purge(object) + return true if object.is_a? Fog::Storage::Rackspace::File + raise Fog::Errors::NotImplemented.new("#{object.class} does not support CDN purging") if object + end end @@ -61,6 +65,15 @@ module Fog @enabled = true end end + + def purge(object) + if object.is_a? Fog::Storage::Rackspace::File + delete_object object.directory.key, object.key + else + raise Fog::Errors::NotImplemented.new("#{object.class} does not support CDN purging") if object + end + true + end def enabled? @enabled diff --git a/lib/fog/rackspace/models/storage/directory.rb b/lib/fog/rackspace/models/storage/directory.rb index af2d850c2..4ecdfa7da 100644 --- a/lib/fog/rackspace/models/storage/directory.rb +++ b/lib/fog/rackspace/models/storage/directory.rb @@ -31,9 +31,13 @@ module Fog end end - def public=(new_public) + def public=(new_public) @public = new_public end + + def public? + @public ||= !public_url.nil? + end def public_url requires :key @@ -56,17 +60,17 @@ module Fog requires :key service.put_container(key) - if service.cdn && @public + if service.cdn && public? # if public and CDN connection then update cdn to public uri_header = 'X-CDN-URI' if service.rackspace_cdn_ssl == true uri_header = 'X-CDN-SSL-URI' end @public_url = service.cdn.put_container(key, 'X-CDN-Enabled' => 'True').headers[uri_header] - elsif service.cdn && !@public + elsif service.cdn && !public? service.cdn.put_container(key, 'X-CDN-Enabled' => 'False') @public_url = nil - elsif !service.cdn && @public + elsif !service.cdn && public? # if public but no CDN connection then error raise(Fog::Storage::Rackspace::Error.new("Directory can not be set as :public without a CDN provided")) end diff --git a/lib/fog/rackspace/models/storage/file.rb b/lib/fog/rackspace/models/storage/file.rb index 6b090b530..b04859537 100644 --- a/lib/fog/rackspace/models/storage/file.rb +++ b/lib/fog/rackspace/models/storage/file.rb @@ -63,11 +63,23 @@ module Fog def public=(new_public) new_public end + + def public? + directory.public? + end def public_url requires :key self.collection.get_url(self.key) end + + def purge_from_cdn + if public? + service.cdn.purge(self) + else + false + end + end def save(options = {}) requires :body, :directory, :key diff --git a/lib/fog/rackspace/requests/cdn/delete_object.rb b/lib/fog/rackspace/requests/cdn/delete_object.rb new file mode 100644 index 000000000..65ce13e00 --- /dev/null +++ b/lib/fog/rackspace/requests/cdn/delete_object.rb @@ -0,0 +1,37 @@ +module Fog + module CDN + class Rackspace + class Real + + # Delete an existing object + # + # ==== Parameters + # * container<~String> - Name of container to delete + # * object<~String> - Name of object to delete + # + def delete_object(container, object) + request( + :expects => 204, + :method => 'DELETE', + :path => "#{Fog::Rackspace.escape(container)}/#{Fog::Rackspace.escape(object)}" + ) + end + end + + class Mock + + def delete_object(container, object) + response = Excon::Response.new + response.status = 204 + response.headers = { + "Content-Length"=>"0", + "Date"=>"Fri, 01 Feb 2013 21:34:33 GMT", + "X-Trans-Id"=>"tx860f26bd76284a849384c0a467767b57" + } + response.body = "" + response + end + end + end + end +end diff --git a/lib/fog/rackspace/requests/cdn/get_containers.rb b/lib/fog/rackspace/requests/cdn/get_containers.rb index 2af5ca17c..657519ade 100644 --- a/lib/fog/rackspace/requests/cdn/get_containers.rb +++ b/lib/fog/rackspace/requests/cdn/get_containers.rb @@ -26,6 +26,40 @@ module Fog end end + + class Mock + + def get_containers(options = {}) + response = Excon::Response.new + response.status = 200 + response.headers = { + "Content-Length"=>"4402", + "Date"=>"Fri, 01 Feb 2013 21:16:54 GMT", + "Content-Type"=>"application/json", + "X-Trans-Id"=>"tx6c79ea47300941c49f2291b4d47d4ef5" + } + response.body = [ + { "log_retention"=>false, + "cdn_ios_uri"=>"http://a590286a323fec6aed22-d1e9259b2132e81da48ed3e1e802ef22.iosr.cf1.rackcdn.com", + "ttl"=>3600, + "cdn_enabled"=>true, + "cdn_streaming_uri"=>"http://168e307d41afe64f1a62-d1e9259b2132e81da48ed3e1e802ef22.r2.stream.cf1.rackcdn.com", + "name"=>"brown", "cdn_uri"=>"http://6e8f4bf5125c9c2e4e3a-d1e9259b2132e81da48ed3e1e802ef22.r2.cf1.rackcdn.com", + "cdn_ssl_uri"=>"https://f83cb7d39e0b9ff9581b-d1e9259b2132e81da48ed3e1e802ef22.ssl.cf1.rackcdn.com" + }, + { "log_retention"=>false, + "cdn_ios_uri"=>"http://b141f80caedd02158f10-cf33674d895dc8b8e6e5207fdbd5cae4.iosr.cf1.rackcdn.com", + "ttl"=>5000, + "cdn_enabled"=>false, + "cdn_streaming_uri"=>"http://ea5feee96b8087a3d5e5-cf33674d895dc8b8e6e5207fdbd5cae4.r72.stream.cf1.rackcdn.com", + "name"=>"fogcontainertests", "cdn_uri"=>"http://0115a9de56617a5d5473-cf33674d895dc8b8e6e5207fdbd5cae4.r72.cf1.rackcdn.com", + "cdn_ssl_uri"=>"https://a5df8bd8a418ca88061e-cf33674d895dc8b8e6e5207fdbd5cae4.ssl.cf1.rackcdn.com" + } + ] + response + end + end + end end end diff --git a/lib/fog/rackspace/requests/cdn/head_container.rb b/lib/fog/rackspace/requests/cdn/head_container.rb index 0779ad73c..2be8632e2 100644 --- a/lib/fog/rackspace/requests/cdn/head_container.rb +++ b/lib/fog/rackspace/requests/cdn/head_container.rb @@ -28,6 +28,30 @@ module Fog end end + + class Mock + + def head_container(container) + raise Fog::Storage::Rackspace::NotFound.new "#{container} not found" unless container == 'fogcontainertests' + response = Excon::Response.new + response.status = 204 + response.headers = { + "X-Cdn-Uri"=>"http://e4bbc22477d80eaf22bd-ca4e4e61e477bbd430e1f5b9dc9a19f5.r53.cf1.rackcdn.com", + "X-Cdn-Ios-Uri"=>"http://3c10ef49037f74416445-ca4e4e61e477bbd430e1f5b9dc9a19f5.iosr.cf1.rackcdn.com", + "X-Cdn-Ssl-Uri"=>"https://b722b8ee248259c37901-ca4e4e61e477bbd430e1f5b9dc9a19f5.ssl.cf1.rackcdn.com", + "X-Log-Retention"=>"False", + "X-Cdn-Enabled"=>"True", + "Content-Length"=>"0", + "Date"=>"Fri, 01 Feb 2013 21:25:57 GMT", + "X-Cdn-Streaming-Uri"=>"http://b82027c64cb4dd03670a-ca4e4e61e477bbd430e1f5b9dc9a19f5.r53.stream.cf1.rackcdn.com", + "X-Ttl"=>"259200", + "X-Trans-Id"=>"txca40ffd0412943608bb3e9656c8b81ef" + } + response.body = "" + response + end + end + end end end diff --git a/lib/fog/rackspace/requests/cdn/post_container.rb b/lib/fog/rackspace/requests/cdn/post_container.rb index 39d9e7571..188fbf3da 100644 --- a/lib/fog/rackspace/requests/cdn/post_container.rb +++ b/lib/fog/rackspace/requests/cdn/post_container.rb @@ -25,6 +25,27 @@ module Fog end end + + class Mock + + def post_container(name, options = {}) + raise Fog::Storage::Rackspace::NotFound.new "#{name} not found" unless name == 'fogcontainertests' + response = Excon::Response.new + response.status = 202 + response.headers = { + "X-Cdn-Uri"=>"http://e4bbc22477d80eaf22bd-ca4e4e61e477bbd430e1f5b9dc9a19f5.r53.cf1.rackcdn.com", + "X-Cdn-Ios-Uri"=>"http://3c10ef49037f74416445-ca4e4e61e477bbd430e1f5b9dc9a19f5.iosr.cf1.rackcdn.com", + "X-Cdn-Ssl-Uri"=>"https://b722b8ee248259c37901-ca4e4e61e477bbd430e1f5b9dc9a19f5.ssl.cf1.rackcdn.com", + "Content-Length"=>"58", "Date"=>"Fri, 01 Feb 2013 21:31:30 GMT", + "Content-Type"=>"text/plain; charset=UTF-8", + "X-Cdn-Streaming-Uri"=>"http://b82027c64cb4dd03670a-ca4e4e61e477bbd430e1f5b9dc9a19f5.r53.stream.cf1.rackcdn.com", + "X-Trans-Id"=>"tx4a3206e63dfc446bb5b60e34a62f749d" + } + response.body = "202 Accepted\n\nThe request is accepted for processing.\n\n " + response + end + end + end end end diff --git a/lib/fog/rackspace/requests/cdn/put_container.rb b/lib/fog/rackspace/requests/cdn/put_container.rb index 9d222aaf6..19410ae44 100644 --- a/lib/fog/rackspace/requests/cdn/put_container.rb +++ b/lib/fog/rackspace/requests/cdn/put_container.rb @@ -25,6 +25,27 @@ module Fog end end + + class Mock + + def put_container(name, options = {}) + response = Excon::Response.new + response.status = 201 + response.headers = { + "X-Cdn-Uri"=>"http://e4bbc22477d80eaf22bd-ca4e4e61e477bbd430e1f5b9dc9a19f5.r53.cf1.rackcdn.com", + "X-Cdn-Ios-Uri"=>"http://3c10ef49037f74416445-ca4e4e61e477bbd430e1f5b9dc9a19f5.iosr.cf1.rackcdn.com", + "X-Cdn-Ssl-Uri"=>"https://b722b8ee248259c37901-ca4e4e61e477bbd430e1f5b9dc9a19f5.ssl.cf1.rackcdn.com", + "Content-Length"=>"18", + "Date"=>"Fri, 01 Feb 2013 21:21:45 GMT", + "Content-Type"=>"text/plain; charset=UTF-8", + "X-Cdn-Streaming-Uri"=>"http://b82027c64cb4dd03670a-ca4e4e61e477bbd430e1f5b9dc9a19f5.r53.stream.cf1.rackcdn.com", + "X-Trans-Id"=>"tx1b41ec63189f4862baa65e0c08711772" + } + response.body = "201 Created\n\n\n\n " + response + end + end + end end end diff --git a/tests/rackspace/requests/cdn/cdn_tests.rb b/tests/rackspace/requests/cdn/cdn_tests.rb new file mode 100644 index 000000000..8745f500c --- /dev/null +++ b/tests/rackspace/requests/cdn/cdn_tests.rb @@ -0,0 +1,76 @@ +Shindo.tests('Fog::CDN[:rackspace] | CDN requests', ['rackspace']) do + + @container_format = [String] + + @containers_format = [{ + "cdn_ios_uri" => String, + "log_retention" => Fog::Boolean, + "ttl" => Fixnum, + "cdn_streaming_uri" => String, + "cdn_enabled" => Fog::Boolean, + "name" => String, + "cdn_ssl_uri" => String, + "cdn_uri" => String + }] + + @container_headers = { + "Content-Length" => String, + "X-Cdn-Enabled" => String, + "X-Log-Retention" => String, + "X-Cdn-Ios-Uri" => String, + "X-Ttl" => String, + "X-Cdn-Uri" => String, + "X-Cdn-Ssl-Uri" => String, + "X-Cdn-Streaming-Uri" => String, + "X-Trans-Id" => String, + "Date" => String + } + + begin + unless Fog.mocking? + @directory = Fog::Storage[:rackspace].directories.create(:key => 'fogcontainertests') + @file = @directory.files.create(:key => 'fog_object', :body => lorem_file) + end + + tests('success') do + + tests("#put_container('fogcontainertests')").succeeds do + Fog::CDN[:rackspace].put_container('fogcontainertests', {'X-CDN-Enabled' => true }) + end + + tests("#get_containers").formats(@containers_format) do + Fog::CDN[:rackspace].get_containers.body + end + + tests("#head_container('fogcontainertests')").formats(@container_headers) do + Fog::CDN[:rackspace].head_container('fogcontainertests').headers + end + + tests("#post_container('fogcontainertests')").succeeds do + Fog::CDN[:rackspace].post_container('fogcontainertests', 'X-TTL' => 5000) + end + + #NOTE: you are only allow 25 object purges per day. If this fails, you may be over the limit + tests("#delete_object('fog_object')").succeeds do + Fog::CDN[:rackspace].delete_object('fogcontainertests', 'fog_object') + end + end + ensure + unless Fog.mocking? + @file.destroy if @file + @directory.destroy if @directory + end + end + + tests('failure') do + + tests("#head_container('missing_container')").raises(Fog::Storage::Rackspace::NotFound) do + Fog::CDN[:rackspace].head_container('missing_container') + end + + tests("#post_container('missing_container')").raises(Fog::Storage::Rackspace::NotFound) do + Fog::CDN[:rackspace].post_container('missing_container', 'X-TTL' => 5000) + end + end +end +