Inhabilitar la eliminación no definitiva

Descripción general Uso

En esta página se describe cómo inhabilitar la función de eliminación lógica en los nuevos y los actuales contenedores de tu organización.

La eliminación no definitiva está habilitada de forma predeterminada en los segmentos nuevos para evitar la pérdida de datos. Si es necesario, puedes inhabilitar la eliminación no definitiva de los segmentos que ya tengas modificando la política de eliminación no definitiva. También puedes inhabilitar la eliminación no definitiva de forma predeterminada para los segmentos nuevos configurando una etiqueta predeterminada para toda la organización. Ten en cuenta que, una vez que inhabilites la eliminación lógica, los datos eliminados no se podrán recuperar, incluidos los que se hayan eliminado por error o de forma malintencionada.

Roles obligatorios

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

Estos roles predefinidos contienen los permisos necesarios para inhabilitar la eliminación lógica. Para ver los permisos exactos que se necesitan, despliega la sección Permisos necesarios:

Permisos obligatorios

Para inhabilitar la eliminación lógica, se necesitan los siguientes permisos:

  • storage.buckets.get
  • storage.buckets.update
  • storage.buckets.list (este permiso solo es necesario si tienes previsto usar la Google Cloud consola para seguir las instrucciones de esta página)

    Para ver los permisos obligatorios que se incluyen en el rol Administrador de etiquetas(roles/resourcemanager.tagAdmin), consulta Permisos necesarios para administrar etiquetas.

Para obtener información sobre cómo conceder roles, consulta Usar gestión de identidades y accesos con los contenedores o Gestionar el acceso a los proyectos.

Inhabilitar la eliminación lógica en un segmento específico

Antes de empezar, ten en cuenta lo siguiente:

  • Si inhabilitas una política de eliminación no definitiva de un segmento que tenga objetos eliminados de forma no definitiva durante el tiempo de inhabilitación, los objetos eliminados de forma no definitiva se conservarán hasta que venza el periodo de retención aplicado anteriormente.

  • Después de inhabilitar una política de eliminación no definitiva en tu segmento, Cloud Storage no conservará los objetos que se eliminen.

Sigue estas instrucciones para inhabilitar la eliminación lógica de un segmento específico:

Consola

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

    Ir a Contenedores

  2. En la lista de segmentos, haga clic en el nombre del segmento cuya política de eliminación suave quiera inhabilitar.

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

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

  5. Haz clic en Confirmar.

Para saber cómo obtener información detallada sobre los errores de las operaciones de Cloud Storage en la consola, consulta la sección Solución de problemas. Google Cloud

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

Donde:

  • BUCKET_NAME es el nombre del segmento. Por ejemplo, my-bucket.

APIs REST

API JSON

  1. Tener instalada e inicializadala CLI de gcloud, 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 JSON con una solicitud de PATCH contenedor:

    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 del archivo JSON que has creado en el paso 2.
    • BUCKET_NAME es el nombre del segmento correspondiente. Por ejemplo, my-bucket.

Inhabilitar la eliminación suave de los 100 segmentos más grandes de un proyecto

Con la Google Cloud consola, puedes inhabilitar la eliminación no definitiva en hasta 100 segmentos a la vez. Los segmentos se ordenan por el número de bytes eliminados no definitivamente o por la proporción más alta de bytes eliminados no definitivamente con respecto a los bytes activos. De esta forma, puedes gestionar los segmentos que tengan el mayor impacto en los costes de eliminación no definitiva.

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

    Ir a Contenedores

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

  3. Haga clic en la pestaña Eliminación lógica.

  4. En la lista Principales contenedores por bytes eliminados, seleccione los contenedores en los que quiera inhabilitar la eliminación lógica.

  5. Haz clic en Desactivar eliminación suave.

    La eliminación no definitiva está inhabilitada en los contenedores que ha seleccionado.

Inhabilitar la eliminación lógica en varios o todos los contenedores de un proyecto

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

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

Donde:

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

Inhabilitar la eliminación lógica en todos los contenedores de una carpeta

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

Ejecuta los comandos gcloud projects list y gcloud storage buckets update para enumerar todos los segmentos de una carpeta específica y, a continuación, inhabilita la eliminación suave de todos los segmentos 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

Donde:

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

Inhabilitar la eliminación no definitiva a nivel de 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 lógica en el nivel de organización:

Ejecuta el comando gcloud storage buckets update con la marca --clear-soft-delete y el comodín * para inhabilitar la eliminación suave de todos los contenedores 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 segmentos ya creados. Los objetos que ya se hayan eliminado de forma no definitiva permanecerán en los contenedores hasta que finalice el periodo de retención de eliminación no definitiva, tras lo cual se eliminarán de forma permanente.

Inhabilitar la eliminación lógica de los nuevos contenedores

Aunque la eliminación no definitiva está habilitada de forma predeterminada en los segmentos nuevos, puedes evitar que se habilite de forma predeterminada mediante etiquetas. Las etiquetas usan la clave storage.defaultSoftDeletePolicy para aplicar una política de eliminación suave 0d (cero días) a nivel de organización, lo que inhabilita la función e impide que se conserven los datos eliminados en el futuro.

Sigue estas instrucciones para inhabilitar la eliminación no definitiva de forma predeterminada cuando crees nuevos segmentos. Ten en cuenta que las siguientes instrucciones no son equivalentes a definir una política de organización que exija una política de eliminación no definitiva concreta, lo que significa que puedes habilitar la eliminación no definitiva en segmentos específicos especificando una política si es necesario.

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

    Crea una clave de 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."
    

    Donde:

    • ORGANIZATION_ID es el ID numérico de la organización para la que quieres definir una duración de retención de eliminación no definitiva predeterminada. Por ejemplo, 12345678901. Para saber cómo encontrar el ID de organización, consulta el artículo Obtener el ID de recurso de tu organización.
  2. Crea un valor de etiqueta para 0d (cero días) para inhabilitar el periodo de conservación de la eliminación lógica predeterminado en los nuevos contenedores mediante 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."
    

    Donde:

    • ORGANIZATION_ID es el ID numérico de la organización para la que quieres definir la duración predeterminada de la retención de eliminación no definitiva. Por ejemplo, 12345678901.
  3. Asocia 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
    

    Donde:

    • 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 quieres crear el enlace de etiqueta. Por ejemplo, para asociar una etiqueta a organizations/7890123456, introduce //cloudresourcemanager.googleapis.com/organizations/7890123456.

Inhabilitar la eliminación no definitiva de los contenedores que superen un umbral de coste especificado

Con las bibliotecas de cliente de Cloud para Python, puedes inhabilitar la eliminación lógica de los contenedores que superen un umbral de coste relativo especificado con un ejemplo de biblioteca de cliente de Python. El ejemplo hace lo siguiente:

  1. Calcula el coste relativo del almacenamiento de cada clase de almacenamiento.

  2. Evalúa el coste de eliminación suave acumulado por tus cubos.

  3. Define un umbral de coste para el uso de la eliminación lógica y muestra los segmentos que superan el umbral que has definido. Además, te permite inhabilitar la eliminación lógica en los segmentos que superen el umbral.

Para obtener más información sobre cómo configurar la biblioteca de cliente de Python y usar el ejemplo, consulta la página Analizador de costes de eliminación lógica de Cloud Storage README.md.

En el siguiente ejemplo se inhabilita la eliminación no definitiva de los segmentos que superan un umbral de coste 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()

Siguientes pasos