Skip to content

Commit

Permalink
feat: Copy backup samples (#1802)
Browse files Browse the repository at this point in the history
* Revert "removing samples"

This reverts commit b06a3df.

* removing samples

* changes to samples

* linting

* changes as per comments

* Update samples/snippets/src/main/java/com/example/spanner/SpannerSample.java

Co-authored-by: Knut Olav Løite <koloite@gmail.com>

* Update samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java

Co-authored-by: Knut Olav Løite <koloite@gmail.com>

* don't merge

* Revert "don't merge"

This reverts commit cdf4d17.

* linting

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* linting

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

Co-authored-by: Knut Olav Løite <koloite@gmail.com>
Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Apr 22, 2022
1 parent 18ce38a commit 787ccad
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 16 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ implementation 'com.google.cloud:google-cloud-spanner'
If you are using Gradle without BOM, add this to your dependencies

```Groovy
implementation 'com.google.cloud:google-cloud-spanner:6.23.2'
implementation 'com.google.cloud:google-cloud-spanner:6.23.3'
```

If you are using SBT, add this to your dependencies

```Scala
libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.23.2"
libraryDependencies += "com.google.cloud" % "google-cloud-spanner" % "6.23.3"
```

## Authentication
Expand Down Expand Up @@ -252,6 +252,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-spanner/tree/
| Async Runner Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/AsyncRunnerExample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/AsyncRunnerExample.java) |
| Async Transaction Manager Example | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/AsyncTransactionManagerExample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/AsyncTransactionManagerExample.java) |
| Batch Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/BatchSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/BatchSample.java) |
| Copy Backup Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CopyBackupSample.java) |
| Create Backup With Encryption Key | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateBackupWithEncryptionKey.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CreateBackupWithEncryptionKey.java) |
| Create Database With Default Leader Sample | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithDefaultLeaderSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithDefaultLeaderSample.java) |
| Create Database With Encryption Key | [source code](https://github.com/googleapis/java-spanner/blob/main/samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithEncryptionKey.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-spanner&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/spanner/CreateDatabaseWithEncryptionKey.java) |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright 2022 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.spanner;

// [START spanner_copy_backup]

import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.Timestamp;
import com.google.cloud.spanner.Backup;
import com.google.cloud.spanner.BackupId;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.spanner.admin.database.v1.CopyBackupMetadata;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class CopyBackupSample {
static void copyBackup() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String sourceBackupId = "my-backup";
String destinationBackupId = "my-destination-backup";
try (Spanner spanner =
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
copyBackup(databaseAdminClient, projectId, instanceId, sourceBackupId, destinationBackupId);
}
}

static void copyBackup(
DatabaseAdminClient databaseAdminClient,
String projectId,
String instanceId,
String sourceBackupId,
String destinationBackupId) {

Timestamp expireTime =
Timestamp.ofTimeMicroseconds(
TimeUnit.MICROSECONDS.convert(
System.currentTimeMillis() + TimeUnit.DAYS.toMillis(14),
TimeUnit.MILLISECONDS));
// Creates a copy of an existing backup.
Backup destinationBackup =
databaseAdminClient
.newBackupBuilder(BackupId.of(projectId, instanceId, destinationBackupId))
.setExpireTime(expireTime)
.build();

// Initiate the request which returns an OperationFuture.
System.out.println("Copying backup [" + destinationBackup.getId() + "]...");
OperationFuture<Backup, CopyBackupMetadata> operation =
databaseAdminClient.copyBackup(
BackupId.of(projectId, instanceId, sourceBackupId), destinationBackup);
try {
// Wait for the backup operation to complete.
destinationBackup = operation.get();
System.out.println("Copied backup [" + destinationBackup.getId() + "]");
} catch (ExecutionException e) {
throw (SpannerException) e.getCause();
} catch (InterruptedException e) {
throw SpannerExceptionFactory.propagateInterrupt(e);
}
// Load the metadata of the new backup from the server.
destinationBackup = destinationBackup.reload();
System.out.println(
String.format(
"Backup %s of size %d bytes was copied at %s for version of database at %s",
destinationBackup.getId().getName(),
destinationBackup.getSize(),
LocalDateTime.ofEpochSecond(
destinationBackup.getProto().getCreateTime().getSeconds(),
destinationBackup.getProto().getCreateTime().getNanos(),
OffsetDateTime.now().getOffset()),
LocalDateTime.ofEpochSecond(
destinationBackup.getProto().getVersionTime().getSeconds(),
destinationBackup.getProto().getVersionTime().getNanos(),
OffsetDateTime.now().getOffset())));
return;
}
}
// [END spanner_copy_backup]
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import com.google.common.io.BaseEncoding;
import com.google.longrunning.Operation;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.spanner.admin.database.v1.CopyBackupMetadata;
import com.google.spanner.admin.database.v1.CreateBackupMetadata;
import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
import com.google.spanner.admin.database.v1.OptimizeRestoredDatabaseMetadata;
Expand Down Expand Up @@ -1659,21 +1660,23 @@ static void cancelCreateBackup(
// [END spanner_cancel_backup_create]

// [START spanner_list_backup_operations]
static void listBackupOperations(InstanceAdminClient instanceAdminClient, DatabaseId databaseId) {
static void listBackupOperations(
InstanceAdminClient instanceAdminClient, DatabaseId databaseId, BackupId backupId) {
Instance instance = instanceAdminClient.getInstance(databaseId.getInstanceId().getInstance());
// Get create backup operations for the sample database.
Timestamp last24Hours = Timestamp.ofTimeSecondsAndNanos(TimeUnit.SECONDS.convert(
TimeUnit.HOURS.convert(Timestamp.now().getSeconds(), TimeUnit.SECONDS) - 24,
TimeUnit.HOURS), 0);
String filter =
String.format(
"(metadata.database:%s) AND "
+ "(metadata.@type:type.googleapis.com/"
+ "google.spanner.admin.database.v1.CreateBackupMetadata) AND "
+ "(metadata.progress.start_time > \"%s\")",
databaseId.getName(), last24Hours);
Page<Operation> operations = instance.listBackupOperations(Options.filter(filter));
for (Operation op : operations.iterateAll()) {
"(metadata.@type:type.googleapis.com/"
+ "google.spanner.admin.database.v1.CreateBackupMetadata) "
+ "AND (metadata.database:%s)",
databaseId.getName());
Page<Operation> createBackupOperations = instance.listBackupOperations(
Options.filter(filter));
System.out.println("Create Backup Operations:");
for (Operation op : createBackupOperations.iterateAll()) {
try {
CreateBackupMetadata metadata = op.getMetadata().unpack(CreateBackupMetadata.class);
System.out.println(
Expand All @@ -1687,6 +1690,30 @@ static void listBackupOperations(InstanceAdminClient instanceAdminClient, Databa
System.err.println(e.getMessage());
}
}
// Get copy backup operations for the sample database.
filter =
String.format(
"(metadata.@type:type.googleapis.com/"
+ "google.spanner.admin.database.v1.CopyBackupMetadata) "
+ "AND (metadata.source_backup:%s)",
backupId.getName());
Page<Operation> copyBackupOperations = instance.listBackupOperations(Options.filter(filter));
System.out.println("Copy Backup Operations:");
for (Operation op : copyBackupOperations.iterateAll()) {
try {
CopyBackupMetadata copyBackupMetadata =
op.getMetadata().unpack(CopyBackupMetadata.class);
System.out.println(
String.format(
"Copy Backup %s on backup %s pending: %d%% complete",
copyBackupMetadata.getName(),
copyBackupMetadata.getSourceBackup(),
copyBackupMetadata.getProgress().getProgressPercent()));
} catch (InvalidProtocolBufferException e) {
// The returned operation does not contain CopyBackupMetadata.
System.err.println(e.getMessage());
}
}
}
// [END spanner_list_backup_operations]

Expand Down Expand Up @@ -1840,13 +1867,19 @@ static void updateBackup(DatabaseAdminClient dbAdminClient, BackupId backupId) {
TimeUnit.SECONDS.toMicros(backup.getExpireTime().getSeconds())
+ TimeUnit.NANOSECONDS.toMicros(backup.getExpireTime().getNanos())
+ TimeUnit.DAYS.toMicros(30L));
// New Expire Time must be less than Max Expire Time
expireTime = expireTime.compareTo(backup.getMaxExpireTime())
< 0 ? expireTime : backup.getMaxExpireTime();
int timeDiff = expireTime.compareTo(backup.getExpireTime());
Timestamp newExpireTime = (timeDiff < 0) ? expireTime : backup.getExpireTime();

System.out.println(String.format(
"Updating expire time of backup [%s] to %s...",
backupId.toString(),
LocalDateTime.ofEpochSecond(
expireTime.getSeconds(),
expireTime.getNanos(),
OffsetDateTime.now().getOffset()).toString()));
expireTime.getSeconds(),
expireTime.getNanos(),
OffsetDateTime.now().getOffset()).toString()));

// Update expire time.
backup = backup.toBuilder().setExpireTime(expireTime).build();
Expand Down Expand Up @@ -2048,7 +2081,7 @@ static void run(
BackupId.of(backup.getInstanceId(), backup.getBackup() + "_cancel"));
break;
case "listbackupoperations":
listBackupOperations(instanceAdminClient, database);
listBackupOperations(instanceAdminClient, database, backup);
break;
case "listdatabaseoperations":
listDatabaseOperations(instanceAdminClient, dbAdminClient, database.getInstanceId());
Expand Down Expand Up @@ -2144,14 +2177,14 @@ static void printUsageAndExit() {
System.err.println(" SpannerExample querywithqueryoptions my-instance example-db");
System.err.println(" SpannerExample createbackup my-instance example-db");
System.err.println(" SpannerExample listbackups my-instance example-db");
System.err.println(" SpannerExample listbackupoperations my-instance example-db");
System.err.println(" SpannerExample listbackupoperations my-instance example-db backup-id");
System.err.println(" SpannerExample listdatabaseoperations my-instance example-db");
System.err.println(" SpannerExample restorebackup my-instance example-db");
System.exit(1);
}

public static void main(String[] args) throws Exception {
if (args.length != 3) {
if (args.length != 3 && args.length != 4) {
printUsageAndExit();
}
// [START init_client]
Expand All @@ -2176,6 +2209,9 @@ public static void main(String[] args) throws Exception {
"%s_%02d",
db.getDatabase(), LocalDate.now().get(ChronoField.ALIGNED_WEEK_OF_YEAR));
BackupId backup = BackupId.of(db.getInstanceId(), backupName);
if (args.length == 4) {
backupName = args[3];
}

// [START init_client]
DatabaseClient dbClient = spanner.getDatabaseClient(db);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.example.spanner;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertTrue;

import com.google.cloud.Timestamp;
import com.google.cloud.spanner.Backup;
Expand Down Expand Up @@ -328,6 +329,8 @@ public void testSample() throws Exception {
"Backup %s on database %s pending:",
backupId.getName(),
dbId.getName()));
assertTrue("Out does not contain copy backup operations", out.contains(
"Copy Backup Operations"));
} catch (SpannerException e) {
assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT);
assertThat(e.getMessage()).contains("Cannot evaluate filter expression");
Expand Down

0 comments on commit 787ccad

Please sign in to comment.