michimani.net

AWS CLI で S3 オブジェクトのメタデータを変更する

2020-07-29

AWS CLI を使って Amazon S3 に格納されているオブジェクトのメタデータを変更します。思っていた方法と違ったので、備忘録のための書き残しておきます。

目次

TL;DR

やってみる

AWS CLI のバージョンは、 v2 の現時点の最新バージョンで実行します。

$ aws --version
aws-cli/2.0.35 Python/3.7.4 Darwin/19.5.0 botocore/2.0.0dev39

対象のオブジェクトを追加

まずはメタデータを変更する対象となるオブジェクトを追加します。ファイルは何でも良いので、今回は下記のような JSON ファイルを追加します。

$ cat sample.json | jq .
{
  "message": "AWS CLI ha iizo"
}

今回の対象バケット名は s3-metadata-test-michimani とします。

$ aws s3 cp ./sample.json s3://s3-metadata-test-michimani/sample.json
upload: ./sample.json to s3://s3-metadata-test-michimani/sample.json

ちなみに s3 コマンドは S3 に対する API 高レベルで抽象化したコマンドで、今回のようにバケットにオブジェクトを追加したり、逆にローカルにオブジェクトをコピーしてきたりする場合には楽に使えます。

$ aws s3 help

NAME
       s3 -

DESCRIPTION
       This  section  explains  prominent concepts and notations in the set of
       high-level S3 commands provided.

オブジェクトの情報確認

オブジェクトの追加ができたら、現時点でのオブジェクトの情報を確認します。確認には、 s3api head-object コマンドを使います。

$ aws s3api head-object \
--bucket s3-metadata-test-michimani \
--key sample.json
{
    "AcceptRanges": "bytes",
    "LastModified": "2020-07-28T22:30:41+00:00",
    "ContentLength": 35,
    "ETag": "\"6f1d414f6389f754c0a93fab4727f2d9\"",
    "ContentType": "application/json",
    "Metadata": {}
}

s3api コマンドは先程の s3 コマンドとは違い、 S3 に対する操作を行う各 API を実行するコマンドになっています。 S3 を操作するコマンドにはもう一つ s3control コマンドがありますが、このコマンドではバッチオペレーションやアクセスポイントに関する操作を実行することができます。

メタデータの更新

では、先程追加したオブジェクトに対してメタデータの更新 (追加・削除) を実行してみます。
なお、 AWS CLI では S3 オブジェクトに対してメタデータを更新 (追加・削除) する update-metadata みたいなコマンドはありません。なので、 s3api copy-object コマンドを使います。

$ aws s3api copy-object help
...
SYNOPSIS
            copy-object
          [--acl <value>]
          --bucket <value>
          [--cache-control <value>]
          [--content-disposition <value>]
          [--content-encoding <value>]
          [--content-language <value>]
          [--content-type <value>]
          --copy-source <value>
          [--copy-source-if-match <value>]
          [--copy-source-if-modified-since <value>]
          [--copy-source-if-none-match <value>]
          [--copy-source-if-unmodified-since <value>]
          [--expires <value>]
          [--grant-full-control <value>]
          [--grant-read <value>]
          [--grant-read-acp <value>]
          [--grant-write-acp <value>]
          --key <value>
          [--metadata <value>]
          [--metadata-directive <value>]
          [--tagging-directive <value>]
          [--server-side-encryption <value>]
          [--storage-class <value>]
          [--website-redirect-location <value>]
          [--sse-customer-algorithm <value>]
          [--sse-customer-key <value>]
          [--sse-customer-key-md5 <value>]
          [--ssekms-key-id <value>]
          [--ssekms-encryption-context <value>]
          [--copy-source-sse-customer-algorithm <value>]
          [--copy-source-sse-customer-key <value>]
          [--copy-source-sse-customer-key-md5 <value>]
          [--request-payer <value>]
          [--tagging <value>]
          [--object-lock-mode <value>]
          [--object-lock-retain-until-date <value>]
          [--object-lock-legal-hold-status <value>]
          [--cli-input-json | --cli-input-yaml]
          [--generate-cli-skeleton <value>]
          [--cli-auto-prompt <value>]

バケット名、コピー元オブジェクト、コピー先オブジェクトが必須オプションになっています。メタデータを更新 (追加・削除) する場合は、 --cache-control--metadata オプションに加えて --metadata-directive オブションを使って実行します。

CacheControl の追加

まずはキャッシュに関するメタデータを追加してみます。

$ aws s3api copy-object \
--bucket s3-metadata-test-michimani \
--copy-source s3-metadata-test-michimani/sample.json \
--key sample.json \
--cache-control "public, max-age=31536000" \
--metadata-directive REPLACE

オプションの指定で注意したいのは、 --copy-source オプションで指定する値には バケット名も含める必要がある 点です。

また、 --metadata-directive を指定しないと、下記のようなエラーになります。

An error occurred (InvalidRequest) when calling the CopyObject operation: This copy request is illegal because it is trying to copy an object to itself without changing the object’s metadata, storage class, website redirect location or encryption attributes.

