Class: S33r::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/s33r/client.rb

Overview

Use this class to do operations on the Service, e.g. creating buckets, deleting buckets, listing all buckets, returning a single bucket.

Direct Known Subclasses

Bucket, S3Object

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Client

Create a plain Client.



45
46
47
# File 'lib/s33r/client.rb', line 45

def initialize(options={})
  set_options(options)
end

Instance Attribute Details

#accessObject

Amazon keys.



24
25
26
# File 'lib/s33r/client.rb', line 24

def access
  @access
end

#canned_aclObject

Default canned ACL string to apply to all put requests.



21
22
23
# File 'lib/s33r/client.rb', line 21

def canned_acl
  @canned_acl
end

#created_with_optionsObject (readonly)

Options used to create this Client.



7
8
9
# File 'lib/s33r/client.rb', line 7

def created_with_options
  @created_with_options
end

#expiresObject

Default expiry for authenticated URLs.



18
19
20
# File 'lib/s33r/client.rb', line 18

def expires
  @expires
end

#secretObject

Amazon keys.



24
25
26
# File 'lib/s33r/client.rb', line 24

def secret
  @secret
end

#subdomainObject

Use subdomains (set on host header)



15
16
17
# File 'lib/s33r/client.rb', line 15

def subdomain
  @subdomain
end

#use_sslObject

Use SSL for requests.



12
13
14
# File 'lib/s33r/client.rb', line 12

def use_ssl
  @use_ssl
end

Class Method Details

.init(yaml_file) ⇒ Object

Setup a client from a YAML file.



50
51
52
53
54
# File 'lib/s33r/client.rb', line 50

def self.init(yaml_file)
  config, options = S33r.load_config(yaml_file)
  config.merge!(options)
  self.new(config)
end

Instance Method Details

#bucket_exists?(name, options = {}) ⇒ Boolean

Check whether a bucket exists on S3.

Returns:

  • (Boolean)


233
234
235
236
# File 'lib/s33r/client.rb', line 233

def bucket_exists?(name, options={})
  options[:bucket] = name
  do_head(options).ok?
end

#bucket_namesObject

Just get a sorted array of names of buckets.



130
131
132
# File 'lib/s33r/client.rb', line 130

def bucket_names
  buckets.keys.sort
end

#buckets(options = {}) ⇒ Object Also known as: list_buckets

List all buckets.

Returns an array of Bucket instances; array will be empty if the BucketListing parse fails for any reason (i.e. no <Bucket> elements occur in it).

options is passed through to get_bucket, making it possible to detach retrieved buckets from the Client instance, and to pass other options to the bucket.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/s33r/client.rb', line 106

def buckets(options={})
  resp = do_get
  
  bucket_list_xml = resp.body
  doc = XML.get_xml_doc(S33r.remove_namespace(bucket_list_xml))
  
  buckets = {}
  
  doc.find("//Bucket").to_a.each do |node|
    bucket_name = node.xget('Name')
    if bucket_name
      # CreationDate is a string in format '2006-10-17T15:14:39.000Z'.
      creation_date = Time.parse(node.xget('CreationDate'))
      # The Bucket instances inherit the request dumping behaviour
      # of this client.
      buckets[bucket_name] = get_bucket(bucket_name, options)
    end
  end
  
  buckets
end

#change_log_target_status(bucket_name, state = :on) ⇒ Object

Change the status of a bucket for logging.

logging_on = :on to turn logging on (default), :off to turn logging off.



347
348
349
350
351
352
353
354
# File 'lib/s33r/client.rb', line 347

def change_log_target_status(bucket_name, state=:on)
  logging_on = (:on == state)
  bucket = get_bucket(bucket_name)
  policy = bucket.acl
  logging_on ? policy.add_log_target_grants : policy.remove_log_target_grants
  bucket.acl = policy
  logging_on == policy.log_targetable?
end

#create_bucket(name, options = {}) ⇒ Object

