raca 0.3.3 → 0.4.0
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 +10 -0
- data/README.markdown +16 -1
- data/lib/raca.rb +2 -0
- data/lib/raca/account.rb +50 -6
- data/lib/raca/container.rb +53 -9
- data/lib/raca/containers.rb +4 -0
- data/lib/raca/http_client.rb +5 -1
- data/lib/raca/server.rb +4 -0
- data/lib/raca/servers.rb +4 -0
- data/lib/raca/user.rb +50 -0
- data/lib/raca/users.rb +59 -0
- data/lib/raca/util.rb +2 -2
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e941f8aeb1ac9f4a298aa8bf39d9de49cfeeced0
|
4
|
+
data.tar.gz: cbbb18973fd14aed6dbf03d277229a47668a3019
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff7704021fa4e079271978663d322553e99bcfc7fad5036a5f62381c71d77150df410f42d436c700dbcf7f7f430d4ffba3f35eb606aea90895b17ccf9f4aa9c4
|
7
|
+
data.tar.gz: 07b80eb013f6e8ab98db0b502b382169746d82dd7d4d5981f1f5384a5241e36867e8e1aad4faeec2376c43a7050dfeb403cde1e22110ae7d5a3177d92cb1bc31
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
v0.4.0 (25th August 2014)
|
2
|
+
* Added Raca::Container#temp_upload_url
|
3
|
+
* Renamed Raca::Container#expiring_url to Raca::Container#temp_url
|
4
|
+
* the old method still exists for now but is deprecated
|
5
|
+
* Expand Raca::Container#metadata to include custom metadata
|
6
|
+
* Added raca::Container#set_metadata
|
7
|
+
* For non regioned APIs (like Cloud DNS) the region argument to Raca::Account#public_endpoint
|
8
|
+
can be left off
|
9
|
+
* Added read access to user accounts via Raca::Account#users
|
10
|
+
|
1
11
|
v0.3.3 (26th April 2014)
|
2
12
|
* Added a User-Agent header to all requests
|
3
13
|
* Remove automatic retries after a rackspace timeout
|
data/README.markdown
CHANGED
@@ -112,7 +112,7 @@ is the temp URL key that can be set using Raca::Containers#set_temp_url_key
|
|
112
112
|
ord_containers = account.containers(:ord)
|
113
113
|
ord_containers.set_temp_url_key("secret")
|
114
114
|
dir = ord_containers.get("container_name")
|
115
|
-
puts dir.
|
115
|
+
puts dir.temp_url("remote_key.txt", "secret", Time.now.to_i + 60)
|
116
116
|
|
117
117
|
### Cloud Servers
|
118
118
|
|
@@ -133,6 +133,21 @@ You can use the collection to create a brand new server:
|
|
133
133
|
|
134
134
|
a_server = ord_servers.create("server_name", "1Gb", "Ubuntu 10.04 LTS")
|
135
135
|
|
136
|
+
### Users
|
137
|
+
|
138
|
+
Using an existing Raca::Account object, retrieve a collection of Users like so:
|
139
|
+
|
140
|
+
users = account.users
|
141
|
+
|
142
|
+
You can retrieve an existing user from the collection:
|
143
|
+
|
144
|
+
a_user = users.get("username")
|
145
|
+
|
146
|
+
You can display details for each user with the details method:
|
147
|
+
|
148
|
+
a_user = users.get("username")
|
149
|
+
a_user.details
|
150
|
+
|
136
151
|
## General API principles
|
137
152
|
|
138
153
|
Methods that make calls to an API should never return a raw HTTP response
|
data/lib/raca.rb
CHANGED
data/lib/raca/account.rb
CHANGED
@@ -8,6 +8,7 @@ module Raca
|
|
8
8
|
# the supported rackspace APIs.
|
9
9
|
#
|
10
10
|
class Account
|
11
|
+
IDENTITY_URL = "https://identity.api.rackspacecloud.com/v2.0/"
|
11
12
|
|
12
13
|
def initialize(username, key, cache = nil)
|
13
14
|
@username, @key, @cache = username, key, cache
|
@@ -37,11 +38,28 @@ module Raca
|
|
37
38
|
# account = Raca::Account.new("username", "secret")
|
38
39
|
# puts account.public_endpoint("cloudServers", :syd)
|
39
40
|
#
|
40
|
-
|
41
|
-
|
41
|
+
# Some service APIs are not regioned. In those cases, the region code can be
|
42
|
+
# left off:
|
43
|
+
#
|
44
|
+
# account = Raca::Account.new("username", "secret")
|
45
|
+
# puts account.public_endpoint("cloudDNS")
|
46
|
+
#
|
47
|
+
def public_endpoint(service_name, region = nil)
|
48
|
+
return IDENTITY_URL if service_name == "identity"
|
49
|
+
|
42
50
|
endpoints = service_endpoints(service_name)
|
43
|
-
|
44
|
-
|
51
|
+
if endpoints.size > 1 && region
|
52
|
+
region = region.to_s.upcase
|
53
|
+
endpoints = endpoints.select { |e| e["region"] == region } || {}
|
54
|
+
elsif endpoints.size > 1 && region.nil?
|
55
|
+
raise ArgumentError, "The requested service exists in multiple regions, please specify a region code"
|
56
|
+
end
|
57
|
+
|
58
|
+
if endpoints.size == 0
|
59
|
+
raise ArgumentError, "No matching services found"
|
60
|
+
else
|
61
|
+
endpoints.first["publicURL"]
|
62
|
+
end
|
45
63
|
end
|
46
64
|
|
47
65
|
# Return the names of the available services. As rackspace add new services and
|
@@ -80,13 +98,23 @@ module Raca
|
|
80
98
|
Raca::Servers.new(self, region)
|
81
99
|
end
|
82
100
|
|
101
|
+
# Return a Raca::Users object. Use this to query and manage the users associated
|
102
|
+
# with the current account.
|
103
|
+
#
|
104
|
+
# account = Raca::Account.new("username", "secret")
|
105
|
+
# puts account.users
|
106
|
+
#
|
107
|
+
def users
|
108
|
+
Raca::Users.new(self)
|
109
|
+
end
|
110
|
+
|
83
111
|
# Raca classes use this method to occasionally re-authenticate with the rackspace
|
84
112
|
# servers. You can probably ignore it.
|
85
113
|
#
|
86
114
|
def refresh_cache
|
87
115
|
# Raca::HttpClient depends on Raca::Account, so we intentionally don't use it here
|
88
116
|
# to avoid a circular dependency
|
89
|
-
Net::HTTP.new(
|
117
|
+
Net::HTTP.new(identity_host, 443).tap {|http|
|
90
118
|
http.use_ssl = true
|
91
119
|
}.start {|http|
|
92
120
|
payload = {
|
@@ -98,7 +126,7 @@ module Raca
|
|
98
126
|
}
|
99
127
|
}
|
100
128
|
response = http.post(
|
101
|
-
|
129
|
+
tokens_path,
|
102
130
|
JSON.dump(payload),
|
103
131
|
{'Content-Type' => 'application/json'},
|
104
132
|
)
|
@@ -116,8 +144,24 @@ module Raca
|
|
116
144
|
Raca::HttpClient.new(self, hostname)
|
117
145
|
end
|
118
146
|
|
147
|
+
def inspect
|
148
|
+
"#<Raca::Account:#{__id__} username=#{@username}>"
|
149
|
+
end
|
150
|
+
|
119
151
|
private
|
120
152
|
|
153
|
+
def identity_host
|
154
|
+
URI.parse(IDENTITY_URL).host
|
155
|
+
end
|
156
|
+
|
157
|
+
def identity_path
|
158
|
+
URI.parse(IDENTITY_URL).path
|
159
|
+
end
|
160
|
+
|
161
|
+
def tokens_path
|
162
|
+
File.join(identity_path, "tokens")
|
163
|
+
end
|
164
|
+
|
121
165
|
def raise_on_error(response)
|
122
166
|
error_klass = case response.code.to_i
|
123
167
|
when 400 then BadRequestError
|
data/lib/raca/container.rb
CHANGED
@@ -90,14 +90,14 @@ module Raca
|
|
90
90
|
def download(key, filepath)
|
91
91
|
log "downloading #{key} from #{container_path}"
|
92
92
|
object_path = File.join(container_path, Raca::Util.url_encode(key))
|
93
|
-
|
93
|
+
outer_response = storage_client.get(object_path) do |response|
|
94
94
|
File.open(filepath, 'wb') do |io|
|
95
95
|
response.read_body do |chunk|
|
96
96
|
io.write(chunk)
|
97
97
|
end
|
98
98
|
end
|
99
99
|
end
|
100
|
-
|
100
|
+
outer_response["Content-Length"].to_i
|
101
101
|
end
|
102
102
|
|
103
103
|
# Return an array of files in the container.
|
@@ -151,12 +151,34 @@ module Raca
|
|
151
151
|
def metadata
|
152
152
|
log "retrieving container metadata from #{container_path}"
|
153
153
|
response = storage_client.head(container_path)
|
154
|
+
custom = {}
|
155
|
+
response.each_capitalized_name { |name|
|
156
|
+
custom[name] = response[name] if name[/\AX-Container-Meta-/]
|
157
|
+
}
|
154
158
|
{
|
155
159
|
:objects => response["X-Container-Object-Count"].to_i,
|
156
|
-
:bytes => response["X-Container-Bytes-Used"].to_i
|
160
|
+
:bytes => response["X-Container-Bytes-Used"].to_i,
|
161
|
+
:custom => custom,
|
157
162
|
}
|
158
163
|
end
|
159
164
|
|
165
|
+
# Set metadata headers on the container
|
166
|
+
#
|
167
|
+
# headers = { "X-Container-Meta-Access-Control-Allow-Origin" => "*" }
|
168
|
+
# container.set_metadata(headers)
|
169
|
+
#
|
170
|
+
# Note: Rackspace requires some headers to begin with 'X-Container-Meta-' or other prefixes, e.g. when setting
|
171
|
+
# 'Access-Control-Allow-Origin', it needs to be set as 'X-Container-Meta-Access-Control-Allow-Origin'.
|
172
|
+
# See: http://docs.rackspace.com/files/api/v1/cf-devguide/content/CORS_Container_Header-d1e1300.html
|
173
|
+
# http://docs.rackspace.com/files/api/v1/cf-devguide/content/
|
174
|
+
# POST_updateacontainermeta_v1__account___container__containerServicesOperations_d1e000.html
|
175
|
+
#
|
176
|
+
def set_metadata(headers)
|
177
|
+
log "setting headers for container #{container_path}"
|
178
|
+
response = storage_client.post(container_path, '', headers)
|
179
|
+
(200..299).cover?(response.code.to_i)
|
180
|
+
end
|
181
|
+
|
160
182
|
# Return the key details for CDN access to this container. Can be called
|
161
183
|
# on non CDN enabled containers, but the details won't make much sense.
|
162
184
|
#
|
@@ -186,13 +208,37 @@ module Raca
|
|
186
208
|
(200..299).cover?(response.code.to_i)
|
187
209
|
end
|
188
210
|
|
189
|
-
# Generate
|
190
|
-
# access to files.
|
211
|
+
# Generate an expiring URL for downloading a file that is otherwise private.
|
212
|
+
# Useful for providing temporary access to files.
|
213
|
+
#
|
214
|
+
def temp_url(object_key, temp_url_key, expires_at = Time.now.to_i + 60)
|
215
|
+
private_url("GET", object_key, temp_url_key, expires_at)
|
216
|
+
end
|
217
|
+
|
218
|
+
# DEPRECATED: use temp_url instead, this will be removed in version 1.0
|
191
219
|
#
|
192
220
|
def expiring_url(object_key, temp_url_key, expires_at = Time.now.to_i + 60)
|
193
|
-
|
221
|
+
temp_url(object_key, temp_url_key, expires_at)
|
222
|
+
end
|
223
|
+
|
224
|
+
# Generate a temporary URL for uploading a file to a private container. Anyone
|
225
|
+
# can perform a PUT request to the URL returned from this method and an object
|
226
|
+
# will be created in the container.
|
227
|
+
#
|
228
|
+
def temp_upload_url(object_key, temp_url_key, expires_at = Time.now.to_i + 60)
|
229
|
+
private_url("PUT", object_key, temp_url_key, expires_at)
|
230
|
+
end
|
231
|
+
|
232
|
+
def inspect
|
233
|
+
"#<Raca::Container:#{__id__} region=#{@region} container_name=#{@container_name}>"
|
234
|
+
end
|
235
|
+
|
236
|
+
private
|
237
|
+
|
238
|
+
def private_url(method, object_key, temp_url_key, expires_at)
|
239
|
+
raise ArgumentError, "method must be GET or PUT" unless %w{GET PUT}.include?(method)
|
240
|
+
digest = OpenSSL::Digest.new('sha1')
|
194
241
|
|
195
|
-
method = 'GET'
|
196
242
|
expires = expires_at.to_i
|
197
243
|
path = File.join(container_path, object_key)
|
198
244
|
encoded_path = File.join(container_path, Raca::Util.url_encode(object_key))
|
@@ -204,8 +250,6 @@ module Raca
|
|
204
250
|
"https://#{storage_host}#{encoded_path}?temp_url_sig=#{hmac.hexdigest}&temp_url_expires=#{expires}"
|
205
251
|
end
|
206
252
|
|
207
|
-
private
|
208
|
-
|
209
253
|
# build the request path for listing the contents of a container
|
210
254
|
#
|
211
255
|
def list_request_path(marker, prefix, details, limit)
|
data/lib/raca/containers.rb
CHANGED
data/lib/raca/http_client.rb
CHANGED
@@ -65,6 +65,10 @@ module Raca
|
|
65
65
|
cloud_request(request)
|
66
66
|
end
|
67
67
|
|
68
|
+
def inspect
|
69
|
+
"#<Raca::HttpClient:#{__id__}>"
|
70
|
+
end
|
71
|
+
|
68
72
|
private
|
69
73
|
|
70
74
|
def build_streaming_put_request(path, io, byte_count, headers)
|
@@ -91,7 +95,7 @@ module Raca
|
|
91
95
|
def cloud_request(request, &block)
|
92
96
|
cloud_http do |http|
|
93
97
|
request['X-Auth-Token'] = @account.auth_token
|
94
|
-
request['User-Agent'] = "raca 0.
|
98
|
+
request['User-Agent'] = "raca 0.4.0 (http://rubygems.org/gems/raca)"
|
95
99
|
http.request(request, &block)
|
96
100
|
end
|
97
101
|
end
|
data/lib/raca/server.rb
CHANGED
data/lib/raca/servers.rb
CHANGED
data/lib/raca/user.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Raca
|
2
|
+
# Represents a single user within the current account.
|
3
|
+
#
|
4
|
+
# You probably don't want to instantiate this directly,
|
5
|
+
# see Raca::Account#users
|
6
|
+
#
|
7
|
+
class User
|
8
|
+
attr_reader :username
|
9
|
+
|
10
|
+
def initialize(account, username, opts = {})
|
11
|
+
@account, @username = account, username
|
12
|
+
@identity_url = @account.public_endpoint("identity")
|
13
|
+
@logger = opts[:logger]
|
14
|
+
@logger ||= Rails.logger if defined?(Rails)
|
15
|
+
end
|
16
|
+
|
17
|
+
def details
|
18
|
+
response = identity_client.get(user_path)
|
19
|
+
JSON.load(response.body)["user"]
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"#<Raca::User:#{__id__} @username=#{@username}>"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def identity_host
|
29
|
+
URI.parse(@identity_url).host
|
30
|
+
end
|
31
|
+
|
32
|
+
def identity_path
|
33
|
+
URI.parse(@identity_url).path
|
34
|
+
end
|
35
|
+
|
36
|
+
def user_path
|
37
|
+
@user_path ||= File.join(identity_path, "users") + "?name=" + Raca::Util.url_encode(@username)
|
38
|
+
end
|
39
|
+
|
40
|
+
def identity_client
|
41
|
+
@identity_client ||= @account.http_client(identity_host)
|
42
|
+
end
|
43
|
+
|
44
|
+
def log(msg)
|
45
|
+
if @logger.respond_to?(:debug)
|
46
|
+
@logger.debug msg
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/raca/users.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
module Raca
|
2
|
+
# Represents a collection of users associated with a rackspace account
|
3
|
+
#
|
4
|
+
# You probably don't want to instantiate this directly,
|
5
|
+
# see Raca::Account#users
|
6
|
+
#
|
7
|
+
class Users
|
8
|
+
def initialize(account, opts = {})
|
9
|
+
@account = account
|
10
|
+
@identity_url = @account.public_endpoint("identity")
|
11
|
+
@logger = opts[:logger]
|
12
|
+
@logger ||= Rails.logger if defined?(Rails)
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(username)
|
16
|
+
list.detect { |user| user.username == username }
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
"#<Raca::Users:#{__id__}>"
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# TODO should this (or something like it) be part of the public API?
|
26
|
+
def list
|
27
|
+
log "retrieving users list from #{users_path}"
|
28
|
+
response = identity_client.get(users_path)
|
29
|
+
records = JSON.load(response.body)["users"]
|
30
|
+
records.map { |record|
|
31
|
+
record["username"]
|
32
|
+
}.map { |username|
|
33
|
+
Raca::User.new(@account, username)
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def identity_host
|
38
|
+
URI.parse(@identity_url).host
|
39
|
+
end
|
40
|
+
|
41
|
+
def identity_path
|
42
|
+
URI.parse(@identity_url).path
|
43
|
+
end
|
44
|
+
|
45
|
+
def users_path
|
46
|
+
File.join(identity_path, "users")
|
47
|
+
end
|
48
|
+
|
49
|
+
def identity_client
|
50
|
+
@identity_client ||= @account.http_client(identity_host)
|
51
|
+
end
|
52
|
+
|
53
|
+
def log(msg)
|
54
|
+
if @logger.respond_to?(:debug)
|
55
|
+
@logger.debug msg
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/raca/util.rb
CHANGED
@@ -3,8 +3,8 @@ module Raca
|
|
3
3
|
class Util
|
4
4
|
# CGI.escape, but without special treatment on spaces
|
5
5
|
def self.url_encode(str)
|
6
|
-
str.gsub(%r{([^a-zA-Z0-9_./-]
|
7
|
-
'%' + match.unpack('
|
6
|
+
str.gsub(%r{([^a-zA-Z0-9_./-])}) do |match|
|
7
|
+
'%' + match.unpack('H*').first.scan(/../).join("%").upcase
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: raca
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Healy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '3.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '3.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: webmock
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -99,6 +99,8 @@ files:
|
|
99
99
|
- lib/raca/http_client.rb
|
100
100
|
- lib/raca/server.rb
|
101
101
|
- lib/raca/servers.rb
|
102
|
+
- lib/raca/user.rb
|
103
|
+
- lib/raca/users.rb
|
102
104
|
- lib/raca/util.rb
|
103
105
|
homepage: http://github.com/conversation/raca
|
104
106
|
licenses:
|
@@ -128,3 +130,4 @@ signing_key:
|
|
128
130
|
specification_version: 4
|
129
131
|
summary: A simple wrapper for the Rackspace Cloud API with no dependencies
|
130
132
|
test_files: []
|
133
|
+
has_rdoc: true
|