Class: CloudFiles::Container

Inherits:
Object
  • Object
show all
Defined in:
lib/cloudfiles/container.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection, name) ⇒ Container

Retrieves an existing CloudFiles::Container object tied to the current CloudFiles::Connection. If the requested container does not exist, it will raise a CloudFiles::Exception::NoSuchContainer Exception.

Will likely not be called directly, instead use connection.container(‘container_name’) to retrieve the object.



16
17
18
19
20
21
22
# File 'lib/cloudfiles/container.rb', line 16

def initialize(connection, name)
  @connection = connection
  @name = name
  # Load the metadata now, so we'll get a CloudFiles::Exception::NoSuchContainer exception should the container
  # not exist.
  self.
end

Instance Attribute Details

#connectionObject (readonly)

The parent CloudFiles::Connection object for this container



10
11
12
# File 'lib/cloudfiles/container.rb', line 10

def connection
  @connection
end

#nameObject (readonly)

Name of the container which corresponds to the instantiated container class



7
8
9
# File 'lib/cloudfiles/container.rb', line 7

def name
  @name
end

Instance Method Details

#bytesObject

Size of the container (in bytes)



110
111
112
# File 'lib/cloudfiles/container.rb', line 110

def bytes
  self.[:bytes]
end

#cdn_available?Boolean

Returns:

  • (Boolean)


444
445
446
# File 'lib/cloudfiles/container.rb', line 444

def cdn_available?
  self.connection.cdn_available?
end

#cdn_enabledObject Also known as: cdn_enabled?, public?

Returns true if the container is public and CDN-enabled. Returns false otherwise.

Aliased as container.public?

public_container.cdn_enabled?
=> true

private_container.public?
=> false


128
129
130
# File 'lib/cloudfiles/container.rb', line 128

def cdn_enabled
  cdn_available? && self.[:cdn_enabled]
end

#cdn_logObject Also known as: log_retention?, cdn_log?

Returns true if log retention is enabled on this container, false otherwise



165
166
167
# File 'lib/cloudfiles/container.rb', line 165

def cdn_log
  self.[:cdn_log]
end

#cdn_metadataObject

Retrieves CDN-Enabled Meta Data



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/cloudfiles/container.rb', line 56

def 
  return @cdn_metadata if @cdn_metadata
  if cdn_available?
    @cdn_metadata = (
      begin
        response = SwiftClient.head_container(self.connection.cdnurl, self.connection.authtoken, escaped_name)
        cdn_enabled = ((response["x-cdn-enabled"] || "").downcase == "true") ? true : false
      rescue ClientException => e
        cdn_enabled = false
      end
      {
        :cdn_enabled => cdn_enabled,
        :cdn_ttl => cdn_enabled ? response["x-ttl"].to_i : nil,
        :cdn_url => cdn_enabled ? response["x-cdn-uri"] : nil,
        :cdn_ssl_url => cdn_enabled ? response["x-cdn-ssl-uri"] : nil,
        :cdn_streaming_url => cdn_enabled ? response["x-cdn-streaming-uri"] : nil,
        :cdn_log => (cdn_enabled and response["x-log-retention"] == "True") ? true : false
      }
    )
  else
    @cdn_metadata = {}
  end
end

#cdn_ssl_urlObject

CDN SSL container URL (if container is public)



145
146
147
# File 'lib/cloudfiles/container.rb', line 145

def cdn_ssl_url
  self.[:cdn_ssl_url]
end

#cdn_streaming_urlObject

CDN Streaming container URL (if container is public)



150
151
152
# File 'lib/cloudfiles/container.rb', line 150

def cdn_streaming_url
  self.[:cdn_streaming_url]
end

#cdn_ttlObject

CDN container TTL (if container is public)



135
136
137
# File 'lib/cloudfiles/container.rb', line 135

def cdn_ttl
  self.[:cdn_ttl]
end

#cdn_urlObject

CDN container URL (if container is public)



