Skip to content

Commit adb188b

Browse files
panerorenn9541amanda-tarafa
authored andcommitted
feat[Spanner]: Add Multi Region Encryption samples
1 parent 5c9c7d0 commit adb188b

18 files changed

+551
-71
lines changed

spanner/api/Spanner.Samples.Tests/CopyBackupTest.cs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2022 Google Inc.
1+
// Copyright 2022 Google Inc.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -30,17 +30,12 @@ public CopyBackupTest(SpannerFixture spannerFixture)
3030
public void CopyBackup()
3131
{
3232
CopyBackupSample copyBackupSample = new CopyBackupSample();
33-
string source_Project_id = _spannerFixture.ProjectId;
34-
string source_Instance_id = _spannerFixture.InstanceId;
35-
string source_backupId = _spannerFixture.BackupId;
36-
string target_Project_id = _spannerFixture.ProjectId;
37-
string target_Instance_id = _spannerFixture.InstanceId;
38-
string target_backupId = SpannerFixture.GenerateId("test_", 16);
39-
DateTimeOffset expireTime = DateTimeOffset.UtcNow.AddHours(12);
4033

41-
Backup backup = copyBackupSample.CopyBackup(source_Instance_id, source_Project_id, source_backupId,
42-
target_Instance_id, target_Project_id, target_backupId, expireTime);
34+
Backup backup = copyBackupSample.CopyBackup(
35+
sourceProjectId: _spannerFixture.ProjectId, sourceInstanceId: _spannerFixture.InstanceId, sourceBackupId: _spannerFixture.BackupId,
36+
targetProjectId: _spannerFixture.ProjectId, targetInstanceId: _spannerFixture.InstanceId, targetBackupId: SpannerFixture.GenerateId("test_", 16),
37+
expireTime: DateTimeOffset.UtcNow.AddHours(6));
4338

4439
Assert.NotNull(backup);
4540
}
46-
}
41+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2024 Google Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using Google.Cloud.Spanner.Admin.Database.V1;
16+
using System;
17+
using System.Linq;
18+
using System.Threading.Tasks;
19+
using Xunit;
20+
21+
[Collection(nameof(SpannerFixture))]
22+
public class CopyBackupWithMultiRegionEncryptionAsyncTest
23+
{
24+
private readonly SpannerFixture _fixture;
25+
26+
public CopyBackupWithMultiRegionEncryptionAsyncTest(SpannerFixture fixture)
27+
{
28+
_fixture = fixture;
29+
}
30+
31+
[SkippableFact]
32+
public async Task TestCopyBackupWithMultiRegionEncryptionAsync()
33+
{
34+
CopyBackupWithMultiRegionEncryptionAsyncSample copyBackupSample = new CopyBackupWithMultiRegionEncryptionAsyncSample();
35+
36+
var backup = await copyBackupSample.CopyBackupWithMultiRegionEncryptionAsync(
37+
sourceProjectId: _fixture.ProjectId, sourceInstanceId: _fixture.InstanceId, sourceBackupId: _fixture.BackupId,
38+
targetProjectId: _fixture.ProjectId, targetInstanceId: _fixture.InstanceId, targetBackupId: SpannerFixture.GenerateId("test_", 16),
39+
expireTime: DateTimeOffset.UtcNow.AddHours(6), kmsKeyNames: _fixture.KmsKeyNames);
40+
41+
Assert.All(backup.EncryptionInformation, encryptionInfo => _fixture.KmsKeyNames.Any(keyName => encryptionInfo.KmsKeyVersion.StartsWith(keyName.ToString())));
42+
}
43+
}

