Home > Mobile >  AWS Ruby bindings not at parity with AWS CLI for S3?
AWS Ruby bindings not at parity with AWS CLI for S3?

Time:05-05

I want to set be able to set metadata on more than 50 files stored in an S3 bucket, but the AWS CLI does not directly support simply changing metadata. The purpose of the metadata is to cause an HTTP 301 Redirect to be issued when a web browser requests those files. Only 50 rules are allowed per bucket, so per-object metadata must be applied, instead of writing rules in XML or JSON.

The AWS CLI only supports setting metadata during a copy; this deficiency of the AWS CLI and SDKs is unfortunate, but the REST interface that underlies all the language bindings apparently does not provide the facility. I have seen several ways of performing copies, including (re)copying a file on top of itself and setting the metadata during the copy.

Here is one such way, which (re)copies old_file.html to an S3 bucket and sets the desired metadata (a header that causes an HTTP 301 Redirect):

$ aws s3 cp \
  old_file.html \
  s3://bucket_name/old_file.html \
  --website-redirect /new_file.html

Awkward, but workable. If CloudFront is employed, a cache invalidation will be required before the 301 redirect will actually be sent to the web browser:

$ aws cloudfront create-invalidation \
  --distribution-id "$AWS_CLOUDFRONT_DIST_ID" \
  --paths "old_file.html"

No problem there. A little patience for the invalidation to happen, and the redirect eventually works.

Things appear to get harder when using the Ruby v3 binding. Seems there is no direct analog for the above awkwardness.

Suggestions for equivalent Ruby code? I could of course shell out from Ruby and invoke the AWS CLI (and I will do that if I must ), but that feels like cheating.

CodePudding user response:

The AWS docs sometimes explain things in ways that are more complicated than necessary. This is all that is required to upload a local file (old_path) to a bucket, and redirect requests for that file to another file (new_path), which was previously uploaded.

def redirect(bucket, old_path, new_path)
  s3 = Aws::S3::Client.new
  s3.put_object({
    body: IO.read(old_path),
    bucket: bucket,
    key: old_path,
    website_redirect_location: new_path,
  })
end

The code assumes that ~/.aws/config exists. Otherwise, Aws::S3::Client.new will raise an exception.

I wrote about this in detail on my blog.

  • Related