Create a new Bucket.



152
153
154
155
# File 'lib/s33r/client.rb', line 152

def create_bucket(name, options={})
  options[:create] = true
  get_bucket(name, options)
end

#delete_bucket(bucket_name, options = {}) ⇒ Object

  • :escape => true: CGI::escape keys when they are appended to the path.



223
224
225
226
227
228
229
230
# File 'lib/s33r/client.rb', line 223

def delete_bucket(bucket_name, options={})
  options[:bucket] = bucket_name
  if options[:force]
    options[:escape] = true
    listing(options).keys.each { |key| do_delete(options.merge(:key => key)) }
  end
  do_delete(options).ok?
end

#get_acl(options = {}) ⇒ Object Also known as: acl

Get an ACL.



304
305
306
307
308
309
310
311
312
# File 'lib/s33r/client.rb', line 304

def get_acl(options={})
  options[:acl] = true
  resp = do_get(options)
  if resp.ok?
    S3ACL::Policy.from_xml(resp.body)
  else
    nil
  end
end

#get_bucket(bucket_name, options = {}) {|bucket| ... } ⇒ Object

Get a Client instance bound to a bucket.

options:

  • :orphan => true: create the Client in isolation from the Service and don’t inherit any of its instance settings.

Other options are passed through to Bucket.new.

Yields:

  • (bucket)


141
142
143
144
145
146
147
148
149
# File 'lib/s33r/client.rb', line 141

def get_bucket(bucket_name, options={})
  orphan = options.delete(:orphan)
  unless orphan
    options.merge!(settings) { |key, old_val, new_val| old_val }
  end
  bucket = Bucket.new(bucket_name, options)
  yield bucket if block_given?
  bucket
end

#list_bucket(bucket_name, options = {}) ⇒ Object

List content of a bucket.



213
214
215
216
# File 'lib/s33r/client.rb', line 213

def list_bucket(bucket_name, options={})
  options[:bucket] = bucket_name
  listing(options)
end

#listing(options = {}) ⇒ Object Also known as: objects

List entries in a bucket.

options: hash of options on the bucket listing request, passed as querystring parameters to S3 (see docs.amazonwebservices.com/AmazonS3/2006-03-01/).

  • :prefix => 'some_string': restrict results to keys beginning with ‘some_string’

  • :marker => 'some_string': restict results to keys occurring lexicographically after ‘some_string’

  • :max_keys => Integer: return at most this number of keys (maximum possible value is 1000)

  • :delimiter => 'some_string': keys containing the same string between prefix and the delimiter are rolled up into a CommonPrefixes element inside the response

NB if you pass a :marker, this takes up one of your :max_keys; so if you are fetching page two from a bucket, and you want 10 items, you need to set :max_keys to 11.

To page through a bucket 10 keys at a time, you can do:

listing = list_bucket('mybucket', :max_keys => 10)
listing = list_bucket('mybucket', :max_keys => 11, :marker => listing.last_key)
listing = list_bucket('mybucket', :max_keys => 11, :marker => listing.last_key)
etc.

Note in the example code, listing is a BucketListing instance; call its contents method to get a hash of the keys in the bucket, along with associated objects.

Returns BucketListing instance. – TODO: testing



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/s33r/client.rb', line 182

def listing(options={})
  querystring = options[:querystring] || {}
  
  # Check :max_keys isn't higher than the maximum allowed by S3.
  if options[:max_keys]
    max_keys = options[:max_keys].to_i
    if max_keys > BUCKET_LIST_MAX_MAX_KEYS
      raise BucketListingMaxKeysError, "max_keys option to list bucket cannot be > #{BUCKET_LIST_MAX_MAX_KEYS}"
    end
    querystring['max-keys'] = max_keys
  end
  
  ['prefix', 'marker', 'delimiter'].each do |key|
    key_sym = key.to_sym
    querystring[key] = options[key_sym] if options[key_sym]
  end
  
  options[:querystring] = querystring

  resp = do_get(options)
  
  if resp.ok?
    @listing = BucketListing.new(resp.body)
  else
    raise resp.s3_error
  end