--metadata-directive オプションに対する値は COPY または REPLACE を指定します。

--metadata-directive (string)
Specifies whether the metadata is copied from the source  object  or
replaced with metadata provided in the request.

Possible values:

o COPY

o REPLACE

REPLACE を指定すると、 copy-object 実行時に指定したメタデータで上書きすることができます。この 上書き には注意が必要なので、これについては後ほど書きます。


では、念のためメタデータが追加できたか確認してみます。

$ aws s3api head-object \
--bucket s3-metadata-test-michimani \
--key sample.json
{
    "AcceptRanges": "bytes",
    "LastModified": "2020-07-28T22:56:15+00:00",
    "ContentLength": 35,
    "ETag": "\"6f1d414f6389f754c0a93fab4727f2d9\"",
    "CacheControl": "public, max-age=31536000",
    "ContentType": "binary/octet-stream",
    "Metadata": {}
}

CacheControl のメタデータが追加されています。

カスタムメタデータを追加する

次に、先程の CacheControl加えて ユーザ独自のカスタムメタデータを追加してみます。カスタムメタデータを追加する場合は、 --metadata オプションでキーと値を指定します。

今回は、 stage というキーで dev という値を持つメタデータを追加してみます。

$ aws s3api copy-object \
--bucket s3-metadata-test-michimani \
--copy-source s3-metadata-test-michimani/sample.json \
--key sample.json \
--metadata stage=dev \
--metadata env=dev,env-name=development
{
    "CopyObjectResult": {
        "ETag": "\"6f1d414f6389f754c0a93fab4727f2d9\"",
        "LastModified": "2020-07-28T23:06:06+00:00"
    }
}

確認してみます。

$ aws s3api head-object \
--bucket s3-metadata-test-michimani \
--key sample.json
{
    "AcceptRanges": "bytes",
    "LastModified": "2020-07-28T23:11:08+00:00",
    "ContentLength": 35,
    "ETag": "\"6f1d414f6389f754c0a93fab4727f2d9\"",
    "ContentType": "binary/octet-stream",
    "Metadata": {
        "env": "dev",
        "env-name": "development"
    }
}

カスタムメタデータは正しく追加されましたが、先程追加した CacheControl が削除されてしまいました。これは --metadata-directive REPLACE を指定したために元のメタデータを上書きするからです。

元のメタデータを保持したまま別のメタデータを追加する場合には、あらためて元のメタデータも指定する必要があるようです。

$ aws s3api copy-object \
--bucket s3-metadata-test-michimani \
--copy-source s3-metadata-test-michimani/sample.json \
--key sample.json \
--cache-control "public, max-age=31536000" \
--metadata-directive REPLACE \
--metadata env=dev,env-name=development
{
    "CopyObjectResult": {
        "ETag": "\"6f1d414f6389f754c0a93fab4727f2d9\"",
        "LastModified": "2020-07-28T23:23:22+00:00"
    }
}

確認してみます。

$ aws s3api head-object \
--bucket s3-metadata-test-michimani \
--key sample.json
{
    "AcceptRanges": "bytes",
    "LastModified": "2020-07-28T23:23:22+00:00",
    "ContentLength": 35,
    "ETag": "\"6f1d414f6389f754c0a93fab4727f2d9\"",
    "CacheControl": "public, max-age=31536000",
    "ContentType": "binary/octet-stream",
    "Metadata": {
        "env": "dev",
        "env-name": "development"
    }
}

無事にメタデータを追加することができました。

--metadata オプションでは、上記のように キー=値 という形式で指定する他、 JSON 形式でも指定できます。

--metadata (map)
  A map of metadata to store with the object in S3.

  key -> (string)

  value -> (string)

Shorthand Syntax:

  KeyName1=string,KeyName2=string

JSON Syntax:

  {"string": "string"
    ...}

メタデータの削除

メタデータを削除する場合は、削除したいメタデータを 指定せずに a3api copy-object コマンドを実行します。

例えば、 カスタムメタデータの stage-name を削除したい場合、次のように実行します。

$ aws s3api head-object \
--bucket s3-metadata-test-michimani \
--key sample.json
{
    "AcceptRanges": "bytes",
    "LastModified": "2020-07-28T23:25:14+00:00",
    "ContentLength": 35,
    "ETag": "\"6f1d414f6389f754c0a93fab4727f2d9\"",
    "CacheControl": "public, max-age=31536000",
    "ContentType": "binary/octet-stream",
    "Metadata": {
        "env": "dev"
    }
}

削除 というよりは、やはり 上書き という意識で実行するのが良さそうです。

まとめ

AWS CLI を使って Amazon S3 に格納されているオブジェクトのメタデータを変更してみた話でした。

やる前には、 update-metadataput-metadata みたいなコマンドがあってそれを使えばいいと思っていましたが、そうではなかったようです。追加や削除をする場合でも、コピーして 上書きする というのがポイントかなと思いました。


comments powered by Disqus