From 0c61fa5a61e137c1a0070ea7ee5c54bcf6672b70 Mon Sep 17 00:00:00 2001 From: Peter Weldon Date: Thu, 19 Jan 2012 19:25:39 +0000 Subject: [PATCH] [aws|storage] Add bucket lifecycle / object expiration requests. --- .../parsers/storage/get_bucket_lifecycle.rb | 32 ++++++++++ .../storage/delete_bucket_lifecycle.rb | 30 +++++++++ .../requests/storage/get_bucket_lifecycle.rb | 41 ++++++++++++ .../requests/storage/put_bucket_lifecycle.rb | 48 ++++++++++++++ lib/fog/aws/storage.rb | 4 ++ tests/aws/requests/storage/bucket_tests.rb | 62 +++++++++++++++++++ 6 files changed, 217 insertions(+) create mode 100644 lib/fog/aws/parsers/storage/get_bucket_lifecycle.rb create mode 100644 lib/fog/aws/requests/storage/delete_bucket_lifecycle.rb create mode 100644 lib/fog/aws/requests/storage/get_bucket_lifecycle.rb create mode 100644 lib/fog/aws/requests/storage/put_bucket_lifecycle.rb diff --git a/lib/fog/aws/parsers/storage/get_bucket_lifecycle.rb b/lib/fog/aws/parsers/storage/get_bucket_lifecycle.rb new file mode 100644 index 000000000..81014f229 --- /dev/null +++ b/lib/fog/aws/parsers/storage/get_bucket_lifecycle.rb @@ -0,0 +1,32 @@ +module Fog + module Parsers + module Storage + module AWS + + class GetBucketLifecycle < Fog::Parsers::Base + + def reset + @rule = {} + @response = { 'Rules' => [] } + end + + def end_element(name) + case name + when 'ID', 'Prefix' + @rule[name] = value + when 'Status' + @rule['Enabled'] = value == 'Enabled' + when 'Days' + @rule[name] = value.to_i + when 'Rule' + @response['Rules'] << @rule + @rule = {} + end + end + + end + + end + end + end +end diff --git a/lib/fog/aws/requests/storage/delete_bucket_lifecycle.rb b/lib/fog/aws/requests/storage/delete_bucket_lifecycle.rb new file mode 100644 index 000000000..72f2a7328 --- /dev/null +++ b/lib/fog/aws/requests/storage/delete_bucket_lifecycle.rb @@ -0,0 +1,30 @@ +module Fog + module Storage + class AWS + class Real + + # Delete lifecycle configuration for a bucket + # + # ==== Parameters + # * bucket_name<~String> - name of bucket to delete lifecycle configuration from + # + # ==== Returns + # * response<~Excon::Response>: + # * status<~Integer> - 204 + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketDELETElifecycle.html + + def delete_bucket_lifecycle(bucket_name) + request({ + :expects => 204, + :headers => {}, + :host => "#{bucket_name}.#{@host}", + :method => 'DELETE', + :query => {'lifecycle' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/requests/storage/get_bucket_lifecycle.rb b/lib/fog/aws/requests/storage/get_bucket_lifecycle.rb new file mode 100644 index 000000000..56791471e --- /dev/null +++ b/lib/fog/aws/requests/storage/get_bucket_lifecycle.rb @@ -0,0 +1,41 @@ +module Fog + module Storage + class AWS + class Real + + require 'fog/aws/parsers/storage/get_bucket_lifecycle' + + # Get bucket lifecycle configuration + # + # ==== Parameters + # * bucket_name<~String> - name of bucket to get lifecycle configuration for + # + # ==== Returns + # * response<~Excon::Response>: + # * body<~Hash>: + # * 'Rules'<~Array> - object expire rules + # * 'ID'<~String> - Unique identifier for the rule + # * 'Prefix'<~String> - Prefix identifying one or more objects to which the rule applies + # * 'Enabled'<~Boolean> - if rule is currently being applied + # * 'Days'<~Integer> - lifetime, in days, of the objects that are subject to the rule + # + # ==== See Also + # http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETlifecycle.html + + def get_bucket_lifecycle(bucket_name) + request({ + :expects => 200, + :headers => {}, + :host => "#{bucket_name}.#{@host}", + :idempotent => true, + :method => 'GET', + :parser => Fog::Parsers::Storage::AWS::GetBucketLifecycle.new, + :query => {'lifecycle' => nil} + }) + end + + end + end + end +end + diff --git a/lib/fog/aws/requests/storage/put_bucket_lifecycle.rb b/lib/fog/aws/requests/storage/put_bucket_lifecycle.rb new file mode 100644 index 000000000..a147560d2 --- /dev/null +++ b/lib/fog/aws/requests/storage/put_bucket_lifecycle.rb @@ -0,0 +1,48 @@ +module Fog + module Storage + class AWS + class Real + + # Change lifecycle configuration for an S3 bucket + # + # ==== Parameters + # * bucket_name<~String> - name of bucket to set lifecycle configuration for + # * lifecycle<~Hash>: + # * 'Rules'<~Array> - object expire rules + # * 'ID'<~String> - Unique identifier for the rule + # * 'Prefix'<~String> - Prefix identifying one or more objects to which the rule applies + # * 'Enabled'<~Boolean> - if rule is currently being applied + # * 'Days'<~Integer> - lifetime, in days, of the objects that are subject to the rule + # ==== See Also + # http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUTlifecycle.html + + def put_bucket_lifecycle(bucket_name, lifecycle) + builder = Nokogiri::XML::Builder.new do + LifecycleConfiguration { + lifecycle['Rules'].each do |rule| + Rule { + ID rule['ID'] + Prefix rule['Prefix'] + Status rule['Enabled'] ? 'Enabled' : 'Disabled' + Expiration { Days rule['Days'] } + } + end + } + end + + body = builder.to_xml + + request({ + :body => body, + :expects => 200, + :headers => {'Content-MD5' => Base64.encode64(Digest::MD5.digest(body)).chomp!, + 'Content-Type' => 'application/xml'}, + :host => "#{bucket_name}.#{@host}", + :method => 'PUT', + :query => {'lifecycle' => nil} + }) + end + end + end + end +end diff --git a/lib/fog/aws/storage.rb b/lib/fog/aws/storage.rb index 77bdcf003..483265241 100644 --- a/lib/fog/aws/storage.rb +++ b/lib/fog/aws/storage.rb @@ -19,11 +19,13 @@ module Fog request :complete_multipart_upload request :copy_object request :delete_bucket + request :delete_bucket_lifecycle request :delete_bucket_policy request :delete_bucket_website request :delete_object request :get_bucket request :get_bucket_acl + request :get_bucket_lifecycle request :get_bucket_location request :get_bucket_logging request :get_bucket_object_versions @@ -45,6 +47,7 @@ module Fog request :post_object_hidden_fields request :put_bucket request :put_bucket_acl + request :put_bucket_lifecycle request :put_bucket_logging request :put_bucket_policy request :put_bucket_versioning @@ -338,6 +341,7 @@ DATA for key in (params[:query] || {}).keys.sort if %w{ acl + lifecycle location logging notification diff --git a/tests/aws/requests/storage/bucket_tests.rb b/tests/aws/requests/storage/bucket_tests.rb index edb7ebbfe..e4bf3726b 100644 --- a/tests/aws/requests/storage/bucket_tests.rb +++ b/tests/aws/requests/storage/bucket_tests.rb @@ -179,6 +179,68 @@ Shindo.tests('Fog::Storage[:aws] | bucket requests', [:aws]) do Fog::Storage[:aws].delete_bucket_website(@aws_bucket_name) end + tests('bucket lifecycle') do + pending if Fog.mocking? + + lifecycle = {'Rules' => [{'ID' => 'test rule', 'Prefix' => '/prefix', 'Enabled' => true, 'Days' => 42}]} + tests('non-existant bucket') do + tests('#put_bucket_lifecycle').returns([404, 'NoSuchBucket']) do + begin + Fog::Storage[:aws].put_bucket_lifecycle('fognonbucket', lifecycle) + rescue Excon::Errors::NotFound => e + [e.response.status, e.response.body.match(%r{(.*)})[1]] + end + end + tests('#get_bucket_lifecycle').returns([404, 'NoSuchBucket']) do + begin + Fog::Storage[:aws].get_bucket_lifecycle('fognonbucket') + rescue Excon::Errors::NotFound => e + [e.response.status, e.response.body.match(%r{(.*)})[1]] + end + end + tests('#delete_bucket_lifecycle').returns([404, 'NoSuchBucket']) do + begin + Fog::Storage[:aws].delete_bucket_lifecycle('fognonbucket') + rescue Excon::Errors::NotFound => e + [e.response.status, e.response.body.match(%r{(.*)})[1]] + end + end + end + tests('no lifecycle') do + tests('#get_bucket_lifecycle').returns([404, 'NoSuchLifecycleConfiguration']) do + begin + Fog::Storage[:aws].get_bucket_lifecycle(@aws_bucket_name) + rescue Excon::Errors::NotFound => e + [e.response.status, e.response.body.match(%r{(.*)})[1]] + end + end + tests('#delete_bucket_lifecycle').succeeds do + Fog::Storage[:aws].delete_bucket_lifecycle(@aws_bucket_name) + end + end + tests('create').succeeds do + Fog::Storage[:aws].put_bucket_lifecycle(@aws_bucket_name, lifecycle) + end + tests('read').returns(lifecycle) do + Fog::Storage[:aws].get_bucket_lifecycle(@aws_bucket_name).body + end + lifecycle = { 'Rules' => 5.upto(6).map { |i| {'ID' => "rule\##{i}", 'Prefix' => i.to_s, 'Enabled' => true, 'Days' => i} } } + tests('update').returns(lifecycle) do + Fog::Storage[:aws].put_bucket_lifecycle(@aws_bucket_name, lifecycle) + Fog::Storage[:aws].get_bucket_lifecycle(@aws_bucket_name).body + end + tests('delete').succeeds do + Fog::Storage[:aws].delete_bucket_lifecycle(@aws_bucket_name) + end + tests('read').returns([404, 'NoSuchLifecycleConfiguration']) do + begin + Fog::Storage[:aws].get_bucket_lifecycle(@aws_bucket_name) + rescue Excon::Errors::NotFound => e + [e.response.status, e.response.body.match(%r{(.*)})[1]] + end + end + end + tests("#delete_bucket('#{@aws_bucket_name}')").succeeds do Fog::Storage[:aws].delete_bucket(@aws_bucket_name) end