S3バケットのファイルをaws s3 cp s3://<<バケット名>> <<ダウンロードディレクトリ>> --recursive
と再帰的にダウンロードしようとした際に、オブジェクトキーにコロン(:)
が含まれていてうまくダウンロードできなかった話。
これは後述するWindowsで利用できない文字 かつ S3のオブジェクトキーで利用が推奨されていない文字である コロン(:)
が悪さをしていたケースとなります。
本記事ではコロン等がありWIndowsでは一括でローカルにダウンロードできなかった際の対策をPowerShellで書いてみました。
Windowsではファイルに利用できない文字がある
Windows
ではファイルに利用できない文字が色々とありますが、コロン(:)
はその中の一文字です。
ちなみにWindows
で利用できない名前は下記Path
クラスのGetInvalidFileNameChars
メソッドで取得できます。
Path.GetInvalidFileNameChars Method
S3ではオブジェクトキーの命名についてと非推奨の文字がある
S3ではバケット内のオブジェクトを一意に識別する要素としてオブジェクトキーがありますが。
このオブジェクトキーについて、AWSドキュメントでは上記のようにガイドラインと非推奨な文字が記載されています。
Windowsでは利用できないコロン(:)
について、非推奨とはなっていますが。
あくまで非推奨のためオブジェクトキーとしては利用できます。
Windowsでは利用できない文字が、S3のオブジェクトキーにあるとどうなるか
上記のような差異があるため、S3のオブジェクトキーにWindowsの駄目文字を含んでいる場合に、Windows上でaws cli
にて該当ファイルを含むS3バケットを'sync'だったり、cp
に--recursive
オプションをつけて一括ダウンロードしようとした場合。
オブジェクトキーに含まれる駄目文字がネックになってダウンロードが失敗します。
ファイル名にWindowsの駄目文字が含まれているだけなので、ダウンロード先の指定でコロンを抜いたファイル名にすれば問題なくダウンロードできます。
# 下記はコマンドではfoo:bar.txtというファイルを作成しようとしてエラー
# $lastexitcodeが1で終了します
aws cp s3://<<バケット名>>/foo:bar.txt ./
#下記はダウンロード先をfoo_bar.txtという文字に変えているのでダウンロードOK
aws cp s3://<<バケット名>>/foo:bar.txt .foo_bar.txt
ダウンロード対象のファイル名が少ない場合は、1ファイルずつリネームしながらダウンロードすれば問題ありませんが、対象が多い場合面倒です。
今回駄目だったケースについて
回避策の前に、今回駄目だったケースについて。
基本はコロンのような非推奨な制約のある文字をS3のオブジェクトキーに使わないようにするのが一番の解決策かとは思います。
が、そもそも今回問題となったケースについて。
今回、一括でダウンロードしたかったバケットはAWS Backup
の標準機能 Backup Audit Manager
でAWS Bakup
のバックアップ結果をS3にレポート出力しているバケットでした。
Backup Audit Manager
ではS3に保管するオブジェクトキーに日付情報が含まれていますが、日付情報がISO 8601となっており、このため出力されるオブジェクトキーにコロンが含まれてしまいます。
AWS BackupAudit Managerとバックアップの監査およびレポートの作成をする
上記画像をみると、出力されたレポートのオブジェクトキーにコロンが含まれている事がわかります。
このため、このままの状態でダウンロード先を変更しないでaws-cli
コマンドでダウンロードするとエラーになります。
なお、マネジメントコンソール上からこのファイルをダウンロードした場合は、コロン
が_
に置換されてダウンロードされる動作となっていました。
PowerShellでダウンロード先の駄目文字を置換しながら一括ダウンロードする
ファイルの数がそこそこあったのでPowerShellで下記のように記述して一括してダウンロードしてみました。
$bucketName = '<<バケット名>>'
$directory = 'c:\temp\backup_report'
# s3バケットのオブジェクトキー一覧をリスト
$s3ObjectKeys = aws s3api list-objects --bucket $bucketName --output text --query "Contents[].{Key:Key}"
foreach ( $s3ObjectKey in $s3ObjectKeys ) {
$source = "s3://{0}/{1}" -f $bucketName , $s3ObjectKey
# 駄目文字をリプレイス(ディレクトリ構造は残したいので/はリプレイス対象から除外)
$replaceS3ObjectKey = [RegEx]::Replace($source, "[{0}]" -f [RegEx]::Escape(([string][System.IO.Path]::GetInvalidFileNameChars() -replace '/' , '')) , '')
$destinationPath = Join-Path -Path $directory -ChildPath $replaceS3ObjectKey
# s3 cpでダウンロード
aws s3 cp $source $destinationPath
}
総評
バケットを一括ダウンロードしようとしてファイルが保存されず、最初は訳がわかりませんでしたが。
--debug
をオプションをつけて実行し、結果を眺めていると、これはコロンが不味そうだとわかりました。
検索すると下記のissueがありました。
Can't sync to Windows when colon in file name (cont..) #5813
AWS標準機能を用いて出力したレポートのオブジェクトキーに非推奨のコロンが入っているのはちょっと残念な気はしますが。