spanner/api/Spanner.Samples.Tests/CreateBackupWithEncryptionKeyAsyncTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2021 Google Inc.
1+
// Copyright 2021 Google Inc.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@ public CreateBackupWithEncryptionKeyAsyncTest(SpannerFixture fixture)
3232
[SkippableFact]
3333
public async Task TestCreatBackupWithEncryptionKeyAsync()
3434
{
35-
Skip.If(!_fixture.RunCmekBackupSampleTests, SpannerFixture.SkipCmekBackupSamplesMessage);
35+
Skip.If(_fixture.SkipCmekBackupSampleTests, SpannerFixture.SkipCmekBackupSamplesMessage);
3636
// Create a backup with a custom encryption key.
3737
var sample = new CreateBackupWithEncryptionKeyAsyncSample();
3838
var backup = await sample.CreateBackupWithEncryptionKeyAsync(_fixture.ProjectId, _fixture.InstanceId, _fixture.FixedEncryptedDatabaseId, _fixture.EncryptedBackupId, _fixture.KmsKeyName);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2024 Google Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using Google.Cloud.Spanner.Admin.Database.V1;
16+
using System;
17+
using System.Linq;
18+
using System.Threading.Tasks;
19+
using Xunit;
20+
21+
/// <summary>
22+
/// Tests creating a backup using MR CMEK.
23+
/// </summary>
24+
[Collection(nameof(SpannerFixture))]
25+
public class CreateBackupWithMultiRegionEncryptionAsyncTest
26+
{
27+
private readonly SpannerFixture _fixture;
28+
29+
public CreateBackupWithMultiRegionEncryptionAsyncTest(SpannerFixture fixture)
30+
{
31+
_fixture = fixture;
32+
}
33+
34+
[SkippableFact]
35+
public async Task TestCreateBackupWithMultiRegionEncryptionAsync()
36+
{
37+
Skip.If(_fixture.SkipCmekBackupSampleTests, SpannerFixture.SkipCmekBackupSamplesMessage);
38+
// Create a backup with custom encryption keys.
39+
var sample = new CreateBackupWithMultiRegionEncryptionAsyncSample();
40+
var backup = await sample.CreateBackupWithMultiRegionEncryptionAsync(_fixture.ProjectId, _fixture.InstanceId, _fixture.FixedMultiRegionEncryptedBackupId, _fixture.MultiRegionEncryptedBackupId, _fixture.KmsKeyNames);
41+
Assert.All(backup.EncryptionInformation, encryptionInfo => _fixture.KmsKeyNames.Any(keyName => encryptionInfo.KmsKeyVersion.StartsWith(keyName.ToString())));
42+
}
43+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2024 Google Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System.Threading.Tasks;
16+
using Xunit;
17+
using Google.Cloud.Spanner.Admin.Database.V1;
18+
using System.Linq;
19+
20+
/// <summary>
21+
/// Tests creating a databases using MR CMEK.
22+
/// </summary>
23+
[Collection(nameof(SpannerFixture))]
24+
public class CreateDatabaseWithMultiRegionEncryptionAsyncTest
25+
{
26+
private readonly SpannerFixture _fixture;
27+
28+
public CreateDatabaseWithMultiRegionEncryptionAsyncTest(SpannerFixture fixture)
29+
{
30+
_fixture = fixture;
31+
}
32+
33+
[Fact]
34+
public async Task TestCreateDatabaseWithMultiRegionEncryptionAsync()
35+
{
36+
// Create a database with custom encryption keys.
37+
var sample = new CreateDatabaseWithMultiRegionEncryptionAsyncSample();
38+
var database = await sample.CreateDatabaseWithMultiRegionEncryptionAsync(_fixture.ProjectId, _fixture.InstanceId, _fixture.MultiRegionEncryptedDatabaseId, _fixture.KmsKeyNames);
39+
Assert.All(database.EncryptionConfig.KmsKeyNamesAsCryptoKeyNames, keyName => _fixture.KmsKeyNames.Contains(keyName));
40+
}
41+
}

spanner/api/Spanner.Samples.Tests/RestoreDatabaseWithEncryptionKeyAsyncTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2021 Google Inc.
1+
// Copyright 2021 Google Inc.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@ public RestoreDatabaseWithEncryptionKeyAsyncTest(SpannerFixture fixture)
3333
[SkippableFact]
3434
public async Task TestRestoreDatabaseWithEncryptionKeyAsync()
3535
{
36-
Skip.If(!_fixture.RunCmekBackupSampleTests, SpannerFixture.SkipCmekBackupSamplesMessage);
36+
Skip.If(_fixture.SkipCmekBackupSampleTests, SpannerFixture.SkipCmekBackupSamplesMessage);
3737
var sample = new RestoreDatabaseWithEncryptionAsyncSample();
3838
var database = await sample.RestoreDatabaseWithEncryptionAsync(_fixture.ProjectId, _fixture.InstanceId, _fixture.EncryptedRestoreDatabaseId, _fixture.FixedEncryptedBackupId, _fixture.KmsKeyName);
3939
Assert.Equal(_fixture.KmsKeyName, CryptoKeyName.Parse(database.EncryptionConfig.KmsKeyName));
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2024 Google Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using Google.Cloud.Spanner.Admin.Database.V1;
16+
using System;
17+
using System.Linq;
18+
using System.Threading.Tasks;
19+
using Xunit;
20+
21+
/// <summary>
22+
/// Tests restoring a databases using customer managed encryption.
23+
/// </summary>
24+
[Collection(nameof(SpannerFixture))]
25+
public class RestoreDatabaseWithMultiRegionEncryptionAsyncTest
26+
{
27+
private readonly SpannerFixture _fixture;
28+
29+
public RestoreDatabaseWithMultiRegionEncryptionAsyncTest(SpannerFixture fixture)
30+
{
31+
_fixture = fixture;
32+
}
33+
34+
[SkippableFact]
35+
public async Task TestRestoreDatabaseWithMultiRegionEncryptionAsync()
36+
{
37+
Skip.If(_fixture.SkipCmekBackupSampleTests, SpannerFixture.SkipCmekBackupSamplesMessage);
38+
var sample = new RestoreDatabaseWithMultiRegionEncryptionAsyncSample();
39+
var database = await sample.RestoreDatabaseWithMultiRegionEncryptionAsync(_fixture.ProjectId, _fixture.InstanceId, _fixture.MultiRegionEncryptedDatabaseId, _fixture.FixedMultiRegionEncryptedBackupId, _fixture.KmsKeyNames);
40+
Assert.All(database.EncryptionConfig.KmsKeyNamesAsCryptoKeyNames, keyName => _fixture.KmsKeyNames.Contains(keyName));
41+
}
42+
}

spanner/api/Spanner.Samples.Tests/SpannerFixture.cs

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,23 +60,31 @@ AlbumTitle STRING(MAX)
6060
public string ToBeCancelledBackupId { get; } = GenerateId("my-backup-");
6161
public string RestoredDatabaseId { get; private set; }
6262

63-
public bool RunCmekBackupSampleTests { get; private set; }
63+
public bool SkipCmekBackupSampleTests { get; private set; }
6464
public const string SkipCmekBackupSamplesMessage = "Spanner CMEK backup sample tests are disabled by default for performance reasons. Set the environment variable RUN_SPANNER_CMEK_BACKUP_SAMPLES_TESTS=true to enable the test.";
6565

6666
public string EncryptedDatabaseId { get; private set; }
6767
public string EncryptedBackupId { get; } = GenerateId("my-enc-backup-");
68-
// 'restore' is abbreviated to prevent the name from becoming longer than 30 characters.
6968
public string EncryptedRestoreDatabaseId { get; private set; }
7069

7170
// These are intentionally kept on the instance to avoid the need to create a new encrypted database and backup for each run.
7271
public string FixedEncryptedDatabaseId { get; } = "fixed-enc-backup-db";
7372
public string FixedEncryptedBackupId { get; } = "fixed-enc-backup";
7473

74+
public string MultiRegionEncryptedDatabaseId { get; private set; }
75+
public string MultiRegionEncryptedBackupId { get; } = GenerateId("my-mr-enc-backup-");
76+
public string MultiRegionEncryptedRestoreDatabaseId { get; private set; }
77+
78+
// These are intentionally kept on the instance to avoid the need to create a new encrypted database and backup for each run.
79+
public string FixedMultiRegionEncryptedDatabaseId { get; } = "fixed-mr-backup-db";
80+
public string FixedMultiRegionEncryptedBackupId { get; } = "fixed-mr-backup";
81+
7582
public CryptoKeyName KmsKeyName { get; } = new CryptoKeyName(
7683
Environment.GetEnvironmentVariable("spanner.test.key.project") ?? Environment.GetEnvironmentVariable("GOOGLE_PROJECT_ID"),
7784
Environment.GetEnvironmentVariable("spanner.test.key.location") ?? "us-central1",
7885
Environment.GetEnvironmentVariable("spanner.test.key.ring") ?? "spanner-test-keyring",
7986
Environment.GetEnvironmentVariable("spanner.test.key.name") ?? "spanner-test-key");
87+
public CryptoKeyName[] KmsKeyNames { get; private set; }
8088

8189
public string InstanceIdWithProcessingUnits { get; } = GenerateId("my-ins-pu-");
8290
public string InstanceIdWithMultiRegion { get; } = GenerateId("my-ins-mr-");
@@ -103,6 +111,9 @@ public async Task InitializeAsync()
103111
RestoredDatabaseId = GenerateTempDatabaseId("my-restore-db-");
104112
EncryptedDatabaseId = GenerateTempDatabaseId("my-enc-db-");
105113
EncryptedRestoreDatabaseId = GenerateTempDatabaseId("my-enc-r-db-");
114+
MultiRegionEncryptedDatabaseId = GenerateTempDatabaseId("my-mr-db-");
115+
MultiRegionEncryptedRestoreDatabaseId = GenerateTempDatabaseId("my-mr-r-db-");
116+
KmsKeyNames = new CryptoKeyName[] { KmsKeyName };
106117

107118
DatabaseAdminClient = await DatabaseAdminClient.CreateAsync();
108119
InstanceAdminClient = await InstanceAdminClient.CreateAsync();
@@ -111,7 +122,7 @@ public async Task InitializeAsync()
111122
PgSpannerConnection = new SpannerConnection($"Data Source=projects/{ProjectId}/instances/{InstanceId}/databases/{PostgreSqlDatabaseId}");
112123

113124
bool.TryParse(Environment.GetEnvironmentVariable("RUN_SPANNER_CMEK_BACKUP_SAMPLES_TESTS"), out var runCmekBackupSampleTests);
114-
RunCmekBackupSampleTests = runCmekBackupSampleTests;
125+
SkipCmekBackupSampleTests = !runCmekBackupSampleTests;
115126

116127
await MaybeInitializeTestInstanceAsync();
117128
await CreateInstanceWithMultiRegionAsync();
@@ -122,9 +133,10 @@ public async Task InitializeAsync()
122133

123134
// Create encryption key for creating an encrypted database and optionally backing up and restoring an encrypted database.
124135
await InitializeEncryptionKeys();
125-
if (RunCmekBackupSampleTests)
136+
if (!SkipCmekBackupSampleTests)
126137
{
127138
await InitializeEncryptedBackupAsync();
139+
await InitializeMultiRegionEncryptedBackupAsync();
128140
}
129141
}
130142

@@ -138,9 +150,9 @@ public async Task DisposeAsync()
138150
DeleteInstanceAsync(InstanceIdWithProcessingUnits),
139151
DeleteInstanceAsync(InstanceIdWithInstancePartition),
140152
DeleteBackupAsync(ToBeCancelledBackupId),
141-
DeleteBackupAsync(EncryptedBackupId)
153+
DeleteBackupAsync(EncryptedBackupId),
154+
DeleteBackupAsync(MultiRegionEncryptedRestoreDatabaseId)
142155
};
143-
144156
DeleteInstanceConfig(CreateCustomInstanceConfigId);
145157
DeleteInstanceConfig(UpdateCustomInstanceConfigId);
146158
DeleteInstanceConfig(DeleteCustomInstanceConfigId);
@@ -378,6 +390,38 @@ private async Task InitializeEncryptedBackupAsync()
378390
}
379391
}
380392

