swift-storage 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +88 -1
- data/lib/swift-storage.rb +12 -0
- data/lib/swift_storage/account.rb +0 -3
- data/lib/swift_storage/auth/v1_0.rb +31 -0
- data/lib/swift_storage/auth/v2_0.rb +76 -0
- data/lib/swift_storage/configuration.rb +18 -0
- data/lib/swift_storage/headers.rb +1 -0
- data/lib/swift_storage/object.rb +28 -6
- data/lib/swift_storage/service.rb +43 -45
- data/lib/swift_storage/utils.rb +4 -8
- data/lib/swift_storage/version.rb +1 -1
- data/spec/spec_helper.rb +4 -3
- data/spec/swift/auth_spec.rb +115 -17
- data/spec/swift/container_spec.rb +0 -1
- data/spec/swift/object_spec.rb +42 -0
- data/swift-ruby.gemspec +0 -2
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b0162d1ba572dd8825f19c6d9e2de6e07b66132
|
4
|
+
data.tar.gz: 4c558ab10e1f7e884cd24d7922208007eaa62d5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 512d181c487a915dfce20c76d4555e9359f4e78718ef786bbd4ca037f29e243699104ca7f522149bc389597f004393e9a770bd26021c5feb5b376429a2c06a3f
|
7
|
+
data.tar.gz: 50d19c8dcc6815fbb3d30bf899381c34f8cd75c0f82473aa7f8a34deefb31903417760aff4ab4d1dc232e9247560a765eb347f708b08d12cecaf40455bac56a6
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
## Changelog
|
2
|
+
|
3
|
+
This file is written in reverse chronological order, newer releases will
|
4
|
+
appear at the top.
|
5
|
+
|
6
|
+
## 0.0.6
|
7
|
+
|
8
|
+
* Object#copy_from support
|
9
|
+
[#7](https://github.com/memoways/swift-ruby/pull/7)
|
10
|
+
@mdouchement
|
11
|
+
* Keystone v2 support
|
12
|
+
[#6](https://github.com/memoways/swift-ruby/pull/6)
|
13
|
+
@mdouchement
|
data/README.md
CHANGED
@@ -20,7 +20,88 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
-
|
23
|
+
```rb
|
24
|
+
require 'swift-storage'
|
25
|
+
|
26
|
+
# = Configuration =
|
27
|
+
## With environment variables
|
28
|
+
#
|
29
|
+
# SWIFT_STORAGE_AUTH_VERSION
|
30
|
+
# SWIFT_STORAGE_TENANT
|
31
|
+
# SWIFT_STORAGE_USERNAME
|
32
|
+
# SWIFT_STORAGE_PASSWORD
|
33
|
+
# SWIFT_STORAGE_ENDPOINT
|
34
|
+
# SWIFT_STORAGE_TEMP_URL_KEY
|
35
|
+
#
|
36
|
+
## With Rails initializer
|
37
|
+
#
|
38
|
+
# Some parameters are by default configured with the above environment variables, see configuration.rb
|
39
|
+
SwiftStorage.configure do |config|
|
40
|
+
config.auth_version = '2.0' # Keystone auth version, default is 1.0
|
41
|
+
config.tenant = 'Millennium Falcon' # Aka Openstack project
|
42
|
+
config.username = 'han'
|
43
|
+
config.password = 'YT-1300'
|
44
|
+
config.endpoint = 'https//corellia.lan' # Keystone endpoint
|
45
|
+
config.temp_url_key = '492727ZED' # Secret key for presigned URLs
|
46
|
+
# ...
|
47
|
+
end
|
48
|
+
#
|
49
|
+
## With service initialization
|
50
|
+
#
|
51
|
+
# NB: It overrides initializer configuration
|
52
|
+
swift = SwiftStorage::Service.new(
|
53
|
+
tenant: 'Millennium Falcon',
|
54
|
+
username: 'han',
|
55
|
+
password: 'YT-1300',
|
56
|
+
endpoint: 'https//corellia.lan',
|
57
|
+
temp_url_key: '492727ZED'
|
58
|
+
)
|
59
|
+
|
60
|
+
|
61
|
+
# Authenticate, primary to retrieve Swift Storage URL
|
62
|
+
swift.authenticate!
|
63
|
+
swift.authenticated?
|
64
|
+
# => true
|
65
|
+
|
66
|
+
# Setup Secret key in Swift server
|
67
|
+
swift.account.write(temp_url_key: '492727ZED')
|
68
|
+
|
69
|
+
# Create & get containers
|
70
|
+
swift.containers['source'].create unless swift.containers['source'].exists?
|
71
|
+
source = swift.containers['source']
|
72
|
+
swift.containers['destination'].create unless swift.containers['destination'].exists?
|
73
|
+
destination = swift.containers['destination']
|
74
|
+
|
75
|
+
# Get objects
|
76
|
+
source_obj = source.objects['Kessel.asteroid']
|
77
|
+
destination_obj = destination.objects['SiKlaata.cluster']
|
78
|
+
|
79
|
+
# Upload data into object
|
80
|
+
source_obj.write('Glitterstim', content_type: 'application/spice')
|
81
|
+
# or stream from file
|
82
|
+
File.open('/tmp/Kessel.asteroid', 'r') do |input|
|
83
|
+
source_obj.write(input, content_type: 'application/spice')
|
84
|
+
end
|
85
|
+
|
86
|
+
# Copy an object
|
87
|
+
# Source can be a SwiftStorage::Object or a string like 'source/Kessel.asteroid'
|
88
|
+
destination_obj.copy_from(source_obj)
|
89
|
+
|
90
|
+
# Read data from Swift
|
91
|
+
p destination_obj.read
|
92
|
+
# => Glitterstim
|
93
|
+
|
94
|
+
# Download to a file
|
95
|
+
File.open('/tmp/SiKlaata.cluster', 'w') do |output|
|
96
|
+
destination_obj.read(output)
|
97
|
+
end
|
98
|
+
# or
|
99
|
+
destination_obj.stream_to_file('/tmp/SiKlaata.cluster')
|
100
|
+
|
101
|
+
# Create temporary pre-signed URL
|
102
|
+
p destination_obj.temp_url(Time.now + (3600 * 10), method: :get)
|
103
|
+
# => https//corellia.lan/v1/AUTH_39c47bfd3ecd41938368239813628963/destination/death/star.moon?temp_url_sig=cbd7568b60abcd5862a96eb03af5fa154e851d54&temp_url_expires=1439430168
|
104
|
+
```
|
24
105
|
|
25
106
|
## Contributing
|
26
107
|
|
@@ -29,3 +110,9 @@ TODO: Write usage instructions here
|
|
29
110
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
111
|
4. Push to the branch (`git push origin my-new-feature`)
|
31
112
|
5. Create a new Pull Request
|
113
|
+
|
114
|
+
|
115
|
+
## Contributors
|
116
|
+
|
117
|
+
- Nicolas Goy @kuon
|
118
|
+
- @mdouchement
|
data/lib/swift-storage.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "net/http"
|
2
2
|
require "swift_storage/version"
|
3
|
+
require "swift_storage/configuration"
|
3
4
|
require "swift_storage/errors"
|
4
5
|
require "swift_storage/utils"
|
5
6
|
require "swift_storage/headers"
|
@@ -12,4 +13,15 @@ require "swift_storage/object_collection"
|
|
12
13
|
require "swift_storage/service"
|
13
14
|
|
14
15
|
module SwiftStorage
|
16
|
+
class << self
|
17
|
+
attr_accessor :configuration
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.configuration
|
21
|
+
@configuration ||= Configuration.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.configure
|
25
|
+
yield configuration
|
26
|
+
end
|
15
27
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module SwiftStorage
|
2
|
+
module Auth
|
3
|
+
module V1_0
|
4
|
+
attr_accessor :auth_path
|
5
|
+
|
6
|
+
def authenticate!
|
7
|
+
headers = {
|
8
|
+
Headers::AUTH_USER => "#{tenant}:#{username}",
|
9
|
+
Headers::AUTH_KEY => password
|
10
|
+
}
|
11
|
+
res = request(auth_url, headers: headers)
|
12
|
+
|
13
|
+
h = res.header
|
14
|
+
self.storage_url = h[Headers::STORAGE_URL]
|
15
|
+
@auth_token = h[Headers::AUTH_TOKEN]
|
16
|
+
@storage_token = h[Headers::STORAGE_TOKEN]
|
17
|
+
@auth_at = Time.now
|
18
|
+
end
|
19
|
+
|
20
|
+
def authenticated?
|
21
|
+
!!(self.storage_url && auth_token)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def auth_url
|
27
|
+
File.join(endpoint, @auth_path || 'auth/v1.0')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module SwiftStorage
|
2
|
+
module Auth
|
3
|
+
module V2_0
|
4
|
+
extend Forwardable
|
5
|
+
def_delegators SwiftStorage, :configuration
|
6
|
+
|
7
|
+
attr_accessor :auth_path
|
8
|
+
|
9
|
+
def authenticate!
|
10
|
+
res = request("#{auth_url}/tokens", method: :post, json_data: auth_data)
|
11
|
+
|
12
|
+
JSON.parse(res.body).tap do |body|
|
13
|
+
@auth_token = body['access']['token']['id']
|
14
|
+
storage_endpoint(body['access']['serviceCatalog']) do |endpoint|
|
15
|
+
self.storage_url = endpoint['publicURL']
|
16
|
+
@storage_token = endpoint['id']
|
17
|
+
@auth_at = Time.now
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def authenticated?
|
23
|
+
!!(self.storage_url && auth_token)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def auth_url
|
29
|
+
File.join(endpoint, @auth_path || 'v2.0').chomp('/')
|
30
|
+
end
|
31
|
+
|
32
|
+
def auth_data
|
33
|
+
case configuration.auth_method
|
34
|
+
when :password
|
35
|
+
{
|
36
|
+
auth: {
|
37
|
+
passwordCredentials: {
|
38
|
+
username: username,
|
39
|
+
password: password
|
40
|
+
},
|
41
|
+
configuration.authtenant_type => tenant || username
|
42
|
+
}
|
43
|
+
}
|
44
|
+
when :rax_kskey
|
45
|
+
{
|
46
|
+
auth: {
|
47
|
+
'RAX-KSKEY:apiKeyCredentials' => {
|
48
|
+
username: username,
|
49
|
+
apiKey: password
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
when :key
|
54
|
+
{
|
55
|
+
auth: {
|
56
|
+
apiAccessKeyCredentials: {
|
57
|
+
accessKey: username,
|
58
|
+
secretKey: password
|
59
|
+
},
|
60
|
+
configuration.authtenant_type => tenant || username
|
61
|
+
}
|
62
|
+
}
|
63
|
+
else
|
64
|
+
fail "Unsupported authentication method #{configuration.auth_method}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def storage_endpoint(service_catalog)
|
69
|
+
unless (swift = service_catalog.find { |service| service['type'] == 'object-store' })
|
70
|
+
fail SwiftStorage::Errors::NotFoundError.new 'No object-store service found'
|
71
|
+
end
|
72
|
+
yield swift['endpoints'].sample
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SwiftStorage
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :auth_version, :tenant, :username, :password, :endpoint, :temp_url_key,
|
4
|
+
:auth_method, :authtenant_type
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@auth_version = ENV['SWIFT_STORAGE_AUTH_VERSION'] || '1.0'
|
8
|
+
@tenant = ENV['SWIFT_STORAGE_TENANT']
|
9
|
+
@username = ENV['SWIFT_STORAGE_USERNAME']
|
10
|
+
@password = ENV['SWIFT_STORAGE_PASSWORD']
|
11
|
+
@endpoint = ENV['SWIFT_STORAGE_ENDPOINT']
|
12
|
+
@temp_url_key = ENV['SWIFT_STORAGE_TEMP_URL_KEY']
|
13
|
+
|
14
|
+
@auth_method = :password
|
15
|
+
@authtenant_type = 'tenantName' # `tenantName` or `tenantId`
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/swift_storage/object.rb
CHANGED
@@ -153,6 +153,29 @@ class SwiftStorage::Object < SwiftStorage::Node
|
|
153
153
|
input_stream
|
154
154
|
end
|
155
155
|
|
156
|
+
# Creates a copy of an object that is already stored in Swift.
|
157
|
+
#
|
158
|
+
# @param source [String, SwiftStorage::Object]
|
159
|
+
# The container and object name of the source object or the SwiftStorage::Object source
|
160
|
+
#
|
161
|
+
# @param optional_headers [Hash]
|
162
|
+
# All optional headers supported by Swift API for object copy
|
163
|
+
#
|
164
|
+
# @return [SwiftStorage::Object]
|
165
|
+
# The current object
|
166
|
+
def copy_from(source, optional_headers = {})
|
167
|
+
case source
|
168
|
+
when SwiftStorage::Object
|
169
|
+
path = source.relative_path
|
170
|
+
when String
|
171
|
+
path = source
|
172
|
+
else
|
173
|
+
raise ArgumentError.new('Invalid source type')
|
174
|
+
end
|
175
|
+
|
176
|
+
request(path, method: :copy, headers: optional_headers.merge(H::DESTINATION => relative_path))
|
177
|
+
self
|
178
|
+
end
|
156
179
|
|
157
180
|
# Generates a public URL with an expiration time
|
158
181
|
#
|
@@ -184,13 +207,12 @@ class SwiftStorage::Object < SwiftStorage::Node
|
|
184
207
|
File.join(service.storage_url, relative_path)
|
185
208
|
end
|
186
209
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
210
|
+
# Returns the object's relative path (container name with object name)
|
211
|
+
#
|
212
|
+
# @return [String]
|
213
|
+
# The object relative path.
|
214
|
+
#
|
191
215
|
def relative_path
|
192
216
|
File.join(container.name, name)
|
193
217
|
end
|
194
|
-
|
195
218
|
end
|
196
|
-
|
@@ -1,9 +1,13 @@
|
|
1
1
|
require 'uri'
|
2
|
+
require 'json'
|
3
|
+
require 'swift_storage/auth/v1_0'
|
4
|
+
require 'swift_storage/auth/v2_0'
|
2
5
|
|
3
6
|
class SwiftStorage::Service
|
4
|
-
|
5
7
|
include SwiftStorage::Utils
|
6
8
|
include SwiftStorage
|
9
|
+
extend Forwardable
|
10
|
+
def_delegators SwiftStorage, :configuration
|
7
11
|
|
8
12
|
attr_reader :tenant,
|
9
13
|
:endpoint,
|
@@ -17,41 +21,31 @@ class SwiftStorage::Service
|
|
17
21
|
:storage_path,
|
18
22
|
:temp_url_key
|
19
23
|
|
20
|
-
def initialize(tenant:
|
21
|
-
username:
|
22
|
-
password:
|
23
|
-
endpoint:
|
24
|
-
temp_url_key:
|
24
|
+
def initialize(tenant: configuration.tenant,
|
25
|
+
username: configuration.username,
|
26
|
+
password: configuration.password,
|
27
|
+
endpoint: configuration.endpoint,
|
28
|
+
temp_url_key: configuration.temp_url_key)
|
25
29
|
@temp_url_key = temp_url_key
|
26
30
|
|
27
31
|
%w(tenant username password endpoint).each do |n|
|
28
32
|
eval("#{n} or raise ArgumentError, '#{n} is required'")
|
29
33
|
eval("@#{n} = #{n}")
|
30
34
|
end
|
31
|
-
self.storage_url = File.join(endpoint, 'v1', "AUTH_#{tenant}")
|
32
35
|
|
36
|
+
setup_auth
|
33
37
|
@sessions = {}
|
34
38
|
end
|
35
39
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
h = res.header
|
47
|
-
self.storage_url = h[Headers::STORAGE_URL]
|
48
|
-
@auth_token = h[Headers::AUTH_TOKEN]
|
49
|
-
@storage_token = h[Headers::STORAGE_TOKEN]
|
50
|
-
@auth_at = Time.new
|
51
|
-
end
|
52
|
-
|
53
|
-
def authenticated?
|
54
|
-
!!(storage_url && auth_token)
|
40
|
+
def setup_auth
|
41
|
+
case configuration.auth_version
|
42
|
+
when '1.0'
|
43
|
+
extend SwiftStorage::Auth::V1_0
|
44
|
+
when '2.0'
|
45
|
+
extend SwiftStorage::Auth::V2_0
|
46
|
+
else
|
47
|
+
fail "Unsupported auth version #{configuration.auth_version}"
|
48
|
+
end
|
55
49
|
end
|
56
50
|
|
57
51
|
def containers
|
@@ -77,26 +71,26 @@ class SwiftStorage::Service
|
|
77
71
|
|
78
72
|
method = method.to_s.upcase
|
79
73
|
# Limit methods
|
80
|
-
%w{GET PUT HEAD}.include?(method) or raise ArgumentError,
|
74
|
+
%w{GET PUT HEAD}.include?(method) or raise ArgumentError, 'Only GET, PUT, HEAD supported'
|
81
75
|
|
82
76
|
expires = expires.to_i
|
83
|
-
object_path_escaped = File.join(storage_path, escape(container), escape(object,
|
77
|
+
object_path_escaped = File.join(storage_path, escape(container), escape(object, '/'))
|
84
78
|
object_path_unescaped = File.join(storage_path, escape(container), object)
|
85
79
|
|
86
80
|
string_to_sign = "#{method}\n#{expires}\n#{object_path_unescaped}"
|
87
81
|
|
88
|
-
sig
|
82
|
+
sig = sig_to_hex(hmac('sha1', temp_url_key, string_to_sign))
|
89
83
|
|
90
84
|
klass = scheme == 'http' ? URI::HTTP : URI::HTTPS
|
91
85
|
|
92
86
|
temp_url_options = {
|
93
|
-
:
|
94
|
-
:
|
95
|
-
:
|
96
|
-
:
|
97
|
-
:
|
98
|
-
:
|
99
|
-
:
|
87
|
+
scheme: scheme,
|
88
|
+
host: storage_host,
|
89
|
+
port: storage_port,
|
90
|
+
path: object_path_escaped,
|
91
|
+
query: URI.encode_www_form(
|
92
|
+
temp_url_sig: sig,
|
93
|
+
temp_url_expires: expires
|
100
94
|
)
|
101
95
|
}
|
102
96
|
klass.build(temp_url_options).to_s
|
@@ -115,13 +109,15 @@ class SwiftStorage::Service
|
|
115
109
|
end
|
116
110
|
|
117
111
|
def request(path_or_url,
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
112
|
+
method: :get,
|
113
|
+
headers: nil,
|
114
|
+
params: nil,
|
115
|
+
json_data: nil,
|
116
|
+
input_stream: nil,
|
117
|
+
output_stream: nil)
|
123
118
|
headers ||= {}
|
124
119
|
headers.merge!(Headers::AUTH_TOKEN => auth_token) if authenticated?
|
120
|
+
headers.merge!(Headers::CONTENT_TYPE => 'application/json') if json_data
|
125
121
|
headers.merge!(Headers::CONNECTION => 'keep-alive', Headers::PROXY_CONNECTION => 'keep-alive')
|
126
122
|
|
127
123
|
if !(path_or_url =~ /^http/)
|
@@ -159,10 +155,16 @@ class SwiftStorage::Service
|
|
159
155
|
req = Net::HTTP::Post.new(path, headers)
|
160
156
|
when :put
|
161
157
|
req = Net::HTTP::Put.new(path, headers)
|
158
|
+
when :copy
|
159
|
+
req = Net::HTTP::Copy.new(path, headers)
|
162
160
|
else
|
163
161
|
raise ArgumentError, "Method #{method} not supported"
|
164
162
|
end
|
165
163
|
|
164
|
+
if json_data
|
165
|
+
req.body = JSON.generate(json_data)
|
166
|
+
end
|
167
|
+
|
166
168
|
if input_stream
|
167
169
|
if String === input_stream
|
168
170
|
input_stream = StringIO.new(input_stream)
|
@@ -200,10 +202,6 @@ class SwiftStorage::Service
|
|
200
202
|
:username,
|
201
203
|
:password
|
202
204
|
|
203
|
-
def auth_url
|
204
|
-
File.join(endpoint, 'auth/v1.0')
|
205
|
-
end
|
206
|
-
|
207
205
|
def check_response!(response)
|
208
206
|
case response.code
|
209
207
|
when /^2/
|
data/lib/swift_storage/utils.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'openssl'
|
2
2
|
|
3
|
+
module SwiftStorage::Utils
|
3
4
|
include SwiftStorage::Errors
|
4
5
|
|
5
6
|
def hmac(type, key, data)
|
@@ -8,16 +9,11 @@ module SwiftStorage::Utils
|
|
8
9
|
end
|
9
10
|
|
10
11
|
def sig_to_hex(str)
|
11
|
-
|
12
|
-
c.to_s(16)
|
13
|
-
}.map { |h|
|
14
|
-
h.size == 1 ? "0#{h}" : h
|
15
|
-
}.join
|
12
|
+
Digest.hexencode(str)
|
16
13
|
end
|
17
14
|
|
18
15
|
def struct(h)
|
19
|
-
return
|
16
|
+
return if h.empty?
|
20
17
|
Struct.new(*h.keys.map(&:to_sym)).new(*h.values)
|
21
18
|
end
|
22
|
-
|
23
19
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,7 +2,6 @@ require "swift-storage"
|
|
2
2
|
require_relative "support/local_server"
|
3
3
|
|
4
4
|
module TestServerMixin
|
5
|
-
|
6
5
|
def h
|
7
6
|
SwiftStorage::Headers
|
8
7
|
end
|
@@ -30,7 +29,7 @@ module TestServerMixin
|
|
30
29
|
:password => 'testpassword',
|
31
30
|
:endpoint => server.base_url,
|
32
31
|
:temp_url_key => 'A1234'
|
33
|
-
)
|
32
|
+
).tap { |s| s.storage_url = test_storage_url }
|
34
33
|
end
|
35
34
|
|
36
35
|
def test_storage_url
|
@@ -52,8 +51,10 @@ module TestServerMixin
|
|
52
51
|
def random_length
|
53
52
|
Random.rand(5000) + 1000
|
54
53
|
end
|
54
|
+
end
|
55
55
|
|
56
|
-
|
56
|
+
SwiftStorage.configure do |config|
|
57
|
+
config.auth_version = '1.0'
|
57
58
|
end
|
58
59
|
|
59
60
|
RSpec::Matchers.define :send_request do |method, path, options={}|
|
data/spec/swift/auth_spec.rb
CHANGED
@@ -1,25 +1,123 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe 'Auth' do
|
4
4
|
subject { swift_service }
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
5
|
+
|
6
|
+
context 'when v1 is used' do
|
7
|
+
before do
|
8
|
+
headers(
|
9
|
+
h::STORAGE_URL => test_storage_url,
|
10
|
+
h::AUTH_TOKEN => 'auth_token',
|
11
|
+
h::STORAGE_TOKEN => 'storage_token'
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'authenticates' do
|
16
|
+
expect { subject.authenticate! }.to send_request(:get, '/auth/v1.0',
|
17
|
+
headers: { h::AUTH_USER => 'test:testuser', h::AUTH_KEY => 'testpassword' })
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'sets the authentication token' do
|
21
|
+
subject.authenticate!
|
22
|
+
expect(subject.auth_token).to eq('auth_token')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'sets the storage url' do
|
26
|
+
subject.authenticate!
|
27
|
+
expect(subject.storage_url).to eq(test_storage_url)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'sets the storage token' do
|
31
|
+
subject.authenticate!
|
32
|
+
expect(subject.storage_token).to eq('storage_token')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when v2 is used' do
|
37
|
+
let(:credentials) do
|
38
|
+
{
|
39
|
+
auth: {
|
40
|
+
passwordCredentials: {
|
41
|
+
username: 'testuser',
|
42
|
+
password: 'testpassword'
|
43
|
+
},
|
44
|
+
subject.configuration.authtenant_type => 'test'
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
let(:body) do
|
49
|
+
{
|
50
|
+
'access' => {
|
51
|
+
'token' => {
|
52
|
+
'id' => 'auth_token'
|
53
|
+
},
|
54
|
+
'serviceCatalog' => [
|
55
|
+
{
|
56
|
+
'endpoints' => [
|
57
|
+
{
|
58
|
+
'id' => 'storage_token',
|
59
|
+
'publicURL' => test_storage_url
|
60
|
+
}
|
61
|
+
],
|
62
|
+
'type' => 'object-store'
|
63
|
+
}
|
64
|
+
]
|
65
|
+
}
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
before do
|
70
|
+
SwiftStorage.configuration.auth_version = '2.0'
|
71
|
+
allow(JSON).to receive(:parse).and_return(body)
|
72
|
+
end
|
73
|
+
after { SwiftStorage.configuration.auth_version = '1.0' }
|
74
|
+
|
75
|
+
it 'authenticates' do
|
76
|
+
expect { subject.authenticate! }.to send_request(:post, '/v2.0/tokens',
|
77
|
+
json_data: credentials.to_json)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'sets the authentication token' do
|
81
|
+
subject.authenticate!
|
82
|
+
expect(subject.auth_token).to eq('auth_token')
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when there is an object-store' do
|
86
|
+
it 'sets the storage url' do
|
87
|
+
subject.authenticate!
|
88
|
+
expect(subject.storage_url).to eq(test_storage_url)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'sets the storage token' do
|
92
|
+
subject.authenticate!
|
93
|
+
expect(subject.storage_token).to eq('storage_token')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when there is no object-store' do
|
98
|
+
let(:bad_body) do
|
99
|
+
{
|
100
|
+
'access' => {
|
101
|
+
'token' => {
|
102
|
+
'id' => 'auth_token'
|
103
|
+
},
|
104
|
+
'serviceCatalog' => []
|
105
|
+
}
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
before do
|
110
|
+
allow(JSON).to receive(:parse).and_return(bad_body)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'raises an error' do
|
114
|
+
expect{ subject.authenticate! }
|
115
|
+
.to raise_error(SwiftStorage::Service::NotFoundError, 'No object-store service found')
|
116
|
+
end
|
117
|
+
end
|
20
118
|
end
|
21
119
|
|
22
|
-
it
|
120
|
+
it 'failure' do
|
23
121
|
status(401)
|
24
122
|
|
25
123
|
expect{ subject.authenticate! }.to raise_error(SwiftStorage::Service::AuthError)
|
data/spec/swift/object_spec.rb
CHANGED
@@ -44,4 +44,46 @@ RSpec.describe SwiftStorage::Object do
|
|
44
44
|
expect(subject.metadata.jon_doe).to eq('a meta')
|
45
45
|
end
|
46
46
|
|
47
|
+
describe '#copy_from' do
|
48
|
+
subject { swift_service.containers['some_destination_container'].objects['some_copied_object'] }
|
49
|
+
let(:source) { swift_service.containers['some_source_container'].objects['some_object'] }
|
50
|
+
|
51
|
+
it 'adds optional headers to request' do
|
52
|
+
expect { subject.copy_from(source, 'X-Object-Falcon' => 'Awesome') }.to send_request(
|
53
|
+
:copy,
|
54
|
+
'/v1/AUTH_test/some_source_container/some_object',
|
55
|
+
headers: { h::DESTINATION => 'some_destination_container/some_copied_object', 'X-Object-Falcon' => 'Awesome' }
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when source is a SwiftStorage::Object' do
|
60
|
+
it 'copies the source' do
|
61
|
+
expect { subject.copy_from(source) }.to send_request(
|
62
|
+
:copy,
|
63
|
+
'/v1/AUTH_test/some_source_container/some_object',
|
64
|
+
headers: { h::DESTINATION => 'some_destination_container/some_copied_object' }
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when source is a string' do
|
70
|
+
it 'copies the source' do
|
71
|
+
expect { subject.copy_from(source.relative_path) }.to send_request(
|
72
|
+
:copy,
|
73
|
+
'/v1/AUTH_test/some_source_container/some_object',
|
74
|
+
headers: { h::DESTINATION => 'some_destination_container/some_copied_object' }
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when source is an integer' do
|
80
|
+
it 'raises an error' do
|
81
|
+
expect { subject.copy_from(42) }.to raise_error(ArgumentError, 'Invalid source type')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'returns destination object' do
|
86
|
+
expect(subject.copy_from(source).relative_path).to eq('some_destination_container/some_copied_object')
|
87
|
+
end
|
88
|
+
end
|
47
89
|
end
|
data/swift-ruby.gemspec
CHANGED
@@ -18,8 +18,6 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
|
22
|
-
|
23
21
|
spec.add_development_dependency "bundler", "~> 1.7"
|
24
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
25
23
|
spec.add_development_dependency "rspec", "~> 3.1.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swift-storage
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicolas Goy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -132,6 +132,7 @@ files:
|
|
132
132
|
- ".gitignore"
|
133
133
|
- ".rspec"
|
134
134
|
- ".yardopts"
|
135
|
+
- CHANGELOG.md
|
135
136
|
- Gemfile
|
136
137
|
- Guardfile
|
137
138
|
- LICENSE.txt
|
@@ -139,6 +140,9 @@ files:
|
|
139
140
|
- Rakefile
|
140
141
|
- lib/swift-storage.rb
|
141
142
|
- lib/swift_storage/account.rb
|
143
|
+
- lib/swift_storage/auth/v1_0.rb
|
144
|
+
- lib/swift_storage/auth/v2_0.rb
|
145
|
+
- lib/swift_storage/configuration.rb
|
142
146
|
- lib/swift_storage/container.rb
|
143
147
|
- lib/swift_storage/container_collection.rb
|
144
148
|
- lib/swift_storage/errors.rb
|
@@ -176,7 +180,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
176
180
|
version: '0'
|
177
181
|
requirements: []
|
178
182
|
rubyforge_project:
|
179
|
-
rubygems_version: 2.
|
183
|
+
rubygems_version: 2.4.5
|
180
184
|
signing_key:
|
181
185
|
specification_version: 4
|
182
186
|
summary: Swift storage client.
|