Inhabilita la opción de borrar de forma no definitiva

Descripción general Uso

En esta página, se describe cómo inhabilitar la función de eliminación no definitiva en los buckets nuevos y existentes de tu organización.

La eliminación no definitiva está habilitada en buckets nuevos de forma predeterminada para evitar la pérdida de datos. Si es necesario, puedes inhabilitar la eliminación no definitiva para los buckets existentes si modificas la política de eliminación no definitiva. También puedes inhabilitar la eliminación no definitiva de forma predeterminada para los buckets nuevos si configuras una etiqueta predeterminada para toda la organización. Ten en cuenta que, una vez que inhabilites la opción de borrar de forma no definitiva, no podrás recuperar los datos borrados, incluidas las eliminaciones accidentales o maliciosas.

Roles obligatorios

Para obtener los permisos que necesitas para inhabilitar la eliminación sin confirmación, pide a tu administrador que te otorgue los siguientes roles de IAM a nivel de la organización:

Estos roles predefinidos contienen los permisos necesarios para inhabilitar la eliminación no definitiva. Para ver los permisos exactos que son necesarios, expande la sección Permisos requeridos:

Permisos necesarios

Se requieren los siguientes permisos para inhabilitar la eliminación no definitiva:

  • storage.buckets.get
  • storage.buckets.update
  • storage.buckets.list (este permiso es necesario si planeas usar la consola de Google Cloud para ejecutar las instrucciones en esta página)

    Para conocer los permisos necesarios que se incluyen como parte del rol de administrador de etiquetas(roles/resourcemanager.tagAdmin), consulta Permisos necesarios para administrar etiquetas.

Para obtener más información sobre cómo otorgar roles, consulta Usa IAM con buckets o Administra el acceso a los proyectos.

Inhabilita la opción de borrar de forma no definitiva para un bucket específico

Antes de comenzar, considera lo siguiente:

  • Si inhabilitas una política de eliminación no definitiva de tu bucket que tiene objetos borrados de forma no definitiva durante la inhabilitación, los objetos borrados de forma no definitiva existentes se retienen hasta que venza el período de retención aplicado anteriormente.

  • Después de inhabilitar una política de eliminación no definitiva en tu bucket, Cloud Storage no retiene los objetos borrados recientemente.

Usa las siguientes instrucciones para inhabilitar la función borrar de forma no definitiva para un bucket específico:

Console

  1. En la consola de Google Cloud, ve a la página Buckets de Cloud Storage.

    Ir a Buckets

  2. En la lista de buckets, haz clic en el nombre del bucket cuya política de eliminación no definitiva deseas inhabilitar.

  3. Haz clic en la pestaña Protección.

  4. En la sección Política de eliminación no definitiva, haz clic en Inhabilitar para inhabilitar la política de eliminación no definitiva.

  5. Haz clic en Confirmar.

Para obtener información sobre cómo ver detalles de errores acerca de operaciones fallidas de Cloud Storage en la consola de Google Cloud, consulta Solución de problemas.

Línea de comandos

Ejecuta el comando gcloud storage buckets update con la marca --clear-soft-delete:

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

Aquí:

  • BUCKET_NAME es el nombre del depósito. Por ejemplo, my-bucket.

API de REST

API de JSON

  1. Tener la gcloud CLI instalada e inicializada, lo que te permite generar un token de acceso para el encabezado Authorization.

  2. Crea un archivo JSON que contenga la siguiente información:

    {
      "softDeletePolicy": {
        "retentionDurationSeconds": "0"
      }
    }
  3. Usa cURL para llamar a la API de JSON con una solicitud de bucket PATCH:

    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"

    Donde:

    • JSON_FILE_NAME es la ruta de acceso del archivo JSON que creaste en el paso 2.
    • BUCKET_NAME es el nombre del bucket correspondiente. Por ejemplo, my-bucket

Inhabilita la eliminación no definitiva para los 100 buckets más grandes de un proyecto

Con la consola de Google Cloud, puedes inhabilitar la eliminación no definitiva en hasta 100 buckets a la vez, con buckets ordenados por la cantidad de bytes eliminados de forma no definitiva o la proporción más alta de bytes eliminados de forma no definitiva en relación con los bytes activos, lo que te permite administrar los buckets con el mayor impacto en tus costos de eliminación no definitiva.

  1. En la consola de Google Cloud, ve a la página Buckets de Cloud Storage.

    Ir a Buckets

  2. En la página de Cloud Storage, haz clic en Configuración.

  3. Haz clic en la pestaña Borrado temporal.

  4. En la lista Top buckets by deleted bytes, selecciona los buckets para los que deseas inhabilitar la eliminación suave.

  5. Haz clic en Desactivar la opción de borrar de forma no definitiva.

    La eliminación no definitiva está inhabilitada en los buckets que seleccionaste.

Inhabilita la eliminación diferida para varios buckets o todos los buckets de un proyecto

