Class: CloudFiles::Connection

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Connection

Creates a new CloudFiles::Connection object. Uses CloudFiles::Authentication to perform the login for the connection. The authuser is the Rackspace Cloud username, the authkey is the Rackspace Cloud API key.

Setting the :retry_auth option to false will cause an exception to be thrown if your authorization token expires. Otherwise, it will attempt to reauthenticate.

Setting the :snet option to true or setting an environment variable of RACKSPACE_SERVICENET to any value will cause storage URLs to be returned with a prefix pointing them to the internal Rackspace service network, instead of a public URL.

This is useful if you are using the library on a Rackspace-hosted system, as it provides faster speeds, keeps traffic off of the public network, and the bandwidth is not billed.

If you need to connect to a Cloud Files installation that is NOT the standard Rackspace one, set the :auth_url option to the URL of your authentication endpoint. The old option name of :authurl is deprecated. The default is CloudFiles::AUTH_USA (auth.api.rackspacecloud.com/v1.0)

There are two predefined constants to represent the United States-based authentication endpoint and the United Kingdom-based endpoint: CloudFiles::AUTH_USA (the default) and CloudFiles::AUTH_UK - both can be passed to the :auth_url option to quickly choose one or the other.

This will likely be the base class for most operations.

With gem 1.4.8, the connection style has changed. It is now a hash of arguments. Note that the proxy options are currently only supported in the new style.

cf = CloudFiles::Connection.new(:username => "MY_USERNAME", :api_key => "MY_API_KEY", :auth_url => CloudFiles::AUTH_UK, :retry_auth => true, :snet => false, :proxy_host => "localhost", :proxy_port => "1234")

The old style (positional arguments) is deprecated and will be removed at some point in the future.

cf = CloudFiles::Connection.new(MY_USERNAME, MY_API_KEY, RETRY_AUTH, USE_SNET)


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/cloudfiles/connection.rb', line 81

def initialize(*args)
  if args[0].is_a?(Hash)
    options = args[0]
    @authuser = options[:username] ||( raise CloudFiles::Exception::Authentication, "Must supply a :username")
    @authkey = options[:api_key] || (raise CloudFiles::Exception::Authentication, "Must supply an :api_key")
    @auth_url = options[:authurl] || CloudFiles::AUTH_USA
    @auth_url = options[:auth_url] || CloudFiles::AUTH_USA
    @retry_auth = options[:retry_auth] || true
    @snet = ENV['RACKSPACE_SERVICENET'] || options[:snet]
    @proxy_host = options[:proxy_host]
    @proxy_port = options[:proxy_port]
  else
    @authuser = args[0] ||( raise CloudFiles::Exception::Authentication, "Must supply the username as the first argument")
    @authkey = args[1] || (raise CloudFiles::Exception::Authentication, "Must supply the API key as the second argument")
    @retry_auth = args[2] || true
    @snet = (ENV['RACKSPACE_SERVICENET'] || args[3]) ? true : false
    @auth_url = CloudFiles::AUTH_USA
  end
  @authok = false
  @http = {}
  CloudFiles::Authentication.new(self)
end

Instance Attribute Details

#auth_urlObject (readonly)

API host to authenticate to



16
17
18
# File 'lib/cloudfiles/connection.rb', line 16

def auth_url
  @auth_url
end

#authkeyObject (readonly)

Authentication key provided when the CloudFiles class was instantiated



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

def authkey
  @authkey
end

#authokObject

Instance variable that is set when authorization succeeds



47
48
49
# File 'lib/cloudfiles/connection.rb', line 47

def authok
  @authok
end

#authtokenObject

Token returned after a successful authentication



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

def authtoken
  @authtoken
end

#authuserObject (readonly)

Authentication username provided when the CloudFiles class was instantiated



13
14
15
# File 'lib/cloudfiles/connection.rb', line 13

def authuser
  @authuser
end

#cdn_availableObject Also known as: cdn_available?

Set at auth to see if a CDN is available for use



19
20
21
# File 'lib/cloudfiles/connection.rb', line 19

def cdn_available
  @cdn_available
end

#cdnmgmthostObject

Hostname of the CDN management server



23
24
25
# File 'lib/cloudfiles/connection.rb', line 23

def cdnmgmthost
  @cdnmgmthost
end

#cdnmgmtpathObject

Path for managing containers on the CDN management server



26
27
28
# File 'lib/cloudfiles/connection.rb', line 26

def cdnmgmtpath
  @cdnmgmtpath
end

#cdnmgmtportObject

Port number for the CDN server



29
30
31
# File 'lib/cloudfiles/connection.rb', line 29

def cdnmgmtport
  @cdnmgmtport
end

#cdnmgmtschemeObject

URI scheme for the CDN server



32
33
34
# File 'lib/cloudfiles/connection.rb', line 32

def cdnmgmtscheme
  @cdnmgmtscheme
end

#proxy_hostObject (readonly)

Optional proxy variables



50
51
52
# File 'lib/cloudfiles/connection.rb', line 50

def proxy_host
  @proxy_host
end

#proxy_portObject (readonly)

Returns the value of attribute proxy_port.



