Desativar a exclusão reversível

Visão geral Uso

Esta página descreve como desativar o recurso de exclusão reversível em buckets novos e atuais da sua organização.

A exclusão reversível é ativada em buckets novos por padrão para evitar a perda de dados. Quando necessário, é possível desativar a exclusão reversível para buckets atuais modificando a política de exclusão reversível. Também é possível desativá-la por padrão para novos buckets definindo uma tag padrão em toda a organização. Depois que você desativa a exclusão reversível, os dados excluídos não podem ser recuperados, incluindo exclusões acidentais ou maliciosas.

Funções exigidas

Para receber as permissões necessárias e desativar a exclusão reversível, peça ao administrador para conceder a você os seguintes papéis do IAM no nível da organização:

Esses papéis predefinidos contêm as permissões necessárias para desativar a exclusão reversível. Para conferir as permissões exatas necessárias, expanda a seção Permissões necessárias:

Permissões necessárias

As seguintes permissões são necessárias para desativar a exclusão reversível:

  • storage.buckets.get
  • storage.buckets.update
  • storage.buckets.list (essa permissão é necessária se você planeja usar o console do Google Cloud para executar as instruções desta página)

    Para saber mais sobre as permissões necessárias que fazem parte do papel de administrador de tags(roles/resourcemanager.tagAdmin), consulte Permissões necessárias para administrar tags.

Para informações sobre como conceder papéis, consulte Usar o IAM com buckets ou Gerenciar o acesso a projetos.

Desativar a exclusão reversível de um bucket específico

Antes de começar, considere os itens a seguir:

  • Se você desativar uma política de exclusão reversível de um bucket que tenha objetos excluídos de maneira reversível durante o período de desativação, os objetos excluídos de maneira reversível serão mantidos até que a duração de retenção aplicada anteriormente expire.

  • Depois de desativar uma política de exclusão reversível no bucket, o Cloud Storage não retém os objetos recém-excluídos.

Use as instruções a seguir para desativar a exclusão reversível em um bucket específico:

Console

  1. No Console do Google Cloud, acesse a página Buckets do Cloud Storage.

    Acessar buckets

  2. Na lista de buckets, clique no nome do bucket com a política de exclusão reversível que você quer desativar.

  3. Clique na guia Proteção.

  4. Na seção Política de exclusão reversível, clique em Desativar para desativar a política de exclusão reversível.

  5. Clique em Confirmar.

Para saber como acessar informações detalhadas de erro sobre operações do Cloud Storage com falha no console do Google Cloud, consulte Solução de problemas.

Linha de comando

Execute o comando gcloud storage buckets update com a flag --clear-soft-delete:

gcloud storage buckets update --clear-soft-delete gs://BUCKET_NAME

Em que:

  • BUCKET_NAME é o nome do bucket. Por exemplo, my-bucket.

APIs REST

API JSON

  1. Ter a CLI gcloud instalada e inicializada, o que permite gerar um token de acesso para o cabeçalho Authorization.

  2. Crie um arquivo JSON com as informações a seguir:

    {
      "softDeletePolicy": {
        "retentionDurationSeconds": "0"
      }
    }
  3. Use cURL para chamar a API JSON com uma solicitação de PATCH bucket:

    curl -X PATCH --data-binary @JSON_FILE_NAME \
      -H "Authorization: Bearer $(gcloud auth print-access-token)" \
      -H "Content-Type: application/json" \
      "https://storage.googleapis.com/storage/v1/b/BUCKET_NAME"

    Em que:

    • JSON_FILE_NAME é o caminho para o arquivo JSON criado na Etapa 2.
    • BUCKET_NAME é o nome do bucket pertinente. Por exemplo, my-bucket.

Desativar a exclusão reversível dos 100 buckets maiores em um projeto

Com o console do Google Cloud, é possível desativar a exclusão reversível para até 100 buckets de uma vez, com buckets classificados pelos bytes com mais exclusões reversíveis ou pela maior proporção de bytes com exclusão reversível em relação aos bytes ativos. Assim, é possível gerenciar buckets com o maior impacto nos custos de exclusão reversível.

  1. No Console do Google Cloud, acesse a página Buckets do Cloud Storage.

    Acessar buckets

  2. Na página do Cloud Storage, clique em Configurações.

  3. Clique na guia Fazer a exclusão reversível.

  4. Na lista Buckets principais por bytes excluídos, selecione os buckets para os quais você quer desativar a exclusão reversível.

  5. Clique em Desativar a exclusão reversível.

    A exclusão reversível foi desativada nos buckets selecionados.

