はじめに
以前、Amazon S3に何かをコピーするときに、すでに同じものをコピー済みかどうかをチェックするシェル関数 という記事を上げましたが、リファクタして以下に行きつきました。
If-None-Match を使えばスッキリ
ETagでリソースのハッシュを返してくれるWEBサーバーならば、リクエストに比較対象のハッシュ値を指定したIf-None-Match
ヘッダを付加すると、WEBサーバー側にあるリソースのハッシュと同じであれば、304 Not Modified
を返してくれる(はず)。これを使います。
#!/bin/bash
#
# get_status_If_None_Match
#
# パラメータ:
#
# $1: サーバーにあるものと同一かどうかを判定するファイルのパス
# (例: /var/contents/sports/baseball/20160807-001.mov)
#
# $2: 上記のファイルがサーバーに上がっている場合のURL
# (例: http://hoge-journal.s3.amazonaws.com/sports/baseball/20160807-001.mov)
#
function get_status_If_None_Match() {
curl -s -I -o /dev/null $2 \
--header "If-None-Match: \"`openssl md5 $1 | awk '{print $2}'`\"" \
-w '%{http_code}'
}
この関数は、$1
と$2
の状態をWEBサーバが適切に判断して、レスポンスのステータスコードに反映することを前提に、以下の値を出力することを想定しています。
$1と$2の状態 | 値 |
---|---|
$2 が示すリソースは$1 で指定したファイルと同一 |
304 |
$2 が示すリソースは$1 で指定したファイルと異なる。 |
200 |
$2 で指定したリソースは存在しない。(ので使用不可) |
404(403) |
使用例
元記事の例にこの関数を使うとすると
if [ $((`get_status_If_None_Match ${FILE_PATH} ${S3_URL}`)) -ne 304 ]; then
aws s3 cp ${FILE_PATH} ${S3_BUCKET_PATH} --acl public-read
fi
とすればよい。
参考
- wikipedia HTTP ETag
追記
以下の部分は、さらにコードを短くできる。
openssl md5 $1 | awk '{print $2}'
上記は、md5
コマンドが使えるのなら、これを-q
(quiet)オプションとともに使って、
md5 -q $1
で代替可能