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 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.