140
141
142
# File 'lib/cloudfiles/container.rb', line 140

def cdn_url
  self.[:cdn_url]
end

#container_metadataObject

Retrieves Metadata for the container



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/cloudfiles/container.rb', line 42

def 
  @metadata ||= (
    begin
      response = SwiftClient.head_container(self.connection.storageurl, self.connection.authtoken, escaped_name)
      resphash = {}
      response.to_hash.select { |k,v| k.match(/^x-container-meta/) }.each { |x| resphash[x[0]] = x[1].to_s }
      {:bytes => response["x-container-bytes-used"].to_i, :count => response["x-container-object-count"].to_i, :metadata => resphash, :container_read => response["x-container-read"], :container_write => response["x-container-write"]}
    rescue ClientException => e
      raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (e.status.to_s =~ /^20/)
    end
  )
end

#countObject

Number of objects in the container



115
116
117
# File 'lib/cloudfiles/container.rb', line 115

def count
  self.[:count]
end

#create_object(objectname, make_path = false) ⇒ Object

Creates a new CloudFiles::StorageObject in the current container.

If an object with the specified name exists in the current container, that object will be returned. Otherwise, an empty new object will be returned.

Passing in the optional make_path argument as true will create zero-byte objects to simulate a filesystem path to the object, if an objectname with path separators (“/path/to/myfile.mp3”) is supplied. These path objects can be used in the Container.objects method.



310
311
312
# File 'lib/cloudfiles/container.rb', line 310

def create_object(objectname, make_path = false)
  CloudFiles::StorageObject.new(self, objectname, false, make_path)
end

#delete_object(objectname) ⇒ Object

Removes an CloudFiles::StorageObject from a container. True is returned if the removal is successful. Throws NoSuchObjectException if the object doesn’t exist. Throws InvalidResponseException if the request fails.

container.delete_object('new.txt')
=> true

container.delete_object('nonexistent_file.txt')
=> NoSuchObjectException: Object nonexistent_file.txt does not exist


322
323
324
325
326
327
328
329
330
# File 'lib/cloudfiles/container.rb', line 322

def delete_object(objectname)
  begin
    SwiftClient.delete_object(self.connection.storageurl, self.connection.authtoken, escaped_name, objectname)
    true
  rescue ClientException => e
    raise CloudFiles::Exception::NoSuchObject, "Object #{objectname} does not exist" if (e.status.to_s == "404")
    raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status}" unless (e.status.to_s =~ /^20/)
  end
end

#empty?Boolean

Returns true if a container is empty and returns false otherwise.

new_container.empty?
=> true

full_container.empty?
=> false

Returns:

  • (Boolean)


282
283
284
# File 'lib/cloudfiles/container.rb', line 282

def empty?
  return ([:count].to_i == 0)? true : false
end

#escaped_nameObject



448
449
450
# File 'lib/cloudfiles/container.rb', line 448

def escaped_name
  CloudFiles.escape(@name)
end

#log_retention=(value) ⇒ Object

Change the log retention status for this container. Values are true or false.

These logs will be periodically (at unpredictable intervals) compressed and uploaded to a “.CDN_ACCESS_LOGS” container in the form of “container_name.YYYYMMDDHH-XXXX.gz”.



176
177
178
179
180
181
182
183
184
# File 'lib/cloudfiles/container.rb', line 176

def log_retention=(value)
  raise Exception::CDNNotAvailable unless cdn_available?
  begin
    SwiftClient.post_container(self.connection.cdnurl, self.connection.authtoken, escaped_name, {"x-log-retention" => value.to_s.capitalize})
    true
  rescue ClientException => e
    raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status}" unless (e.status.to_s == "201" or e.status.to_s == "202")
  end
end

#make_privateObject

Makes a container private and returns true upon success. Throws NoSuchContainerException if the container doesn’t exist or if the request fails.

Note that if the container was previously public, it will continue to exist out on the CDN until it expires.

