radosgw-s3 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6c32f6f0402f284ca0d2db932700ef45d05c8488
4
+ data.tar.gz: 06235b61e1ce7933c13e47d3e8f2c9628fb1b2ef
5
+ SHA512:
6
+ metadata.gz: e68ff57af1d4f71b530bcc784eb143c7666a34d4fee7ec875a3b4ad5df0749461dbdc4b0aab6c2a50be5b395caad095a99175a7a4104595713997237b32cba9c
7
+ data.tar.gz: bba508b3da38e2b39f20e03368c042793d7154ad62194dc0ad39b7f383d0d81f3ebb9e8cef3123fd00b53b7f746487820a9864f5c1fe1c4f9fd332e092a22d83
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ *.gem
7
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "{}"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright {yyyy} {name of copyright owner}
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
202
+
data/README.rdoc ADDED
@@ -0,0 +1,126 @@
1
+ = radosgw-S3
2
+
3
+ This gem is used to access ceph storage and to create radosgw-admin user.
4
+
5
+
6
+ == Installation
7
+
8
+ gem install radosgw-s3
9
+
10
+ = Ceph-radosgw user
11
+
12
+
13
+ radosgw-admin guide to {create radosgw user}[http://docs.ceph.com/docs/master/radosgw/admin/].
14
+
15
+
16
+ == Usage
17
+
18
+ === Initialize the service
19
+
20
+ require "radosgw-s3"
21
+ service = CEPH::Radosgw.new(:ipaddress => "RADOSGW_HOST_IP",
22
+ :username => "RADOSGW_HOST_USERNAME",
23
+ :user_password => "RADOSGW_HOST_USER_PASSWORD",
24
+ )
25
+
26
+
27
+ === create user
28
+
29
+ service.user_create("UID_NAME")
30
+
31
+ It will give you the access_key and secret_key in hash format
32
+ Eg : {"access_key"=>"8OC3R0QYPOW9TWE6M4L7", "secret_key"=>"+dDV9U+0hx7VufeFGWvF+34AC9g1IcrsIrOzLtZL"}
33
+
34
+ == See also
35
+
36
+ * radosgw-admin[http://docs.ceph.com/docs/master/radosgw/admin/]
37
+
38
+
39
+ = radosgw-S3
40
+
41
+ radosgw-S3 library provides access to {Ceph's radosgw storage}[http://docs.ceph.com/docs/master/radosgw/].
42
+
43
+ === Initialize the service
44
+
45
+ require "radosgw-s3"
46
+ service = S3::Service.new(:access_key_id => "...",
47
+ :secret_access_key => "...",
48
+ :host => "127.0.0.1")
49
+
50
+ === List buckets
51
+
52
+ service.buckets
53
+ #=> [#<S3::Bucket:first-bucket>,
54
+ # #<S3::Bucket:second-bucket>]
55
+
56
+ === Find bucket
57
+
58
+ first_bucket = service.buckets.find("first-bucket")
59
+ #=> #<S3::Bucket:first-bucket>
60
+
61
+ === Create bucket
62
+
63
+ new_bucket = service.buckets.build("newbucketname")
64
+ new_bucket.save(:location => :eu)
65
+
66
+
67
+ === List objects in a bucket
68
+
69
+ first_bucket.objects
70
+ #=> [#<S3::Object:/first-bucket/lenna.png>,
71
+ # #<S3::Object:/first-bucket/lenna_mini.png>]
72
+
73
+ === Find object in a bucket
74
+
75
+ object = first_bucket.objects.find("lenna.png")
76
+ #=> #<S3::Object:/first-bucket/lenna.png>
77
+
78
+ === Access object metadata (cached from find)
79
+
80
+ object.content_type
81
+ #=> "image/png"
82
+
83
+ === Access object content (downloads the object)
84
+
85
+ object.content
86
+ #=> "\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00..."
87
+
88
+ === Delete an object
89
+
90
+ object.destroy
91
+ #=> true
92
+
93
+ === Create an object
94
+
95
+ new_object = bucket.objects.build("bender.png")
96
+ #=> #<S3::Object:/synergy-staging/bender.png>
97
+
98
+ new_object.content = open("bender.png")
99
+
100
+ new_object.save
101
+ #=> true
102
+
103
+ Please note that new objects are created with "private" ACL by
104
+ default.
105
+
106
+ === Fetch ACL
107
+
108
+ object = bucket.objects.find('lenna.png')
109
+ object.request_acl # or bucket.request_acl
110
+
111
+ This will return hash with all users/groups and theirs permissions
112
+
113
+ === Modify ACL
114
+
115
+ object = bucket.objects.find("lenna.png")
116
+ object.copy(:key => "lenna.png", :bucket => bucket, :acl => :public_read)
117
+
118
+ == See also
119
+
120
+ * rubygems[http://rubygems.org/gems/radosgw-s3]
121
+ * repository[http://github.com/megamsys/radosgw-s3]
122
+ * {issue tracker}[http://github.com/megamsys/radosgw-s3/issues]
123
+
124
+ == Copyright
125
+
126
+ See LICENSE[http://github.com/megamsys/s3/raw/master/LICENSE] for details.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+ Bundler.setup
4
+
5
+ require "rake/testtask"
6
+ require "rdoc/task"
7
+
8
+ Rake::TestTask.new(:test) do |test|
9
+ test.libs << "lib" << "test"
10
+ test.pattern = "test/**/*_test.rb"
11
+ test.verbose = true
12
+ end
13
+
14
+ Rake::RDocTask.new do |rdoc|
15
+ rdoc.rdoc_dir = "rdoc"
16
+ rdoc.title = "radosgw-s3 #{S3::VERSION}"
17
+ rdoc.rdoc_files.include("README.rdoc")
18
+ rdoc.rdoc_files.include("lib/**/*.rb")
19
+ end
20
+
21
+ task :default => :test
@@ -0,0 +1,35 @@
1
+ require 'net/ssh'
2
+ require 'json'
3
+
4
+ module CEPH
5
+ class Radosgw
6
+
7
+ attr_reader :username, :ipaddress, :user_password, :uid
8
+
9
+
10
+ def initialize(options)
11
+ raise ArgumentError, "Missing :username." if !options[:username]
12
+ raise ArgumentError, "Missing :ipaddress." if !options[:ipaddress]
13
+ raise ArgumentError, "Missing :user_password." if !options[:user_password]
14
+
15
+ @username = options.fetch(:username)
16
+ @ipaddress = options.fetch(:ipaddress)
17
+ @user_password = options.fetch(:user_password)
18
+ end
19
+
20
+
21
+
22
+ def user_create(uid)
23
+ ceph_user_json = ""
24
+ Net::SSH.start( @ipaddress, @username, :password => @user_password ) do|ssh|
25
+ ceph_user_json = ssh.exec!("sudo radosgw-admin user create --uid='#{uid}' --display-name='radosgw demo user from s3 gem'")
26
+ end
27
+
28
+
29
+ ceph_user_hash = JSON.parse(ceph_user_json)
30
+ secret_hash = {"access_key" => "#{ceph_user_hash['keys'][0]['access_key']}", "secret_key" => "#{ceph_user_hash['keys'][0]['secret_key']}" }
31
+ secret_hash
32
+ end
33
+
34
+ end
35
+ end
data/lib/radosgw-s3.rb ADDED
@@ -0,0 +1,29 @@
1
+ require "base64"
2
+ require "cgi"
3
+ require "digest/md5"
4
+ require "forwardable"
5
+ require "net/http"
6
+ require "net/https"
7
+ require "openssl"
8
+ require "rexml/document"
9
+ require "time"
10
+
11
+ require "proxies"
12
+ require "s3/objects_extension"
13
+ require "s3/buckets_extension"
14
+ require "s3/parser"
15
+ require "s3/bucket"
16
+ require "s3/connection"
17
+ require "s3/exceptions"
18
+ require "s3/object"
19
+ require "s3/request"
20
+ require "s3/service"
21
+ require "s3/signature"
22
+ require "s3/version"
23
+
24
+ require "ceph/radosgw"
25
+
26
+ module S3
27
+ # Default (and only) host serving S3 stuff
28
+ HOST = "s3.amazonaws.com"
29
+ end
data/lib/s3/bucket.rb ADDED
@@ -0,0 +1,217 @@
1
+ module S3
2
+ class Bucket
3
+ include Parser
4
+ include Proxies
5
+ extend Forwardable
6
+
7
+ attr_reader :name, :service, :acl
8
+
9
+ def_instance_delegators :service, :service_request
10
+ private_class_method :new
11
+
12
+ # Retrieves the bucket information from the server. Raises an
13
+ # S3::Error exception if the bucket doesn't exist or you don't
14
+ # have access to it.
15
+ def retrieve
16
+ bucket_headers
17
+ self
18
+ end
19
+
20
+ # Returns location of the bucket, e.g. "EU"
21
+ def location(reload = false)
22
+ return @location if defined?(@location) and not reload
23
+ @location = location_constraint
24
+ end
25
+
26
+ # Compares the bucket with other bucket. Returns true if the names
27
+ # of the buckets are the same, and both have the same services
28
+ # (see Service equality)
29
+ def ==(other)
30
+ self.name == other.name and self.service == other.service
31
+ end
32
+
33
+ # Retrieves acl for bucket from the server.
34
+ #
35
+ # Return:
36
+ # hash: user|group => permission
37
+ def request_acl
38
+ body = bucket_request(:get, :params => "acl").body
39
+ parse_acl(body)
40
+ end
41
+
42
+ # Assigns a new ACL to the bucket. Please note that ACL is not
43
+ # retrieved from the server and set to "private" by default.
44
+ #
45
+ # Valid Values: :private | :public_read | :public_read_write | authenticated_read
46
+ #
47
+ # ==== Example
48
+ # bucket.acl = :public_read
49
+ def acl=(acl)
50
+ @acl = acl.to_s.gsub("_","-") if acl
51
+ end
52
+
53
+ # Similar to retrieve, but catches S3::Error::NoSuchBucket
54
+ # exceptions and returns false instead. Also catch S3::Error::ForbiddenBucket
55
+ # and return true
56
+ def exists?
57
+ retrieve
58
+ true
59
+ rescue Error::ForbiddenBucket
60
+ true
61
+ rescue Error::NoSuchBucket
62
+ false
63
+ end
64
+
65
+ # Destroys given bucket. Raises an S3::Error::BucketNotEmpty
66
+ # exception if the bucket is not empty. You can destroy non-empty
67
+ # bucket passing true (to force destroy)
68
+ def destroy(force = false)
69
+ delete_bucket
70
+ true
71
+ rescue Error::BucketNotEmpty
72
+ if force
73
+ objects.destroy_all
74
+ retry
75
+ else
76
+ raise
77
+ end
78
+ end
79
+
80
+ # Saves the newly built bucket.
81
+ #
82
+ # ==== Options
83
+ # * <tt>:location</tt> - location of the bucket
84
+ # (<tt>:eu</tt> or <tt>us</tt>)
85
+ # * Any other options are passed through to
86
+ # Connection#request
87
+ def save(options = {})
88
+ options = {:location => options} unless options.is_a?(Hash)
89
+ create_bucket_configuration(options)
90
+ true
91
+ end
92
+
93
+ # Returns true if the name of the bucket can be used like +VHOST+
94
+ # name. If the bucket contains characters like underscore it can't
95
+ # be used as +VHOST+ (e.g. <tt>bucket_name.s3.amazonaws.com</tt>)
96
+ def vhost?
97
+ !service.use_ssl && service.use_vhost && "#@name.#{HOST}" =~ /\A#{URI::REGEXP::PATTERN::HOSTNAME}\Z/
98
+ end
99
+
100
+ # Returns host name of the bucket according (see #vhost? method)
101
+ def host
102
+ vhost? ? "#@name.#{HOST}" : "#{HOST}"
103
+ end
104
+
105
+ # Returns path prefix for non +VHOST+ bucket. Path prefix is used
106
+ # instead of +VHOST+ name, e.g. "bucket_name/"
107
+ def path_prefix
108
+ vhost? ? "" : "#@name/"
109
+ end
110
+
111
+ # Returns the objects in the bucket and caches the result
112
+ #
113
+ # ==== Parameters
114
+ # * <tt>params</tt> - additional params for <tt>list_bucket</tt>
115
+ # request.
116
+ def objects(params = {})
117
+ Proxy.new(lambda { list_bucket(params) }, :owner => self, :extend => ObjectsExtension)
118
+ end
119
+
120
+ # Returns the object with the given key. Does not check whether the
121
+ # object exists. But also does not issue any HTTP requests, so it's
122
+ # much faster than objects.find
123
+ def object(key)
124
+ Object.send(:new, self, :key => key)
125
+ end
126
+
127
+ def inspect #:nodoc:
128
+ "#<#{self.class}:#{name}>"
129
+ end
130
+
131
+ def save_acl(options = {})
132
+ headers = {}
133
+ headers[:content_length] = 0
134
+ headers[:x_amz_acl] = options[:acl] || acl || "private"
135
+
136
+ bucket_request(:put, :headers => headers, :path => name)
137
+ end
138
+
139
+ private
140
+
141
+ attr_writer :service
142
+
143
+ def location_constraint
144
+ response = bucket_request(:get, :params => {:location => nil})
145
+ parse_location_constraint(response.body)
146
+ end
147
+
148
+ def list_bucket(params = {})
149
+ response = bucket_request(:get, :params => params)
150
+ max_keys = params[:max_keys]
151
+ objects_attributes = parse_list_bucket_result(response.body)
152
+
153
+ # If there are more than 1000 objects S3 truncates listing and
154
+ # we need to request another listing for the remaining objects.
155
+ while parse_is_truncated(response.body)
156
+ next_request_options = {:marker => URI.escape(objects_attributes.last[:key])}
157
+
158
+ if max_keys
159
+ break if objects_attributes.length >= max_keys
160
+ next_request_options[:max_keys] = max_keys - objects_attributes.length
161
+ end
162
+
163
+ response = bucket_request(:get, :params => params.merge(next_request_options))
164
+ objects_attributes += parse_list_bucket_result(response.body)
165
+ end
166
+
167
+ objects_attributes.map { |object_attributes| Object.send(:new, self, object_attributes) }
168
+ end
169
+
170
+ def bucket_headers(options = {})
171
+ bucket_request(:head, :params => options)
172
+ rescue Error::ResponseError => e
173
+ case e.response.code.to_i
174
+ when 404
175
+ raise Error::ResponseError.exception("NoSuchBucket").new("The specified bucket does not exist.", nil)
176
+ when 403
177
+ raise Error::ResponseError.exception("ForbiddenBucket").new("The specified bucket exist but you do not have access to it.", nil)
178
+ else
179
+ raise e
180
+ end
181
+ end
182
+
183
+ def create_bucket_configuration(options = {})
184
+ location = options[:location].to_s.upcase if options[:location]
185
+ options[:headers] ||= {}
186
+ if location and location != "US"
187
+ options[:body] = "<CreateBucketConfiguration><LocationConstraint>#{location}</LocationConstraint></CreateBucketConfiguration>"
188
+ options[:headers][:content_type] = "application/xml"
189
+ end
190
+ bucket_request(:put, options)
191
+ end
192
+
193
+ def delete_bucket
194
+ bucket_request(:delete)
195
+ end
196
+
197
+ def initialize(service, name) #:nodoc:
198
+ self.service = service
199
+ self.name = name
200
+ end
201
+
202
+ def name=(name)
203
+ raise ArgumentError.new("Invalid bucket name: #{name}") unless name_valid?(name)
204
+ @name = name
205
+ end
206
+
207
+ def bucket_request(method, options = {})
208
+ path = "#{path_prefix}#{options[:path]}"
209
+ service_request(method, options.merge(:host => host, :path => path))
210
+ end
211
+
212
+ def name_valid?(name)
213
+ name =~ /\A[a-z0-9][a-z0-9\._-]{2,254}\Z/i and name !~ /\A#{URI::REGEXP::PATTERN::IPV4ADDR}\Z/
214
+ end
215
+
216
+ end
217
+ end