Desativar a exclusão reversível para vários ou todos os buckets em um projeto

Usando a CLI do Google Cloud, execute o comando gcloud storage buckets update com a flag --project e o curinga * para desativar em massa a exclusão reversível em vários ou todos os buckets de um projeto:

gcloud storage buckets update --project=PROJECT_ID --clear-soft-delete gs://*

Em que:

  • PROJECT_ID é o código do projeto. Por exemplo, my-project.

Desativar a exclusão reversível em todos os buckets de uma pasta

Usando a CLI do Google Cloud, execute os comandos gcloud projects list e gcloud storage buckets update para desativar a exclusão reversível em buckets em todos os projetos de uma pasta especificada.

Execute os comandos gcloud projects list e gcloud storage buckets update para listar todos os buckets em uma pasta especificada e desativar a exclusão reversível em todos os buckets na pasta:

gcloud projects list --filter="parent.id: FOLDER_ID" --format="value(projectId)" | while read project
do
  gcloud storage buckets update --project=$project --clear-soft-delete gs://*
done

Em que:

  • FOLDER_ID é o nome da pasta. Por exemplo, 123456.

Desativar a exclusão reversível no nível da organização

Usando a CLI do Google Cloud, execute o comando gcloud storage buckets update com a flag --clear-soft-delete e o curinga * para desativar a exclusão suave no nível da organização:

Execute o comando gcloud storage buckets update com a flag --clear-soft-delete e o curinga * para desativar a exclusão reversível em todos os buckets da sua organização:

gcloud projects list --format="value(projectId)" | while read project
do
  gcloud storage buckets update --project=$project --clear-soft-delete gs://*
done

O Cloud Storage desativa a exclusão reversível nos buckets atuais. Os objetos que já foram excluídos de maneira reversível permanecem nos buckets até que a duração da retenção da exclusão reversível seja concluída. Depois disso, eles são excluídos permanentemente.

Desativar a exclusão reversível para novos buckets

Embora a exclusão reversível seja ativada por padrão em novos buckets, é possível impedir a ativação padrão dela usando tags. As tags usam a chave storage.defaultSoftDeletePolicy para aplicar uma política de exclusão reversível 0d (zero dias) no nível da organização, o que desativa o recurso e impede a retenção futura dos dados excluídos.

Siga as instruções abaixo para desativar a exclusão reversível por padrão ao criar novos buckets. As instruções a seguir não são equivalentes à configuração de uma política da organização que exige uma política de exclusão reversível específica. Isso significa que você ainda pode ativar a exclusão reversível em determinados buckets especificando uma política, se necessário.

  1. Usando a CLI do Google Cloud, crie a tag storage.defaultSoftDeletePolicy, que é usada para mudar a duração padrão da retenção para exclusões reversíveis em novos buckets. So nome da tag storage.defaultSoftDeletePolicy atualiza a duração de retenção padrão para exclusão reversível.

    Crie uma chave de tag usando o comando gcloud resource-manager tags keys create:

    gcloud resource-manager tags keys create storage.defaultSoftDeletePolicy \
     --parent=organizations/ORGANIZATION_ID \
     --description="Configures the default softDeletePolicy for new Storage buckets."
    

    Em que:

    • ORGANIZATION_ID é o ID numérico da organização em que você quer definir um método de retenção para exclusões reversíveis de duração. Por exemplo, 12345678901. Para saber como encontrar o ID da organização, consulte Como ter acesso ao ID do recurso da organização.
  2. Crie um valor de tag para 0d (zero dias) para desativar o período de retenção da exclusão reversível por padrão em novos buckets usando o comando gcloud resource-manager tags values create:

    gcloud resource-manager tags values create 0d \
      --parent=ORGANIZATION_ID/storage.defaultSoftDeletePolicy \
      --description="Disables soft delete for new Storage buckets."
    

    Em que:

    • ORGANIZATION_ID é o ID numérico da organização em que você quer definir a duração padrão da retenção para exclusões reversíveis. Por exemplo, 12345678901.
  3. Anexe a tag ao recurso usando o comando gcloud resource-manager tags bindings create:

    gcloud resource-manager tags bindings create \
     --tag-value=ORGANIZATION_ID/storage.defaultSoftDeletePolicy/0d \
     --parent=RESOURCE_ID
    

    Em que:

    • ORGANIZATION_ID é o ID numérico da organização em que a tag foi criada. Por exemplo, 12345678901.

    • RESOURCE_ID é o nome completo da organização para criar a vinculação de tag. Por exemplo, para anexar uma tag a organizations/7890123456, digite //cloudresourcemanager.googleapis.com/organizations/7890123456.

