Utiliser la suppression réversible

Présentation Utilisation

Cette page explique comment activer, désactiver, mettre à jour et vérifier l'état de la règle de suppression réversible sur un bucket. Pour savoir comment lister et restaurer les objets ayant été soumis à la suppression réversible, consultez la page Utiliser des objets soumis à suppression réversible. Pour plus d'informations sur la suppression réversible, consultez la présentation. Pour désactiver cette fonctionnalité, consultez la section Désactiver la suppression réversible.

Rôles requis

Pour obtenir les autorisations nécessaires pour créer et gérer des règles de suppression réversible, demandez à votre administrateur de vous accorder le rôle IAM Administrateur de l'espace de stockage (roles/storage.admin) sur le bucket ou le projet qui contient le bucket.

Ce rôle prédéfini contient les autorisations requises pour créer et gérer des règles de suppression réversible. Pour connaître les autorisations exactes requises, développez la section Autorisations requises :

Autorisations requises

Les autorisations suivantes sont requises pour créer et gérer des règles de suppression réversible :

  • storage.buckets.get
  • storage.buckets.update
  • storage.buckets.list (cette autorisation n'est nécessaire que si vous prévoyez d'utiliser la console Google Cloud pour suivre les instructions de cette page)

Pour en savoir plus sur l'attribution de rôles, consultez la section Utiliser IAM avec des buckets ou Gérer les accès aux projets.

Modifier la règle de suppression réversible d'un bucket

Pour activer, désactiver ou mettre à jour la règle de suppression réversible d'un bucket, procédez comme suit :

Console

  1. Dans la console Google Cloud, accédez à la page Buckets Cloud Storage.

    Accéder à la page "Buckets"

  2. Dans la liste des buckets, cliquez sur le nom du bucket dont vous souhaitez gérer la stratégie de suppression réversible.

  3. Cliquez sur l'onglet Protection.

  4. Dans la section Règle de suppression réversible, effectuez l'une des actions suivantes :

    • Si le bucket ne dispose pas de règle de suppression réversible, cliquez sur Modifier, choisissez une unité de temps et une durée pour votre durée de conservation, puis cliquez sur Save.

    • Si le bucket est associé à une règle de suppression réversible, cliquez sur Modifier pour modifier l'unité de temps et la durée de conservation.

Pour savoir comment obtenir des informations détaillées sur les erreurs liées aux opérations Cloud Storage ayant échoué dans la console Google Cloud, consultez la section Dépannage.

Ligne de commande

Pour ajouter ou modifier la règle de suppression réversible sur un bucket, exécutez la commande gcloud storage buckets update avec l'option --soft-delete-duration :

  gcloud storage buckets update gs://BUCKET_NAME --soft-delete-duration=SOFT_DELETE_DURATION

Où :

  • BUCKET_NAME est le nom du bucket. Exemple : my-bucket.
  • SOFT_DELETE_DURATION spécifie la durée de conservation des objets supprimés de façon réversible. Par exemple, 2w1d correspond à deux semaines et à un jour. Pour en savoir plus, consultez la section Durée de conservation de la suppression réversible.

API REST

API JSON

  1. Vous devez installer et initialiser gcloud CLI afin de générer un jeton d'accès pour l'en-tête Authorization.

    Vous pouvez également créer un jeton d'accès à l'aide d'OAuth 2.0 Playground et l'inclure dans l'en-tête Authorization.

  2. Créez un fichier JSON contenant les informations suivantes :

    {
      "softDeletePolicy": {
        "retentionDurationSeconds": "TIME_IN_SECONDS"
      }
    }

    TIME_IN_SECONDS correspond à la durée, en secondes pendant laquelle vous souhaitez conserver les objets soumis à suppression réversible. Exemple : 2678400. Pour en savoir plus, consultez la section Durée de conservation de la suppression réversible.

  3. Exécutez cURL pour appeler l'API JSON avec une requête 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"

    Où :

    • JSON_FILE_NAME correspond au chemin d'accès au fichier JSON que vous avez créé à l'étape 2.
    • BUCKET_NAME correspond au nom du bucket concerné. Exemple :my-bucket

Supprimer la règle de suppression réversible d'un bucket

Console

  1. Dans la console Google Cloud, accédez à la page Buckets Cloud Storage.

    Accéder à la page "Buckets"

  2. Dans la liste des buckets, cliquez sur le nom du bucket dont vous souhaitez supprimer la règle de suppression réversible.

  3. Cliquez sur l'onglet Protection.

  4. Dans la section Règle de suppression réversible, cliquez sur Désactiver pour supprimer la règle de suppression réversible du bucket.

  5. Cliquez sur Confirmer.

