Skip to content

Commit 07416aa

Browse files
feat(compute): add compute instance create replicated boot disk sample (GoogleCloudPlatform#9735)
* Implemented compute_instance_create_replicated_boot_disk sample, created test * Fixed test * Fixed code as requested in the comments * Fixed Util class * Fixed code
1 parent 3b9ac56 commit 07416aa

File tree

2 files changed

+180
-35
lines changed

2 files changed

+180
-35
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package compute;
18+
19+
// [START compute_instance_create_replicated_boot_disk]
20+
import com.google.cloud.compute.v1.AttachedDisk;
21+
import com.google.cloud.compute.v1.AttachedDiskInitializeParams;
22+
import com.google.cloud.compute.v1.Instance;
23+
import com.google.cloud.compute.v1.InstancesClient;
24+
import com.google.cloud.compute.v1.NetworkInterface;
25+
import com.google.cloud.compute.v1.Operation;
26+
import com.google.cloud.compute.v1.Operation.Status;
27+
import java.io.IOException;
28+
import java.util.ArrayList;
29+
import java.util.List;
30+
import java.util.concurrent.ExecutionException;
31+
import java.util.concurrent.TimeUnit;
32+
import java.util.concurrent.TimeoutException;
33+
34+
public class CreateInstanceWithRegionalDiskFromSnapshot {
35+
36+
public static void main(String[] args) throws IOException, ExecutionException,
37+
InterruptedException, TimeoutException {
38+
// TODO(developer): Replace these variables before running the sample
39+
// Project ID or project number of the Cloud project you want to use.
40+
String projectId = "YOUR_PROJECT_ID";
41+
// Name of the zone in which you want to create the instance.
42+
String zone = "us-central1-a";
43+
// Name of the instance you want to create.
44+
String instanceName = "YOUR_INSTANCE_NAME";
45+
// Name for the replicated disk.
46+
String diskName = "YOUR_REPLICATED_DISK_NAME";
47+
String region = zone.substring(0, zone.length() - 2);
48+
// Type of the disk.
49+
String diskType = String.format(
50+
"projects/%s/regions/%s/diskTypes/pd-standard", projectId, region);
51+
// The full path and name of the snapshot that you want to use as the source for the new disk.
52+
String snapshotLink = String.format("projects/%s/global/snapshots/%s", projectId,
53+
"SNAPSHOT_NAME");
54+
// An iterable collection of zone names in which you want to keep
55+
// the new disks' replicas. One of the replica zones of the clone must match
56+
// the zone of the source disk.
57+
List<String> replicaZones = new ArrayList<>();
58+
59+
createInstanceWithRegionalDiskFromSnapshot(projectId, zone, instanceName, diskName, diskType,
60+
snapshotLink, replicaZones);
61+
}
62+
63+
// Creates a new VM instance with regional disk from a snapshot and specifies replica zones.
64+
public static Status createInstanceWithRegionalDiskFromSnapshot(
65+
String projectId, String zone, String instanceName, String diskName,
66+
String diskType, String snapshotLink, List<String> replicaZones)
67+
throws IOException, ExecutionException, InterruptedException, TimeoutException {
68+
// Initialize client that will be used to send requests. This client only needs to be created
69+
// once, and can be reused for multiple requests.
70+
try (InstancesClient instancesClient = InstancesClient.create()) {
71+
AttachedDiskInitializeParams initializeParams = AttachedDiskInitializeParams.newBuilder()
72+
.setSourceSnapshot(snapshotLink)
73+
.setDiskType(diskType)
74+
.setDiskName(diskName)
75+
.addAllReplicaZones(replicaZones)
76+
.build();
77+
78+
// Boot disk configuration
79+
AttachedDisk bootDisk = AttachedDisk.newBuilder()
80+
.setBoot(true)
81+
.setAutoDelete(true) // Optional: Delete disk when instance is deleted.
82+
.setType(AttachedDisk.Type.PERSISTENT.toString())
83+
.setInitializeParams(initializeParams)
84+
.build();
85+
86+
// Network interface configuration (using the default network)
87+
NetworkInterface networkInterface = NetworkInterface.newBuilder()
88+
.setNetwork("global/networks/default")
89+
.build();
90+
91+
// Create the instance resource
92+
Instance instanceResource = Instance.newBuilder()
93+
.setName(instanceName)
94+
.setMachineType(String.format("zones/%s/machineTypes/n1-standard-1", zone))
95+
.addDisks(bootDisk)
96+
.addNetworkInterfaces(networkInterface)
97+
.build();
98+
99+
Operation response = instancesClient.insertAsync(projectId, zone, instanceResource).get(3,
100+
TimeUnit.MINUTES);
101+
102+
if (response.hasError()) {
103+
throw new Error("Error creating instance! " + response.getError());
104+
}
105+
return response.getStatus();
106+
}
107+
}
108+
}
109+
// [END compute_instance_create_replicated_boot_disk]

compute/cloud-client/src/test/java/compute/InstanceOperationsIT.java

Lines changed: 71 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,34 @@
2020
import static com.google.common.truth.Truth.assertWithMessage;
2121
import static compute.Util.getZone;
2222

23+
import com.google.cloud.compute.v1.CreateSnapshotRegionDiskRequest;
2324
import com.google.cloud.compute.v1.Disk;
2425
import com.google.cloud.compute.v1.Instance;
2526
import com.google.cloud.compute.v1.Instance.Status;
2627
import com.google.cloud.compute.v1.InstancesClient;
28+
import com.google.cloud.compute.v1.Operation;
29+
import com.google.cloud.compute.v1.RegionDisksClient;
30+
import com.google.cloud.compute.v1.Snapshot;
2731
import compute.disks.CloneEncryptedDisk;
2832
import compute.disks.CreateEncryptedDisk;
2933
import compute.disks.DeleteDisk;
34+
import compute.disks.DeleteSnapshot;
35+
import compute.disks.RegionalCreateFromSource;
3036
import java.io.ByteArrayOutputStream;
3137
import java.io.IOException;
3238
import java.io.PrintStream;
3339
import java.nio.charset.StandardCharsets;
3440
import java.time.LocalDateTime;
41+
import java.util.Arrays;
42+
import java.util.List;
43+
import java.util.Optional;
3544
import java.util.UUID;
3645
import java.util.concurrent.ExecutionException;
3746
import java.util.concurrent.TimeUnit;
3847
import java.util.concurrent.TimeoutException;
3948
import org.junit.Assert;
4049
import org.junit.jupiter.api.AfterAll;
41-
import org.junit.jupiter.api.AfterEach;
4250
import org.junit.jupiter.api.BeforeAll;
43-
import org.junit.jupiter.api.BeforeEach;
4451
import org.junit.jupiter.api.Test;
4552
import org.junit.jupiter.api.Timeout;
4653
import org.junit.runner.RunWith;
@@ -52,13 +59,21 @@ public class InstanceOperationsIT {
5259

5360
private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT");
5461
private static final String ZONE = getZone();
62+
private static final String REGION = ZONE.substring(0, ZONE.length() - 2);
5563
private static String MACHINE_NAME;
5664
private static String MACHINE_NAME_ENCRYPTED;
5765
private static String DISK_NAME;
5866
private static String ENCRYPTED_DISK_NAME;
5967
private static String RAW_KEY;
60-
61-
private ByteArrayOutputStream stdOut;
68+
private static String INSTANCE_NAME;
69+
private static final String DISK_TYPE = String.format("regions/%s/diskTypes/pd-standard", REGION);
70+
private static String REPLICATED_DISK_NAME;
71+
private static String SNAPSHOT_NAME;
72+
private static final String DISK_SNAPSHOT_LINK =
73+
String.format("projects/%s/global/snapshots/%s", PROJECT_ID, SNAPSHOT_NAME);
74+
private static final List<String> REPLICA_ZONES = Arrays.asList(
75+
String.format("projects/%s/zones/%s-a", PROJECT_ID, REGION),
76+
String.format("projects/%s/zones/%s-b", PROJECT_ID, REGION));
6277

6378
// Check if the required environment variables are set.
6479
public static void requireEnvVar(String envVarName) {
@@ -72,47 +87,42 @@ public static void setUp()
7287
requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS");
7388
requireEnvVar("GOOGLE_CLOUD_PROJECT");
7489

75-
final PrintStream out = System.out;
76-
ByteArrayOutputStream stdOut = new ByteArrayOutputStream();
77-
System.setOut(new PrintStream(stdOut));
78-
7990
MACHINE_NAME = "test-instance-operation-" + UUID.randomUUID();
8091
MACHINE_NAME_ENCRYPTED = "test-instance-encrypted-" + UUID.randomUUID();
8192
DISK_NAME = "test-clone-disk-enc-" + UUID.randomUUID();
8293
ENCRYPTED_DISK_NAME = "test-disk-enc-" + UUID.randomUUID();
8394
RAW_KEY = Util.getBase64EncodedKey();
84-
85-
// Cleanup existing stale resources.
86-
Util.cleanUpExistingInstances("test-instance-", PROJECT_ID, ZONE);
87-
Util.cleanUpExistingDisks("test-clone-disk-enc-", PROJECT_ID, ZONE);
88-
Util.cleanUpExistingDisks("test-disk-enc-", PROJECT_ID, ZONE);
95+
INSTANCE_NAME = "test-instance-" + UUID.randomUUID();
96+
REPLICATED_DISK_NAME = "test-disk-replicated-" + UUID.randomUUID();
97+
SNAPSHOT_NAME = "test-snapshot-" + UUID.randomUUID().toString().split("-")[0];
8998

9099
compute.CreateInstance.createInstance(PROJECT_ID, ZONE, MACHINE_NAME);
91100
compute.CreateEncryptedInstance
92101
.createEncryptedInstance(PROJECT_ID, ZONE, MACHINE_NAME_ENCRYPTED, RAW_KEY);
102+
RegionalCreateFromSource.createRegionalDisk(PROJECT_ID, REGION, REPLICA_ZONES,
103+
REPLICATED_DISK_NAME, DISK_TYPE, 200, Optional.empty(), Optional.empty());
104+
createDiskSnapshot(PROJECT_ID, REGION, REPLICATED_DISK_NAME, SNAPSHOT_NAME);
93105

94106
TimeUnit.SECONDS.sleep(30);
95-
96-
stdOut.close();
97-
System.setOut(out);
98107
}
99108

100-
101109
@AfterAll
102110
public static void cleanup()
103111
throws IOException, InterruptedException, ExecutionException, TimeoutException {
104-
final PrintStream out = System.out;
105-
ByteArrayOutputStream stdOut = new ByteArrayOutputStream();
106-
System.setOut(new PrintStream(stdOut));
112+
// Cleanup existing stale resources.
113+
Util.cleanUpExistingInstances("test-instance-", PROJECT_ID, ZONE);
114+
Util.cleanUpExistingDisks("test-clone-disk-enc-", PROJECT_ID, ZONE);
115+
Util.cleanUpExistingDisks("test-disk-enc-", PROJECT_ID, ZONE);
116+
Util.cleanUpExistingRegionalDisks("test-disk-replicated-", PROJECT_ID, REGION);
117+
Util.cleanUpExistingSnapshots("test-snapshot-", PROJECT_ID);
107118

108119
// Delete all instances created for testing.
109120
compute.DeleteInstance.deleteInstance(PROJECT_ID, ZONE, MACHINE_NAME_ENCRYPTED);
110121
compute.DeleteInstance.deleteInstance(PROJECT_ID, ZONE, MACHINE_NAME);
122+
compute.DeleteInstance.deleteInstance(PROJECT_ID, ZONE, INSTANCE_NAME);
111123
DeleteDisk.deleteDisk(PROJECT_ID, ZONE, DISK_NAME);
112124
DeleteDisk.deleteDisk(PROJECT_ID, ZONE, ENCRYPTED_DISK_NAME);
113-
114-
stdOut.close();
115-
System.setOut(out);
125+
DeleteSnapshot.deleteSnapshot(PROJECT_ID, SNAPSHOT_NAME);
116126
}
117127

118128
private static Instance getInstance(String machineName) throws IOException {
@@ -121,16 +131,28 @@ private static Instance getInstance(String machineName) throws IOException {
121131
}
122132
}
123133

124-
@BeforeEach
125-
public void beforeEach() {
126-
stdOut = new ByteArrayOutputStream();
127-
System.setOut(new PrintStream(stdOut));
128-
}
129-
130-
@AfterEach
131-
public void afterEach() {
132-
stdOut = null;
133-
System.setOut(null);
134+
public static void createDiskSnapshot(String project, String region, String diskName,
135+
String snapshotName)
136+
throws IOException, ExecutionException, InterruptedException, TimeoutException {
137+
try (RegionDisksClient disksClient = RegionDisksClient.create()) {
138+
139+
CreateSnapshotRegionDiskRequest createSnapshotDiskRequest =
140+
CreateSnapshotRegionDiskRequest.newBuilder()
141+
.setProject(project)
142+
.setRegion(region)
143+
.setDisk(diskName)
144+
.setSnapshotResource(Snapshot.newBuilder()
145+
.setName(snapshotName)
146+
.build())
147+
.build();
148+
149+
Operation operation = disksClient.createSnapshotAsync(createSnapshotDiskRequest)
150+
.get(3, TimeUnit.MINUTES);
151+
152+
if (operation.hasError()) {
153+
throw new Error("Failed to create the snapshot");
154+
}
155+
}
134156
}
135157

136158
@Test
@@ -204,14 +226,17 @@ public void testEncryptedInstanceOperations()
204226
@Test
205227
public void testCloneEncryptedDisk()
206228
throws IOException, ExecutionException, InterruptedException, TimeoutException {
207-
Assert.assertEquals(Util.getInstanceStatus(PROJECT_ID, ZONE, MACHINE_NAME_ENCRYPTED),
208-
"RUNNING");
229+
ByteArrayOutputStream stdOut = new ByteArrayOutputStream();
230+
System.setOut(new PrintStream(stdOut));
231+
209232
Instance instance = getInstance(MACHINE_NAME_ENCRYPTED);
210233
String diskType = String.format("zones/%s/diskTypes/pd-standard", ZONE);
211234
CloneEncryptedDisk.createDiskFromCustomerEncryptedKey(PROJECT_ID, ZONE, DISK_NAME, diskType, 10,
212235
instance.getDisks(0).getSource(), RAW_KEY.getBytes(
213236
StandardCharsets.UTF_8));
214237
assertThat(stdOut.toString()).contains("Disk cloned with customer encryption key.");
238+
239+
stdOut.close();
215240
}
216241

217242
@Test
@@ -228,4 +253,15 @@ public void testCreateEncryptedDisk()
228253
Assert.assertNotNull(encryptedDisk.getDiskEncryptionKey());
229254
Assert.assertNotNull(encryptedDisk.getDiskEncryptionKey().getSha256());
230255
}
256+
257+
@Test
258+
public void testCreateInstanceWithRegionalDiskFromSnapshot()
259+
throws IOException, ExecutionException, InterruptedException, TimeoutException {
260+
Operation.Status status = CreateInstanceWithRegionalDiskFromSnapshot
261+
.createInstanceWithRegionalDiskFromSnapshot(
262+
PROJECT_ID, ZONE, INSTANCE_NAME, REPLICATED_DISK_NAME,
263+
DISK_TYPE, DISK_SNAPSHOT_LINK, REPLICA_ZONES);
264+
265+
assertThat(status).isEqualTo(Operation.Status.DONE);
266+
}
231267
}

0 commit comments

Comments
 (0)