Versehentliches Löschen der Datenbank verhindern

Auf dieser Seite wird beschrieben, wie Sie Spanner-Datenbanken vor versehentlichem Löschen schützen.

Der Löschschutz für Spanner-Datenbanken verhindert das versehentliche Löschen vorhandener Datenbanken durch Nutzer oder Dienstkonten, die die erforderlichen IAM-Berechtigungen zum Löschen der Datenbank haben. Durch Aktivieren des Löschschutzes für Datenbanken können Sie Datenbanken schützen, die für Ihre Anwendung und Dienste wichtig sind. Verwenden Sie den Schutz vor Datenbanklöschungen zusammen mit der Wiederherstellung zu einem bestimmten Zeitpunkt und Sicherungsfeatures, um einen umfassenden Satz von Datenschutzfunktionen für Ihre Spanner-Datenbanken bereitzustellen.

Die Einstellung für den Löschschutz ist standardmäßig deaktiviert, wenn Sie eine neue Datenbank erstellen. Sie können die Einstellung für den Löschschutz aktivieren, nachdem die Datenbank erfolgreich erstellt wurde. Außerdem können Sie diese Einstellung für eine vorhandene Datenbank aktivieren. Wenn Sie mehrere Datenbanken schützen möchten, aktivieren Sie die Einstellung für jede Datenbank einzeln. Das Aktivieren oder Deaktivieren des Löschschutzes hat keine Auswirkungen auf die Leistung der Datenbank. Wenn Sie eine Datenbank löschen möchten, für die der Datenbankschutz aktiviert ist, müssen Sie den Schutz deaktivieren, bevor Sie die Datenbank löschen können.

Beschränkungen

In den folgenden Fällen können Sie den Löschschutz für Datenbanken nicht aktivieren:

  • Die Datenbank wird gelöscht.
  • Die Datenbank wird aus einer Sicherung wiederhergestellt. Nach Abschluss der Wiederherstellung können Sie den Datenbankschutz aktivieren.

Außerdem übernehmen Sicherungen einer Datenbank und von Datenbanken, die aus einer Sicherung wiederhergestellt wurden, nicht die Einstellung für den Datenbanklöschungsschutz der Quelldatenbank. Nachdem Sie eine Datenbank aus einer Sicherung wiederhergestellt haben, müssen Sie den Löschschutz für die Datenbank separat aktivieren.

Wenn Sie Ihr Projekt löschen, verhindert der Löschschutz für die Spanner-Datenbank das Löschen der Datenbank oder Instanz nicht. Weitere Informationen dazu, was passiert, wenn Sie Ihr Projekt löschen, finden Sie unter Projekte beenden (löschen).

Zugriffssteuerung mit IAM

Sie benötigen bestimmte IAM-Berechtigungen, um die Einstellung für den Löschschutz Ihrer Datenbank zu aktivieren.

Sie benötigen die Berechtigung spanner.databases.update, um den Löschschutz für Datenbanken zu aktivieren oder zu deaktivieren. Wenn Sie nur den Status Ihrer Datenbankkonfiguration ansehen möchten, benötigen Sie die Berechtigung spanner.databases.list oder spanner.databases.get. Informationen zum Gewähren von Spanner-IAM-Berechtigungen finden Sie unter IAM-Berechtigungen anwenden.

Wenn Sie die vordefinierte Rolle Spanner Database Admin roles/spanner.databaseAdmin für Ihre Datenbank haben, können Sie den Löschschutz für Datenbanken aktualisieren und aktivieren.

Sie können den Löschschutz für eine vorhandene Datenbank aktivieren, um ein versehentliches Löschen der Datenbank zu verhindern.

Schutz vor Datenbanklöschung aktivieren

Sie können den Löschschutz für Datenbanken mit der gcloud CLI, den Clientbibliotheken und der REST API oder der RPC API aktivieren. Sie können den Löschschutz für Datenbanken nicht über die Google Cloud Console aktivieren.

gcloud

Führen Sie den folgenden Befehl aus, um die Einstellung für den Löschschutz einer Datenbank zu aktivieren:

  gcloud spanner databases update
  DATABASE_ID --instance=INSTANCE_ID
  --enable-drop-protection [--async]

Folgende Optionen sind erforderlich:

DATABASE_ID
ID der Datenbank.
INSTANCE_ID
ID der Instanz für die Datenbank.

Folgende Optionen sind optional:

--async
Sie können sofort zurückkehren, ohne auf den Abschluss des Vorgangs warten zu müssen.

Clientbibliotheken

C++

void UpdateDatabase(google::cloud::spanner_admin::DatabaseAdminClient client,
                    std::string const& project_id,
                    std::string const& instance_id,
                    std::string const& database_id, bool drop_protection) {
  google::cloud::spanner::Database db(project_id, instance_id, database_id);
  google::spanner::admin::database::v1::Database database;
  database.set_name(db.FullName());
  database.set_enable_drop_protection(drop_protection);
  google::protobuf::FieldMask update_mask;
  update_mask.add_paths("enable_drop_protection");
  auto updated = client.UpdateDatabase(database, update_mask).get();
  if (!updated) throw std::move(updated).status();
  std::cout << "Database " << updated->name() << " successfully updated.\n";
}

C#


using Google.Cloud.Spanner.Admin.Database.V1;
using Google.Cloud.Spanner.Common.V1;
using Google.Protobuf.WellKnownTypes;
using System;
using System.Threading.Tasks;

public class UpdateDatabaseAsyncSample
{
    public async Task<Database> UpdateDatabaseAsync(string projectId, string instanceId, string databaseId)
    {
        var databaseAdminClient = await DatabaseAdminClient.CreateAsync();
        var databaseName = DatabaseName.Format(projectId, instanceId, databaseId);
        Database databaseToUpdate = await databaseAdminClient.GetDatabaseAsync(databaseName);

        databaseToUpdate.EnableDropProtection = true;
        var updateDatabaseRequest = new UpdateDatabaseRequest()
        {
            Database = databaseToUpdate,
            UpdateMask = new FieldMask { Paths = { "enable_drop_protection" } }
        };

        var operation = await databaseAdminClient.UpdateDatabaseAsync(updateDatabaseRequest);

        // Wait until the operation has finished.
        Console.WriteLine("Waiting for the operation to finish.");
        var completedResponse = await operation.PollUntilCompletedAsync();

        if (completedResponse.IsFaulted)
        {
            Console.WriteLine($"Error while updating database {databaseId}: {completedResponse.Exception}");
            throw completedResponse.Exception;
        }

        Console.WriteLine($"Updated database {databaseId}.");

        // Return the updated database.
        return completedResponse.Result;
    }
}

Go

import (
	"context"
	"fmt"
	"io"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "cloud.google.com/go/spanner/admin/database/apiv1/databasepb"
	"google.golang.org/genproto/protobuf/field_mask"
)

func updateDatabase(ctx context.Context, w io.Writer, db string) error {
	// db = `projects/<project>/instances/<instance-id>/database/<database-id>`
	// Instantiate database admin client.
	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return fmt.Errorf("updateDatabase.NewDatabaseAdminClient: %w", err)
	}
	defer adminClient.Close()

	// Instantiate the request for performing update database operation.
	op, err := adminClient.UpdateDatabase(ctx, &adminpb.UpdateDatabaseRequest{
		Database: &adminpb.Database{
			Name:                 db,
			EnableDropProtection: true,
		},
		UpdateMask: &field_mask.FieldMask{
			Paths: []string{"enable_drop_protection"},
		},
	})
	if err != nil {
		return fmt.Errorf("updateDatabase.UpdateDatabase: %w", err)
	}

	// Wait for update database operation to complete.
	fmt.Fprintf(w, "Waiting for update database operation to complete [%s]\n", db)
	if _, err := op.Wait(ctx); err != nil {
		return fmt.Errorf("updateDatabase.Wait: %w", err)
	}
	fmt.Fprintf(w, "Updated database [%s]\n", db)
	return nil
}

Java


import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.Lists;
import com.google.protobuf.FieldMask;
import com.google.spanner.admin.database.v1.Database;
import com.google.spanner.admin.database.v1.DatabaseName;
import com.google.spanner.admin.database.v1.UpdateDatabaseMetadata;
import com.google.spanner.admin.database.v1.UpdateDatabaseRequest;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class UpdateDatabaseSample {

  static void updateDatabase() {
    // TODO(developer): Replace these variables before running the sample.
    final String projectId = "my-project";
    final String instanceId = "my-instance";
    final String databaseId = "my-database";

    updateDatabase(projectId, instanceId, databaseId);
  }

  static void updateDatabase(
      String projectId, String instanceId, String databaseId) {
    try (Spanner spanner =
        SpannerOptions.newBuilder().setProjectId(projectId).build().getService();
        DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
      final Database database =
          Database.newBuilder()
              .setName(DatabaseName.of(projectId, instanceId, databaseId).toString())
              .setEnableDropProtection(true).build();
      final UpdateDatabaseRequest updateDatabaseRequest =
          UpdateDatabaseRequest.newBuilder()
              .setDatabase(database)
              .setUpdateMask(
                  FieldMask.newBuilder().addAllPaths(
                      Lists.newArrayList("enable_drop_protection")).build())
              .build();
      OperationFuture<Database, UpdateDatabaseMetadata> operation =
          databaseAdminClient.updateDatabaseAsync(updateDatabaseRequest);
      System.out.printf("Waiting for update operation for %s to complete...\n", databaseId);
      Database updatedDb = operation.get(5, TimeUnit.MINUTES);
      System.out.printf("Updated database %s.\n", updatedDb.getName());
    } catch (ExecutionException | TimeoutException e) {
      // If the operation failed during execution, expose the cause.
      throw SpannerExceptionFactory.asSpannerException(e.getCause());
    } catch (InterruptedException e) {
      // Throw when a thread is waiting, sleeping, or otherwise occupied,
      // and the thread is interrupted, either before or during the activity.
      throw SpannerExceptionFactory.propagateInterrupt(e);
    }
  }
}

Node.js

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const instanceId = 'my-instance';
// const databaseId = 'my-database';
// const projectId = 'my-project-id';

// Imports the Google Cloud client library
const {Spanner, protos} = require('@google-cloud/spanner');

// creates a client
const spanner = new Spanner({
  projectId: projectId,
});

const databaseAdminClient = spanner.getDatabaseAdminClient();

async function updateDatabase() {
  // Update the database metadata fields
  try {
    console.log(
      `Updating database ${databaseAdminClient.databasePath(
        projectId,
        instanceId,
        databaseId
      )}.`
    );
    const [operation] = await databaseAdminClient.updateDatabase({
      database: {
        name: databaseAdminClient.databasePath(
          projectId,
          instanceId,
          databaseId
        ),
        enableDropProtection: true,
      },
      // updateMask contains the fields to be updated in database
      updateMask: (protos.google.protobuf.FieldMask = {
        paths: ['enable_drop_protection'],
      }),
    });
    console.log(
      `Waiting for update operation for ${databaseId} to complete...`
    );
    await operation.promise();
    console.log(`Updated database ${databaseId}.`);
  } catch (err) {
    console.log('ERROR:', err);
  }
}
updateDatabase();

PHP

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\Database;
use Google\Cloud\Spanner\Admin\Database\V1\GetDatabaseRequest;
use Google\Cloud\Spanner\Admin\Database\V1\UpdateDatabaseRequest;
use Google\Protobuf\FieldMask;

/**
 * Updates the drop protection setting for a database.
 * Example:
 * ```
 * update_database($projectId, $instanceId, $databaseId);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function update_database(string $projectId, string $instanceId, string $databaseId): void
{
    $newUpdateMaskField = new FieldMask([
        'paths' => ['enable_drop_protection']
    ]);
    $databaseAdminClient = new DatabaseAdminClient();
    $databaseFullName = DatabaseAdminClient::databaseName($projectId, $instanceId, $databaseId);
    $database = (new Database())
        ->setEnableDropProtection(true)
        ->setName($databaseFullName);

    printf('Updating database %s', $databaseId);
    $operation = $databaseAdminClient->updateDatabase((new UpdateDatabaseRequest())
        ->setDatabase($database)
        ->setUpdateMask($newUpdateMaskField));

    $operation->pollUntilComplete();

    $database = $databaseAdminClient->getDatabase(
        new GetDatabaseRequest(['name' => $databaseFullName])
    );
    printf(
        'Updated the drop protection for %s to %s' . PHP_EOL,
        $database->getName(),
        $database->getEnableDropProtection()
    );
}

Python

def update_database(instance_id, database_id):
    """Updates the drop protection setting for a database."""
    from google.cloud.spanner_admin_database_v1.types import \
        spanner_database_admin

    spanner_client = spanner.Client()
    database_admin_api = spanner_client.database_admin_api

    request = spanner_database_admin.UpdateDatabaseRequest(
        database=spanner_database_admin.Database(
            name=database_admin_api.database_path(
                spanner_client.project, instance_id, database_id
            ),
            enable_drop_protection=True,
        ),
        update_mask={"paths": ["enable_drop_protection"]},
    )
    operation = database_admin_api.update_database(request=request)
    print(
        "Waiting for update operation for {}/databases/{} to complete...".format(
            database_admin_api.instance_path(spanner_client.project, instance_id),
            database_id,
        )
    )
    operation.result(OPERATION_TIMEOUT_SECONDS)

    print(
        "Updated database {}/databases/{}.".format(
            database_admin_api.instance_path(spanner_client.project, instance_id),
            database_id,
        )
    )

Ruby

require "google/cloud/spanner/admin/database"

##
# This is a snippet for showcasing how to update database.
#
# @param project_id  [String] The ID of the Google Cloud project.
# @param instance_id [String] The ID of the spanner instance.
# @param database_id [String] The ID of the database.
#
def spanner_update_database project_id:, instance_id:, database_id:
  client = Google::Cloud::Spanner::Admin::Database.database_admin project_id: project_id
  db_path = client.database_path project: project_id, instance: instance_id, database: database_id
  database = client.get_database name: db_path

  puts "Updating database #{database.name}"
  database.enable_drop_protection = true
  job = client.update_database database: database, update_mask: { paths: ["enable_drop_protection"] }
  puts "Waiting for update operation for #{database.name} to complete..."
  job.wait_until_done!
  puts "Updated database #{database.name}"
end

Prüfen, ob der Löschschutz für eine Datenbank aktiviert ist

Sie können feststellen, ob der Löschschutz für Ihre Datenbank aktiviert ist, indem Sie die Datenbankkonfiguration aufrufen.

gcloud

Wenn Sie prüfen möchten, ob für eine Datenbank der Löschschutz aktiviert ist, können Sie den Befehl gcloud spanner databases describe ausführen, um detaillierte Informationen zu einer Datenbank abzurufen, oder gcloud spanner databases list ausführen, um detaillierte Informationen zu Datenbanken innerhalb einer Instanz abzurufen.

  gcloud spanner databases describe
  projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID

Folgende Optionen sind erforderlich:

PROJECT_ID
ID des Projekts für die Datenbank.
INSTANCE_ID
ID der Instanz für die Datenbank.
DATABASE_ID
ID der Datenbank.

Wenn der Löschschutz aktiviert ist, wird in der Ausgabe der Parameter enableDropProtection: true angezeigt.

Schutz vor Datenbanklöschung deaktivieren

Sie können den Löschschutz für Datenbanken deaktivieren, wenn eine Datenbank diesen Schutz nicht mehr benötigt oder wenn Sie eine Datenbank löschen müssen, für die diese Einstellung aktiviert ist.

Wenn Sie eine Instanz mit einer oder mehreren Datenbanken mit aktiviertem Löschschutz löschen möchten, müssen Sie zuerst den Löschschutz für alle Datenbanken in dieser Instanz deaktivieren, bevor Sie die Instanz löschen können.

gcloud

Führen Sie den folgenden Befehl aus, um die Einstellung für den Löschschutz einer Datenbank zu deaktivieren:

  gcloud spanner databases update
  DATABASE_ID --instance=INSTANCE_ID
  --no-enable-drop-protection [--async]

Folgende Optionen sind erforderlich:

DATABASE_ID
ID der Datenbank.
INSTANCE_ID
ID der Instanz für die Datenbank.

Folgende Optionen sind optional:

--async
Sie können sofort zurückkehren, ohne auf den Abschluss des Vorgangs warten zu müssen.

Nächste Schritte