Pour savoir comment obtenir des informations détaillées sur les erreurs liées aux opérations Cloud Storage ayant échoué dans la console Google Cloud, consultez la section Dépannage.

Ligne de commande

Pour supprimer la règle de suppression réversible d'un bucket, exécutez la commande gcloud storage buckets update avec l'option --clear-soft-delete :

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

Où :

  • BUCKET_NAME est le nom du bucket. Exemple : my-bucket.

API REST

API JSON

  1. Vous devez installer et initialiser gcloud CLI afin de générer un jeton d'accès pour l'en-tête Authorization.

    Vous pouvez également créer un jeton d'accès à l'aide d'OAuth 2.0 Playground et l'inclure dans l'en-tête Authorization.

  2. Créez un fichier JSON contenant les informations suivantes :

    {
      "softDeletePolicy": {
        "retentionDurationSeconds": "TIME_IN_SECONDS"
      }
    }

    Pour désactiver la règle de suppression réversible d'un bucket, utilisez la valeur 0 pour TIME_IN_SECONDS.

  3. Exécutez cURL pour appeler l'API JSON avec une requête 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"

    Où :

    • JSON_FILE_NAME correspond au chemin d'accès au fichier JSON que vous avez créé à l'étape 2.
    • BUCKET_NAME correspond au nom du bucket concerné. Par exemple, my-bucket.

Vérifier si la règle de suppression réversible est activée sur un bucket

Console

  1. Dans la console Google Cloud, accédez à la page Buckets Cloud Storage.

    Accéder à la page "Buckets"

  2. Dans la liste des buckets, cliquez sur le nom du bucket dont vous souhaitez vérifier la règle de suppression réversible.

  3. Cliquez sur l'onglet Protection.

    L'état s'affiche dans la section Règle de suppression réversible (pour la récupération de données).

Vous pouvez également utiliser l'onglet Protection pour vérifier s'il existe une règle de suppression réversible sur votre bucket.

Pour savoir comment obtenir des informations détaillées sur les erreurs liées aux opérations Cloud Storage ayant échoué dans la console Google Cloud, consultez la section Dépannage.

Ligne de commande

Pour vérifier l'état de la règle de suppression réversible d'un bucket, utilisez la commande gcloud storage buckets describe :

  gcloud storage buckets describe gs://BUCKET_NAME \
      --format="default(soft_delete_policy)"

Où :

  • BUCKET_NAME est le nom du bucket. Exemple : my-bucket.

API REST

API JSON

  1. Vous devez installer et initialiser gcloud CLI afin de générer un jeton d'accès pour l'en-tête Authorization.

    Vous pouvez également créer un jeton d'accès à l'aide d'OAuth 2.0 Playground et l'inclure dans l'en-tête Authorization.

  2. Exécutez cURL pour appeler l'API JSON avec une requête de bucket GET :

    curl -X GET \
      -H "Authorization: Bearer $(gcloud auth print-access-token)" \
      -H "Content-Type: application/json" \
      "https://storage.googleapis.com/storage/v1/b/BUCKET_NAME?fields=softDeletePolicy"

    BUCKET_NAME est le nom du bucket concerné. Exemple :my-bucket

Désactiver la suppression réversible pour plusieurs buckets ou pour tous les buckets d'un projet

Les instructions suivantes expliquent comment désactiver la suppression réversible pour plusieurs buckets ou pour tous les buckets d'un projet. Si vous souhaitez désactiver la suppression réversible au niveau de l'organisation, consultez la section Désactiver la suppression réversible.

Console

La console Google Cloud vous permet de désactiver la suppression réversible pour les buckets triés en fonction du plus grand nombre d'octets supprimés de façon réversible ou du ratio le plus élevé entre les octets supprimés de façon réversible et les octets actifs, afin de réduire les coûts engendrés par l'utilisation de la suppression réversible.

  1. Dans la console Google Cloud, accédez à la page Buckets Cloud Storage.

    Accéder à la page "Buckets"

  2. Sur la page Cloud Storage, cliquez sur Paramètres.

  3. Cliquez sur l'onglet Suppression réversible.

  4. Dans la liste Buckets avec le plus grand nombre d'octets supprimés, sélectionnez les buckets pour lesquels vous souhaitez désactiver la suppression réversible.

  5. Cliquez sur Désactiver la suppression réversible.

    La suppression réversible est désactivée sur les buckets que vous avez sélectionnés.

Ligne de commande

Pour désactiver la suppression réversible pour tous les buckets d'un projet, exécutez la commande gcloud storage buckets update avec l'option --clear-soft-delete :

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

Bibliothèques clientes

Python

Pour en savoir plus, consultez la documentation de référence de l'API Cloud Storage en langage Python.

Pour vous authentifier auprès de Cloud Storage, configurez le service Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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()

Étape suivante