Con Google Cloud CLI, ejecuta el comando gcloud storage buckets update con la marca --project y el comodín * para inhabilitar de forma masiva la eliminación no definitiva para varios o todos los buckets de un proyecto:

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

Aquí:

  • PROJECT_ID es el ID del proyecto. Por ejemplo, my-project

Inhabilita la eliminación no definitiva en todos los buckets de una carpeta

Con Google Cloud CLI, ejecuta los comandos gcloud projects list y gcloud storage buckets update para inhabilitar la eliminación diferida en los buckets de todos los proyectos en una carpeta especificada.

Ejecuta los comandos gcloud projects list y gcloud storage buckets update para enumerar todos los buckets de una carpeta especificada y, luego, inhabilita la eliminación diferida para todos los buckets de la carpeta:

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

Aquí:

  • FOLDER_ID es el nombre de la carpeta. Por ejemplo, 123456.

Inhabilita la opción de borrar de forma no definitiva a nivel de la organización

Con Google Cloud CLI, ejecuta el comando gcloud storage buckets update con la marca --clear-soft-delete y el comodín * para inhabilitar la eliminación sin confirmación a nivel de la organización:

Ejecuta el comando gcloud storage buckets update con la marca --clear-soft-delete y el comodín * para inhabilitar la eliminación diferida para todos los buckets de tu organización:

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

Cloud Storage inhabilita la eliminación no definitiva en los buckets existentes. Los objetos que ya se borraron de forma no definitiva permanecerán en los buckets hasta que se complete su período de retención de eliminación no definitiva, después del cual, se borrarán de forma permanente.

Inhabilita la opción de borrar de forma no definitiva para los buckets nuevos

Si bien la eliminación no definitiva está habilitada de forma predeterminada en buckets nuevos, puedes evitar que se habilite de forma predeterminada con etiquetas. Las etiquetas usan la clave storage.defaultSoftDeletePolicy para aplicar una política de eliminación no definitiva 0d (cero días) a nivel de la organización, lo que inhabilita la función y evita la retención futura de datos eliminados.

Usa las siguientes instrucciones para inhabilitar la función borrar de forma no definitiva de forma predeterminada cuando creas buckets nuevos. Ten en cuenta que las siguientes instrucciones no equivalen a configurar una política de la organización que exija una política de eliminación no definitiva en particular, lo que significa que, si es necesario, puedes habilitar la opción de borrar de forma no definitiva en buckets específicos especificando una política.

  1. Con Google Cloud CLI, crea la etiqueta storage.defaultSoftDeletePolicy que se usa para cambiar la duración de retención de eliminación no definitiva predeterminada en los buckets nuevos. Ten en cuenta que solo el nombre de la etiqueta storage.defaultSoftDeletePolicy actualiza la duración predeterminada de la retención de eliminación no definitiva.

    Crea una etiqueta con el 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."
    

    Aquí:

    • ORGANIZATION_ID es el ID numérico de la organización para la que deseas establecer una duración de retención predeterminada de eliminación no definitiva. Por ejemplo, 12345678901 Para obtener información para encontrar el ID de la organización, consulta Obtén el ID de tu recurso de organización.
  2. Crea un valor de etiqueta para 0d (cero días) para inhabilitar el período de retención de eliminación no definitiva de forma predeterminada en buckets nuevos con el 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."
    

    Aquí:

    • ORGANIZATION_ID es el ID numérico de la organización para la que deseas establecer la duración de retención predeterminada de eliminación no definitiva. Por ejemplo, 12345678901
  3. Adjunta la etiqueta a tu recurso con el comando gcloud resource-manager tags bindings create:

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

    Aquí:

    • ORGANIZATION_ID es el ID numérico de la organización en la que se creó la etiqueta. Por ejemplo, 12345678901

    • RESOURCE_ID es el nombre completo de la organización para la que deseas crear la vinculación de etiquetas. Por ejemplo, para adjuntar una etiqueta a organizations/7890123456, ingresa //cloudresourcemanager.googleapis.com/organizations/7890123456.

Inhabilita la eliminación no definitiva para los buckets que superen un umbral de costo especificado

Con las bibliotecas cliente de Cloud para Python, puedes inhabilitar la eliminación diferida para los buckets que superen un umbral de costo relativo especificado con una muestra de biblioteca cliente de Python. En el ejemplo, se hace lo siguiente:

  1. Calcula el costo relativo del almacenamiento para cada clase de almacenamiento.

  2. Evalúa el costo de eliminación no definitiva que acumulan tus buckets.

  3. Establece un umbral de costo para el uso de la eliminación no definitiva y muestra una lista de los buckets que superan el umbral que estableciste y te permite inhabilitar la eliminación no definitiva para los buckets que superan el umbral.

Para obtener más información sobre cómo configurar la biblioteca cliente de Python y usar el ejemplo, consulta la página README.md del analizador de costos de eliminación suave de Cloud Storage.

En el siguiente ejemplo, se inhabilita la eliminación diferida para los buckets que superan un umbral de costo 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()

¿Qué sigue?