Skip to content

Instantly share code, notes, and snippets.

@krames
Last active December 17, 2015 15:29
Show Gist options
  • Select an option

  • Save krames/5631808 to your computer and use it in GitHub Desktop.

Select an option

Save krames/5631808 to your computer and use it in GitHub Desktop.
This gist contains a patch to allow uploaded large segmented files in memory efficient manner in the Rackspace Cloud. It also includes an example demonstrating it's use. This should only be used with Fog 1.11.1. I am currently working on a pull request to include this in fog proper.
#!/usr/bin/env ruby
# This example demonstrates uploading large files in segments
require 'rubygems' #required for Ruby 1.8.x
require 'fog'
# Size of segment. The Rackspace cloud currently requires files larger than 5GB to be segmented so we will choose 5GB -1 for a size
# http://docs.rackspace.com/files/api/v1/cf-devguide/content/Large_Object_Creation-d1e2019.html
SEGMENT_LIMIT = 5368709119.0
# Size of buffer to use for transfers. Use Excon's default chunk size and if that's not avaliable we will default to 1 MB
BUFFER_SIZE = Excon.defaults[:chunk_size] || 1024 * 1024
def get_user_input(prompt)
print "#{prompt}: "
gets.chomp
end
# Use username defined in ~/.fog file, if absent prompt for username.
# For more details on ~/.fog refer to http://fog.io/about/getting_started.html
def rackspace_username
Fog.credentials[:rackspace_username] || get_user_input("Enter Rackspace Username")
end
# Use api key defined in ~/.fog file, if absent prompt for api key
# For more details on ~/.fog refer to http://fog.io/about/getting_started.html
def rackspace_api_key
Fog.credentials[:rackspace_api_key] || get_user_input("Enter Rackspace API key")
end
# create Cloud Files service
service = Fog::Storage.new({
:provider => 'Rackspace',
:rackspace_username => rackspace_username,
:rackspace_api_key => rackspace_api_key,
})
#Include this after the storage services is loaded to ensure that are patch takes effect
require './patch_large_file_support.rb'
# prompt for directory name
directory_name = get_user_input "\nEnter name of directory to store file"
# prompt for file name
file_name = get_user_input "\nEnter full path of file to upload"
File.open(file_name) do |f|
num_segments = (f.size / SEGMENT_LIMIT).round + 1
puts "This upload of '#{file_name}' will require #{num_segments} segment and 1 manifest file\n"
1.upto(num_segments) do |segment|
print "\nUploading segment #{segment} "
offset = 0
read = 0
service.put_object(directory_name, "large_file/#{segment}", nil, options = {}) do
if (offset < SEGMENT_LIMIT) && (read.zero? || read == BUFFER_SIZE)
print "."
buf = f.sysread(BUFFER_SIZE)
read = buf.size
offset += read
buf
else
""
end
end
end
end
puts "writing manifest"
service.put_object_manifest(directory_name, 'large_file')
puts <<-NOTE
You should now be able to download large_file from the cloud control panel or via the api using the following code:
directory = service.directories.get('#{directory_name}')
File.open('large_file.jpg', 'w') do | f |
directory.files.get("large_file") do | data, remaining, content_length |
print "."
f.syswrite data
end
end
NOTE
require 'rubygems'
require 'fog'
if Fog::VERSION == "1.11.1"
Fog::Logger.warning "PATCHING Fog::Storage::Rackspace::Real to allow uploading of large objects"
module Fog
module Storage
class Rackspace
class Real
def put_object(container, object, data, options = {}, &block)
data = Fog::Storage.parse_data(data)
headers = data[:headers].merge!(options)
params = block_given? ? { :request_block => block } : { :body => data[:body] }
params.merge!(
:expects => 201,
:idempotent => true,
:headers => headers,
:method => 'PUT',
:path => "#{Fog::Rackspace.escape(container)}/#{Fog::Rackspace.escape(object)}"
)
request(params)
end
end
end
end
end
else
Fog::Logger.warning "PATCHING Fog::Storage::Rackspace::Real - does not apply for #{Fog::VERSION}. Please remove it."
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment