openstack-swift 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/Gemfile.lock +2 -2
  2. data/README.rdoc +47 -0
  3. data/doc/Gemfile.html +100 -0
  4. data/doc/Object.html +177 -0
  5. data/doc/Openstack.html +162 -0
  6. data/doc/Openstack/Swift.html +182 -0
  7. data/doc/Openstack/Swift/AuthenticationError.html +151 -0
  8. data/doc/Openstack/Swift/Client.html +316 -0
  9. data/doc/Openstack/Swift/UnauthorizedError.html +147 -0
  10. data/doc/Openstack/Swift/WebApi.html +417 -0
  11. data/doc/Rakefile.html +98 -0
  12. data/doc/created.rid +11 -0
  13. data/doc/images/brick.png +0 -0
  14. data/doc/images/brick_link.png +0 -0
  15. data/doc/images/bug.png +0 -0
  16. data/doc/images/bullet_black.png +0 -0
  17. data/doc/images/bullet_toggle_minus.png +0 -0
  18. data/doc/images/bullet_toggle_plus.png +0 -0
  19. data/doc/images/date.png +0 -0
  20. data/doc/images/find.png +0 -0
  21. data/doc/images/loadingAnimation.gif +0 -0
  22. data/doc/images/macFFBgHack.png +0 -0
  23. data/doc/images/package.png +0 -0
  24. data/doc/images/page_green.png +0 -0
  25. data/doc/images/page_white_text.png +0 -0
  26. data/doc/images/page_white_width.png +0 -0
  27. data/doc/images/plugin.png +0 -0
  28. data/doc/images/ruby.png +0 -0
  29. data/doc/images/tag_green.png +0 -0
  30. data/doc/images/wrench.png +0 -0
  31. data/doc/images/wrench_orange.png +0 -0
  32. data/doc/images/zoom.png +0 -0
  33. data/doc/index.html +88 -0
  34. data/doc/js/darkfish.js +116 -0
  35. data/doc/js/jquery.js +32 -0
  36. data/doc/js/quicksearch.js +114 -0
  37. data/doc/js/thickbox-compressed.js +10 -0
  38. data/doc/lib/openstack-swift/client_rb.html +52 -0
  39. data/doc/lib/openstack-swift/errors_rb.html +52 -0
  40. data/doc/lib/openstack-swift/version_rb.html +52 -0
  41. data/doc/lib/openstack-swift/web_api_rb.html +52 -0
  42. data/doc/lib/openstack-swift_rb.html +66 -0
  43. data/doc/rdoc.css +763 -0
  44. data/doc/spec/openstack-swift/client_spec_rb.html +54 -0
  45. data/doc/spec/openstack-swift/web_api_spec_rb.html +54 -0
  46. data/doc/spec/spec_helper_rb.html +58 -0
  47. data/lib/openstack-swift/api.rb +77 -1
  48. data/lib/openstack-swift/client.rb +12 -57
  49. data/lib/openstack-swift/errors.rb +1 -0
  50. data/lib/openstack-swift/version.rb +1 -1
  51. data/spec/openstack-swift/{web_api_spec.rb → api_spec.rb} +23 -2
  52. data/spec/openstack-swift/client_spec.rb +19 -4
  53. metadata +60 -16
  54. data/openstack-swift-0.1.0.gem +0 -0