Desativar a exclusão reversível para buckets que excedem um limite de custo especificado

Com as bibliotecas de cliente do Cloud para Python, é possível desativar a exclusão temporária de buckets que excedem um limite de custo relativo especificado com um exemplo de biblioteca de cliente do Python. O exemplo faz o seguinte:

  1. Calcula o custo relativo do armazenamento para cada classe.

  2. Avalia o custo da exclusão reversível acumulado pelos seus buckets.

  3. Define um limite de custo para o uso de exclusões reversíveis e lista os buckets que excedem o limite definido. Também permite desativar as exclusões reversíveis nos buckets que excedem o limite.

Para saber mais sobre como configurar a biblioteca de cliente Python e usar o exemplo, consulte a página README.md do analisador de custo de exclusão suave do Cloud Storage.

O exemplo a seguir desativa a exclusão temporária para buckets que ultrapassam um limite de custo especificado:

from __future__ import annotations

import argparse
import json
import google.cloud.monitoring_v3 as monitoring_client


def get_relative_cost(storage_class: str) -> float:
    """Retrieves the relative cost for a given storage class and location.

    Args:
        storage_class: The storage class (e.g., 'standard', 'nearline').

    Returns:
        The price per GB from the https://cloud.google.com/storage/pricing,
        divided by the standard storage class.
    """
    relative_cost = {
        "STANDARD": 0.023 / 0.023,
        "NEARLINE": 0.013 / 0.023,
        "COLDLINE": 0.007 / 0.023,
        "ARCHIVE": 0.0025 / 0.023,
    }

    return relative_cost.get(storage_class, 1.0)


def get_soft_delete_cost(
    project_name: str,
    soft_delete_window: float,
    agg_days: int,
    lookback_days: int,
) -> dict[str, list[dict[str, float]]]:
    """Calculates soft delete costs for buckets in a Google Cloud project.

    Args:
        project_name: The name of the Google Cloud project.
        soft_delete_window: The time window in seconds for considering
          soft-deleted objects (default is 7 days).
        agg_days: Aggregate results over a time period, defaults to 30-day period
        lookback_days: Look back up to upto days, defaults to 360 days

    Returns:
        A dictionary with bucket names as keys and cost data for each bucket,
        broken down by storage class.
    """

    query_client = monitoring_client.QueryServiceClient()

    # Step 1: Get storage class ratios for each bucket.
    storage_ratios_by_bucket = get_storage_class_ratio(
        project_name, query_client, agg_days, lookback_days
    )

    # Step 2: Fetch soft-deleted bytes and calculate costs using Monitoring API.
    soft_deleted_costs = calculate_soft_delete_costs(
        project_name,
        query_client,
        soft_delete_window,
        storage_ratios_by_bucket,
        agg_days,
        lookback_days,
    )

    return soft_deleted_costs


