Désactiver la suppression réversible

Présentation Utilisation

Cette page explique comment désactiver la fonctionnalité de suppression réversible sur les nouveaux buckets et les buckets existants de votre organisation.

La suppression réversible est activée par défaut sur les nouveaux buckets pour éviter la perte de données. Si nécessaire, vous pouvez désactiver la suppression réversible pour les buckets existants en modifiant la règle de suppression réversible, et vous pouvez désactiver la suppression réversible par défaut pour les nouveaux buckets en définissant une balise par défaut pour l'ensemble de l'organisation. Notez qu'une fois la suppression réversible désactivée, vos données supprimées ne peuvent plus être récupérées, y compris en cas de suppression accidentelle ou malveillante.

Rôles requis

Pour obtenir les autorisations nécessaires pour désactiver la suppression temporaire, demandez à votre administrateur de vous accorder les rôles IAM suivants au niveau de l'organisation:

Ces rôles prédéfinis contiennent les autorisations requises pour désactiver la suppression réversible. Pour connaître les autorisations exactes requises, développez la section Autorisations requises :

Autorisations requises

Les autorisations suivantes sont requises pour désactiver la 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 connaître les autorisations requises incluses dans le rôle Administrateur de tags(roles/resourcemanager.tagAdmin), consultez la section Autorisations requises pour administrer des tags.

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.

Désactiver la suppression réversible pour un bucket spécifique

Avant de commencer, prenez en compte les recommandations suivantes :

  • Si vous désactivez une règle de suppression réversible de votre bucket contenant des objets supprimés de façon réversible au moment de la désactivation, les objets supprimés de façon réversible existants sont conservés jusqu'à l'expiration de la durée de conservation précédemment appliquée.

  • Après avoir désactivé une règle de suppression réversible sur votre bucket, Cloud Storage ne conserve pas les objets nouvellement supprimés.

Suivez les instructions ci-dessous pour désactiver la suppression réversible pour un bucket spécifique:

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 désactiver 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 désactiver la règle de suppression réversible.

  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

Exécutez la commande gcloud storage buckets update avec l'option --clear-soft-delete:

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

Où :

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

API REST

API JSON

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

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

    {
      "softDeletePolicy": {
        "retentionDurationSeconds": "0"
      }
    }
  3. Utilisez 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

Désactiver la suppression réversible pour les 100 plus grands buckets d'un projet

Dans la console Google Cloud, vous pouvez désactiver la suppression réversible pour jusqu'à 100 buckets à la fois, en les triant 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. Vous pouvez ainsi gérer les buckets qui ont le plus d'impact sur vos coûts de 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.

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

À l'aide de la Google Cloud CLI, exécutez la commande gcloud storage buckets update avec l'option --project et le caractère générique * pour désactiver la suppression réversible de manière groupée pour plusieurs ou tous les buckets d'un projet:

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

Où :

  • PROJECT_ID est l'ID du projet. Exemple : my-project.

Désactiver la suppression réversible pour tous les buckets d'un dossier

À l'aide de Google Cloud CLI, exécutez les commandes gcloud projects list et gcloud storage buckets update pour désactiver la suppression réversible sur les buckets de tous les projets d'un dossier spécifié.

Exécutez les commandes gcloud projects list et gcloud storage buckets update pour lister tous les buckets sous un dossier spécifié, puis désactivez la suppression réversible pour tous les buckets du dossier:

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

Où :

  • FOLDER_ID est le nom du dossier. Exemple : 123456.

Désactiver la suppression réversible au niveau de l'organisation

À l'aide de Google Cloud CLI, exécutez la commande gcloud storage buckets update avec l'option --clear-soft-delete et l'caractère générique * pour désactiver la suppression temporaire au niveau de l'organisation:

Exécutez la commande gcloud storage buckets update avec l'option --clear-soft-delete et le caractère générique * pour désactiver la suppression réversible pour tous les buckets de votre organisation:

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

Cloud Storage désactive la suppression réversible sur les buckets existants. Les objets qui ont déjà été supprimés de façon réversible restent dans les buckets jusqu'à la fin de la durée de conservation de la suppression réversible, après quoi ils sont définitivement supprimés.

Désactiver la suppression réversible pour les nouveaux buckets

Bien que la suppression réversible soit activée par défaut sur les nouveaux buckets, vous pouvez empêcher son activation par défaut à l'aide de tags. Les balises utilisent la clé storage.defaultSoftDeletePolicy pour appliquer une stratégie de suppression réversible 0d (zéro jour) au niveau de l'organisation, ce qui désactive la fonctionnalité et empêche la conservation future des données supprimées.

Suivez les instructions ci-dessous pour désactiver la suppression réversible par défaut lorsque vous créez des buckets. Notez que les instructions suivantes ne reviennent pas à définir une règle d'administration qui exige une règle de suppression réversible particulière, ce qui signifie que vous pouvez toujours activer la suppression réversible sur des buckets spécifiques en spécifiant une règle si nécessaire.

  1. À l'aide de Google Cloud CLI, créez la balise storage.defaultSoftDeletePolicy, qui permet de modifier la durée de conservation de la suppression réversible par défaut pour les nouveaux buckets. Remarque : Seul le nom du tag storage.defaultSoftDeletePolicy met à jour la durée de conservation de la suppression réversible par défaut.

    Créez une clé à l'aide de la commande 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."
    

    Où :

    • ORGANIZATION_ID correspond à l'ID numérique de l'organisation pour laquelle vous souhaitez définir une durée de conservation pour la suppression réversible par défaut. Exemple :12345678901 Pour savoir comment trouver l'ID de l'organisation, consultez la section Obtenir l'ID de ressource de votre organisation.
  2. Créez une valeur de tag pour 0d (zéro jour) afin de désactiver par défaut la durée de conservation de la suppression réversible sur les nouveaux buckets à l'aide de la commande 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."
    

    Où :

    • ORGANIZATION_ID correspond à l'ID numérique de l'organisation pour laquelle vous souhaitez définir la durée de conservation pour la suppression réversible par défaut. Exemple :12345678901
  3. Associez le tag à votre ressource à l'aide de la commande gcloud resource-manager tags bindings create:

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

    Où :

    • ORGANIZATION_ID correspond à l'ID numérique de l'organisation sous laquelle la balise a été créée. Exemple : 12345678901.

    • RESOURCE_ID correspond au nom complet de l'organisation pour laquelle vous souhaitez créer l'association de tags. Par exemple, pour associer un tag à organizations/7890123456, saisissez //cloudresourcemanager.googleapis.com/organizations/7890123456.

Désactiver la suppression réversible pour les buckets qui dépassent un seuil de coût spécifié

Avec les bibliothèques clientes Cloud pour Python, vous pouvez désactiver la suppression douce pour les buckets qui dépassent un seuil de coût relatif spécifié à l'aide d'un exemple de bibliothèque cliente Python. L'exemple effectue les opérations suivantes:

  1. Calcule le coût relatif du stockage pour chaque classe de stockage.

  2. Évalue les coûts de suppression réversible accumulés par vos buckets.

  3. Définit un seuil de coût pour l'utilisation de la suppression réversible, liste les buckets qui dépassent le seuil que vous avez défini et vous permet de désactiver la suppression réversible pour les buckets qui dépassent ce seuil.

Pour en savoir plus sur la configuration de la bibliothèque cliente Python et l'utilisation de l'exemple, consultez la page README.md de l'outil d'analyse des coûts de suppression temporaire Cloud Storage.

L'exemple suivant désactive la suppression douce pour les buckets qui dépassent un seuil de coût spécifié:

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