radosgw-s3 0.1

Sign up to get free protection for your applications and to get access to all the features.
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