fog-softlayer 0.0.5 → 0.0.7
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 +8 -8
- data/.travis.yml +37 -0
- data/CONTRIBUTING.md +30 -0
- data/README.md +8 -5
- data/docs/cla-corporate.md +133 -0
- data/docs/cla-individual.md +84 -0
- data/docs/fog-softlayer-CCLA.pdf +0 -0
- data/docs/fog-softlayer-CLA.pdf +0 -0
- data/examples/storage.md +107 -0
- data/fog-softlayer.gemspec +1 -0
- data/gemfiles/Gemfile-edge +14 -0
- data/gemfiles/Gemfile-ruby-1.8.7 +14 -0
- data/lib/fog/softlayer.rb +1 -0
- data/lib/fog/softlayer/compute.rb +1 -1
- data/lib/fog/softlayer/compute/shared.rb +1 -1
- data/lib/fog/softlayer/core.rb +17 -1
- data/lib/fog/softlayer/models/storage/directories.rb +40 -0
- data/lib/fog/softlayer/models/storage/directory.rb +50 -0
- data/lib/fog/softlayer/models/storage/file.rb +166 -0
- data/lib/fog/softlayer/models/storage/files.rb +99 -0
- data/lib/fog/softlayer/requests/storage/copy_object.rb +42 -0
- data/lib/fog/softlayer/requests/storage/delete_container.rb +38 -0
- data/lib/fog/softlayer/requests/storage/delete_multiple_objects.rb +67 -0
- data/lib/fog/softlayer/requests/storage/delete_object.rb +40 -0
- data/lib/fog/softlayer/requests/storage/delete_static_large_object.rb +43 -0
- data/lib/fog/softlayer/requests/storage/get_container.rb +68 -0
- data/lib/fog/softlayer/requests/storage/get_containers.rb +51 -0
- data/lib/fog/softlayer/requests/storage/get_object.rb +45 -0
- data/lib/fog/softlayer/requests/storage/get_object_https_url.rb +88 -0
- data/lib/fog/softlayer/requests/storage/head_container.rb +28 -0
- data/lib/fog/softlayer/requests/storage/head_containers.rb +25 -0
- data/lib/fog/softlayer/requests/storage/head_object.rb +23 -0
- data/lib/fog/softlayer/requests/storage/post_set_meta_temp_url_key.rb +37 -0
- data/lib/fog/softlayer/requests/storage/put_container.rb +32 -0
- data/lib/fog/softlayer/requests/storage/put_dynamic_obj_manifest.rb +43 -0
- data/lib/fog/softlayer/requests/storage/put_object.rb +61 -0
- data/lib/fog/softlayer/requests/storage/put_object_manifest.rb +16 -0
- data/lib/fog/softlayer/requests/storage/put_static_obj_manifest.rb +57 -0
- data/lib/fog/softlayer/storage.rb +283 -0
- data/lib/fog/softlayer/version.rb +1 -1
- data/tests/helper.rb +0 -29
- data/tests/helpers/mock_helper.rb +4 -98
- data/tests/softlayer/models/storage/directory_tests.rb +49 -0
- data/tests/softlayer/models/storage/file_tests.rb +56 -0
- data/tests/softlayer/requests/storage/auth_tests.rb +17 -0
- data/tests/softlayer/requests/storage/container_tests.rb +52 -0
- data/tests/softlayer/requests/storage/object_tests.rb +68 -0
- metadata +53 -2
@@ -0,0 +1,28 @@
|
|
1
|
+
module Fog
|
2
|
+
module Storage
|
3
|
+
class Softlayer
|
4
|
+
class Real
|
5
|
+
|
6
|
+
# List number of objects and total bytes stored
|
7
|
+
#
|
8
|
+
# ==== Parameters
|
9
|
+
# * container<~String> - Name of container to retrieve info for
|
10
|
+
#
|
11
|
+
# ==== Returns
|
12
|
+
# * response<~Excon::Response>:
|
13
|
+
# * headers<~Hash>:
|
14
|
+
# * 'X-Container-Object-Count'<~String> - Count of containers
|
15
|
+
# * 'X-Container-Bytes-Used'<~String> - Bytes used
|
16
|
+
def head_container(container)
|
17
|
+
request(
|
18
|
+
:expects => 204,
|
19
|
+
:method => 'HEAD',
|
20
|
+
:path => Fog::Softlayer.escape(container),
|
21
|
+
:query => {'format' => 'json'}
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Fog
|
2
|
+
module Storage
|
3
|
+
class Softlayer
|
4
|
+
class Real
|
5
|
+
|
6
|
+
# List number of containers and total bytes stored
|
7
|
+
#
|
8
|
+
# ==== Returns
|
9
|
+
# * response<~Excon::Response>:
|
10
|
+
# * headers<~Hash>:
|
11
|
+
# * 'X-Account-Container-Count'<~String> - Count of containers
|
12
|
+
# * 'X-Account-Bytes-Used'<~String> - Bytes used
|
13
|
+
def head_containers
|
14
|
+
request(
|
15
|
+
:expects => 204,
|
16
|
+
:method => 'HEAD',
|
17
|
+
:path => '',
|
18
|
+
:query => {'format' => 'json'}
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Fog
|
2
|
+
module Storage
|
3
|
+
class Softlayer
|
4
|
+
class Real
|
5
|
+
|
6
|
+
# Get headers for object
|
7
|
+
#
|
8
|
+
# ==== Parameters
|
9
|
+
# * container<~String> - Name of container to look in
|
10
|
+
# * object<~String> - Name of object to look for
|
11
|
+
#
|
12
|
+
def head_object(container, object)
|
13
|
+
request({
|
14
|
+
:expects => 200,
|
15
|
+
:method => 'HEAD',
|
16
|
+
:path => "#{Fog::Softlayer.escape(container)}/#{Fog::Softlayer.escape(object)}"
|
17
|
+
}, false)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Fog
|
2
|
+
module Storage
|
3
|
+
class Softlayer
|
4
|
+
|
5
|
+
class Real
|
6
|
+
|
7
|
+
# Set the account wide Temp URL Key. This is a secret key that's
|
8
|
+
# used to generate signed expiring URLs.
|
9
|
+
#
|
10
|
+
# Once the key has been set with this request you should create new
|
11
|
+
# Storage objects with the :temp_url_key option then use
|
12
|
+
# the get_object_https_url method to generate expiring URLs.
|
13
|
+
#
|
14
|
+
# *** CAUTION *** changing this secret key will invalidate any expiring
|
15
|
+
# URLS generated with old keys.
|
16
|
+
#
|
17
|
+
# ==== Parameters
|
18
|
+
# * key<~String> - The new Temp URL Key
|
19
|
+
#
|
20
|
+
# ==== Returns
|
21
|
+
# * response<~Excon::Response>
|
22
|
+
#
|
23
|
+
# ==== See Also
|
24
|
+
# http://docs.rackspace.com/files/api/v1/cf-devguide/content/Set_Account_Metadata-d1a4460.html
|
25
|
+
def post_set_meta_temp_url_key(key)
|
26
|
+
request(
|
27
|
+
:expects => [201, 202, 204],
|
28
|
+
:method => 'POST',
|
29
|
+
:headers => {'X-Account-Meta-Temp-Url-Key' => key}
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Fog
|
2
|
+
module Storage
|
3
|
+
class Softlayer
|
4
|
+
class Mock
|
5
|
+
def put_container(name)
|
6
|
+
@containers[name] = {} unless @containers[name]
|
7
|
+
response = Excon::Response.new
|
8
|
+
response.body = ''
|
9
|
+
response.status = 201
|
10
|
+
response
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Real
|
15
|
+
|
16
|
+
# Create a new container
|
17
|
+
#
|
18
|
+
# ==== Parameters
|
19
|
+
# * name<~String> - Name for container, should be < 256 bytes and must not contain '/'
|
20
|
+
#
|
21
|
+
def put_container(name)
|
22
|
+
request(
|
23
|
+
:expects => [201, 202],
|
24
|
+
:method => 'PUT',
|
25
|
+
:path => Fog::Softlayer.escape(name)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Fog
|
2
|
+
module Storage
|
3
|
+
class Softlayer
|
4
|
+
class Real
|
5
|
+
|
6
|
+
# Create a new dynamic large object manifest
|
7
|
+
#
|
8
|
+
# Creates an object with a +X-Object-Manifest+ header that specifies the common prefix ("<container>/<prefix>")
|
9
|
+
# for all uploaded segments. Retrieving the manifest object streams all segments matching this prefix.
|
10
|
+
# Segments must sort in the order they should be concatenated. Note that any future objects stored in the container
|
11
|
+
# along with the segments that match the prefix will be included when retrieving the manifest object.
|
12
|
+
#
|
13
|
+
# All segments must be stored in the same container, but may be in a different container than the manifest object.
|
14
|
+
# The default +X-Object-Manifest+ header is set to "+container+/+object+", but may be overridden in +options+
|
15
|
+
# to specify the prefix and/or the container where segments were stored.
|
16
|
+
# If overridden, names should be CGI escaped (excluding spaces) if needed (see {Fog::Softlayer.escape}).
|
17
|
+
#
|
18
|
+
# @param container [String] Name for container where +object+ will be stored. Should be < 256 bytes and must not contain '/'
|
19
|
+
# @param object [String] Name for manifest object.
|
20
|
+
# @param options [Hash] Config headers for +object+.
|
21
|
+
# @option options [String] 'X-Object-Manifest' ("container/object") "<container>/<prefix>" for segment objects.
|
22
|
+
#
|
23
|
+
# @raise [Fog::Storage::Softlayer::NotFound] HTTP 404
|
24
|
+
# @raise [Excon::Errors::BadRequest] HTTP 400
|
25
|
+
# @raise [Excon::Errors::Unauthorized] HTTP 401
|
26
|
+
# @raise [Excon::Errors::HTTPStatusError]
|
27
|
+
#
|
28
|
+
# @see http://docs.openstack.org/api/openstack-object-storage/1.0/content/dynamic-large-object-creation.html
|
29
|
+
def put_dynamic_obj_manifest(container, object, options = {})
|
30
|
+
path = "#{Fog::Softlayer.escape(container)}/#{Fog::Softlayer.escape(object)}"
|
31
|
+
headers = {'X-Object-Manifest' => path}.merge(options)
|
32
|
+
request(
|
33
|
+
:expects => 201,
|
34
|
+
:headers => headers,
|
35
|
+
:method => 'PUT',
|
36
|
+
:path => path
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Fog
|
2
|
+
module Storage
|
3
|
+
class Softlayer
|
4
|
+
class Mock
|
5
|
+
def put_object(container, object, data, options = {}, &block)
|
6
|
+
if @containers[container]
|
7
|
+
@containers[container][object] = data
|
8
|
+
response = Excon::Response.new
|
9
|
+
response.body = ''
|
10
|
+
response.status = 201
|
11
|
+
response.headers = {"Last-Modified"=>Time.now, "Content-Length"=>0}
|
12
|
+
response
|
13
|
+
else
|
14
|
+
response = Excon::Response.new
|
15
|
+
response.body = '<html><h1>Not Found</h1><p>The resource could not be found.</p></html>'
|
16
|
+
response.status = 404
|
17
|
+
response.headers = {"Content-Length"=>"70", "Content-Type"=>"text/html; charset=UTF-8", "X-Trans-Id"=>"abcdefghijklmnopqrstuvwx-0123456789", "Date"=>Time.now}
|
18
|
+
response
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Real
|
24
|
+
|
25
|
+
# Create a new object
|
26
|
+
#
|
27
|
+
# When passed a block, it will make a chunked request, calling
|
28
|
+
# the block for chunks until it returns an empty string.
|
29
|
+
# In this case the data parameter is ignored.
|
30
|
+
#
|
31
|
+
# ==== Parameters
|
32
|
+
# * container<~String> - Name for container, should be < 256 bytes and must not contain '/'
|
33
|
+
# * object<~String> - Name for object
|
34
|
+
# * data<~String|File> - data to upload
|
35
|
+
# * options<~Hash> - config headers for object. Defaults to {}.
|
36
|
+
# * block<~Proc> - chunker
|
37
|
+
#
|
38
|
+
def put_object(container, object, data, options = {}, &block)
|
39
|
+
if block_given?
|
40
|
+
params = { :request_block => block }
|
41
|
+
headers = options
|
42
|
+
else
|
43
|
+
data = Fog::Storage.parse_data(data)
|
44
|
+
headers = data[:headers].merge!(options)
|
45
|
+
params = { :body => data[:body] }
|
46
|
+
end
|
47
|
+
|
48
|
+
params.merge!(
|
49
|
+
:expects => 201,
|
50
|
+
:idempotent => !params[:request_block],
|
51
|
+
:headers => headers,
|
52
|
+
:method => 'PUT',
|
53
|
+
:path => "#{Fog::Softlayer.escape(container)}/#{Fog::Softlayer.escape(object)}"
|
54
|
+
)
|
55
|
+
|
56
|
+
request(params)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Fog
|
2
|
+
module Storage
|
3
|
+
class Softlayer
|
4
|
+
class Real
|
5
|
+
|
6
|
+
# Create a new dynamic large object manifest
|
7
|
+
#
|
8
|
+
# This is an alias for {#put_dynamic_obj_manifest} for backward compatibility.
|
9
|
+
def put_object_manifest(container, object, options = {})
|
10
|
+
put_dynamic_obj_manifest(container, object, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Fog
|
2
|
+
module Storage
|
3
|
+
class Softlayer
|
4
|
+
class Real
|
5
|
+
|
6
|
+
# Create a new static large object manifest.
|
7
|
+
#
|
8
|
+
# A static large object is similar to a dynamic large object. Whereas a GET for a dynamic large object manifest
|
9
|
+
# will stream segments based on the manifest's +X-Object-Manifest+ object name prefix, a static large object
|
10
|
+
# manifest streams segments which are defined by the user within the manifest. Information about each segment is
|
11
|
+
# provided in +segments+ as an Array of Hash objects, ordered in the sequence which the segments should be streamed.
|
12
|
+
#
|
13
|
+
# When the SLO manifest is received, each segment's +etag+ and +size_bytes+ will be verified.
|
14
|
+
# The +etag+ for each segment is returned in the response to {#put_object}, but may also be calculated.
|
15
|
+
# e.g. +Digest::MD5.hexdigest(segment_data)+
|
16
|
+
#
|
17
|
+
# The maximum number of segments for a static large object is 1000, and all segments (except the last) must be
|
18
|
+
# at least 1 MiB in size. Unlike a dynamic large object, segments are not required to be in the same container.
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# segments = [
|
22
|
+
# { :path => 'segments_container/first_segment',
|
23
|
+
# :etag => 'md5 for first_segment',
|
24
|
+
# :size_bytes => 'byte size of first_segment' },
|
25
|
+
# { :path => 'segments_container/second_segment',
|
26
|
+
# :etag => 'md5 for second_segment',
|
27
|
+
# :size_bytes => 'byte size of second_segment' }
|
28
|
+
# ]
|
29
|
+
# put_static_obj_manifest('my_container', 'my_large_object', segments)
|
30
|
+
#
|
31
|
+
# @param container [String] Name for container where +object+ will be stored.
|
32
|
+
# Should be < 256 bytes and must not contain '/'
|
33
|
+
# @param object [String] Name for manifest object.
|
34
|
+
# @param segments [Array<Hash>] Segment data for the object.
|
35
|
+
# @param options [Hash] Config headers for +object+.
|
36
|
+
#
|
37
|
+
# @raise [Fog::Storage::Softlayer::NotFound] HTTP 404
|
38
|
+
# @raise [Excon::Errors::BadRequest] HTTP 400
|
39
|
+
# @raise [Excon::Errors::Unauthorized] HTTP 401
|
40
|
+
# @raise [Excon::Errors::HTTPStatusError]
|
41
|
+
#
|
42
|
+
# @see http://docs.openstack.org/api/openstack-object-storage/1.0/content/static-large-objects.html
|
43
|
+
def put_static_obj_manifest(container, object, segments, options = {})
|
44
|
+
request(
|
45
|
+
:expects => 201,
|
46
|
+
:method => 'PUT',
|
47
|
+
:headers => options,
|
48
|
+
:body => Fog::JSON.encode(segments),
|
49
|
+
:path => "#{Fog::Softlayer.escape(container)}/#{Fog::Softlayer.escape(object)}",
|
50
|
+
:query => { 'multipart-manifest' => 'put' }
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,283 @@
|
|
1
|
+
require 'fog/softlayer/core'
|
2
|
+
|
3
|
+
module Fog
|
4
|
+
module Storage
|
5
|
+
class Softlayer < Fog::Service
|
6
|
+
requires :softlayer_username, :softlayer_api_key, :softlayer_cluster
|
7
|
+
recognizes :persistent, :softlayer_storage_account, :softlayer_temp_url_key
|
8
|
+
|
9
|
+
model_path 'fog/softlayer/models/storage'
|
10
|
+
model :directory
|
11
|
+
collection :directories
|
12
|
+
model :file
|
13
|
+
collection :files
|
14
|
+
|
15
|
+
request_path 'fog/softlayer/requests/storage'
|
16
|
+
request :copy_object
|
17
|
+
request :delete_container
|
18
|
+
request :delete_object
|
19
|
+
request :delete_multiple_objects
|
20
|
+
request :delete_static_large_object
|
21
|
+
request :get_container
|
22
|
+
request :get_containers
|
23
|
+
request :get_object
|
24
|
+
request :get_object_https_url
|
25
|
+
request :head_container
|
26
|
+
request :head_containers
|
27
|
+
request :head_object
|
28
|
+
request :put_container
|
29
|
+
request :put_object
|
30
|
+
request :put_object_manifest
|
31
|
+
request :put_dynamic_obj_manifest
|
32
|
+
request :put_static_obj_manifest
|
33
|
+
request :post_set_meta_temp_url_key
|
34
|
+
|
35
|
+
class Mock
|
36
|
+
|
37
|
+
def self.data
|
38
|
+
@data ||= Hash.new do |hash, key|
|
39
|
+
hash[key] = {}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.reset
|
44
|
+
@data = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(options={})
|
48
|
+
@softlayer_api_key = options[:softlayer_api_key]
|
49
|
+
@softlayer_username = options[:softlayer_username]
|
50
|
+
@path = '/v1/AUTH_1234'
|
51
|
+
@containers = {}
|
52
|
+
end
|
53
|
+
|
54
|
+
def data
|
55
|
+
self.class.data[@softlayer_username]
|
56
|
+
end
|
57
|
+
|
58
|
+
def reset_data
|
59
|
+
self.class.data.delete(@softlayer_username)
|
60
|
+
end
|
61
|
+
|
62
|
+
def change_account(account)
|
63
|
+
@original_path ||= @path
|
64
|
+
version_string = @original_path.split('/')[1]
|
65
|
+
@path = "/#{version_string}/#{account}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def reset_account_name
|
69
|
+
@path = @original_path
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
class Real
|
75
|
+
attr_reader :auth_url
|
76
|
+
attr_accessor :auth_token, :auth_expires
|
77
|
+
|
78
|
+
def initialize(options={})
|
79
|
+
@api_key = options[:softlayer_api_key]
|
80
|
+
@username = options[:softlayer_username]
|
81
|
+
@cluster = options[:softlayer_cluster]
|
82
|
+
@storage_account = options[:softlayer_storage_account] || default_storage_account
|
83
|
+
@connection_options = options[:connection_options] || {}
|
84
|
+
authenticate
|
85
|
+
@persistent = options[:persistent] || false
|
86
|
+
@connection = Fog::Core::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
|
87
|
+
@temp_url_key = options[:softlayer_temp_url_key] || get_temp_url_key_for_account
|
88
|
+
end
|
89
|
+
|
90
|
+
def auth_url
|
91
|
+
"https://#{@cluster}.#{Fog::Softlayer::SL_STORAGE_AUTH_URL}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def reload
|
95
|
+
@connection.reset
|
96
|
+
end
|
97
|
+
|
98
|
+
def request(params = {}, parse_json = true)
|
99
|
+
begin
|
100
|
+
params.is_a?(Hash) or raise ArgumentError, "#{self.class}#request params must be a Hash"
|
101
|
+
params = _build_params(params)
|
102
|
+
response = @connection.request(params)
|
103
|
+
|
104
|
+
if response.status == 401 && !!@auth_token
|
105
|
+
@auth_token = nil; @auth_expires = nil
|
106
|
+
authenticate
|
107
|
+
response = @connection.request(params)
|
108
|
+
end
|
109
|
+
|
110
|
+
if !response.body.empty? && parse_json && response.get_header('Content-Type') =~ %r{application/json}
|
111
|
+
response.body = Fog::JSON.decode(response.body)
|
112
|
+
end
|
113
|
+
|
114
|
+
response
|
115
|
+
rescue Excon::Errors::HTTPStatusError => error
|
116
|
+
raise case error
|
117
|
+
when Excon::Errors::NotFound
|
118
|
+
Fog::Storage::Softlayer::NotFound.slurp(error)
|
119
|
+
else
|
120
|
+
error
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def _auth_headers
|
128
|
+
{
|
129
|
+
:headers => {
|
130
|
+
'User-Agent' => "Fog SoftLayer Adapter #{Fog::Softlayer::VERSION}",
|
131
|
+
'X-Auth-User' => "#{@storage_account}:#{@username}",
|
132
|
+
'X-Auth-Key' => @api_key
|
133
|
+
}
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
def _build_params(params)
|
138
|
+
output = {
|
139
|
+
:method => params.delete(:method) || :get
|
140
|
+
}
|
141
|
+
|
142
|
+
output[:path] = params[:path] ? "#{@path}/#{params.delete(:path)}".sub(/\/$/, '') : @path
|
143
|
+
|
144
|
+
output = output.deep_merge(params)
|
145
|
+
output.deep_merge(_headers)
|
146
|
+
end
|
147
|
+
|
148
|
+
def _headers
|
149
|
+
{
|
150
|
+
:headers => {
|
151
|
+
'Content-Type' => 'application/json',
|
152
|
+
'Accept' => 'application/json',
|
153
|
+
'X-Auth-Token' => @auth_token
|
154
|
+
}
|
155
|
+
}
|
156
|
+
end
|
157
|
+
|
158
|
+
def authenticate
|
159
|
+
if requires_auth?
|
160
|
+
connection = Fog::Core::Connection.new(auth_url, false, _auth_headers)
|
161
|
+
response = connection.request(:method => :get)
|
162
|
+
|
163
|
+
raise Fog::Errors::Error.new("Could not authenticate Object Storage User.") unless response.status.between?(200, 208)
|
164
|
+
|
165
|
+
@auth_token = response.headers['X-Auth-Token']
|
166
|
+
@auth_expires = Time.now + response.headers['X-Auth-Token-Expires'].to_i
|
167
|
+
@storage_token = response.headers['X-Storage-Token']
|
168
|
+
|
169
|
+
uri = URI.parse(response.headers['X-Storage-Url'])
|
170
|
+
@host = uri.host
|
171
|
+
@path = uri.path
|
172
|
+
@path.sub!(/\/$/, '')
|
173
|
+
@port = uri.port
|
174
|
+
@scheme = uri.scheme
|
175
|
+
end
|
176
|
+
true
|
177
|
+
end
|
178
|
+
|
179
|
+
def default_storage_account
|
180
|
+
slapi = Fog::Compute[:softlayer].request(:account, :get_hub_network_storage)
|
181
|
+
slapi.body.map { |store| store['username'] }.first if slapi.body and slapi.body.instance_of? Array
|
182
|
+
end
|
183
|
+
|
184
|
+
def get_temp_url_key_for_account
|
185
|
+
request.headers['X-Account-Meta-Temp-Url-Key']
|
186
|
+
end
|
187
|
+
|
188
|
+
def requires_auth?
|
189
|
+
!@auth_token || !@auth_expires || (@auth_expires.to_i - Time.now.to_i) < 30
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
|
196
|
+
# Thanks to @camertron! https://gist.github.com/camertron/2939093
|
197
|
+
module Memory
|
198
|
+
# sizes are a guess, close enough for Mocks
|
199
|
+
REF_SIZE = 4 # ?
|
200
|
+
OBJ_OVERHEAD = 4 # ?
|
201
|
+
FIXNUM_SIZE = 4 # ?
|
202
|
+
|
203
|
+
# informational output from analysis
|
204
|
+
MemoryInfo = Struct.new :roots, :objects, :bytes, :loops
|
205
|
+
|
206
|
+
def self.analyze(*roots)
|
207
|
+
an = Analyzer.new
|
208
|
+
an.roots = roots
|
209
|
+
an.analyze
|
210
|
+
end
|
211
|
+
|
212
|
+
class Analyzer
|
213
|
+
attr_accessor :roots
|
214
|
+
attr_reader :result
|
215
|
+
|
216
|
+
def analyze
|
217
|
+
@result = MemoryInfo.new roots, 0, 0, 0
|
218
|
+
@objs = {}
|
219
|
+
|
220
|
+
queue = roots.dup
|
221
|
+
|
222
|
+
until queue.empty?
|
223
|
+
obj = queue.shift
|
224
|
+
|
225
|
+
case obj
|
226
|
+
when IO
|
227
|
+
visit(obj)
|
228
|
+
when String
|
229
|
+
visit(obj) { @result.bytes += obj.size }
|
230
|
+
when Fixnum
|
231
|
+
@result.bytes += FIXNUM_SIZE
|
232
|
+
when Array
|
233
|
+
visit(obj) do
|
234
|
+
@result.bytes += obj.size * REF_SIZE
|
235
|
+
queue.concat(obj)
|
236
|
+
end
|
237
|
+
when Hash
|
238
|
+
visit(obj) do
|
239
|
+
@result.bytes += obj.size * REF_SIZE * 2
|
240
|
+
obj.each {|k,v| queue.push(k).push(v)}
|
241
|
+
end
|
242
|
+
when Enumerable
|
243
|
+
visit(obj) do
|
244
|
+
obj.each do |o|
|
245
|
+
@result.bytes += REF_SIZE
|
246
|
+
queue.push(o)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
else
|
250
|
+
visit(obj) do
|
251
|
+
obj.instance_variables.each do |var|
|
252
|
+
@result.bytes += REF_SIZE
|
253
|
+
queue.push(obj.instance_variable_get(var))
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
@result
|
260
|
+
end
|
261
|
+
|
262
|
+
private
|
263
|
+
def visit(obj)
|
264
|
+
id = obj.object_id
|
265
|
+
|
266
|
+
if @objs.has_key? id
|
267
|
+
@result.loops += 1
|
268
|
+
false
|
269
|
+
else
|
270
|
+
@objs[id] = true
|
271
|
+
@result.bytes += OBJ_OVERHEAD
|
272
|
+
@result.objects += 1
|
273
|
+
yield obj if block_given?
|
274
|
+
true
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|