end

#logging(options = {}) ⇒ Object

Get the logging status for a resource.

options:

  • :for_bucket => 'bucket': get the logging status for a bucket. (Alias for :bucket; if both supplied, :bucket takes preference.)



361
362
363
364
365
366
367
368
369
370
# File 'lib/s33r/client.rb', line 361

def logging(options={})
  options[:logging] = true
  options[:bucket] ||= options[:for_bucket]
  resp = do_get(options)
  if resp.ok?
    LoggingResource.from_xml(resp.body)
  else
    nil
  end
end

#logs_off(options = {}) ⇒ Object

Turn off logging for a bucket.

options:

  • :bucket => 'bucket': bucket to turn logging off for.



402
403
404
405
# File 'lib/s33r/client.rb', line 402

def logs_off(options={})
  options[:logging] = true
  put(LoggingResource.new, options)
end

#logs_to(target_bucket, options = {}) ⇒ Object

Enable logging for a bucket.

target_bucket is the target for the logs. The bucket you want to log is passed in options.

options

  • :bucket => 'bucket': bucket to log.

  • :for_bucket => 'bucket': syntactic sugar; alias for :bucket. If :bucket and :for_bucket are provided, :bucket takes preference.

  • :prefix => 'some-prefix-': specify a prefix for log files; otherwise ‘log-<bucket name>-’ is used



383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/s33r/client.rb', line 383

def logs_to(target_bucket, options={})
  target_bucket_name = target_bucket.is_a?(Bucket) ? target_bucket.name : target_bucket
  log_prefix = options[:prefix] || "log-#{target_bucket_name}-"
  options[:bucket] ||= options[:for_bucket]
  
  target_bucket_acl = get_acl(:bucket => target_bucket_name)
  unless target_bucket_acl.log_targetable?
    raise BucketNotLogTargetable, "The bucket #{target_bucket_name} cannot be specified as a log target"
  end
  
  logging_resource = LoggingResource.new(target_bucket_name, log_prefix)
  options[:logging] = true
  put(logging_resource, options)
end

#make_privateObject

Make a resource private



333
334
335
# File 'lib/s33r/client.rb', line 333

def make_private
  set_acl(get_acl().remove_public_read_grant)
end

#make_publicObject

Make a resource public



328
329
330
# File 'lib/s33r/client.rb', line 328

def make_public
  set_acl(get_acl().add_public_read_grant)
end

#public?(options = {}) ⇒ Boolean

Is a resource public?

Returns:

  • (Boolean)


323
324
325
# File 'lib/s33r/client.rb', line 323

def public?(options={})
  get_acl(options).public_readable?
end

#put(thing, options = {}, headers = {}) ⇒ Object

Put a “thing” onto S3.

thing may be a string, an S3Object, an S3ACL::Policy, a LoggingResource or a file handle.

Anything you pass in options will override any values inferred from the thing (e.g. content type, key).

options:

  • :key => 'some-key' (required unless thing is an S3Object).

  • :bucket => 'some-bucket'

  • :content_type => 'text/plain'

  • :render_as_attachment => Boolean

  • :file => true: thing is a filename, so load it as a file

  • :canned_acl => 'public': one of S33r::CANNED_ACLS, to set a canned acl on a put.

– TODO: finish documentation for options



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
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
# File 'lib/s33r/client.rb', line 256