51
52
53
# File 'lib/cloudfiles/connection.rb', line 51

def proxy_port
  @proxy_port
end

#storagehostObject

Hostname of the storage server



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

def storagehost
  @storagehost
end

#storagepathObject

Path for managing containers/objects on the storage server



38
39
40
# File 'lib/cloudfiles/connection.rb', line 38

def storagepath
  @storagepath
end

#storageportObject

Port for managing the storage server



41
42
43
# File 'lib/cloudfiles/connection.rb', line 41

def storageport
  @storageport
end

#storageschemeObject

URI scheme for the storage server



44
45
46
# File 'lib/cloudfiles/connection.rb', line 44

def storagescheme
  @storagescheme
end

Instance Method Details

#authok?Boolean

Returns true if the authentication was successful and returns false otherwise.

cf.authok?
=> true

Returns:

  • (Boolean)


108
109
110
# File 'lib/cloudfiles/connection.rb', line 108

def authok?
  @authok
end

#bytesObject

The total size in bytes under this connection



144
145
146
# File 'lib/cloudfiles/connection.rb', line 144

def bytes
  get_info[:bytes]
end

#cfreq(method, server, path, port, scheme, headers = {}, data = nil, attempts = 0, &block) ⇒ Object

This method actually makes the HTTP calls out to the server



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/cloudfiles/connection.rb', line 271

def cfreq(method, server, path, port, scheme, headers = {}, data = nil, attempts = 0, &block) # :nodoc:
  start = Time.now
  headers['Transfer-Encoding'] = "chunked" if data.is_a?(IO)
  hdrhash = headerprep(headers)
  start_http(server, path, port, scheme, hdrhash)
  request = Net::HTTP.const_get(method.to_s.capitalize).new(path, hdrhash)
  if data
    if data.respond_to?(:read)
      request.body_stream = data
    else
      request.body = data
    end
    unless data.is_a?(IO)
      request.content_length = data.respond_to?(:lstat) ? data.stat.size : data.size
    end
  else
    request.content_length = 0
  end
  response = @http[server].request(request, &block)
  raise CloudFiles::Exception::ExpiredAuthToken if response.code == "401"
  response
rescue Errno::EPIPE, Timeout::Error, Errno::EINVAL, EOFError, IOError
  # Server closed the connection, retry
  raise CloudFiles::Exception::Connection, "Unable to reconnect to #{server} after #{count} attempts" if attempts >= 5
  attempts += 1
  begin
    @http[server].finish
  rescue
    nil
  end
  start_http(server, path, port, scheme, headers)
  retry
rescue ExpiredAuthTokenException
  raise CloudFiles::Exception::Connection, "Authentication token expired and you have requested not to retry" if @retry_auth == false
  CloudFiles::Authentication.new(self)
  retry
end

#container(name) ⇒ Object Also known as: get_container

Returns an CloudFiles::Container object that can be manipulated easily. Throws a NoSuchContainerException if the container doesn’t exist.

container = cf.container('test')
container.count
=> 2


123
124
125
# File 'lib/cloudfiles/connection.rb', line 123

def container(name)
  CloudFiles::Container.new(self, name)
end

#container_exists?(containername) ⇒ Boolean

Returns true if the requested container exists and returns false otherwise.

cf.container_exists?('good_container')
=> true

cf.container_exists?('bad_container')
=> false

Returns:

  • (Boolean)


210
211
212
213
# File 'lib/cloudfiles/connection.rb', line 210

def container_exists?(containername)
  response = cfreq("HEAD", @storagehost, "#{@storagepath}/#{CloudFiles.escape containername}", @storageport, @storagescheme)
  return (response.code == "204")? true : false ;
end

#containers(limit = 0, marker = "") ⇒ Object Also known as: list_containers

Gathers a list of the containers that exist for the account and returns the list of container names as an array. If no containers exist, an empty array is returned. Throws an InvalidResponseException if the request fails.

If you supply the optional limit and marker parameters, the call will return the number of containers specified in limit, starting after the object named in marker.

cf.containers
=> ["backup", "Books", "cftest", "test", "video", "webpics"]

cf.containers(2,'cftest')
=> ["test", "video"]


165
166
167
168
169
170
171
172
173
# File 'lib/cloudfiles/connection.rb', line 165

def containers(limit = 0, marker = "")
  query = []
  query << "limit=#{CloudFiles.escape limit.to_s}" if limit.to_i > 0
  query << "marker=#{CloudFiles.escape marker.to_s}" unless marker.to_s.empty?
  response = cfreq("GET", @storagehost, "#{@storagepath}?#{query.join '&'}", @storageport, @storagescheme)
  return [] if (response.code == "204")
  raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "200")
  CloudFiles.lines(response.body)
end

#containers_detail(limit = 0, marker = "") ⇒ Object Also known as: list_containers_info

Retrieves a list of containers on the account along with their sizes (in bytes) and counts of the objects held within them. If no containers exist, an empty hash is returned. Throws an InvalidResponseException if the request fails.

If you supply the optional limit and marker parameters, the call will return the number of containers specified in limit, starting after the object named in marker.