@@ -0,0 +1,54 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
+
5
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
6
+ <head>
7
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
8
+
9
+ <title>File: client_spec.rb [RDoc Documentation]</title>
10
+
11
+ <link type="text/css" media="screen" href="../../rdoc.css" rel="stylesheet" />
12
+
13
+ <script src="../../js/jquery.js" type="text/javascript"
14
+ charset="utf-8"></script>
15
+ <script src="../../js/thickbox-compressed.js" type="text/javascript"
16
+ charset="utf-8"></script>
17
+ <script src="../../js/quicksearch.js" type="text/javascript"
18
+ charset="utf-8"></script>
19
+ <script src="../../js/darkfish.js" type="text/javascript"
20
+ charset="utf-8"></script>
21
+ </head>
22
+
23
+ <body class="file file-popup">
24
+ <div id="metadata">
25
+ <dl>
26
+ <dt class="modified-date">Last Modified</dt>
27
+ <dd class="modified-date">2011-08-15 16:04:27 -0300</dd>
28
+
29
+
30
+ <dt class="requires">Requires</dt>
31
+ <dd class="requires">
32
+ <ul>
33
+
34
+ <li>openstack-swift</li>
35
+
36
+ </ul>
37
+ </dd>
38
+
39
+
40
+
41
+ </dl>
42
+ </div>
43
+
44
+ <div id="documentation">
45
+
46
+ <div class="description">
47
+ <h2>Description</h2>
48
+
49
+ </div>
50
+
51
+ </div>
52
+ </body>
53
+ </html>
54
+
@@ -0,0 +1,54 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
+
5
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
6
+ <head>
7
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
8
+
9
+ <title>File: web_api_spec.rb [RDoc Documentation]</title>
10
+
11
+ <link type="text/css" media="screen" href="../../rdoc.css" rel="stylesheet" />
12
+
13
+ <script src="../../js/jquery.js" type="text/javascript"
14
+ charset="utf-8"></script>
15
+ <script src="../../js/thickbox-compressed.js" type="text/javascript"
16
+ charset="utf-8"></script>
17
+ <script src="../../js/quicksearch.js" type="text/javascript"
18
+ charset="utf-8"></script>
19
+ <script src="../../js/darkfish.js" type="text/javascript"
20
+ charset="utf-8"></script>
21
+ </head>
22
+
23
+ <body class="file file-popup">
24
+ <div id="metadata">
25
+ <dl>
26
+ <dt class="modified-date">Last Modified</dt>
27
+ <dd class="modified-date">2011-08-15 15:34:19 -0300</dd>
28
+
29
+
30
+ <dt class="requires">Requires</dt>
31
+ <dd class="requires">
32
+ <ul>
33
+
34
+ <li>openstack-swift</li>
35
+
36
+ </ul>
37
+ </dd>
38
+
39
+
40
+
41
+ </dl>
42
+ </div>
43
+
44
+ <div id="documentation">
45
+
46
+ <div class="description">
47
+ <h2>Description</h2>
48
+
49
+ </div>
50
+
51
+ </div>
52
+ </body>
53
+ </html>
54
+
@@ -0,0 +1,58 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
+
5
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
6
+ <head>
7
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
8
+
9
+ <title>File: spec_helper.rb [RDoc Documentation]</title>
10
+
11
+ <link type="text/css" media="screen" href="../rdoc.css" rel="stylesheet" />
12
+
13
+ <script src="../js/jquery.js" type="text/javascript"
14
+ charset="utf-8"></script>
15
+ <script src="../js/thickbox-compressed.js" type="text/javascript"
16
+ charset="utf-8"></script>
17
+ <script src="../js/quicksearch.js" type="text/javascript"
18
+ charset="utf-8"></script>
19
+ <script src="../js/darkfish.js" type="text/javascript"
20
+ charset="utf-8"></script>
21
+ </head>
22
+
23
+ <body class="file file-popup">
24
+ <div id="metadata">
25
+ <dl>
26
+ <dt class="modified-date">Last Modified</dt>
27
+ <dd class="modified-date">2011-08-15 15:33:54 -0300</dd>
28
+
29
+
30
+ <dt class="requires">Requires</dt>
31
+ <dd class="requires">
32
+ <ul>
33
+
34
+ <li>rubygems</li>
35
+
36
+ <li>bundler/setup</li>
37
+
38
+ <li>openstack-swift</li>
39
+
40
+ </ul>
41
+ </dd>
42
+
43
+
44
+
45
+ </dl>
46
+ </div>
47
+
48
+ <div id="documentation">
49
+
50
+ <div class="description">
51
+ <h2>Description</h2>
52
+
53
+ </div>
54
+
55
+ </div>
56
+ </body>
57
+ </html>
58
+
@@ -3,6 +3,7 @@ module Openstack
3
3
  module Swift
4
4
  module Api
5
5
  extend self
6
+ MAX_SIZE = 4 * 1024 ** 3
6
7
 
7
8
  # Authentication method to get the url and token to conect to swift
8
9
  # Returns:
@@ -121,8 +122,64 @@ module Openstack
121
122
  file.close rescue nil
122
123
  end
123
124
 
124
- # Uploads a given object to a given container
125
+ # Delete a object for a given container and object name
126
+ def delete_object(url, token, container, object)
127
+ res = HTTParty.delete("#{url}/#{container}/#{object}", :headers => {"X-Auth-Token"=> token})
128
+ raise "Could not delete object '#{object}'" if res.code < 200 or res.code >= 300
129
+ true
130
+ end
131
+
132
+ # Delete all files listed on a manifest following the swift standard order
133
+ # What it does is try to delete all files in sequence from a given manifest until there are no files to delete
134
+ # returning a 404 error code. We don't know how many files are stored for a manifest file.
135
+ def delete_objects_from_manifest(url, token, container, manifest)
136
+ manifest_info = object_stat(url, token, container, manifest)
137
+ files_path = "#{manifest_info["x-object-manifest"]}%08d"
138
+
139
+ manifest_info["content-length"].to_i.times do |index|
140
+ res = HTTParty.delete("#{url}/#{files_path % index}", :headers => {"X-Auth-Token"=> token})
141
+ raise ObjectNotFoundError if res.code == 404
142
+ end
143
+ rescue ObjectNotFoundError
144
+ true
145
+ end
146
+
125
147
  def upload_object(url, token, container, file_path, options={})
148
+ options[:segments_size] ||= MAX_SIZE
149
+
150
+ create_container(url, token, container) rescue nil
151
+
152
+ file_name, file_mtime, file_size = file_info(file_path)
153
+
154
+ if file_size > options[:segments_size]
155
+ create_container(url, token, "#{container}_segments") rescue nil
156
+
157
+ segments_minus_one = file_size / options[:segments_size]
158
+ last_piece = file_size - segments_minus_one * options[:segments_size]
159
+ segments_minus_one.times do |segment|
160
+ upload_segment(
161
+ url, token, "#{container}_segments", file_path,
162
+ :size => options[:segments_size],
163
+ :position => options[:segments_size] * segment,
164
+ :object_name => upload_path_for(file_path, segment)
165
+ )
166
+ end
167
+
168
+ upload_segment(
169
+ url, token, "#{container}_segments", file_path,
170
+ :size => last_piece,
171
+ :position => options[:segments_size] * segments_minus_one,
172
+ :object_name => upload_path_for(file_path, segments_minus_one)
173
+ )
174
+
175
+ create_manifest(url, token, container, file_path)
176
+ else
177
+ upload_segment(url, token, container, file_path)
178
+ end
179
+ end
180
+
181
+ # Uploads a given object to a given container
182
+ def upload_segment(url, token, container, file_path, options={})
126
183
  options[:object_name] ||= file_path.match(/.+\/(.+?)$/)[1]
127
184
  file = File.open(file_path, "rb")
128
185
 
@@ -142,6 +199,25 @@ module Openstack
142
199
  ensure
143
200
  file.close rescue nil
144
201
  end
202
+
203
+ private
204
+ # Returns the standard swift path for a given file path and segment
205
+ def upload_path_for(file_path, segment)
206
+ "%s/%s/%s/%08d" % (file_info(file_path) << segment)
207
+ end
208
+
209
+ # Get relevant informations about a file
210
+ # Returns an array with:
211
+ # file_name
212
+ # file_mtime
213
+ # file_size
214
+ def file_info(file_path)
215
+ [
216
+ file_path.match(/.+\/(.+?)$/)[1],
217
+ File.mtime(file_path).to_f.round(2),
218
+ File.size(file_path)
219
+ ]
220
+ end
145
221
  end
146
222
  end
147
223
  end
@@ -2,9 +2,6 @@
2
2
  module Openstack
3
3
  module Swift
4
4
  class Client
5
- SWIFT_API = Openstack::Swift::Api
6
- MAX_SIZE = 4 * 1024 ** 3
7
-
8
5
  # Initialize method
9
6
  # It uses the authenticate method to store the tokens for future requests
10
7
  def initialize(proxy, user, password)
@@ -17,7 +14,7 @@ module Openstack
17
14
  # avoiding to request a new token for each request
18
15
  # It should be used to force a new token
19
16
  def authenticate!
20
- @url, _, @token = SWIFT_API.auth(@proxy, @user, @password)
17
+ @url, _, @token = Api.auth(@proxy, @user, @password)
21
18
 
