fog-brightbox 0.3.0 → 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.md +8 -0
- data/lib/fog/brightbox.rb +1 -0
- data/lib/fog/brightbox/config.rb +102 -2
- data/lib/fog/brightbox/core.rb +1 -0
- data/lib/fog/brightbox/models/compute/api_client.rb +3 -1
- data/lib/fog/brightbox/models/storage/directories.rb +45 -0
- data/lib/fog/brightbox/models/storage/directory.rb +53 -0
- data/lib/fog/brightbox/models/storage/file.rb +166 -0
- data/lib/fog/brightbox/models/storage/files.rb +104 -0
- data/lib/fog/brightbox/oauth2.rb +140 -136
- data/lib/fog/brightbox/requests/storage/copy_object.rb +27 -0
- data/lib/fog/brightbox/requests/storage/delete_container.rb +22 -0
- data/lib/fog/brightbox/requests/storage/delete_multiple_objects.rb +67 -0
- data/lib/fog/brightbox/requests/storage/delete_object.rb +23 -0
- data/lib/fog/brightbox/requests/storage/delete_static_large_object.rb +43 -0
- data/lib/fog/brightbox/requests/storage/get_container.rb +44 -0
- data/lib/fog/brightbox/requests/storage/get_containers.rb +33 -0
- data/lib/fog/brightbox/requests/storage/get_object.rb +29 -0
- data/lib/fog/brightbox/requests/storage/get_object_http_url.rb +21 -0
- data/lib/fog/brightbox/requests/storage/get_object_https_url.rb +85 -0
- data/lib/fog/brightbox/requests/storage/head_container.rb +28 -0
- data/lib/fog/brightbox/requests/storage/head_containers.rb +25 -0
- data/lib/fog/brightbox/requests/storage/head_object.rb +23 -0
- data/lib/fog/brightbox/requests/storage/post_set_meta_temp_url_key.rb +37 -0
- data/lib/fog/brightbox/requests/storage/put_container.rb +27 -0
- data/lib/fog/brightbox/requests/storage/put_dynamic_obj_manifest.rb +43 -0
- data/lib/fog/brightbox/requests/storage/put_object.rb +42 -0
- data/lib/fog/brightbox/requests/storage/put_object_manifest.rb +16 -0
- data/lib/fog/brightbox/requests/storage/put_static_obj_manifest.rb +57 -0
- data/lib/fog/brightbox/storage.rb +166 -0
- data/lib/fog/brightbox/storage/authentication_request.rb +52 -0
- data/lib/fog/brightbox/storage/config.rb +23 -0
- data/lib/fog/brightbox/storage/connection.rb +83 -0
- data/lib/fog/brightbox/storage/errors.rb +11 -0
- data/lib/fog/brightbox/version.rb +1 -1
- data/spec/fog/brightbox/config_spec.rb +62 -1
- data/spec/fog/brightbox/storage/authentication_request_spec.rb +77 -0
- data/spec/fog/brightbox/storage/config_spec.rb +40 -0
- data/spec/fog/brightbox/storage/connection_errors_spec.rb +54 -0
- data/spec/fog/brightbox/storage/connection_spec.rb +120 -0
- data/spec/fog/storage/brightbox_spec.rb +290 -0
- metadata +40 -3
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'fog/core/collection'
|
2
|
+
require 'fog/brightbox/models/storage/file'
|
3
|
+
|
4
|
+
module Fog
|
5
|
+
module Storage
|
6
|
+
class Brightbox
|
7
|
+
|
8
|
+
class Files < Fog::Collection
|
9
|
+
|
10
|
+
attribute :directory
|
11
|
+
attribute :limit
|
12
|
+
attribute :marker
|
13
|
+
attribute :path
|
14
|
+
attribute :prefix
|
15
|
+
|
16
|
+
model Fog::Storage::Brightbox::File
|
17
|
+
|
18
|
+
def all(options = {})
|
19
|
+
requires :directory
|
20
|
+
options = {
|
21
|
+
'limit' => limit,
|
22
|
+
'marker' => marker,
|
23
|
+
'path' => path,
|
24
|
+
'prefix' => prefix
|
25
|
+
}.merge!(options)
|
26
|
+
merge_attributes(options)
|
27
|
+
parent = directory.collection.get(
|
28
|
+
directory.key,
|
29
|
+
options
|
30
|
+
)
|
31
|
+
if parent
|
32
|
+
load(parent.files.map {|file| file.attributes})
|
33
|
+
else
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
alias :each_file_this_page :each
|
39
|
+
def each
|
40
|
+
if !block_given?
|
41
|
+
self
|
42
|
+
else
|
43
|
+
subset = dup.all
|
44
|
+
|
45
|
+
subset.each_file_this_page {|f| yield f}
|
46
|
+
while subset.length == (subset.limit || 10000)
|
47
|
+
subset = subset.all(:marker => subset.last.key)
|
48
|
+
subset.each_file_this_page {|f| yield f}
|
49
|
+
end
|
50
|
+
|
51
|
+
self
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def get(key, &block)
|
56
|
+
requires :directory
|
57
|
+
data = service.get_object(directory.key, key, &block)
|
58
|
+
file_data = data.headers.merge({
|
59
|
+
:body => data.body,
|
60
|
+
:key => key
|
61
|
+
})
|
62
|
+
new(file_data)
|
63
|
+
rescue Fog::Storage::Brightbox::NotFound
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_url(key)
|
68
|
+
requires :directory
|
69
|
+
if self.directory.public_url
|
70
|
+
"#{self.directory.public_url}/#{Fog::Storage::Brightbox.escape(key, '/')}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_http_url(key, expires, options = {})
|
75
|
+
requires :directory
|
76
|
+
service.get_object_http_url(directory.key, key, expires, options)
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_https_url(key, expires, options = {})
|
80
|
+
requires :directory
|
81
|
+
service.get_object_https_url(directory.key, key, expires, options)
|
82
|
+
end
|
83
|
+
|
84
|
+
def head(key, options = {})
|
85
|
+
requires :directory
|
86
|
+
data = service.head_object(directory.key, key)
|
87
|
+
file_data = data.headers.merge({
|
88
|
+
:key => key
|
89
|
+
})
|
90
|
+
new(file_data)
|
91
|
+
rescue Fog::Storage::Brightbox::NotFound
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def new(attributes = {})
|
96
|
+
requires :directory
|
97
|
+
super({ :directory => directory }.merge!(attributes))
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/fog/brightbox/oauth2.rb
CHANGED
@@ -3,164 +3,168 @@
|
|
3
3
|
#
|
4
4
|
# @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10
|
5
5
|
#
|
6
|
-
module Fog
|
7
|
-
|
8
|
-
|
9
|
-
# based on the arguments passed in
|
10
|
-
#
|
11
|
-
# @param [Fog::Core::Connection] connection
|
12
|
-
# @param [CredentialSet] credentials
|
13
|
-
#
|
14
|
-
# @return [Excon::Response]
|
15
|
-
def request_access_token(connection, credentials)
|
16
|
-
token_strategy = credentials.best_grant_strategy
|
17
|
-
|
18
|
-
header_content = "#{credentials.client_id}:#{credentials.client_secret}"
|
19
|
-
encoded_credentials = Base64.encode64(header_content).chomp
|
20
|
-
|
21
|
-
connection.request(
|
22
|
-
:path => "/token",
|
23
|
-
:expects => 200,
|
24
|
-
:headers => {
|
25
|
-
'Authorization' => "Basic #{encoded_credentials}",
|
26
|
-
'Content-Type' => 'application/json'
|
27
|
-
},
|
28
|
-
:method => 'POST',
|
29
|
-
:body => Fog::JSON.encode(token_strategy.authorization_body_data)
|
30
|
-
)
|
31
|
-
end
|
6
|
+
module Fog
|
7
|
+
module Brightbox
|
8
|
+
module OAuth2
|
32
9
|
|
33
|
-
|
34
|
-
|
35
|
-
#
|
36
|
-
# @todo Interface to update certain credentials (after password change)
|
37
|
-
#
|
38
|
-
class CredentialSet
|
39
|
-
attr_reader :client_id, :client_secret, :username, :password
|
40
|
-
attr_reader :access_token, :refresh_token, :expires_in
|
10
|
+
# This builds the simplest form of requesting an access token
|
11
|
+
# based on the arguments passed in
|
41
12
|
#
|
42
|
-
# @param [
|
43
|
-
# @param [
|
44
|
-
# @param [Hash] options
|
45
|
-
# @option options [String] :username
|
46
|
-
# @option options [String] :password
|
13
|
+
# @param [Fog::Core::Connection] connection
|
14
|
+
# @param [CredentialSet] credentials
|
47
15
|
#
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
16
|
+
# @return [Excon::Response]
|
17
|
+
def request_access_token(connection, credentials)
|
18
|
+
token_strategy = credentials.best_grant_strategy
|
19
|
+
|
20
|
+
header_content = "#{credentials.client_id}:#{credentials.client_secret}"
|
21
|
+
encoded_credentials = Base64.encode64(header_content).chomp
|
22
|
+
|
23
|
+
connection.request(
|
24
|
+
:path => "/token",
|
25
|
+
:expects => 200,
|
26
|
+
:headers => {
|
27
|
+
'Authorization' => "Basic #{encoded_credentials}",
|
28
|
+
'Content-Type' => 'application/json'
|
29
|
+
},
|
30
|
+
:method => 'POST',
|
31
|
+
:body => Fog::JSON.encode(token_strategy.authorization_body_data)
|
32
|
+
)
|
56
33
|
end
|
57
34
|
|
58
|
-
#
|
59
|
-
#
|
60
|
-
|
61
|
-
|
62
|
-
|
35
|
+
# Encapsulates credentials required to request access tokens from the
|
36
|
+
# Brightbox authorisation servers
|
37
|
+
#
|
38
|
+
# @todo Interface to update certain credentials (after password change)
|
39
|
+
#
|
40
|
+
class CredentialSet
|
41
|
+
attr_reader :client_id, :client_secret, :username, :password
|
42
|
+
attr_reader :access_token, :refresh_token, :expires_in
|
43
|
+
#
|
44
|
+
# @param [String] client_id
|
45
|
+
# @param [String] client_secret
|
46
|
+
# @param [Hash] options
|
47
|
+
# @option options [String] :username
|
48
|
+
# @option options [String] :password
|
49
|
+
#
|
50
|
+
def initialize(client_id, client_secret, options = {})
|
51
|
+
@client_id = client_id
|
52
|
+
@client_secret = client_secret
|
53
|
+
@username = options[:username]
|
54
|
+
@password = options[:password]
|
55
|
+
@access_token = options[:access_token]
|
56
|
+
@refresh_token = options[:refresh_token]
|
57
|
+
@expires_in = options[:expires_in]
|
58
|
+
end
|
63
59
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
60
|
+
# Returns true if user details are available
|
61
|
+
# @return [Boolean]
|
62
|
+
def user_details?
|
63
|
+
!!(@username && @password)
|
64
|
+
end
|
68
65
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
66
|
+
# Is an access token available for these credentials?
|
67
|
+
def access_token?
|
68
|
+
!!@access_token
|
69
|
+
end
|
73
70
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
71
|
+
# Is a refresh token available for these credentials?
|
72
|
+
def refresh_token?
|
73
|
+
!!@refresh_token
|
74
|
+
end
|
75
|
+
|
76
|
+
# Updates the credentials with newer tokens
|
77
|
+
def update_tokens(access_token, refresh_token = nil, expires_in = nil)
|
78
|
+
@access_token = access_token
|
79
|
+
@refresh_token = refresh_token
|
80
|
+
@expires_in = expires_in
|
81
|
+
end
|
82
|
+
|
83
|
+
# Based on available credentials returns the best strategy
|
84
|
+
#
|
85
|
+
# @todo Add a means to dictate which should or shouldn't be used
|
86
|
+
#
|
87
|
+
def best_grant_strategy
|
88
|
+
if refresh_token?
|
89
|
+
RefreshTokenStrategy.new(self)
|
90
|
+
elsif user_details?
|
91
|
+
UserCredentialsStrategy.new(self)
|
92
|
+
else
|
93
|
+
ClientCredentialsStrategy.new(self)
|
94
|
+
end
|
95
|
+
end
|
79
96
|
end
|
80
97
|
|
81
|
-
#
|
98
|
+
# This strategy class is the basis for OAuth2 grant types
|
99
|
+
#
|
100
|
+
# @abstract Need to implement {#authorization_body_data} to return a
|
101
|
+
# Hash matching the expected parameter form for the OAuth request
|
82
102
|
#
|
83
|
-
# @todo
|
103
|
+
# @todo Strategies should be able to validate if credentials are suitable
|
104
|
+
# so just client credentials cannot be used with user strategies
|
84
105
|
#
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
elsif user_details?
|
89
|
-
UserCredentialsStrategy.new(self)
|
90
|
-
else
|
91
|
-
ClientCredentialsStrategy.new(self)
|
106
|
+
class GrantTypeStrategy
|
107
|
+
def initialize(credentials)
|
108
|
+
@credentials = credentials
|
92
109
|
end
|
93
|
-
end
|
94
|
-
end
|
95
110
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
# Hash matching the expected parameter form for the OAuth request
|
100
|
-
#
|
101
|
-
# @todo Strategies should be able to validate if credentials are suitable
|
102
|
-
# so just client credentials cannot be used with user strategies
|
103
|
-
#
|
104
|
-
class GrantTypeStrategy
|
105
|
-
def initialize(credentials)
|
106
|
-
@credentials = credentials
|
111
|
+
def authorization_body_data
|
112
|
+
raise "Not implemented"
|
113
|
+
end
|
107
114
|
end
|
108
115
|
|
109
|
-
|
110
|
-
|
116
|
+
# This implements client based authentication/authorization
|
117
|
+
# based on the existing trust relationship using the `none`
|
118
|
+
# grant type.
|
119
|
+
#
|
120
|
+
class ClientCredentialsStrategy < GrantTypeStrategy
|
121
|
+
def authorization_body_data
|
122
|
+
{
|
123
|
+
"grant_type" => "none",
|
124
|
+
"client_id" => @credentials.client_id
|
125
|
+
}
|
126
|
+
end
|
111
127
|
end
|
112
|
-
end
|
113
128
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
129
|
+
# This passes user details through so the returned token
|
130
|
+
# carries the privileges of the user not account limited
|
131
|
+
# by the client
|
132
|
+
#
|
133
|
+
class UserCredentialsStrategy < GrantTypeStrategy
|
134
|
+
def authorization_body_data
|
135
|
+
{
|
136
|
+
"grant_type" => "password",
|
137
|
+
"client_id" => @credentials.client_id,
|
138
|
+
"username" => @credentials.username,
|
139
|
+
"password" => @credentials.password
|
140
|
+
}
|
141
|
+
end
|
124
142
|
end
|
125
|
-
end
|
126
143
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
}
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
# This strategy attempts to use a refresh_token gained during an earlier
|
143
|
-
# request to reuse the credentials given originally
|
144
|
-
#
|
145
|
-
class RefreshTokenStrategy < GrantTypeStrategy
|
146
|
-
def authorization_body_data
|
147
|
-
{
|
148
|
-
"grant_type" => "refresh_token",
|
149
|
-
"client_id" => @credentials.client_id,
|
150
|
-
"refresh_token" => @credentials.refresh_token
|
151
|
-
}
|
144
|
+
# This strategy attempts to use a refresh_token gained during an earlier
|
145
|
+
# request to reuse the credentials given originally
|
146
|
+
#
|
147
|
+
class RefreshTokenStrategy < GrantTypeStrategy
|
148
|
+
def authorization_body_data
|
149
|
+
{
|
150
|
+
"grant_type" => "refresh_token",
|
151
|
+
"client_id" => @credentials.client_id,
|
152
|
+
"refresh_token" => @credentials.refresh_token
|
153
|
+
}
|
154
|
+
end
|
152
155
|
end
|
153
|
-
end
|
154
156
|
|
155
|
-
|
157
|
+
private
|
156
158
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
159
|
+
# This updates the current credentials if passed a valid response
|
160
|
+
#
|
161
|
+
# @param [CredentialSet] credentials Credentials to update
|
162
|
+
# @param [Excon::Response] response Response object to parse value from
|
163
|
+
#
|
164
|
+
def update_credentials_from_response(credentials, response)
|
165
|
+
response_data = Fog::JSON.decode(response.body)
|
166
|
+
credentials.update_tokens(response_data["access_token"], response_data["refresh_token"], response_data["expires_in"])
|
167
|
+
end
|
165
168
|
end
|
166
169
|
end
|
170
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Fog
|
2
|
+
module Storage
|
3
|
+
class Brightbox
|
4
|
+
class Real
|
5
|
+
|
6
|
+
# Copy object
|
7
|
+
#
|
8
|
+
# ==== Parameters
|
9
|
+
# * source_container_name<~String> - Name of source bucket
|
10
|
+
# * source_object_name<~String> - Name of source object
|
11
|
+
# * target_container_name<~String> - Name of bucket to create copy in
|
12
|
+
# * target_object_name<~String> - Name for new copy of object
|
13
|
+
# * options<~Hash> - Additional headers
|
14
|
+
def copy_object(source_container_name, source_object_name, target_container_name, target_object_name, options={})
|
15
|
+
headers = { 'X-Copy-From' => "/#{source_container_name}/#{source_object_name}" }.merge(options)
|
16
|
+
request({
|
17
|
+
:expects => 201,
|
18
|
+
:headers => headers,
|
19
|
+
:method => 'PUT',
|
20
|
+
:path => "#{Fog::Storage::Brightbox.escape(target_container_name)}/#{Fog::Storage::Brightbox.escape(target_object_name)}"
|
21
|
+
})
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Fog
|
2
|
+
module Storage
|
3
|
+
class Brightbox
|
4
|
+
class Real
|
5
|
+
|
6
|
+
# Delete an existing container
|
7
|
+
#
|
8
|
+
# ==== Parameters
|
9
|
+
# * name<~String> - Name of container to delete
|
10
|
+
#
|
11
|
+
def delete_container(name)
|
12
|
+
request(
|
13
|
+
:expects => 204,
|
14
|
+
:method => 'DELETE',
|
15
|
+
:path => Fog::Storage::Brightbox.escape(name)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|