Class: Condo::Strata::OpenStackSwift

Inherits:
Object
  • Object
show all
Defined in:
lib/condo/strata/open_stack_swift.rb

Overview

NOTE

Set Account Metadata Key for Public Access before this will work - X-Account-Meta-Temp-Url-Key: <your key>

Constant Summary collapse

MIN_CHUNK_SIZE =
2.megabytes

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ OpenStackSwift

Returns a new instance of OpenStackSwift.

Raises:

  • (ArgumentError)


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/condo/strata/open_stack_swift.rb', line 13

def initialize(options)
    @options = {
        :name => :OpenStackSwift,
        :location => :dfw,
        :fog => {
            :provider => 'OpenStack',
            :openstack_username => options[:username],
            :openstack_api_key => options[:secret_key],
            :openstack_temp_url_key => options[:temp_url_key],
            :openstack_auth_url => options[:auth_url] || 'https://identity.api.rackspacecloud.com/v2.0/tokens' # is US and UK is 'lon.auth.api.rackspacecloud.com'
        }
    }.merge!(options)

    case @options[:location]
        when :dfw, :dallas, :DFW
            @options[:location] = 'https://storage101.dfw1.clouddrive.com'
            @options[:fog][:openstack_region] = 'DFW'
        when :ord, :chicago, :ORD
            @options[:location] = 'https://storage101.ord1.clouddrive.com'
            @options[:fog][:openstack_region] = 'ORD'
        when :iad, :virginia, :IAD
            @options[:location] = 'https://storage101.iad1.clouddrive.com'
            @options[:fog][:openstack_region] = 'IAD'
        when :lon, :london, :LON
            @options[:location] = 'https://storage101.lon1.clouddrive.com'
            @options[:fog][:openstack_region] = 'LON'
        when :syd, :sydney, :SYD
            @options[:location] = 'https://storage101.syd1.clouddrive.com'
            @options[:fog][:openstack_region] = 'SYD'
        when :hkg, :hong_kong, :HKG
            @options[:location] = 'https://storage101.hkg1.clouddrive.com'
            @options[:fog][:openstack_region] = 'HKG'
        else
            @options[:fog][:openstack_management_url] = "#{@options[:location]}/v1/#{@options[:storage_url]}"
    end


    raise ArgumentError, 'Swift Storage URL missing' if @options[:storage_url].nil?
    raise ArgumentError, 'Swift Temp URL Key missing' if @options[:temp_url_key].nil?


    @options[:location] = @options[:location].to_sym
end

Instance Method Details

#allow_cors(domains = 'http://localhost:9000', options_age = 10, headers = 'etag, content-type, accept, origin, x-requested-with') ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
# File 'lib/condo/strata/open_stack_swift.rb', line 78

def allow_cors(domains = 'http://localhost:9000', options_age = 10, headers = 'etag, content-type, accept, origin, x-requested-with')
    fog_connection.request(
        :expects  => [201, 202, 204],
        :method   => 'POST',
        :headers  => {
            'X-Container-Meta-Access-Control-Allow-Origin' => domains,
            'X-Container-Meta-Access-Control-Max-Age' => options_age,
            'X-Container-Meta-Access-Control-Allow-Headers' => headers
        }
    )
end

#destroy(upload) ⇒ Object



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/condo/strata/open_stack_swift.rb', line 210

def destroy(upload)
    connection = fog_connection
    directory = connection.directories.get(upload.bucket_name)    # it is assumed this exists - if not then the upload wouldn't have taken place

    if upload.resumable
        begin
            directory.files.all({'prefix' => upload.object_key}).each do |file|
                begin
                    return false unless file.destroy
                rescue ::Fog::Storage::OpenStack::NotFound => e
                end
            end
        rescue ::Fog::Storage::OpenStack::NotFound => e
        end
    end

    file = directory.files.get(upload.object_key)    # this is the manifest when resumable

    return true if file.nil?
    return file.destroy
end

#fog_connectionObject



204
205
206
207
# File 'lib/condo/strata/open_stack_swift.rb', line 204

def fog_connection
    @fog = @fog || Fog::Storage.new(@options[:fog])
    return @fog
end

#get_object(options) ⇒ Object

Create a signed URL for accessing a private file



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/condo/strata/open_stack_swift.rb', line 92