cf.containers_detail
=> { "container1" => { :bytes => "36543", :count => "146" },
     "container2" => { :bytes => "105943", :count => "25" } }


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/cloudfiles/connection.rb', line 186

def containers_detail(limit = 0, marker = "")
  query = ['format=xml']
  query << "limit=#{CloudFiles.escape limit.to_s}" if limit.to_i > 0
  query << "marker=#{CloudFiles.escape marker.to_s}" unless marker.to_s.empty?
  response = cfreq("GET", @storagehost, "#{@storagepath}?#{query.join '&'}", @storageport, @storagescheme)
  return {} if (response.code == "204")
  raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "200")
  doc = REXML::Document.new(response.body)
  detailhash = {}
  doc.elements.each("account/container/") { |c|
    detailhash[c.elements["name"].text] = { :bytes => c.elements["bytes"].text, :count => c.elements["count"].text  }
  }
  doc = nil
  return detailhash
end

#countObject

The total number of containers under this connection



149
150
151
# File 'lib/cloudfiles/connection.rb', line 149

def count
  get_info[:count]
end

#create_container(containername) ⇒ Object

Creates a new container and returns the CloudFiles::Container object. Throws an InvalidResponseException if the request fails.

Slash (/) and question mark (?) are invalid characters, and will be stripped out. The container name is limited to 256 characters or less.

container = cf.create_container('new_container')
container.name
=> "new_container"

container = cf.create_container('bad/name')
=> SyntaxException: Container name cannot contain the characters '/' or '?'


227
228
229
230
231
232
233
# File 'lib/cloudfiles/connection.rb', line 227

def create_container(containername)
  raise CloudFiles::Exception::Syntax, "Container name cannot contain the characters '/' or '?'" if containername.match(/[\/\?]/)
  raise CloudFiles::Exception::Syntax, "Container name is limited to 256 characters" if containername.length > 256
  response = cfreq("PUT", @storagehost, "#{@storagepath}/#{CloudFiles.escape containername}", @storageport, @storagescheme)
  raise CloudFiles::Exception::InvalidResponse, "Unable to create container #{containername}" unless (response.code == "201" || response.code == "202")
  CloudFiles::Container.new(self, containername)
end

#delete_container(containername) ⇒ Object

Deletes a container from the account. Throws a NonEmptyContainerException if the container still contains objects. Throws a NoSuchContainerException if the container doesn’t exist.

cf.delete_container('new_container')
=> true

cf.delete_container('video')
=> NonEmptyContainerException: Container video is not empty

cf.delete_container('nonexistent')
=> NoSuchContainerException: Container nonexistent does not exist


246
247
248
249
250
251
# File 'lib/cloudfiles/connection.rb', line 246

def delete_container(containername)
  response = cfreq("DELETE", @storagehost, "#{@storagepath}/#{CloudFiles.escape containername}", @storageport, @storagescheme)
  raise CloudFiles::Exception::NonEmptyContainer, "Container #{containername} is not empty" if (response.code == "409")
  raise CloudFiles::Exception::NoSuchContainer, "Container #{containername} does not exist" unless (response.code == "204")
  true
end

#get_infoObject

Sets instance variables for the bytes of storage used for this account/connection, as well as the number of containers stored under the account. Returns a hash with :bytes and :count keys, and also sets the instance variables.

cf.get_info
=> {:count=>8, :bytes=>42438527}
cf.bytes
=> 42438527


135
136
137
138
139
140
141
# File 'lib/cloudfiles/connection.rb', line 135

def get_info
  response = cfreq("HEAD", @storagehost, @storagepath, @storageport, @storagescheme)
  raise CloudFiles::Exception::InvalidResponse, "Unable to obtain account size" unless (response.code == "204")
  @bytes = response["x-account-bytes-used"].to_i
  @count = response["x-account-container-count"].to_i
  {:bytes => @bytes, :count => @count}
end

#public_containers(enabled_only = false) ⇒ Object

Gathers a list of public (CDN-enabled) containers that exist for an account and returns the list of container names as an array. If no containers are public, an empty array is returned. Throws a InvalidResponseException if the request fails.

If you pass the optional argument as true, it will only show containers that are CURRENTLY being shared on the CDN, as opposed to the default behavior which is to show all containers that have EVER been public.

cf.public_containers
=> ["video", "webpics"]


262
263
264
265
266
267
268
# File 'lib/cloudfiles/connection.rb', line 262

def public_containers(enabled_only = false)
  paramstr = enabled_only == true ? "enabled_only=true" : ""
  response = cfreq("GET", @cdnmgmthost, "#{@cdnmgmtpath}?#{paramstr}", @cdnmgmtport, @cdnmgmtscheme)
  return [] if (response.code == "204")
  raise CloudFiles::Exception::InvalidResponse, "Invalid response code #{response.code}" unless (response.code == "200")
  CloudFiles.lines(response.body)
end

#snet?Boolean

Returns true if the library is requesting the use of the Rackspace service network

Returns:

  • (Boolean)


113
114
115
# File 'lib/cloudfiles/connection.rb', line 113

def snet?
  @snet
end