swift-storage 0.0.5 → 0.0.6
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 +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.
|