Last active
January 8, 2025 14:04
-
-
Save libkazz/8d6ad4d315440118938f358ca839485d to your computer and use it in GitHub Desktop.
S3 バージョニングをつかって誤って削除/更新したファイルを戻す
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'json' | |
| class Revert | |
| attr_reader :uploaded_files, :deleted_files, :bucket_name | |
| # S3 のバージョニングからファイルを復旧させる | |
| # NOTE: 更新していないファイルを指定しても1つバージョンを戻してしまうことに注意 | |
| # | |
| # - 誤って更新してしまったファイルを直前のバージョンに戻す | |
| # - 誤って削除してしまったファイルを戻す | |
| # | |
| def self.run(uploaded_files: [], deleted_files: [], bucket_name:) | |
| new(bucket_name: bucket_name) | |
| .execute(uploaded_files: uploaded_files, deleted_files: deleted_files) | |
| end | |
| def initialize(bucket_name:) | |
| @bucket_name = bucket_name | |
| end | |
| def execute(uploaded_files: [], deleted_files: []) | |
| uploaded_files.each do |path| | |
| revert_to_previous_version!(path) | |
| end | |
| deleted_files.each do |path| | |
| restore_deleted!(path) | |
| end | |
| end | |
| def revert_to_version!(path, version) | |
| command = "aws s3api copy-object " \ | |
| + "--bucket #{bucket_name} " \ | |
| + "--copy-source #{bucket_name}/#{path}?versionId=#{version} " \ | |
| + "--key #{path}" | |
| system(command) | |
| puts "Revert: #{path} (#{version})" | |
| end | |
| # 1つ前のバージョンに戻す | |
| def revert_to_previous_version!(path) | |
| version = previous_version(path) | |
| return nil unless version | |
| revert_to_version!(path, version) | |
| end | |
| # 削除フラグを削除してファイルを復旧する | |
| def restore_deleted!(path) | |
| version = delete_marker_version(path) | |
| command = "aws s3api delete-object --bucket #{bucket_name} --key #{path} --version-id #{version}" | |
| system(command) | |
| puts "Restore: #{path} (#{version})" | |
| end | |
| def previous_version(path) | |
| command = "aws s3api list-object-versions --bucket '#{bucket_name}' --prefix #{path} " | |
| # + "--query 'Versions[].[Key, VersionId, IsLatest]'" | |
| response = JSON.parse(`#{command}`) | |
| previous = response["Versions"] | |
| .select { !_1["IsLatest"] } | |
| .sort_by { _1["LastModified"] } | |
| .last | |
| # previous がない場合は nil を返す | |
| previous&.fetch("VersionId") | |
| end | |
| def delete_marker_version(path) | |
| command = "aws s3api list-object-versions --bucket '#{bucket_name}' --prefix #{path}" | |
| response = JSON.parse(`#{command}`) | |
| delete_markers = response["DeleteMarkers"] | |
| delete_markers.detect { _1["IsLatest"] }["VersionId"] | |
| end | |
| end | |
| if __FILE__ == $PROGRAM_NAME | |
| bucket_name = "localworks.jp" | |
| uploaded_files = File.readlines("hoge2-upload.txt") | |
| .reject { _1.start_with?('#') } | |
| .map do |line| | |
| line | |
| .chomp | |
| .sub(%r{\A.*s3://localworks.jp/}, "") | |
| .sub(/ +$/, "") | |
| end | |
| deleted_files = File.readlines("hoge2-delete.txt") | |
| .reject { _1.start_with?('#') } | |
| .map do |line| | |
| line | |
| .chomp | |
| .sub(%r{\A.*s3://localworks.jp/}, "") | |
| .sub(/ +$/, "") | |
| end | |
| Revert | |
| .new(bucket_name: bucket_name) | |
| .execute(uploaded_files: uploaded_files, deleted_files: deleted_files) | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment