swift-storage 0.0.1
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 +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +7 -0
- data/lib/swift-storage.rb +15 -0
- data/lib/swift_storage/account.rb +35 -0
- data/lib/swift_storage/container.rb +67 -0
- data/lib/swift_storage/container_collection.rb +34 -0
- data/lib/swift_storage/errors.rb +15 -0
- data/lib/swift_storage/headers.rb +23 -0
- data/lib/swift_storage/node.rb +133 -0
- data/lib/swift_storage/object.rb +172 -0
- data/lib/swift_storage/object_collection.rb +34 -0
- data/lib/swift_storage/service.rb +201 -0
- data/lib/swift_storage/utils.rb +23 -0
- data/lib/swift_storage/version.rb +3 -0
- data/spec/spec_helper.rb +139 -0
- data/spec/support/local_server.rb +86 -0
- data/spec/swift/auth_spec.rb +27 -0
- data/spec/swift/object_spec.rb +46 -0
- data/spec/swift/temp_url_spec.rb +19 -0
- data/swift-ruby.gemspec +31 -0
- metadata +188 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e3246e84c36a57fc2892b66434fda76d6a0985c5
|
4
|
+
data.tar.gz: 76f1ad2fa5f6b47e0d704ca2ec2095d3ac1ee7fc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9d0bee3254a69d404e1ef30e9ee454cc81d894dcb59a69dd7c2e5d4e8269ce5a38b402a5cfaf54527bbbada5f80190ddd16094eaf2703094fb28ff069c5f6a79
|
7
|
+
data.tar.gz: 5035e8d1b0ac40516926bf47aab4e6d3a8597c23bc3acff638cce78018b1da0b18000281b9cb67b4f19878c6fe2ce8fc18bd74d37cc42343061f3eab28d17705
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Nicolas Goy
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Swift::Ruby
|
2
|
+
|
3
|
+
Ruby client for Openstack swift
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'swift-ruby'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install swift-ruby
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it ( https://github.com/[my-github-username]/swift-ruby/fork )
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "swift_storage/version"
|
3
|
+
require "swift_storage/errors"
|
4
|
+
require "swift_storage/utils"
|
5
|
+
require "swift_storage/headers"
|
6
|
+
require "swift_storage/node"
|
7
|
+
require "swift_storage/account"
|
8
|
+
require "swift_storage/container"
|
9
|
+
require "swift_storage/container_collection"
|
10
|
+
require "swift_storage/object"
|
11
|
+
require "swift_storage/object_collection"
|
12
|
+
require "swift_storage/service"
|
13
|
+
|
14
|
+
module SwiftStorage
|
15
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class SwiftStorage::Account < SwiftStorage::Node
|
2
|
+
|
3
|
+
parent_node :service
|
4
|
+
|
5
|
+
|
6
|
+
# Write account meta data
|
7
|
+
#
|
8
|
+
# @param temp_url_key [String]
|
9
|
+
# The shared secret used to sign temporary URLs.
|
10
|
+
# Changing this key will invalidate all temporary URLs signed with the older
|
11
|
+
# key.
|
12
|
+
#
|
13
|
+
def write(temp_url_key: nil)
|
14
|
+
h = {}
|
15
|
+
h[H::ACCOUNT_TEMP_URL_KEY] = temp_url_key if temp_url_key
|
16
|
+
|
17
|
+
request(relative_path, :method => :post, :headers => h)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns the temporary URL key
|
21
|
+
#
|
22
|
+
# @return [String]
|
23
|
+
# Key used to sign temporary URLs
|
24
|
+
#
|
25
|
+
def temp_url_key
|
26
|
+
metadata.temp_url_key rescue nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def relative_path
|
30
|
+
''
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class SwiftStorage::Container < SwiftStorage::Node
|
2
|
+
|
3
|
+
parent_node :service
|
4
|
+
|
5
|
+
|
6
|
+
def relative_path
|
7
|
+
name
|
8
|
+
end
|
9
|
+
|
10
|
+
header_attributes :bytes_used,
|
11
|
+
:object_count
|
12
|
+
|
13
|
+
|
14
|
+
# Returns the object collection for this container
|
15
|
+
#
|
16
|
+
# @return [SwiftStorage::ObjectCollection]
|
17
|
+
# The object collection.
|
18
|
+
#
|
19
|
+
def objects
|
20
|
+
@objects ||= SwiftStorage::ObjectCollection.new(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Create the container
|
24
|
+
#
|
25
|
+
def create
|
26
|
+
request(relative_path, :method => :put)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Write the container meta data
|
30
|
+
#
|
31
|
+
# @note This overrides all ACL set on the container.
|
32
|
+
#
|
33
|
+
# Each ACL is a string in the following format:
|
34
|
+
#
|
35
|
+
# - `team:jon` give access to user "jon" of account "team"
|
36
|
+
#
|
37
|
+
# @param read_acl [Array<String>]
|
38
|
+
# An array of ACL.
|
39
|
+
#
|
40
|
+
# @param write_acl [Array<String>]
|
41
|
+
# An array of ACL.
|
42
|
+
#
|
43
|
+
def write(write_acl: nil, read_acl: nil)
|
44
|
+
h = {}
|
45
|
+
read_acl = read_acl.join(',') if read_acl.respond_to?(:to_ary)
|
46
|
+
write_acl = write_acl.join(',') if write_acl.respond_to?(:to_ary)
|
47
|
+
|
48
|
+
h[H::CONTAINER_READ] = read_acl
|
49
|
+
h[H::CONTAINER_WRITE] = write_acl
|
50
|
+
|
51
|
+
request(relative_path, :method => :post, :headers => h)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Read the container meta data
|
55
|
+
#
|
56
|
+
# @return [Struct]
|
57
|
+
# A struct with `read` and `write` ACL, each entry contains an Array of
|
58
|
+
# String.
|
59
|
+
def acl
|
60
|
+
r = headers.read.split(',') rescue nil
|
61
|
+
w = headers.write.split(',') rescue nil
|
62
|
+
struct(:read => r, :write => w)
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
end
|
67
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class SwiftStorage::ContainerCollection < SwiftStorage::Node
|
2
|
+
|
3
|
+
parent_node :service
|
4
|
+
|
5
|
+
|
6
|
+
# Return all containers
|
7
|
+
#
|
8
|
+
# @note This method will return only the first 1000 containers.
|
9
|
+
#
|
10
|
+
# @return [Array<SwiftStorage::Container>]
|
11
|
+
# Containers in this collection.
|
12
|
+
#
|
13
|
+
def all
|
14
|
+
get_lines('').map { |name| SwiftStorage::Container.new(service, name)}
|
15
|
+
end
|
16
|
+
|
17
|
+
# Return a particular container
|
18
|
+
#
|
19
|
+
# @note This always return a container, regadeless of it's existence
|
20
|
+
# on the server. This call do NOT contact the server.
|
21
|
+
#
|
22
|
+
# @param name [String]
|
23
|
+
# The name (sometimes named key) of the container
|
24
|
+
#
|
25
|
+
# @return [SwiftStorage::Object]
|
26
|
+
# Container with given name
|
27
|
+
#
|
28
|
+
def [](name)
|
29
|
+
SwiftStorage::Container.new(service, name)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SwiftStorage
|
2
|
+
|
3
|
+
module Headers
|
4
|
+
STORAGE_URL = 'X-Storage-Url'.freeze
|
5
|
+
AUTH_TOKEN = 'X-Auth-Token'.freeze
|
6
|
+
AUTH_USER = 'X-Auth-User'.freeze
|
7
|
+
AUTH_KEY = 'X-Auth-Key'.freeze
|
8
|
+
STORAGE_TOKEN = 'X-Storage-Token'.freeze
|
9
|
+
CONNECTION = 'Connection'.freeze
|
10
|
+
PROXY_CONNECTION = 'Proxy-Connection'.freeze
|
11
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
12
|
+
CONTENT_DISPOSITION = 'Content-Disposition'.freeze
|
13
|
+
DELETE_AT = 'X-Delete-At'.freeze
|
14
|
+
DELETE_AFTER = 'X-Delete-After'.freeze
|
15
|
+
CACHE_CONTROL = 'Cache-Control'.freeze
|
16
|
+
EXPIRES = 'Expires'.freeze
|
17
|
+
OBJECT_MANIFEST = 'X-Object-Manifest'.freeze
|
18
|
+
CONTAINER_READ = 'X-Container-Read'.freeze
|
19
|
+
CONTAINER_WRITE = 'X-Container-Write'.freeze
|
20
|
+
ACCOUNT_TEMP_URL_KEY = 'X-Account-Meta-Temp-URL-Key'.freeze
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
class SwiftStorage::Node
|
2
|
+
|
3
|
+
include SwiftStorage::Utils
|
4
|
+
|
5
|
+
attr_accessor :parent,
|
6
|
+
:name
|
7
|
+
|
8
|
+
def initialize(parent, name=nil)
|
9
|
+
@parent = parent
|
10
|
+
@name = name
|
11
|
+
end
|
12
|
+
|
13
|
+
def request(*args)
|
14
|
+
service.request(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the service for this node
|
18
|
+
#
|
19
|
+
# @return [SwiftStorage::Service]
|
20
|
+
# The service this node is bound to
|
21
|
+
#
|
22
|
+
def service
|
23
|
+
unless defined?(@service)
|
24
|
+
p = parent
|
25
|
+
while p && !(SwiftStorage::Service === p)
|
26
|
+
p = p.parent
|
27
|
+
end
|
28
|
+
@service = p
|
29
|
+
end
|
30
|
+
@service
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_lines(path)
|
34
|
+
headers = {'Accept' => 'text/plain'}
|
35
|
+
response = request(path, :headers => headers)
|
36
|
+
body = response.body
|
37
|
+
if body.nil? || body.empty?
|
38
|
+
[]
|
39
|
+
else
|
40
|
+
body.lines.map(&:strip)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"#<#{self.class.name} #{name}>"
|
46
|
+
end
|
47
|
+
|
48
|
+
def relative_path
|
49
|
+
raise NotImplemented
|
50
|
+
end
|
51
|
+
|
52
|
+
def headers
|
53
|
+
return @headers if @headers
|
54
|
+
|
55
|
+
response ||= request(relative_path, :method => :head)
|
56
|
+
|
57
|
+
h = {}
|
58
|
+
metadata = h[:metadata] = {}
|
59
|
+
response.to_hash.each_pair do |k,v|
|
60
|
+
if k =~ /^X-#{self.class.header_name}-Meta-?(.+)/i
|
61
|
+
k = $1
|
62
|
+
t = metadata
|
63
|
+
elsif k =~ /^X-#{self.class.header_name}-?(.+)/i
|
64
|
+
k = $1
|
65
|
+
t = h
|
66
|
+
else
|
67
|
+
t = h
|
68
|
+
end
|
69
|
+
k = k.downcase.gsub(/\W/, '_')
|
70
|
+
v = v.first if v.respond_to?(:to_ary)
|
71
|
+
t[k] = v
|
72
|
+
end
|
73
|
+
@headers = struct(h)
|
74
|
+
end
|
75
|
+
|
76
|
+
def metadata
|
77
|
+
@metadata ||= struct(headers.metadata)
|
78
|
+
end
|
79
|
+
|
80
|
+
def clear_cache
|
81
|
+
@headers = nil
|
82
|
+
@metadata = nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def exists?
|
86
|
+
request(relative_path, :method => :head) && true
|
87
|
+
rescue SwiftStorage::Errors::NotFoundError
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
91
|
+
def delete
|
92
|
+
request(relative_path, :method => :delete)
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def self.header_name
|
99
|
+
self.name.split(':').last
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def self.header_attributes(*args)
|
104
|
+
args.each do |a|
|
105
|
+
define_method(a.to_sym) do
|
106
|
+
headers[a]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.parent_node(name)
|
112
|
+
define_method(name.to_sym) do
|
113
|
+
parent
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def merge_metadata(headers, metadata)
|
118
|
+
return if metadata.nil?
|
119
|
+
metadata.each do |k,v|
|
120
|
+
sanitized_key = k.to_s.gsub(/\W/, '-')
|
121
|
+
sanitized_key = sanitized_key.split('-').reject{|o| o.nil? || o.empty?}
|
122
|
+
full_key = ['X', self.class.header_name, 'Meta'] + sanitized_key
|
123
|
+
full_key = full_key.map(&:capitalize).join('-')
|
124
|
+
headers[full_key] = v.to_s
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
H = SwiftStorage::Headers
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
|