def get_object(options)
    options = {}.merge!(options)    # Need to deep copy here
    options[:object_options] = {
        :expires => 5.minutes.from_now,
        :verb => :get,
        :headers => {},
        :parameters => {}
    }.merge!(options[:object_options] || {})
    options.merge!(@options)

    # provide the signed request
    sign_request(options)[:url]
end

#get_parts(options) ⇒ Object

Returns the part we are up to



142
143
144
145
146
147
148
# File 'lib/condo/strata/open_stack_swift.rb', line 142

def get_parts(options)
    {
        :type => :parts,
        # NOTE:: This is legacy V1 - before parallel uploads
        :current_part => options[:resumable_id]
    }
end

#locationObject



63
64
65
# File 'lib/condo/strata/open_stack_swift.rb', line 63

def location
    @options[:location]
end

#nameObject



58
59
60
# File 'lib/condo/strata/open_stack_swift.rb', line 58

def name
    @options[:name]
end

#new_upload(options) ⇒ Object

Creates a new upload request (either single shot or multi-part)

> Passed: bucket_name, object_key, object_options, file_size



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/condo/strata/open_stack_swift.rb', line 109

def new_upload(options)
    options = {}.merge!(options)    # Need to deep copy here
    options[:object_options] = {
        :expires => 5.minutes.from_now,
        :verb => :put,
        :headers => {},
        :parameters => {}
    }.merge!(options[:object_options])
    options.merge!(@options)

    options[:object_options][:headers]['ETag'] = options[:file_id] if options[:file_id].present? && options[:object_options][:headers]['ETag'].nil?
    options[:object_options][:headers]['Content-Type'] = 'binary/octet-stream' if options[:object_options][:headers]['Content-Type'].nil?


    # Decide what type of request is being sent
    request = {}
    # 2 mb (minimum chunk size)
    if options[:file_size] > MIN_CHUNK_SIZE

        options[:object_key] = options[:object_key] + gen_part_ext(options[:file_size], 1)        # Append the part number
        request[:type] = :chunked_upload
    else

        request[:type] = :direct_upload
    end

    # provide the signed request
    request[:signature] = sign_request(options)
    request
end

#set_metadata_key(key) ⇒ Object

Here for convenience



69
70
71
72
73
74
75
# File 'lib/condo/strata/open_stack_swift.rb', line 69

def (key)
    fog_connection.request(
        :expects  => [201, 202, 204],
        :method   => 'POST',
        :headers  => {'X-Account-Meta-Temp-Url-Key' => key}
    )
end

#set_part(options) ⇒ Object

Returns the requests for uploading parts and completing a resumable upload



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/condo/strata/open_stack_swift.rb', line 152

def set_part(options)
    options[:object_options] = {
        :expires => 5.minutes.from_now,
        :headers => {},
        :parameters => {},
        :verb => :put
    }.merge!(options[:object_options])
    options.merge!(@options)


    request = {}
    if options[:part] == 'finish'
        # Dynamic large object now have to be created on the server...
        # Static Large Objects could be created client side.
        if @options[:use_static_large_objects]
            options[:object_options][:headers]['ETag'] = options[:file_id] if options[:file_id].present?
            options[:object_options][:headers]['Content-Type'] = 'text/plain'
            options[:object_key] = CGI::escape(options[:object_key])
            request[:signature] = sign_request(options, 'multipart-manifest=put&')
        else
            key = CGI::escape options[:object_key]

            # Send the commitment request
            fog_connection.request(
                :expects  => [200, 201],
                :method   => 'PUT',
                :headers  => {
                    'X-Object-Manifest' => "#{CGI::escape options[:bucket_name]}/#{key}/p"
                },
                path: "#{CGI::escape options[:bucket_name]}/#{key}"
            )

            return {}
        end
    else
        # Send the part upload request
        options[:object_options][:headers]['ETag'] = options[:file_id] if options[:file_id].present? && options[:object_options][:headers]['ETag'].nil?
        options[:object_options][:headers]['Content-Type'] = 'binary/octet-stream'
        object_key = CGI::escape(options[:object_key]) + gen_part_ext(options[:file_size], options[:part])
        options[:object_key] = object_key
        request[:type] = :part_upload

        # Required for static large objects
        request[:path] = "#{CGI::escape options[:bucket_name]}/#{object_key}"
        request[:signature] = sign_request(options)
    end

    # provide the signed request
    request
end