container.make_private
=> true


399
400
401
402
403
404
405
406
407
408
409
# File 'lib/cloudfiles/container.rb', line 399

def make_private
  raise Exception::CDNNotAvailable unless cdn_available?
  headers = { "X-CDN-Enabled" => "False" }
  begin
    SwiftClient.post_container(self.connection.cdnurl, self.connection.authtoken, escaped_name, headers)
    refresh
    true
  rescue ClientException => e
    raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (e.status.to_s == "201" || e.status.to_s == "202")
  end
end

#make_public(options = {:ttl => 86400}) ⇒ Object

Makes a container publicly available via the Cloud Files CDN and returns true upon success. Throws NoSuchContainerException if the container doesn’t exist or if the request fails.

Takes an optional hash of options, including:

:ttl, which is the CDN cache TTL in seconds (default 86400 seconds or 1 day, minimum 3600 or 1 hour, maximum 259200 or 3 days)

:user_agent_acl, a Perl-compatible regular expression limiting access to this container to user agents matching the given regular expression

:referrer_acl, a Perl-compatible regular expression limiting access to this container to HTTP referral URLs matching the given regular expression

container.make_public(:ttl => 8900, :user_agent_acl => "/Mozilla/", :referrer_acl => "/^http://rackspace.com")
=> true


345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/cloudfiles/container.rb', line 345

def make_public(options = {:ttl => 86400})
  raise Exception::CDNNotAvailable unless cdn_available?
  if options.is_a?(Fixnum)
    print "DEPRECATED: make_public takes a hash of options now, instead of a TTL number"
    ttl = options
    options = {:ttl => ttl}
  end

  begin
    SwiftClient.put_container(self.connection.cdnurl, self.connection.authtoken, escaped_name)
  rescue ClientException => e
    raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (e.status.to_s == "201" || e.status.to_s == "202")
  end
  headers = { "X-TTL" => options[:ttl].to_s , "X-CDN-Enabled" => "True" }
  headers["X-User-Agent-ACL"] = options[:user_agent_acl] if options[:user_agent_acl]
  headers["X-Referrer-ACL"] = options[:referrer_acl] if options[:referrer_acl]

  post_with_headers(headers)
  # raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist" unless (response.code == "201" || response.code == "202")
  refresh
  true
end

#metadataObject

Returns the container’s metadata as a nicely formatted hash, stripping off the X-Meta-Object- prefix that the system prepends to the key name.

object.metadata
=> {"ruby"=>"cool", "foo"=>"bar"}


85
86
87
88
89
# File 'lib/cloudfiles/container.rb', line 85

def 
  metahash = {}
  self.[:metadata].each{ |key, value| metahash[key.gsub(/x-container-meta-/, '').gsub(/%20/, ' ')] = URI.decode(value).gsub(/\+\-/, ' ') }
  metahash
end

#object(objectname) ⇒ Object Also known as: get_object

Returns the CloudFiles::StorageObject for the named object. Refer to the CloudFiles::StorageObject class for available methods. If the object exists, it will be returned. If the object does not exist, a NoSuchObjectException will be thrown.

object = container.object('test.txt')
object.data
=> "This is test data"

object = container.object('newfile.txt')
=> NoSuchObjectException: Object newfile.txt does not exist


196
197
198
199
# File 'lib/cloudfiles/container.rb', line 196

def object(objectname)
  o = CloudFiles::StorageObject.new(self, objectname, true)
  return o
end

#object_exists?(objectname) ⇒ Boolean

Returns true if object exists and returns false otherwise.

container.object_exists?('goodfile.txt')
=> true

container.object_exists?('badfile.txt')
=> false

Returns:

  • (Boolean)


293
294
295
296
297
298
299
300
# File 'lib/cloudfiles/container.rb', line 293

def object_exists?(objectname)
  begin
    response = SwiftClient.head_object(self.connection.storageurl, self.connection.authtoken, escaped_name, objectname)
    true
  rescue ClientException => e
    false
  end
