Skip to content

Commit

Permalink
feat(Spanner): enable drop db protection (#6008)
Browse files Browse the repository at this point in the history
  • Loading branch information
vishwarajanand authored Jun 20, 2023
1 parent ae597e5 commit d97c721
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Spanner/src/Connection/ConnectionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

/**
* Describes a connection to the Cloud Spanner API
*
* @internal
*/
interface ConnectionInterface
{
Expand Down Expand Up @@ -148,6 +150,11 @@ public function listDatabases(array $args);
*/
public function createDatabase(array $args);

/**
* @param array $args
*/
public function updateDatabase(array $args);

/**
* @param array $args
*/
Expand Down
17 changes: 17 additions & 0 deletions Spanner/src/Connection/Grpc.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@

/**
* Connection to Cloud Spanner over gRPC
*
* @internal
*/
class Grpc implements ConnectionInterface
{
Expand Down Expand Up @@ -679,6 +681,21 @@ public function createDatabase(array $args)
return $this->operationToArray($res, $this->serializer, $this->lroResponseMappers);
}

/**
* @param array $args
*/
public function updateDatabase(array $args)
{
$databaseInfo = $this->serializer->decodeMessage(new Database(), $this->pluck('database', $args));
$databaseName = $databaseInfo->getName();
$updateMask = $this->serializer->decodeMessage(new FieldMask(), $this->pluck('updateMask', $args));
return $this->send([$this->getDatabaseAdminClient(), 'updateDatabase'], [
$databaseInfo,
$updateMask,
$this->addResourcePrefixHeader($args, $databaseName)
]);
}

/**
* @param array $args
*/
Expand Down
37 changes: 37 additions & 0 deletions Spanner/src/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,43 @@ public function restore($backup, array $options = [])
return $this->instance->createDatabaseFromBackup($this->name, $backup, $options);
}

/**
* Update an existing Cloud Spanner database.
*
* Example:
* ```
* $operation = $database->updateDatabase(['enableDropProtection' => true]);
* ```
*
* @codingStandardsIgnoreStart
* @see https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#updatedatabaserequest UpdateDatabaseRequest
* @codingStandardsIgnoreEnd
*
* @param array $options [optional] {
* Configuration Options
*
* @type bool $enableDropProtection If `true`, delete operations for Database
* and Instance will be blocked. **Defaults to** `false`.
* }
* @return LongRunningOperation<Database>
*/
public function updateDatabase(array $options = [])
{
$fieldMask = [];
if (isset($options['enableDropProtection'])) {
$fieldMask[] = 'enable_drop_protection';
}
return $this->info = $this->connection->updateDatabase([
'database' => [
'name' => $this->name,
'enableDropProtection' => $options['enableDropProtection'] ?? false,
],
'updateMask' => [
'paths' => $fieldMask
]
] + $options);
}

/**
* Update the Database schema by running a SQL statement.
*
Expand Down
46 changes: 46 additions & 0 deletions Spanner/tests/System/AdminTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

namespace Google\Cloud\Spanner\Tests\System;

use Google\Cloud\Core\Exception\FailedPreconditionException;
use Google\Cloud\Core\LongRunning\LongRunningOperation;
use Google\Cloud\Spanner\Admin\Database\V1\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\DatabaseDialect;
Expand Down Expand Up @@ -129,6 +130,51 @@ public function testDatabase()
$this->assertEquals($db->ddl()[0], $stmt);
}

public function testDatabaseDropProtection()
{
$this->skipEmulatorTests();
$instance = self::$instance;

$dbName = uniqid(self::TESTING_PREFIX);
$op = $instance->createDatabase($dbName);

$this->assertInstanceOf(LongRunningOperation::class, $op);
$db = $op->pollUntilComplete();
$this->assertInstanceOf(Database::class, $db);

$info = $db->reload();
$this->assertFalse($info['enableDropProtection']);

$op = $db->updateDatabase(['enableDropProtection' => true]);
$op->pollUntilComplete();
$info = $db->reload();
$this->assertTrue($info['enableDropProtection']);

// delete database should throw
$isDropThrows = false;
try {
$db->drop();
} catch (FailedPreconditionException $ex) {
$isDropThrows = true;
$this->assertStringContainsStringIgnoringCase(
'enable_drop_protection',
$ex->getMessage()
);
}
$this->assertTrue($isDropThrows);
$this->assertTrue($db->exists());

// disable drop databases config
$op = $db->updateDatabase(['enableDropProtection' => false]);
$op->pollUntilComplete();
$info = $db->reload();
$this->assertFalse($info['enableDropProtection']);

// drop should succeed
$db->drop();
$this->assertFalse($db->exists());
}

public function testCreateCustomerManagedInstanceConfiguration()
{
$this->skipEmulatorTests();
Expand Down
21 changes: 21 additions & 0 deletions Spanner/tests/Unit/DatabaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,27 @@ public function testCreate()
$this->assertInstanceOf(LongRunningOperation::class, $op);
}

/**
* @group spanner-admin
*/
public function testUpdateDatabase()
{
$this->connection->updateDatabase(Argument::allOf(
Argument::withEntry('database', [
'name' => DatabaseAdminClient::databaseName(self::PROJECT, self::INSTANCE, self::DATABASE),
'enableDropProtection' => true,
]),
Argument::withEntry('updateMask', ['paths' => ['enable_drop_protection']])
))->shouldBeCalledTimes(1)->willReturn([
'enableDropProtection' => true
]);

$this->database->___setProperty('connection', $this->connection->reveal());

$res = $this->database->updateDatabase(['enableDropProtection' => true]);
$this->assertTrue($res['enableDropProtection']);
}

/**
* @group spanner-admin
*/
Expand Down

0 comments on commit d97c721

Please sign in to comment.