Closed2

Cloud Storage のバケットを空にする

ピン留めされたアイテム
HikosaburouHikosaburou

APIやライブラリを使ってCloud Storageのバケットを削除しようとすると、次のようなエラーが出ることがある:

Error: The bucket you tried to delete is not empty.

文字通りバケット内にオブジェクトが残っているからエラーになっているわけだが、コンソールでバケットの中を見ると空っぽ。こういう時はバケットのバージョニングが有効になっていて、オブジェクトの削除済みのバージョンが残っている可能性が高い。

古いバージョンのオブジェクトが残っているかどうかは gcloud storage コマンドで確かめられる。

$ gcloud storage ls -a gs://my-bucket --project=$MY_PROJECT_ID

というわけで、バケット削除をする際には、事前に「バケット内の全オブジェクトの全バージョンを削除する」処理を書くことになる。

というわけでTypeScriptでざっと書いた。

  • 「指定したオブジェクトの全バージョンを削除する」はできないようなので、「オブジェクトの全バージョンをlistで取得して逐次削除する」形になった。 objects を適当なチャンクに分けて Promise.all() で並行して削除しても良さそう。
  • objects.list() の際に versions: true のパラメータを渡すことで全バージョンが取得できる。
import { storage_v1, google } from "googleapis";

const MAX_RESULTS = 1000;
const BUCKET_NAME = 'my-bucket';

async function getAllObjectVersions({
  client,
  bucketName,
  objects = [],
  nextPageToken,
}: {
  client: storage_v1.Storage;
  bucketName: string;
  objects?: storage_v1.Schema$Object[];
  nextPageToken?: string;
}): Promise<storage_v1.Schema$Object[]> {
  const params: storage_v1.Params$Resource$Objects$List = {
    bucket: bucketName,
    maxResults: MAX_RESULTS,
    pageToken: nextPageToken,
    versions: true, // 全バージョンを取得する
  };
  const response = await client.objects.list(params);
  const concatenatedObjects = [...objects, ...response.data.items];

  if (response.data?.nextPageToken == null) return concatenatedObjects;
  return getAllObjectVersions({
    client,
    bucketName,
    objects: concatenatedObjects,
    nextPageToken: response.data.nextPageToken,
  });
}

async function main() {
  const auth = new google.auth.GoogleAuth({
    scopes: ["https://www.googleapis.com/auth/cloud-platform"],
  });
  const client = google.storage({ version: "v1", auth });
  const objects = await getAllObjectVersions({ client, bucketName: BUCKET_NAME });
  console.log(objects);

  // 逐次削除
  for (const object of objects) {
    const params: storage_v1.Params$Resource$Objects$Delete = {
      bucket: bucketName,
      object: object.name,
      generation: object.generation,
    };
    await client.objects.delete(params);
  }
}

(async () => {
  try {
    await main();
  } catch (error) {
    console.error(error);
  }
})();
このスクラップは2023/11/07にクローズされました