22
19
  if @url.blank? or @token.blank?
23
20
  raise AuthenticationError
@@ -31,7 +28,7 @@ module Openstack
31
28
  # object_count: Number of objects that this account have allocated
32
29
  # container_count: Number of container
33
30
  def account_info
34
- headers = SWIFT_API.account(@url, @token)
31
+ headers = Api.account(@url, @token)
35
32
  {
36
33
  "bytes_used" => headers["x-account-bytes-used"],
37
34
  "object_count" => headers["x-account-object-count"],
@@ -46,7 +43,7 @@ module Openstack
46
43
  # manifest
47
44
  # content_length
48
45
  def object_info(container, object)
49
- headers = SWIFT_API.object_stat(@url, @token, container, object)
46
+ headers = Api.object_stat(@url, @token, container, object)
50
47
  {
51
48
  "last_modified" => headers["last-modified"],
52
49
  "md5" => headers["etag"],
@@ -58,63 +55,21 @@ module Openstack
58
55
 
59
56
  # This method uploads a file from a given to a given container
60
57
  def upload(container, file_path, options={})
61
- options[:segments_size] ||= MAX_SIZE
62
-
63
- SWIFT_API.create_container(@url, @token, container) rescue nil
64
-
65
- file_name, file_mtime, file_size = file_info(file_path)
66
-
67
- if file_size > options[:segments_size]
68
- SWIFT_API.create_container(@url, @token, "#{container}_segments") rescue nil
69
-
70
- segments_minus_one = file_size / options[:segments_size]
71
- last_piece = file_size - segments_minus_one * options[:segments_size]
72
- segments_minus_one.times do |segment|
73
- upload_path_for(file_path, segment)
74
- SWIFT_API.upload_object(
75
- @url, @token, "#{container}_segments", file_path,
76
- :size => options[:segments_size],
77
- :position => options[:segments_size] * segment,
78
- :object_name => segment_path
79
- )
80
- end
81
-
82
- SWIFT_API.upload_object(
83
- @url, @token, "#{container}_segments", file_path,
84
- :size => last_piece,
85
- :position => options[:segments_size] * segments_minus_one,
86
- :object_name => upload_path_for(file_path, segments_minus_one)
87
- )
88
-
89
- SWIFT_API.create_manifest(@url, @token, container, file_path)
90
- else
91
- SWIFT_API.upload_object(@url, @token, container, file_path)
92
- end
58
+ Api.upload_object(@url, @token, container, file_path, options)
93
59
  end
94
60
 
95
61
  # This method downloads a object from a given container
96
62
  def download(container, object)
97
- SWIFT_API.download_object(@url, @token, container, object)
63
+ Api.download_object(@url, @token, container, object)
98
64
  end
99
65
 
100
- private
101
-
102
- # Returns the standard swift path for a given file path and segment
103
- def upload_path_for(file_path, segment)
104
- "%s/%s/s/%08d" % (file_info(file_path) << segment)
105
- end
106
-
107
- # Get relevant informations about a file
108
- # Returns an array with:
109
- # file_name
110
- # file_mtime
111
- # file_size
112
- def file_info(file_path)
113
- [
114
- file_path.match(/.+\/(.+?)$/)[1],
115
- File.mtime(file_path).to_f.round(2),
116
- File.size(file_path)
117
- ]
66
+ # Delete a given object from a given container
67
+ def delete(container, object)
68
+ if object_info(container, object)["manifest"]
69
+ Api.delete_objects_from_manifest(@url, @token, container, object)
70
+ else
71
+ Api.delete_object(@url, @token, container, object)
72
+ end
118
73
  end
119
74
  end
120
75
  end
@@ -1,4 +1,5 @@
1
1
  # -*- coding: UTF-8 -*-
2
2
  module Openstack::Swift
3
3
  class AuthenticationError < Exception; end
4
+ class ObjectNotFoundError < Exception; end
4
5
  end
@@ -1,6 +1,6 @@
1
1
  # -*- coding: UTF-8 -*-
2
2
  module Openstack
3
3
  module Swift
4
- VERSION = "0.1.1"
4
+ VERSION = "0.2.0"
5
5
  end
6
6
  end
@@ -33,7 +33,7 @@ describe Openstack::Swift::Api do
33
33
  end
34
34
 
35
35
  context "when authenticated" do
36
- let!(:swift_dummy_file){ File.open("/tmp/swift-dummy", "w") {|f| f.puts("test file"*1000)} }
36
+ let!(:swift_dummy_file){ File.open("/tmp/swift-dummy", "w") {|f| f.puts("test file"*2000)}; "/tmp/swift-dummy" }
37
37
 
38
38
  before do
39
39
  @url, _, @token = subject.auth(
@@ -70,10 +70,31 @@ describe Openstack::Swift::Api do
70
70
  subject.create_container(@url, @token, "pothix_container").should be_true
71
71
  end
72
72
 
73
+ context "whe excluding an object" do
74
+ before { @container = "morellon" }
75
+
76
+ it "should delete an existent object" do
77
+ subject.upload_object(@url, @token, @container, "/tmp/swift-dummy").should be_true
78
+ subject.delete_object(@url, @token, @container, "swift-dummy").should be_true
79
+ end
80
+ end
81
+
82
+ context "when excluding all objects from a manifest" do
83
+ it "should remove all objects from a given manifest" do
84
+ container = "multiseg"
85
+ subject.upload_object(@url, @token, container, swift_dummy_file, {:segments_size => 1024})
86
+ manifest = subject.object_stat(@url, @token, container, "swift-dummy")["x-object-manifest"]
87
+ segment_path = manifest.split("/")[1..-1].join("/") + "/00000000"
88
+ subject.object_stat(@url, @token, "#{container}_segments", segment_path)["etag"].should_not be_nil
89
+ subject.delete_objects_from_manifest(@url, @token, container, "swift-dummy").should be_true
90
+ subject.object_stat(@url, @token, "#{container}_segments", segment_path)["etag"].should be_nil
91
+ end
92
+ end
93
+
73
94
  context "when excluding a container" do
74
95
  before { @container = "pothix_container" }
75
96
 
76
- it "should delete a existent container" do
97
+ it "should delete an existent container" do
77
98
  subject.create_container(@url, @token, @container).should be_true
78
99
  subject.delete_container(@url, @token, @container).should be_true
79
100
  end
@@ -25,10 +25,11 @@ describe "Openstack::Swift::Client" do
25
25
  context "when authenticated" do
26
26
  subject { Openstack::Swift::Client.new(Openstack::SwiftConfig[:url], Openstack::SwiftConfig[:user], Openstack::SwiftConfig[:pass]) }
27
27
 
28
- it "should upload a splitted file and create its manifest" do
29
- pending "WTF...Not working for a unknown reason"
30
- subject.upload("pothix", swift_dummy_file, {:segments_size => 1024*2})
31
- subject.object_info("pothix", "swifty-dummy")["manifest"].should_not be_nil
28
+ it "should try to upload" do
29
+ expect {
30
+ subject.upload("pothix", swift_dummy_file, {:segments_size => 1024*2})
31
+ }.to_not raise_error
32
+ subject.object_info("pothix", "swift-dummy")["manifest"].should_not be_nil
32
33
  end
33
34
 
34
35
  it "should download an splitted file" do
@@ -43,5 +44,19 @@ describe "Openstack::Swift::Client" do
43
44
  account_info.should have_key("object_count")
44
45
  account_info.should have_key("container_count")
45
46
  end
47
+
48
+ context "when deleting" do
49
+ it "should call the delete method for a non manifest file" do
50
+ Openstack::Swift::Api.should_receive(:object_stat).and_return({"x-object-manifest" => nil})
51
+ Openstack::Swift::Api.should_receive(:delete_object)
52
+ subject.delete("pothix","swift-dummy")
53
+ end
54
+
55
+ it "should call the delete_objects_from_manifest method for a manifest file" do
56
+ Openstack::Swift::Api.should_receive(:object_stat).and_return({"x-object-manifest" => "pothix_segments/swift-dummy/1313763802.0/9001/"})
57
+ Openstack::Swift::Api.should_receive(:delete_objects_from_manifest)
58
+ subject.delete("pothix","swift-dummy")
59
+ end
60
+ end
46
61
  end
47
62
  end