def put(thing, options={}, headers={})
  is_file = options[:file]
  
  # thing is a file, so load it.
  if is_file and thing.is_a?(String)
    # Use the filename as the key unless it is set already.
    options[:key] ||= thing
    
    # Guess the content type unless it's been set.
    unless options[:content_type]
      mime_type = guess_mime_type(thing)
      content_type = mime_type.simplified
      options[:content_type] = content_type
    end
  elsif thing.is_a?(S3Object)
    options[:key] ||= thing.key
    data = thing.value
    options[:content_type] ||= thing.content_type
    options[:render_as_attachment] ||= thing.render_as_attachment
    headers = (thing.meta)
  elsif thing.is_a?(Policy) || thing.is_a?(LoggingResource)
    data = thing.to_xml
    options[:content_type] = 'text/xml'
  else
    data = thing
  end
  
  key = options[:key]
  
  # Headers for content type etc.
  headers.merge! content_headers(options[:content_type], key, options[:render_as_attachment])
  
  if is_file
    File.open(thing) do |data|
      do_put(data, options, headers).ok?
    end
  else
    do_put(data, options, headers).ok?
  end
end

#put_file(filename, options = {}, headers = {}) ⇒ Object

Put a file onto S3 (shortcut to put).



298
299
300
301
# File 'lib/s33r/client.rb', line 298

def put_file(filename, options={}, headers={})
  options[:file] = true
  put(filename, options, headers)
end

#request_defaultsObject

Get default options passed to every call to do_request.



27
28
29
30
31
32
33
34
35
36
# File 'lib/s33r/client.rb', line 27

def request_defaults
  defaults = {}
  defaults[:use_ssl] = @use_ssl
  defaults[:subdomain] = @subdomain
  defaults[:expires] = @expires
  defaults[:access] = @access
  defaults[:secret] = @secret
  defaults[:canned_acl] = @canned_acl
  defaults
end

#set_acl(policy, options = {}) ⇒ Object Also known as: acl=

Set an ACL.



316
317
318
319
# File 'lib/s33r/client.rb', line 316

def set_acl(policy, options={})
  options[:acl] = true
  put(policy, options)
end

#set_options(options = {}) ⇒ Object

Set options for the client.

options may include the following which alter how the Client interacts with S3; they also influence URLs you may generate from the Client:

  • :access => 'aws access key' (defaults to nil)

  • :secret => 'aws secret access key' (defaults to nil)

  • :use_ssl => false: to use plain HTTP for requests sent by this bucket (default=true). If a bucket has :use_ssl => true, any URLs you generate from it will be SSL URLs unless you explicitly disable this behaviour (see url for details).

  • :expires => <datetime specifier>: set the default value to be passed as the :expires option when generating authenticated URLs. Should be parseable by S33r.parse_expiry.

  • :canned_acl => 'public-read': set a default canned acl to apply to all put requests.

  • :subdomain => false: set to true to use subdomains in URLs

These options change the behaviour of the HTTP client which actually sends the request:

  • :chunk_size => Integer: use a non-standard chunk size; default is to use S33r::DEFAULT_CHUNK_SIZE.

  • :persistent => true: use persistent HTTP connections (default=false).

  • :dump_requests => true: to dump all request headers before the request is sent.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/s33r/client.rb', line 78

def set_options(options={})
  # General client options.
  @access = options[:access]
  @secret = options[:secret]
  @subdomain = false
  @subdomain = true if (true == options[:subdomain])
  @use_ssl = true
  @use_ssl = false if (false == options[:use_ssl])
  @expires = options[:expires] || 'never'
  @canned_acl = options[:canned_acl] || nil
  
  # Options specific to the mechanics of the HTTP request.
  @dump_requests = options[:dump_requests] || false
  @chunk_size = options[:chunk_size]
  @persistent = options[:persistent] || false
  
  @created_with_options = options
end

#settingsObject

Get the settings for this client.



39
40
41
42
# File 'lib/s33r/client.rb', line 39

def settings
  request_defaults.merge(:dump_requests => dump_requests, 
  :chunk_size => chunk_size, :persistent => persistent)
end

#url(options = {}) ⇒ Object

Get a URL for a thing.



338
339
340
341
# File 'lib/s33r/client.rb', line 338

def url(options={})
  options = request_defaults.merge(options)
  s3_url(options)
end