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.



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

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

Instance Attribute Details

#accessObject

Amazon keys.



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

def access
  @access
end

#canned_aclObject

Default canned ACL string to apply to all put requests.



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

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.



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

def expires
  @expires
end

#secretObject

Amazon keys.



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

def secret
  @secret
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.



46
47
48
49
50
# File 'lib/s33r/client.rb', line 46

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)


226
227
228
229
# File 'lib/s33r/client.rb', line 226

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

#bucket_namesObject

Just get a sorted array of names of buckets.



123
124
125
# File 'lib/s33r/client.rb', line 123

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.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/s33r/client.rb', line 99

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.



340
341
342
343
344
345
346
347
# File 'lib/s33r/client.rb', line 340

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.



145
146
147
148
# File 'lib/s33r/client.rb', line 145

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.



216
217
218
219
220
221
222
223
# File 'lib/s33r/client.rb', line 216

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.



297
298
299
300
301
302
303
304
305
# File 'lib/s33r/client.rb', line 297

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)


134
135
136
137
138
139
140
141
142
# File 'lib/s33r/client.rb', line 134

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.



206
207
208
209
# File 'lib/s33r/client.rb', line 206

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



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/s33r/client.rb', line 175

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.)



354
355
356
357
358
359
360
361
362
363
# File 'lib/s33r/client.rb', line 354

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.



395
396
397
398
# File 'lib/s33r/client.rb', line 395

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



376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/s33r/client.rb', line 376

def logs_to(target_bucket, options={})
  target_bucket_name = target_bucket.is_a?(Bucket) ? target_bucket.name : target_bucket
  log_prefix = options[:prefix] || "log-#{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



326
327
328
# File 'lib/s33r/client.rb', line 326

def make_private
  set_acl(get_acl().remove_public_read_grant)
end

#make_publicObject

Make a resource public



321
322
323
# File 'lib/s33r/client.rb', line 321

def make_public
  set_acl(get_acl().add_public_read_grant)
end

#public?(options = {}) ⇒ Boolean

Is a resource public?

Returns:

  • (Boolean)


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

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



249
250
251
252
253
254
255
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
# File 'lib/s33r/client.rb', line 249

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).



291
292
293
294
# File 'lib/s33r/client.rb', line 291

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.



24
25
26
27
28
29
30
31
32
# File 'lib/s33r/client.rb', line 24

def request_defaults
  defaults = {}
  defaults[:use_ssl] = @use_ssl
  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.



309
310
311
312
# File 'lib/s33r/client.rb', line 309

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.

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.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/s33r/client.rb', line 73

def set_options(options={})
  # General client options.
  @access = options[:access]
  @secret = options[:secret]
  @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.



35
36
37
38
# File 'lib/s33r/client.rb', line 35

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.



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

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