end

#objects(params = {}) ⇒ Object Also known as: list_objects

Gathers a list of all available objects in the current container and returns an array of object names.

container = cf.container("My Container")
container.objects                     #=> [ "cat", "dog", "donkey", "monkeydir", "monkeydir/capuchin"]

Pass a limit argument to limit the list to a number of objects:

container.objects(:limit => 1)                  #=> [ "cat" ]

Pass an marker with or without a limit to start the list at a certain object:

container.objects(:limit => 1, :marker => 'dog')                #=> [ "donkey" ]

Pass a prefix to search for objects that start with a certain string:

container.objects(:prefix => "do")       #=> [ "dog", "donkey" ]

Only search within a certain pseudo-filesystem path:

container.objects(:path => 'monkeydir')     #=> ["monkeydir/capuchin"]

Only grab “virtual directories”, based on a single-character delimiter (no “directory” objects required):

container.objects(:delimiter => '/')      #=> ["monkeydir"]

All arguments to this method are optional.

Returns an empty array if no object exist in the container. Throws an InvalidResponseException if the request fails.



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/cloudfiles/container.rb', line 220

def objects(params = {})
  params[:marker] ||= params[:offset] unless params[:offset].nil?
  query = []
  params.each do |param, value|
    if [:full_listing, :limit, :marker, :prefix, :path, :delimiter].include? param
      query << "#{param}=#{CloudFiles.escape(value.to_s)}"
    end
  end
  begin
    response = SwiftClient.get_container(self.connection.storageurl, self.connection.authtoken, escaped_name, params[:marker], params[:limit], params[:prefix], params[:delimiter], params[:full_listing])
    return response[1].collect{|o| o['name']}
  rescue ClientException => e
    raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status}" unless (e.status.to_s == "200")
  end
end

#objects_detail(params = {}) ⇒ Object Also known as: list_objects_info

Retrieves a list of all objects in the current container along with their size in bytes, hash, and content_type. If no objects exist, an empty hash is returned. Throws an InvalidResponseException if the request fails. Takes a parameter hash as an argument, in the same form as the objects method.

Accepts the same options as objects to limit the returned set.

Returns a hash in the same format as the containers_detail from the CloudFiles class.

container.objects_detail
=> {"test.txt"=>{:content_type=>"application/octet-stream",
                 :hash=>"e2a6fcb4771aa3509f6b27b6a97da55b",
                 :last_modified=>Mon Jan 19 10:43:36 -0600 2009,
                 :bytes=>"16"},
    "new.txt"=>{:content_type=>"application/octet-stream",
                :hash=>"0aa820d91aed05d2ef291d324e47bc96",
                :last_modified=>Wed Jan 28 10:16:26 -0600 2009,
                :bytes=>"22"}
   }


255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/cloudfiles/container.rb', line 255

def objects_detail(params = {})
  params[:marker] ||= params[:offset] unless params[:offset].nil?
  query = ["format=xml"]
  params.each do |param, value|
    if [:full_listing, :limit, :marker, :prefix, :path, :delimiter].include? param
      query << "#{param}=#{CloudFiles.escape(value.to_s)}"
    end
  end
  begin
    response = SwiftClient.get_container(self.connection.storageurl, self.connection.authtoken, escaped_name, params[:marker], params[:limit], params[:prefix], params[:delimiter], params[:full_listing])
    # Can't use the Hash[*arr] trick here, blows the stack if the there are too many objects
    return response[1].inject(Hash.new) do |h, o|
      h[o['name']] = { :bytes => o["bytes"], :hash => o["hash"], :content_type => o["content_type"], :last_modified => DateTime.parse(o["last_modified"]) }; h
    end
  rescue ClientException => e
    raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status}" unless (e.status.to_s == "200")
  end
end

#post_with_headers(headers = {}) ⇒ Object