393+
private async Task InitializeMultiRegionEncryptedBackupAsync()
394+
{
395+
// Sample backup for MR CMEK restore test.
396+
try
397+
{
398+
CreateDatabaseWithMultiRegionEncryptionAsyncSample createDatabaseAsyncSample = new CreateDatabaseWithMultiRegionEncryptionAsyncSample();
399+
InsertDataAsyncSample insertDataAsyncSample = new InsertDataAsyncSample();
400+
await createDatabaseAsyncSample.CreateDatabaseWithMultiRegionEncryptionAsync(ProjectId, InstanceId, FixedMultiRegionEncryptedDatabaseId, KmsKeyNames);
401+
await insertDataAsyncSample.InsertDataAsync(ProjectId, InstanceId, FixedMultiRegionEncryptedDatabaseId);
402+
}
403+
catch (Exception e) when (e.ToString().Contains("Database already exists"))
404+
{
405+
// We intentionally keep an existing database around to reduce
406+
// the likelihood of test timeouts when creating a backup so
407+
// it's ok to get an AlreadyExists error.
408+
Console.WriteLine($"Database {FixedMultiRegionEncryptedDatabaseId} already exists.");
409+
}
410+
411+
try
412+
{
413+
CreateBackupWithMultiRegionEncryptionAsyncSample createBackupSample = new CreateBackupWithMultiRegionEncryptionAsyncSample();
414+
await createBackupSample.CreateBackupWithMultiRegionEncryptionAsync(ProjectId, InstanceId, FixedMultiRegionEncryptedDatabaseId, FixedMultiRegionEncryptedBackupId, KmsKeyNames);
415+
}
416+
catch (RpcException e) when (e.StatusCode == StatusCode.AlreadyExists)
417+
{
418+
// We intentionally keep an existing backup around to reduce
419+
// the likelihood of test timeouts when creating a backup so
420+
// it's ok to get an AlreadyExists error.
421+
Console.WriteLine($"Backup {FixedMultiRegionEncryptedBackupId} already exists.");
422+
}
423+
}
424+
381425
private async Task DeleteInstanceAsync(string instanceId)
382426
{
383427
try

spanner/api/Spanner.Samples/CopyBackup.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2022 Google Inc.
1+
// Copyright 2022 Google Inc.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -22,18 +22,19 @@
2222

2323
public class CopyBackupSample
2424
{
25-
public Backup CopyBackup(string sourceInstanceId, string sourceProjectId, string sourceBackupId,
26-
string targetInstanceId, string targetProjectId, string targetBackupId,
25+
public Backup CopyBackup(
26+
string sourceProjectId, string sourceInstanceId, string sourceBackupId,
27+
string targetProjectId, string targetInstanceId, string targetBackupId,
2728
DateTimeOffset expireTime)
2829
{
2930
DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.Create();
3031

3132
var request = new CopyBackupRequest
3233
{
33-
SourceBackupAsBackupName = new BackupName(sourceProjectId, sourceInstanceId, sourceBackupId),
34+
SourceBackupAsBackupName = new BackupName(sourceProjectId, sourceInstanceId, sourceBackupId),
3435
ParentAsInstanceName = new InstanceName(targetProjectId, targetInstanceId),
3536
BackupId = targetBackupId,
36-
ExpireTime = Timestamp.FromDateTimeOffset(expireTime)
37+
ExpireTime = Timestamp.FromDateTimeOffset(expireTime)
3738
};
3839

3940
var response = databaseAdminClient.CopyBackup(request);
@@ -50,10 +51,10 @@ public Backup CopyBackup(string sourceInstanceId, string sourceProjectId, string
5051

5152
Console.WriteLine($"Backup created successfully.");
5253
Console.WriteLine($"Backup with Id {sourceBackupId} has been copied from {sourceProjectId}/{sourceInstanceId} to {targetProjectId}/{targetInstanceId} Backup {targetBackupId}");
53-
Console.WriteLine($"Backup {backup.Name} of size {backup.SizeBytes} bytes was created at {backup.CreateTime} from {backup.Database} and is in state {backup.State} and has version time {backup.VersionTime.ToDateTime()}");
54+
Console.WriteLine($"Backup {backup.Name} of size {backup.SizeBytes} bytes was created at {backup.CreateTime} from {backup.Database} and is in state {backup.State} and has version time {backup.VersionTime}");
5455

5556
return backup;
5657
}
5758
}
5859

59-
// [END spanner_copy_backup]
60+
// [END spanner_copy_backup]

0 commit comments

Comments
 (0)