diff --git a/lib/fog/storage/models/ninefold/directories.rb b/lib/fog/storage/models/ninefold/directories.rb index 2088638f3..e3e12c825 100644 --- a/lib/fog/storage/models/ninefold/directories.rb +++ b/lib/fog/storage/models/ninefold/directories.rb @@ -13,20 +13,25 @@ module Fog def all directory ? ns = directory.key : ns = '' + ns = ns + '/' unless ns =~ /\/$/ data = connection.get_namespace(ns).body[:DirectoryList] data = {:DirectoryEntry => []} if data.kind_of? String data[:DirectoryEntry] = [data[:DirectoryEntry]] if data[:DirectoryEntry].kind_of? Hash dirs = data[:DirectoryEntry].select {|de| de[:FileType] == 'directory'} - dirs.each {|d| d[:Filename] = ns + '/' + d[:Filename] if directory} - load(data[:DirectoryEntry].select {|de| de[:FileType] == 'directory'}) + dirs.each do |d| + d[:Filename] = ns + d[:Filename] if directory + d[:Filename] += '/' unless d[:Filename] =~ /\/$/ + end + load(dirs) end def get(key, options = {}) return nil if key == '' # Root dir shouldn't be retrieved like this. - res = connection.get_namespace key + key =~ /\/$/ ? ns = key : ns = key + '/' + res = connection.get_namespace ns emc_meta = res.headers['x-emc-meta'] obj_id = emc_meta.scan(/objectid=(\w+),/).flatten[0] - new(:objectid => obj_id, :key => key) + new(:objectid => obj_id, :key => ns) rescue Fog::Storage::Ninefold::NotFound nil end diff --git a/lib/fog/storage/models/ninefold/directory.rb b/lib/fog/storage/models/ninefold/directory.rb index 9bfe97e42..a71ee9aea 100644 --- a/lib/fog/storage/models/ninefold/directory.rb +++ b/lib/fog/storage/models/ninefold/directory.rb @@ -28,14 +28,19 @@ module Fog end def save - self.key = attributes[:directory].key + '/' + key if attributes[:directory] + self.key = attributes[:directory].key + key if attributes[:directory] + self.key = key + '/' unless key =~ /\/$/ res = connection.post_namespace key reload end def destroy(opts={}) if opts[:recursive] - directories.each { |d| d.destroy(opts) } + files.each {|f| f.destroy } + directories.each do |d| + d.files.each {|f| f.destroy } + d.destroy(opts) + end end connection.delete_namespace key end diff --git a/lib/fog/storage/models/ninefold/file.rb b/lib/fog/storage/models/ninefold/file.rb new file mode 100644 index 000000000..9de908aad --- /dev/null +++ b/lib/fog/storage/models/ninefold/file.rb @@ -0,0 +1,91 @@ +require 'fog/core/model' + +module Fog + module Storage + class Ninefold + + class File < Fog::Model + + identity :key, :aliases => :Filename + + attribute :content_length, :aliases => ['bytes', 'Content-Length'], :type => :integer + attribute :content_type, :aliases => ['content_type', 'Content-Type'] + attribute :objectid, :aliases => :ObjectID + + def body + attributes[:body] ||= if last_modified + collection.get(identity).body + else + '' + end + end + + def body=(new_body) + attributes[:body] = new_body + end + + def directory + @directory + end + + def destroy + requires :directory, :key + connection.delete_namespace(directory.key + key) + true + end + + # def owner=(new_owner) + # if new_owner + # attributes[:owner] = { + # :display_name => new_owner['DisplayName'], + # :id => new_owner['ID'] + # } + # end + # end + + def public=(new_public) + # NOOP - we don't need to flag files as public, getting the public URL for a file handles it. + end + + # By default, expire in 5 years + def public_url(expires = (Time.now + 5 * 365 * 24 * 60 * 60)) + requires :objectid + # TODO - more efficient method to get this? + storage = Fog::Storage.new(:provider => 'Ninefold') + uri = URI::HTTP.build(:scheme => Fog::Storage::Ninefold::STORAGE_SCHEME, :host => Fog::Storage::Ninefold::STORAGE_HOST, :port => Fog::Storage::Ninefold::STORAGE_PORT.to_i, :path => "/rest/objects/#{objectid}" ) + Fog::Storage.new(:provider => 'Ninefold').uid + + + sb = "GET\n" + sb += uri.path.downcase + "\n" + sb += storage.uid + "\n" + sb += String(expires.to_i()) + + signature = storage.sign( sb ) + uri.query = "uid=#{CGI::escape(storage.uid)}&expires=#{expires.to_i()}&signature=#{CGI::escape(signature)}" + uri.to_s + end + + def save(options = {}) + requires :body, :directory, :key + directory.kind_of?(Directory) ? ns = directory.key : ns = directory + ns += key + options['Content-Type'] = content_type if content_type + data = connection.post_namespace(ns, :body => body) + #p data + self.objectid = data.headers['location'].split('/')[-1] + merge_attributes(data.headers) + true + end + + private + + def directory=(new_directory) + @directory = new_directory + end + + end + + end + end +end diff --git a/lib/fog/storage/models/ninefold/files.rb b/lib/fog/storage/models/ninefold/files.rb new file mode 100644 index 000000000..1ee9f3008 --- /dev/null +++ b/lib/fog/storage/models/ninefold/files.rb @@ -0,0 +1,72 @@ +require 'fog/core/collection' +require 'fog/storage/models/ninefold/file' + +module Fog + module Storage + class Ninefold + + class Files < Fog::Collection + + attribute :directory + attribute :limit + attribute :marker + attribute :path + attribute :prefix + + model Fog::Storage::Ninefold::File + + def all(options = {}) + requires :directory + directory ? ns = directory.key : ns = '' + ns = ns + '/' unless ns =~ /\/$/ + data = connection.get_namespace(ns).body[:DirectoryList] + data = {:DirectoryEntry => []} if data.kind_of? String + data[:DirectoryEntry] = [data[:DirectoryEntry]] if data[:DirectoryEntry].kind_of? Hash + files = data[:DirectoryEntry].select {|de| de[:FileType] == 'regular'} + files.each do |s| + s[:directory] = directory + end + # TODO - Load additional file meta? + load(files) + end + + def get(key, &block) + requires :directory + data = connection.get_namespace(directory.key + key, :parse => false)#, &block) + file_data = data.headers.merge({ + :body => data.body, + :key => key + }) + new(file_data) + rescue Fog::Storage::Ninefold::NotFound + nil + end + + def get_url(key) + requires :directory + if self.directory.public_url + "#{self.directory.public_url}/#{key}" + end + end + + def head(key, options = {}) + requires :directory + data = connection.head_object(directory.key, key) + file_data = data.headers.merge({ + :key => key + }) + new(file_data) + rescue Fog::Storage::Rackspace::NotFound + nil + end + + def new(attributes = {}) + requires :directory + super({ :directory => directory }.merge!(attributes)) + end + + end + + end + end +end diff --git a/lib/fog/storage/ninefold.rb b/lib/fog/storage/ninefold.rb index 80dc01a02..43b091999 100644 --- a/lib/fog/storage/ninefold.rb +++ b/lib/fog/storage/ninefold.rb @@ -14,8 +14,8 @@ module Fog model_path 'fog/storage/models/ninefold' model :directory collection :directories - # model :file - # collection :files + model :file + collection :files request_path 'fog/storage/requests/ninefold' # request :delete_container @@ -54,6 +54,15 @@ module Fog @connection = Fog::Connection.new("#{Fog::Storage::Ninefold::STORAGE_SCHEME}://#{Fog::Storage::Ninefold::STORAGE_HOST}:#{Fog::Storage::Ninefold::STORAGE_PORT}", true) # persistent end + def uid + @ninefold_storage_token#.split('/')[-1] + end + + def sign(string) + value = ::HMAC::SHA1.digest( @ninefold_storage_secret_decoded, string ) + Base64.encode64( value ).chomp() + end + def reload @connection.reset end @@ -89,7 +98,7 @@ module Fog signstring += "/rest/" + URI.unescape( req_path ).downcase query_str = params[:query].map{|k,v| "#{k}=#{v}"}.join('&') - signstring += '?' + params[:query] unless query_str.empty? + signstring += '?' + query_str unless query_str.empty? signstring += "\n" customheaders = {} diff --git a/lib/fog/storage/requests/ninefold/delete_namespace.rb b/lib/fog/storage/requests/ninefold/delete_namespace.rb index 462511a87..d9ad7b8c6 100644 --- a/lib/fog/storage/requests/ninefold/delete_namespace.rb +++ b/lib/fog/storage/requests/ninefold/delete_namespace.rb @@ -4,14 +4,13 @@ module Fog class Real def delete_namespace(namespace = '', options = {}) - namespace = namespace + '/' unless namespace =~ /\/$/ options = options.reject {|key, value| value.nil?} - request( - :expects => 204, - :method => 'DELETE', - :path => "namespace/" + namespace, - :query => options - ) + request({ + :expects => 204, + :method => 'DELETE', + :path => "namespace/" + namespace, + :query => options + }.merge(options)) end end diff --git a/lib/fog/storage/requests/ninefold/get_namespace.rb b/lib/fog/storage/requests/ninefold/get_namespace.rb index 45b669a62..28b6b13b6 100644 --- a/lib/fog/storage/requests/ninefold/get_namespace.rb +++ b/lib/fog/storage/requests/ninefold/get_namespace.rb @@ -4,15 +4,14 @@ module Fog class Real def get_namespace(namespace = '', options = {}) - namespace = namespace + '/' unless namespace =~ /\/$/ options = options.reject {|key, value| value.nil?} - request( - :expects => 200, - :method => 'GET', - :path => "namespace/" + namespace, - :query => options, - :parse => true - ) + request({ + :expects => 200, + :method => 'GET', + :path => "namespace/" + namespace, + :query => {}, + :parse => true + }.merge(options)) end end diff --git a/lib/fog/storage/requests/ninefold/post_namespace.rb b/lib/fog/storage/requests/ninefold/post_namespace.rb index 76634e3a1..6a314a46a 100644 --- a/lib/fog/storage/requests/ninefold/post_namespace.rb +++ b/lib/fog/storage/requests/ninefold/post_namespace.rb @@ -4,15 +4,14 @@ module Fog class Real def post_namespace(namespace = '', options = {}) - namespace = namespace + '/' unless namespace =~ /\/$/ options = options.reject {|key, value| value.nil?} - request( - :expects => 201, - :method => 'POST', - :path => "namespace/" + namespace, - :query => options, - :parse => true - ) + request({ + :expects => 201, + :method => 'POST', + :path => "namespace/" + namespace, + :query => {}, + :parse => true + }.merge(options)) end end diff --git a/tests/storage/models/ninefold/nested_directories_tests.rb b/tests/storage/models/ninefold/nested_directories_tests.rb index e3c81b82d..47967261b 100644 --- a/tests/storage/models/ninefold/nested_directories_tests.rb +++ b/tests/storage/models/ninefold/nested_directories_tests.rb @@ -11,7 +11,7 @@ if storage_providers.keys.include? :ninefold ninefold.directories.get('sub').directories.count end - tests("create a directory in a sub dir").returns('sub/path/newdir') do + tests("create a directory in a sub dir").returns('sub/path/newdir/') do ninefold.directories.get('sub/path').directories.create(:key => 'newdir').identity end