def calculate_soft_delete_costs(
    project_name: str,
    query_client: monitoring_client.QueryServiceClient,
    soft_delete_window: float,
    storage_ratios_by_bucket: dict[str, float],
    agg_days: int,
    lookback_days: int,
) -> dict[str, list[dict[str, float]]]:
    """Calculates the relative cost of enabling soft delete for each bucket in a
       project for certain time frame in secs.

    Args:
        project_name: The name of the Google Cloud project.
        query_client: A Monitoring API query client.
        soft_delete_window: The time window in seconds for considering
          soft-deleted objects (default is 7 days).
        storage_ratios_by_bucket: A dictionary of storage class ratios per bucket.
        agg_days: Aggregate results over a time period, defaults to 30-day period
        lookback_days: Look back up to upto days, defaults to 360 days

    Returns:
        A dictionary with bucket names as keys and a list of cost data
        dictionaries
        for each bucket, broken down by storage class.
    """
    soft_deleted_bytes_time = query_client.query_time_series(
        monitoring_client.QueryTimeSeriesRequest(
            name=f"projects/{project_name}",
            query=f"""
                    {{  # Fetch 1: Soft-deleted (bytes seconds)
                        fetch gcs_bucket :: storage.googleapis.com/storage/v2/deleted_bytes
                        | value val(0) * {soft_delete_window}\'s\'  # Multiply by soft delete window
                        | group_by [resource.bucket_name, metric.storage_class], window(), .sum;

                        # Fetch 2: Total byte-seconds (active objects)
                        fetch gcs_bucket :: storage.googleapis.com/storage/v2/total_byte_seconds
                        | filter metric.type != 'soft-deleted-object'
                        | group_by [resource.bucket_name, metric.storage_class], window(1d), .mean  # Daily average
                        | group_by [resource.bucket_name, metric.storage_class], window(), .sum  # Total over window

                    }}  # End query definition
                    | every {agg_days}d  # Aggregate over larger time intervals
                    | within {lookback_days}d  # Limit data range for analysis
                    | ratio  # Calculate ratio (soft-deleted (bytes seconds)/ total (bytes seconds))
                    """,
        )
    )

    buckets: dict[str, list[dict[str, float]]] = {}
    missing_distribution_storage_class = []
    for data_point in soft_deleted_bytes_time.time_series_data:
        bucket_name = data_point.label_values[0].string_value
        storage_class = data_point.label_values[1].string_value
        # To include location-based cost analysis:
        # 1. Uncomment the line below:
        # location = data_point.label_values[2].string_value
        # 2. Update how you calculate 'relative_storage_class_cost' to factor in location
        soft_delete_ratio = data_point.point_data[0].values[0].double_value
        distribution_storage_class = bucket_name + " - " + storage_class
        storage_class_ratio = storage_ratios_by_bucket.get(
            distribution_storage_class
        )
        if storage_class_ratio is None:
            missing_distribution_storage_class.append(
                distribution_storage_class)
        buckets.setdefault(bucket_name, []).append({
            # Include storage class and location data for additional plotting dimensions.
            # "storage_class": storage_class,
            # 'location': location,
            "soft_delete_ratio": soft_delete_ratio,
            "storage_class_ratio": storage_class_ratio,
            "relative_storage_class_cost": get_relative_cost(storage_class),
        })

    if missing_distribution_storage_class:
        print(
            "Missing storage class for following buckets:",
            missing_distribution_storage_class,
        )
        raise ValueError("Cannot proceed with missing storage class ratios.")

    return buckets


def get_storage_class_ratio(
    project_name: str,
    query_client: monitoring_client.QueryServiceClient,
    agg_days: int,
    lookback_days: int,
) -> dict[str, float]:
    """Calculates storage class ratios for each bucket in a project.

    This information helps determine the relative cost contribution of each
    storage class to the overall soft-delete cost.

    Args:
        project_name: The Google Cloud project name.
        query_client: Google Cloud's Monitoring Client's QueryServiceClient.
        agg_days: Aggregate results over a time period, defaults to 30-day period
        lookback_days: Look back up to upto days, defaults to 360 days

    Returns:
        Ratio of Storage classes within a bucket.
    """
    request = monitoring_client.QueryTimeSeriesRequest(
        name=f"projects/{project_name}",
        query=f"""
            {{
            # Fetch total byte-seconds for each bucket and storage class
            fetch gcs_bucket :: storage.googleapis.com/storage/v2/total_byte_seconds
            | group_by [resource.bucket_name, metric.storage_class], window(), .sum;
            # Fetch total byte-seconds for each bucket (regardless of class)
            fetch gcs_bucket :: storage.googleapis.com/storage/v2/total_byte_seconds
            | group_by [resource.bucket_name], window(), .sum
            }}
            | ratio  # Calculate ratios of storage class size to total size
            | every {agg_days}d
            | within {lookback_days}d
            """,
    )

    storage_class_ratio = query_client.query_time_series(request)

    storage_ratios_by_bucket = {}
    for time_series in storage_class_ratio.time_series_data:
        bucket_name = time_series.label_values[0].string_value
        storage_class = time_series.label_values[1].string_value
        ratio = time_series.point_data[0].values[0].double_value

        # Create a descriptive key for the dictionary
        key = f"{bucket_name} - {storage_class}"
        storage_ratios_by_bucket[key] = ratio

    return storage_ratios_by_bucket


def soft_delete_relative_cost_analyzer(
    project_name: str,
    cost_threshold: float = 0.0,
    soft_delete_window: float = 604800,
    agg_days: int = 30,
    lookback_days: int = 360,
    list_buckets: bool = False,
    ) -> str | dict[str, float]: # Note potential string output
    """Identifies buckets exceeding the relative cost threshold for enabling soft delete.

    Args:
        project_name: The Google Cloud project name.
        cost_threshold: Threshold above which to consider removing soft delete.
        soft_delete_window: Time window for calculating soft-delete costs (in
          seconds).
        agg_days: Aggregate results over this time period (in days).
        lookback_days: Look back up to this many days.
        list_buckets: Return a list of bucket names (True) or JSON (False,
          default).

    Returns:
        JSON formatted results of buckets exceeding the threshold and costs
        *or* a space-separated string of bucket names.
    """

    buckets: dict[str, float] = {}
    for bucket_name, storage_sources in get_soft_delete_cost(
        project_name, soft_delete_window, agg_days, lookback_days
    ).items():
        bucket_cost = 0.0
        for storage_source in storage_sources:
            bucket_cost += (
                storage_source["soft_delete_ratio"]
                * storage_source["storage_class_ratio"]
                * storage_source["relative_storage_class_cost"]
            )
        if bucket_cost > cost_threshold:
            buckets[bucket_name] = round(bucket_cost, 4)

    if list_buckets:
        return " ".join(buckets.keys())  # Space-separated bucket names
    else:
        return json.dumps(buckets, indent=2)  # JSON output


def soft_delete_relative_cost_analyzer_main() -> None:
    # Sample run: python storage_soft_delete_relative_cost_analyzer.py <Project Name>
    parser = argparse.ArgumentParser(
        description="Analyze and manage Google Cloud Storage soft-delete costs."
    )
    parser.add_argument(
        "project_name", help="The name of the Google Cloud project to analyze."
    )
    parser.add_argument(
        "--cost_threshold",
        type=float,
        default=0.0,
        help="Relative Cost threshold.",
    )
    parser.add_argument(
        "--soft_delete_window",
        type=float,
        default=604800.0,
        help="Time window (in seconds) for considering soft-deleted objects.",
    )
    parser.add_argument(
        "--agg_days",
        type=int,
        default=30,
        help=(
            "Time window (in days) for aggregating results over a time period,"
            " defaults to 30-day period"
        ),
    )
    parser.add_argument(
        "--lookback_days",
        type=int,
        default=360,
        help=(
            "Time window (in days) for considering the how old the bucket to be."
        ),
    )
    parser.add_argument(
        "--list",
        type=bool,
        default=False,
        help="Return the list of bucketnames seperated by space.",
    )

    args = parser.parse_args()

    response = soft_delete_relative_cost_analyzer(
        args.project_name,
        args.cost_threshold,
        args.soft_delete_window,
        args.agg_days,
        args.lookback_days,
        args.list,
    )
    if not args.list:
        print(
            "To remove soft-delete policy from the listed buckets run:\n"
            # Capture output
            "python storage_soft_delete_relative_cost_analyzer.py"
            " [your-project-name] --[OTHER_OPTIONS] --list > list_of_buckets.txt \n"
            "cat list_of_buckets.txt | gcloud storage buckets update -I "
            "--clear-soft-delete",
            response,
        )
        return
    print(response)


if __name__ == "__main__":
    soft_delete_relative_cost_analyzer_main()

A seguir