384
385
386
387
388
389
390
# File 'lib/cloudfiles/container.rb', line 384

def post_with_headers(headers = {})
  begin
    SwiftClient.post_container(cdn_enabled? ? self.connection.cdnurl : self.connection.storageurl, self.connection.authtoken, escaped_name, headers)
  rescue ClientException => e
    raise CloudFiles::Exception::NoSuchContainer, "Container #{@name} does not exist (response code: #{e.status.to_s})" unless (e.status.to_s =~ /^20/)
  end
end

#purge_from_cdn(email = nil) ⇒ Object

Purges CDN Edge Cache for all objects inside of this container

:email, An valid email address or comma seperated

list of emails to be notified once purge is complete .

 container.purge_from_cdn
 => true

or 

 container.purge_from_cdn("[email protected]")
 => true

or

 container.purge_from_cdn("[email protected], [email protected]")
 => true


428
429
430
431
432
433
434
435
436
437
438
# File 'lib/cloudfiles/container.rb', line 428

def purge_from_cdn(email=nil)
  raise Exception::CDNNotAvailable unless cdn_available?
  headers = {}
  headers = {"X-Purge-Email" => email} if email
  begin
    SwiftClient.delete_container(self.connection.cdnurl, self.connection.authtoken, escaped_name, headers)
    true
  rescue ClientException => e
    raise CloudFiles::Exception::Connection, "Error Unable to Purge Container: #{@name}" unless (e.status.to_s > "200" && e.status.to_s < "299")
  end
end

#read_aclObject

used by openstack swift



155
156
157
# File 'lib/cloudfiles/container.rb', line 155

def read_acl
  self.[:container_read]
end

#refreshObject Also known as: populate

Refreshes data about the container and populates class variables. Items are otherwise loaded in a lazy loaded fashion.

container.count
=> 2
[Upload new file to the container]
container.count
=> 2
container.populate
container.count
=> 3


35
36
37
38
# File 'lib/cloudfiles/container.rb', line 35

def refresh
  @metadata = @cdn_metadata = nil
  true
end

#set_metadata(metadatahash) ⇒ Object

Sets the metadata for an object. By passing a hash as an argument, you can set the metadata for an object. New calls to set metadata are additive. To remove metadata, set the value of the key to nil.

Throws NoSuchObjectException if the container doesn’t exist. Throws InvalidResponseException if the request fails.



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/cloudfiles/container.rb', line 96

def (metadatahash)
  headers = {}
  metadatahash.each{ |key, value| headers['X-Container-Meta-' + CloudFiles.escape(key.to_s.capitalize)] = value.to_s }
  begin
    SwiftClient.post_container(self.connection.storageurl, self.connection.authtoken, escaped_name, headers)
    self.refresh
    true
  rescue ClientException => e
    raise CloudFiles::Exception::NoSuchObject, "Container #{@name} does not exist" if (e.status.to_s == "404")
    raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{e.status}" unless (e.status.to_s =~ /^20/)
  end
end

#set_read_acl(read_string) ⇒ Object

Only to be used with openstack swift



377
378
379
380
381
382
# File 'lib/cloudfiles/container.rb', line 377

def set_read_acl(read_string)
  refresh
  headers = {"X-Container-Read" => read_string}
  post_with_headers(headers)
  true
end

#set_write_acl(write_string) ⇒ Object

Only to be used with openstack swift



369
370
371
372
373
374
# File 'lib/cloudfiles/container.rb', line 369

def set_write_acl(write_string)
  refresh
  headers = {"X-Container-Write" => write_string}
  post_with_headers(headers)
  true
end

#to_sObject

:nodoc:



440
441
442
# File 'lib/cloudfiles/container.rb', line 440

def to_s # :nodoc:
  @name
end

#write_aclObject

used by openstack swift



160
161
162
# File 'lib/cloudfiles/container.rb', line 160

def write_acl
  self.[:container_write]
end