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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d525d090d4dbe2874240e7451565618d0d480d7e
4
- data.tar.gz: 47148dab992b2dd489d7a5497188c2f63ff2c806
3
+ metadata.gz: 4b0162d1ba572dd8825f19c6d9e2de6e07b66132
4
+ data.tar.gz: 4c558ab10e1f7e884cd24d7922208007eaa62d5b
5
5
  SHA512:
6
- metadata.gz: 8fc976131b1deb83dbd0fa8f3c536dbb9772745fd0a1514d03605922ad61fa00aba2dc4b312e42bb36a1127a9971b9994ad1d0d6b08e5e4120ae7429821e34b2
7
- data.tar.gz: 4ba694a3082d546bd22634f0d3edfb2df7c53367ced334b95d2dc5f1f881049016076ff26d48d85a0537615223f6ae498337568873575cc555d4a772622a9cc6
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
- TODO: Write usage instructions here
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
@@ -29,7 +29,4 @@ class SwiftStorage::Account < SwiftStorage::Node
29
29
  def relative_path
30
30
  ''
31
31
  end
32
-
33
-
34
32
  end
35
-
@@ -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
@@ -18,6 +18,7 @@ module SwiftStorage
18
18
  CONTAINER_READ = 'X-Container-Read'.freeze
19
19
  CONTAINER_WRITE = 'X-Container-Write'.freeze
20
20
  ACCOUNT_TEMP_URL_KEY = 'X-Account-Meta-Temp-URL-Key'.freeze
21
+ DESTINATION = 'Destination'.freeze
21
22
  end
22
23
 
23
24
  end
@@ -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
- private
188
-
189
- H = SwiftStorage::Headers
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: ENV['SWIFT_STORAGE_TENANT'],
21
- username: ENV['SWIFT_STORAGE_USERNAME'],
22
- password: ENV['SWIFT_STORAGE_PASSWORD'],
23
- endpoint: ENV['SWIFT_STORAGE_ENDPOINT'],
24
- temp_url_key: ENV['SWIFT_STORAGE_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 authenticate!
37
- @auth_token = nil
38
- @storage_token = nil
39
- @auth_at = nil
40
- headers = {
41
- Headers::AUTH_USER => "#{tenant}:#{username}",
42
- Headers::AUTH_KEY => password
43
- }
44
- res = request(auth_url, :headers => headers)
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, "Only GET, PUT, HEAD supported"
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 = sig_to_hex(hmac('sha1', temp_url_key, string_to_sign))
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
- :scheme => scheme,
94
- :host => storage_host,
95
- :port => storage_port,
96
- :path => object_path_escaped,
97
- :query => URI.encode_www_form(
98
- :temp_url_sig => sig,
99
- :temp_url_expires => expires
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
- method: :get,
119
- headers: nil,
120
- params: nil,
121
- input_stream: nil,
122
- output_stream: nil)
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/
@@ -1,5 +1,6 @@
1
- module SwiftStorage::Utils
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
- str.unpack("C*").map { |c|
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 nil if h.empty?
16
+ return if h.empty?
20
17
  Struct.new(*h.keys.map(&:to_sym)).new(*h.values)
21
18
  end
22
-
23
19
  end
@@ -1,3 +1,3 @@
1
1
  module SwiftStorage
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  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={}|
@@ -1,25 +1,123 @@
1
- require "spec_helper"
1
+ require 'spec_helper'
2
2
 
3
3
  RSpec.describe 'Auth' do
4
4
  subject { swift_service }
5
- it "success" do
6
- headers(
7
- h::STORAGE_URL => test_storage_url,
8
- h::AUTH_TOKEN => 'auth_token',
9
- h::STORAGE_TOKEN => 'storage_token'
10
- )
11
-
12
- expect{ subject.authenticate! }.to send_request(:get, '/auth/v1.0', :headers => {
13
- h::AUTH_USER => 'test:testuser',
14
- h::AUTH_KEY => 'testpassword'
15
- })
16
-
17
- expect(subject.auth_token).to eq('auth_token')
18
- expect(subject.storage_url).to eq(test_storage_url)
19
- expect(subject.storage_token).to eq('storage_token')
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 "failure" do
120
+ it 'failure' do
23
121
  status(401)
24
122
 
25
123
  expect{ subject.authenticate! }.to raise_error(SwiftStorage::Service::AuthError)
@@ -9,4 +9,3 @@ RSpec.describe SwiftStorage::Container do
9
9
  )
10
10
  end
11
11
  end
12
-
@@ -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.5
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-01-17 00:00:00.000000000 Z
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.2.2
183
+ rubygems_version: 2.4.5
180
184
  signing_key:
181
185
  specification_version: 4
182
186
  summary: Swift storage client.