swift_client 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -0
- data/lib/swift_client/null_cache.rb +11 -0
- data/lib/swift_client/version.rb +1 -1
- data/lib/swift_client.rb +51 -7
- data/test/swift_client_test.rb +42 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb7d0291c3fcc0d03fd4aa4711c8c7c4a06b46bf
|
4
|
+
data.tar.gz: 8caa6d7f8e4e21ce1567f7d968e6197fd83760f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88d70e38c7d901e1625c03d12e7a9e016f7d26a3687c1ad3282cc7c29847a3cdfc168ce275453cfd69aff8e27a7ece108c25d2438c3e989beae693d8c17688dd
|
7
|
+
data.tar.gz: eada405a14079e11075ba3a378461c2975da0ef2107609dcf706dca2373da5fde6eea263376873bab01455e38d84d2dd512feacc9a15b84c9395ef55ae0b2bbc
|
data/README.md
CHANGED
@@ -146,6 +146,12 @@ SwiftClient offers the following requests:
|
|
146
146
|
* paginate_objects(container_name, query = {}) -> Enumerator
|
147
147
|
* public_url(object_name, container_name) -> HTTParty::Response
|
148
148
|
* temp_url(object_name, container_name, options = {}) -> HTTParty::Response
|
149
|
+
* bulk_delete(entries) -> entries
|
150
|
+
|
151
|
+
## bulk_delete
|
152
|
+
|
153
|
+
Takes an array containing container_name/object_name entries.
|
154
|
+
Automatically slices and sends 1_000 items per request.
|
149
155
|
|
150
156
|
## Contributing
|
151
157
|
|
data/lib/swift_client/version.rb
CHANGED
data/lib/swift_client.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
|
2
2
|
require "swift_client/version"
|
3
|
+
require "swift_client/null_cache"
|
3
4
|
|
4
5
|
require "httparty"
|
5
6
|
require "mime-types"
|
@@ -25,12 +26,13 @@ class SwiftClient
|
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
|
-
attr_accessor :options, :auth_token, :storage_url
|
29
|
+
attr_accessor :options, :auth_token, :storage_url, :cache_store
|
29
30
|
|
30
31
|
def initialize(options = {})
|
31
32
|
raise(OptionError, "Setting expires_in connection wide is deprecated") if options[:expires_in]
|
32
33
|
|
33
34
|
self.options = options
|
35
|
+
self.cache_store = options[:cache_store] || SwiftClient::NullCache.new
|
34
36
|
|
35
37
|
authenticate
|
36
38
|
end
|
@@ -158,8 +160,25 @@ class SwiftClient
|
|
158
160
|
"#{storage_url}/#{container_name}/#{object_name}?temp_url_sig=#{signature}&temp_url_expires=#{expires}"
|
159
161
|
end
|
160
162
|
|
163
|
+
def bulk_delete(items)
|
164
|
+
items.each_slice(1_000) do |slice|
|
165
|
+
request :delete, "/?bulk-delete", :body => slice.join("\n"), :headers => { "Content-Type" => "text/plain" }
|
166
|
+
end
|
167
|
+
|
168
|
+
items
|
169
|
+
end
|
170
|
+
|
161
171
|
private
|
162
172
|
|
173
|
+
def cache_key
|
174
|
+
auth_keys = [:auth_url, :username, :access_key, :user_id, :user_domain, :user_domain_id, :domain_name,
|
175
|
+
:domain_id, :token, :project_id, :project_name, :project_domain_name, :project_domain_id, :tenant_name]
|
176
|
+
|
177
|
+
auth_key = auth_keys.collect { |key| options[key] }.inspect
|
178
|
+
|
179
|
+
Digest::SHA1.hexdigest(auth_key)
|
180
|
+
end
|
181
|
+
|
163
182
|
def find_header_key(headers, key)
|
164
183
|
headers.keys.detect { |k| k.downcase == key.downcase }
|
165
184
|
end
|
@@ -187,12 +206,38 @@ class SwiftClient
|
|
187
206
|
end
|
188
207
|
|
189
208
|
def authenticate
|
209
|
+
return if authenticate_from_cache
|
210
|
+
|
190
211
|
return authenticate_v3 if options[:auth_url] =~ /v3/
|
191
212
|
return authenticate_v2 if options[:auth_url] =~ /v2/
|
192
213
|
|
193
214
|
authenticate_v1
|
194
215
|
end
|
195
216
|
|
217
|
+
def authenticate_from_cache
|
218
|
+
cached_auth_token = cache_store.get("swift_client:auth_token:#{cache_key}")
|
219
|
+
cached_storage_url = cache_store.get("swift_client:storage_url:#{cache_key}")
|
220
|
+
|
221
|
+
return false if cached_auth_token.nil? || cached_storage_url.nil?
|
222
|
+
|
223
|
+
if cached_auth_token != auth_token || cached_storage_url != storage_url
|
224
|
+
self.auth_token = cached_auth_token
|
225
|
+
self.storage_url = cached_storage_url
|
226
|
+
|
227
|
+
return true
|
228
|
+
end
|
229
|
+
|
230
|
+
false
|
231
|
+
end
|
232
|
+
|
233
|
+
def set_authentication_details(auth_token, storage_url)
|
234
|
+
cache_store.set("swift_client:auth_token:#{cache_key}", auth_token)
|
235
|
+
cache_store.set("swift_client:storage_url:#{cache_key}", storage_url)
|
236
|
+
|
237
|
+
self.auth_token = auth_token
|
238
|
+
self.storage_url = storage_url
|
239
|
+
end
|
240
|
+
|
196
241
|
def authenticate_v1
|
197
242
|
[:auth_url, :username, :api_key].each do |key|
|
198
243
|
raise(AuthenticationError, "#{key} missing") unless options[key]
|
@@ -202,8 +247,7 @@ class SwiftClient
|
|
202
247
|
|
203
248
|
raise(AuthenticationError, "#{response.code}: #{response.message}") unless response.success?
|
204
249
|
|
205
|
-
|
206
|
-
self.storage_url = options[:storage_url] || response.headers["X-Storage-Url"]
|
250
|
+
set_authentication_details response.headers["X-Auth-Token"], options[:storage_url] || response.headers["X-Storage-Url"]
|
207
251
|
end
|
208
252
|
|
209
253
|
def authenticate_v2
|
@@ -231,8 +275,7 @@ class SwiftClient
|
|
231
275
|
|
232
276
|
raise(AuthenticationError, "#{response.code}: #{response.message}") unless response.success?
|
233
277
|
|
234
|
-
|
235
|
-
self.storage_url = options[:storage_url]
|
278
|
+
set_authentication_details response.parsed_response["access"]["token"]["id"], options[:storage_url]
|
236
279
|
end
|
237
280
|
|
238
281
|
def authenticate_v3
|
@@ -277,10 +320,11 @@ class SwiftClient
|
|
277
320
|
|
278
321
|
raise(AuthenticationError, "#{response.code}: #{response.message}") unless response.success?
|
279
322
|
|
280
|
-
|
281
|
-
self.storage_url = options[:storage_url] || storage_url_from_v3_response(response)
|
323
|
+
storage_url = options[:storage_url] || storage_url_from_v3_response(response)
|
282
324
|
|
283
325
|
raise(AuthenticationError, "storage_url missing") unless storage_url
|
326
|
+
|
327
|
+
set_authentication_details response.headers["X-Subject-Token"], storage_url
|
284
328
|
end
|
285
329
|
|
286
330
|
def storage_url_from_v3_response(response)
|
data/test/swift_client_test.rb
CHANGED
@@ -1,6 +1,20 @@
|
|
1
1
|
|
2
2
|
require File.expand_path("../test_helper", __FILE__)
|
3
3
|
|
4
|
+
class MemoryCache
|
5
|
+
def initialize
|
6
|
+
@cache = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def set(key, value)
|
10
|
+
@cache[key] = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(key)
|
14
|
+
@cache[key]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
4
18
|
class SwiftClientTest < MiniTest::Test
|
5
19
|
def setup
|
6
20
|
stub_request(:get, "https://example.com/auth/v1.0").with(:headers => { "X-Auth-Key" => "secret", "X-Auth-User" => "account:username" }).to_return(:status => 200, :body => "", :headers => { "X-Auth-Token" => "Token", "X-Storage-Url" => "https://example.com/v1/AUTH_account" })
|
@@ -11,6 +25,22 @@ class SwiftClientTest < MiniTest::Test
|
|
11
25
|
assert_equal "https://example.com/v1/AUTH_account", @swift_client.storage_url
|
12
26
|
end
|
13
27
|
|
28
|
+
def test_authenticate_from_cache
|
29
|
+
cache = MemoryCache.new
|
30
|
+
cache.set("swift_client:auth_token:49f42f2927701ba93a5bf9750da8fedfa197fa82", "Cached token")
|
31
|
+
cache.set("swift_client:storage_url:49f42f2927701ba93a5bf9750da8fedfa197fa82", "https://cache.example.com/v1/AUTH_account")
|
32
|
+
|
33
|
+
@swift_client = SwiftClient.new(:auth_url => "https://example.com/auth/v1.0", :username => "account:username", :api_key => "secret", :temp_url_key => "Temp url key", :cache_store => cache)
|
34
|
+
|
35
|
+
assert_equal "Cached token", @swift_client.auth_token
|
36
|
+
assert_equal "https://cache.example.com/v1/AUTH_account", @swift_client.storage_url
|
37
|
+
|
38
|
+
@swift_client.send(:authenticate) # Re-authenticate
|
39
|
+
|
40
|
+
assert_equal "Token", @swift_client.auth_token
|
41
|
+
assert_equal "https://example.com/v1/AUTH_account", @swift_client.storage_url
|
42
|
+
end
|
43
|
+
|
14
44
|
def test_v3_authentication_unscoped_with_password
|
15
45
|
stub_request(:post, "https://auth.example.com/v3/auth/tokens").with(:body => JSON.dump("auth" => { "identity" => { "methods" => ["password"], "password" => { "user" => { "name" => "username", "password" => "secret", "domain" => { "name" => "example.com" }}}}})).to_return(:status => 200, :body => JSON.dump("token" => "..."), :headers => { "X-Subject-Token" => "Token", "Content-Type" => "application/json" })
|
16
46
|
|
@@ -134,6 +164,18 @@ class SwiftClientTest < MiniTest::Test
|
|
134
164
|
assert_equal containers, @swift_client.get_containers.parsed_response
|
135
165
|
end
|
136
166
|
|
167
|
+
def test_bulk_delete
|
168
|
+
objects = [
|
169
|
+
"container1/object1",
|
170
|
+
"container1/object2",
|
171
|
+
"container2/object1"
|
172
|
+
]
|
173
|
+
|
174
|
+
stub_request(:delete, "https://example.com/v1/AUTH_account/?bulk-delete").with(:body => objects.join("\n"), :headers => { "Content-Type" => "text/plain", "X-Auth-Token" => "Token" }).to_return(:status => 200,:body => "", :headers => { "Content-Type" => "application/json" })
|
175
|
+
|
176
|
+
assert @swift_client.bulk_delete(objects)
|
177
|
+
end
|
178
|
+
|
137
179
|
def test_paginate_containers
|
138
180
|
containers = [
|
139
181
|
{ "count" => 1, "bytes" => 1, "name" => "container-1" },
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swift_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Vetter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -122,6 +122,7 @@ files:
|
|
122
122
|
- README.md
|
123
123
|
- Rakefile
|
124
124
|
- lib/swift_client.rb
|
125
|
+
- lib/swift_client/null_cache.rb
|
125
126
|
- lib/swift_client/version.rb
|
126
127
|
- swift_client.gemspec
|
127
128
|
- test/swift_client_test.rb
|