diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a16c4cc85a5..1d68a9f342c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -79,7 +79,7 @@ /speech @GoogleCloudPlatform/java-samples-reviewers @yoshi-approver @GoogleCloudPlatform/cloud-samples-reviewers /talent @GoogleCloudPlatform/java-samples-reviewers @yoshi-approver @GoogleCloudPlatform/cloud-samples-reviewers /texttospeech @GoogleCloudPlatform/java-samples-reviewers @yoshi-approver @GoogleCloudPlatform/cloud-samples-reviewers -/translate @GoogleCloudPlatform/java-samples-reviewers @yoshi-approver @GoogleCloudPlatform/cloud-samples-reviewers +/translate @GoogleCloudPlatform/java-samples-reviewers @yoshi-approver @GoogleCloudPlatform/cloud-samples-reviewers @GoogleCloudPlatform/cloud-ml-translate-dev /video @GoogleCloudPlatform/java-samples-reviewers @yoshi-approver @GoogleCloudPlatform/cloud-samples-reviewers /vision @GoogleCloudPlatform/java-samples-reviewers @yoshi-approver @GoogleCloudPlatform/cloud-samples-reviewers diff --git a/.kokoro/tests/run_prptst_tests.sh b/.kokoro/tests/run_prptst_tests.sh index ae07900fef2..38082ee4f70 100755 --- a/.kokoro/tests/run_prptst_tests.sh +++ b/.kokoro/tests/run_prptst_tests.sh @@ -90,11 +90,4 @@ else echo -e "\n Testing completed.\n" fi -# If this is a periodic build, send the test log to the FlakyBot except for Java 8 -# See https://github.com/googleapis/repo-automation-bots/tree/main/packages/flakybot. -if [[ $JAVA_VERSION != "1.8" && $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then - chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot - $KOKORO_GFILE_DIR/linux_amd64/flakybot -fi - exit $RTN diff --git a/.kokoro/tests/run_test_java.sh b/.kokoro/tests/run_test_java.sh index 537c4285e06..9d427468238 100755 --- a/.kokoro/tests/run_test_java.sh +++ b/.kokoro/tests/run_test_java.sh @@ -96,11 +96,4 @@ if [[ "$file" == *"run/"* && ("$file" != *"run/filesystem"* && "$file" != *"run/ fi fi -# If this is a periodic build, send the test log to the FlakyBot except for Java 8 -# See https://github.com/googleapis/repo-automation-bots/tree/main/packages/flakybot. -if [[ $JAVA_VERSION != "1.8" && $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then - chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot - $KOKORO_GFILE_DIR/linux_amd64/flakybot -fi - exit $RTN diff --git a/compute/cloud-client/src/main/java/compute/CreateInstanceWithRegionalDiskFromSnapshot.java b/compute/cloud-client/src/main/java/compute/CreateInstanceWithRegionalDiskFromSnapshot.java new file mode 100644 index 00000000000..e879a7e2d1a --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/CreateInstanceWithRegionalDiskFromSnapshot.java @@ -0,0 +1,109 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute; + +// [START compute_instance_create_replicated_boot_disk] +import com.google.cloud.compute.v1.AttachedDisk; +import com.google.cloud.compute.v1.AttachedDiskInitializeParams; +import com.google.cloud.compute.v1.Instance; +import com.google.cloud.compute.v1.InstancesClient; +import com.google.cloud.compute.v1.NetworkInterface; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateInstanceWithRegionalDiskFromSnapshot { + + public static void main(String[] args) throws IOException, ExecutionException, + InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample + // Project ID or project number of the Cloud project you want to use. + String projectId = "YOUR_PROJECT_ID"; + // Name of the zone in which you want to create the instance. + String zone = "us-central1-a"; + // Name of the instance you want to create. + String instanceName = "YOUR_INSTANCE_NAME"; + // Name for the replicated disk. + String diskName = "YOUR_REPLICATED_DISK_NAME"; + String region = zone.substring(0, zone.length() - 2); + // Type of the disk. + String diskType = String.format( + "projects/%s/regions/%s/diskTypes/pd-standard", projectId, region); + // The full path and name of the snapshot that you want to use as the source for the new disk. + String snapshotLink = String.format("projects/%s/global/snapshots/%s", projectId, + "SNAPSHOT_NAME"); + // An iterable collection of zone names in which you want to keep + // the new disks' replicas. One of the replica zones of the clone must match + // the zone of the source disk. + List replicaZones = new ArrayList<>(); + + createInstanceWithRegionalDiskFromSnapshot(projectId, zone, instanceName, diskName, diskType, + snapshotLink, replicaZones); + } + + // Creates a new VM instance with regional disk from a snapshot and specifies replica zones. + public static Status createInstanceWithRegionalDiskFromSnapshot( + String projectId, String zone, String instanceName, String diskName, + String diskType, String snapshotLink, List replicaZones) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (InstancesClient instancesClient = InstancesClient.create()) { + AttachedDiskInitializeParams initializeParams = AttachedDiskInitializeParams.newBuilder() + .setSourceSnapshot(snapshotLink) + .setDiskType(diskType) + .setDiskName(diskName) + .addAllReplicaZones(replicaZones) + .build(); + + // Boot disk configuration + AttachedDisk bootDisk = AttachedDisk.newBuilder() + .setBoot(true) + .setAutoDelete(true) // Optional: Delete disk when instance is deleted. + .setType(AttachedDisk.Type.PERSISTENT.toString()) + .setInitializeParams(initializeParams) + .build(); + + // Network interface configuration (using the default network) + NetworkInterface networkInterface = NetworkInterface.newBuilder() + .setNetwork("global/networks/default") + .build(); + + // Create the instance resource + Instance instanceResource = Instance.newBuilder() + .setName(instanceName) + .setMachineType(String.format("zones/%s/machineTypes/n1-standard-1", zone)) + .addDisks(bootDisk) + .addNetworkInterfaces(networkInterface) + .build(); + + Operation response = instancesClient.insertAsync(projectId, zone, instanceResource).get(3, + TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error creating instance! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_instance_create_replicated_boot_disk] \ No newline at end of file diff --git a/compute/cloud-client/src/main/java/compute/disks/AttachRegionalDiskForce.java b/compute/cloud-client/src/main/java/compute/disks/AttachRegionalDiskForce.java new file mode 100644 index 00000000000..20e13376e5e --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/AttachRegionalDiskForce.java @@ -0,0 +1,81 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +// [START compute_instance_attach_regional_disk_force] +import com.google.cloud.compute.v1.AttachDiskInstanceRequest; +import com.google.cloud.compute.v1.AttachedDisk; +import com.google.cloud.compute.v1.InstancesClient; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class AttachRegionalDiskForce { + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String projectId = "YOUR_PROJECT_ID"; + // Name of the zone of your compute instance. + String zone = "us-central1-a"; + // The name of the compute instance where you are adding the replicated disk. + String instanceName = "YOUR_INSTANCE_NAME"; + // The region where your replicated disk is located. + String region = "us-central1"; + // The name of the replicated disk. + String diskName = "YOUR_DISK_NAME"; + + attachRegionalDiskForce(projectId, zone, instanceName, region, diskName); + } + + // Attaches a regional disk to the instance, + // forcing the attachment even if other VMs are using the disk. + public static Status attachRegionalDiskForce(String projectId, + String zone, String instanceName, String region, String diskName) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + String diskLink = String.format("projects/%s/regions/%s/disks/%s", + projectId, region, diskName); + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (InstancesClient instancesClient = InstancesClient.create()) { + AttachedDisk attachedDisk = AttachedDisk.newBuilder() + .setSource(diskLink) + .setMode(AttachedDisk.Mode.READ_WRITE.toString()) + .build(); + + AttachDiskInstanceRequest attachDiskRequest = AttachDiskInstanceRequest.newBuilder() + .setProject(projectId) + .setZone(zone) + .setInstance(instanceName) + .setAttachedDiskResource(attachedDisk) + .setForceAttach(true) // Force the attachment + .build(); + + Operation response = instancesClient.attachDiskAsync(attachDiskRequest) + .get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error attaching regional disk! " + response); + } + return response.getStatus(); + } + } +} +// [END compute_instance_attach_regional_disk_force] diff --git a/compute/cloud-client/src/main/java/compute/disks/CreateDiskSecondaryRegional.java b/compute/cloud-client/src/main/java/compute/disks/CreateDiskSecondaryRegional.java new file mode 100644 index 00000000000..dc5c5bdf9f5 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/CreateDiskSecondaryRegional.java @@ -0,0 +1,103 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +// [START compute_disk_create_secondary_regional] +import com.google.cloud.compute.v1.Disk; +import com.google.cloud.compute.v1.DiskAsyncReplication; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.RegionDisksClient; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateDiskSecondaryRegional { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // The project that contains the primary disk. + String primaryProjectId = "PRIMARY_PROJECT_ID"; + // The project that contains the secondary disk. + String secondaryProjectId = "SECONDARY_PROJECT_ID"; + // Name of the primary disk you want to use. + String primaryDiskName = "PRIMARY_DISK_NAME"; + // Name of the disk you want to create. + String secondaryDiskName = "SECONDARY_DISK_NAME"; + // Name of the region in which your primary disk is located. + // Learn more about zones and regions: + // https://cloud.google.com/compute/docs/disks/async-pd/about#supported_region_pairs + String primaryDiskRegion = "us-central1"; + // Name of the region in which you want to create the secondary disk. + String secondaryDiskRegion = "us-east1"; + // Size of the new disk in gigabytes. + // Learn more about disk requirements: + // https://cloud.google.com/compute/docs/disks/async-pd/configure?authuser=0#disk_requirements + long diskSizeGb = 30L; + // The type of the disk you want to create. This value uses the following format: + // "projects/{projectId}/zones/{zone}/diskTypes/ + // (pd-standard|pd-ssd|pd-balanced|pd-extreme)". + String diskType = String.format( + "projects/%s/regions/%s/diskTypes/pd-balanced", secondaryProjectId, secondaryDiskRegion); + + createDiskSecondaryRegional(primaryProjectId, secondaryProjectId, primaryDiskName, + secondaryDiskName, primaryDiskRegion, secondaryDiskRegion, diskSizeGb, diskType); + } + + // Creates a secondary disk in a specified region. + public static Status createDiskSecondaryRegional(String projectId, + String secondaryProjectId, String primaryDiskName, String secondaryDiskName, + String primaryDiskRegion, String secondaryDiskRegion, long diskSizeGb, String diskType) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + List replicaZones = Arrays.asList( + String.format("projects/%s/zones/%s-c", secondaryProjectId, secondaryDiskRegion), + String.format("projects/%s/zones/%s-b", secondaryProjectId, secondaryDiskRegion)); + + String primaryDiskSource = String.format("projects/%s/regions/%s/disks/%s", + projectId, primaryDiskRegion, primaryDiskName); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (RegionDisksClient disksClient = RegionDisksClient.create()) { + DiskAsyncReplication asyncReplication = DiskAsyncReplication.newBuilder() + .setDisk(primaryDiskSource) + .build(); + + Disk disk = Disk.newBuilder() + .addAllReplicaZones(replicaZones) + .setName(secondaryDiskName) + .setSizeGb(diskSizeGb) + .setType(diskType) + .setRegion(secondaryDiskRegion) + .setAsyncPrimaryDisk(asyncReplication) + .build(); + + // Wait for the create disk operation to complete. + Operation response = disksClient.insertAsync(secondaryProjectId, secondaryDiskRegion, disk) + .get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error creating secondary disks! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_disk_create_secondary_regional] \ No newline at end of file diff --git a/compute/cloud-client/src/main/java/compute/disks/CreateDiskSecondaryZonal.java b/compute/cloud-client/src/main/java/compute/disks/CreateDiskSecondaryZonal.java new file mode 100644 index 00000000000..58135d4a3a3 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/CreateDiskSecondaryZonal.java @@ -0,0 +1,92 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +// [START compute_disk_create_secondary] +import com.google.cloud.compute.v1.Disk; +import com.google.cloud.compute.v1.DiskAsyncReplication; +import com.google.cloud.compute.v1.DisksClient; +import com.google.cloud.compute.v1.Operation; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateDiskSecondaryZonal { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // The project that contains the primary disk. + String primaryProjectId = "PRIMARY_PROJECT_ID"; + // The project that contains the secondary disk. + String secondaryProjectId = "SECONDARY_PROJECT_ID"; + // Name of the primary disk you want to use. + String primaryDiskName = "PRIMARY_DISK_NAME"; + // Name of the zone in which your primary disk is located. + // Learn more about zones and regions: + // https://cloud.google.com/compute/docs/disks/async-pd/about#supported_region_pairs + String primaryDiskZone = "us-central1-a"; + // Name of the disk you want to create. + String secondaryDiskName = "SECONDARY_DISK_NAME"; + // Name of the zone in which you want to create the secondary disk. + String secondaryDiskZone = "us-east1-c"; + // Size of the new disk in gigabytes. + long diskSizeGb = 30L; + // The type of the disk you want to create. This value uses the following format: + // "projects/{projectId}/zones/{zone}/diskTypes/ + // (pd-standard|pd-ssd|pd-balanced|pd-extreme)". + String diskType = String.format( + "projects/%s/zones/%s/diskTypes/pd-balanced", secondaryProjectId, secondaryDiskZone); + + createDiskSecondaryZonal(primaryProjectId, secondaryProjectId, primaryDiskName, + secondaryDiskName, primaryDiskZone, secondaryDiskZone, diskSizeGb, diskType); + } + + // Creates a secondary disk in a specified zone. + public static Operation.Status createDiskSecondaryZonal(String primaryProjectId, + String secondaryProjectId, String primaryDiskName, String secondaryDiskName, + String primaryDiskZone, String secondaryDiskZone, long diskSizeGb, String diskType) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (DisksClient disksClient = DisksClient.create()) { + String primaryDiskSource = String.format("projects/%s/zones/%s/disks/%s", + primaryProjectId, primaryDiskZone, primaryDiskName); + + DiskAsyncReplication asyncReplication = DiskAsyncReplication.newBuilder() + .setDisk(primaryDiskSource) + .build(); + Disk disk = Disk.newBuilder() + .setName(secondaryDiskName) + .setZone(secondaryDiskZone) + .setSizeGb(diskSizeGb) + .setType(diskType) + .setAsyncPrimaryDisk(asyncReplication) + .build(); + + Operation response = disksClient.insertAsync(secondaryProjectId, secondaryDiskZone, disk) + .get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error creating secondary disks! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_disk_create_secondary] + diff --git a/compute/cloud-client/src/main/java/compute/disks/CreateDiskWithSnapshotSchedule.java b/compute/cloud-client/src/main/java/compute/disks/CreateDiskWithSnapshotSchedule.java new file mode 100644 index 00000000000..7da6bf12cce --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/CreateDiskWithSnapshotSchedule.java @@ -0,0 +1,73 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +// [START compute_disk_create_with_snapshot_schedule] +import com.google.cloud.compute.v1.Disk; +import com.google.cloud.compute.v1.DisksClient; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateDiskWithSnapshotSchedule { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String projectId = "YOUR_PROJECT_ID"; + // Name of the zone in which you want to create the disk. + String zone = "us-central1-a"; + // Name of the disk you want to create. + String diskName = "YOUR_DISK_NAME"; + // Name of the schedule you want to link to the disk. + String snapshotScheduleName = "YOUR_SCHEDULE_NAME"; + + createDiskWithSnapshotSchedule(projectId, zone, diskName, snapshotScheduleName); + } + + // Creates disk with linked snapshot schedule. + public static Status createDiskWithSnapshotSchedule( + String projectId, String zone, String diskName, String snapshotScheduleName) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (DisksClient disksClient = DisksClient.create()) { + String region = zone.substring(0, zone.lastIndexOf('-')); + // Get the resource policy to link to the disk + String resourcePolicyLink = String.format("projects/%s/regions/%s/resourcePolicies/%s", + projectId, region, snapshotScheduleName); + + Disk disk = Disk.newBuilder() + .setName(diskName) + .setZone(zone) + .addAllResourcePolicies(List.of(resourcePolicyLink)) + .build(); + + Operation response = disksClient.insertAsync(projectId, zone, disk).get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Disk creation failed! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_disk_create_with_snapshot_schedule] diff --git a/compute/cloud-client/src/main/java/compute/disks/CreateReplicatedDisk.java b/compute/cloud-client/src/main/java/compute/disks/CreateReplicatedDisk.java new file mode 100644 index 00000000000..384921da4f9 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/CreateReplicatedDisk.java @@ -0,0 +1,88 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +// [START compute_disk_regional_replicated] +import com.google.cloud.compute.v1.Disk; +import com.google.cloud.compute.v1.InsertRegionDiskRequest; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.RegionDisksClient; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateReplicatedDisk { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String projectId = "YOUR_PROJECT_ID"; + // The region for the replicated disk to reside in. + // The disk must be in the same region as the VM that you plan to attach it to. + String region = "us-central1"; + // The zones within the region where the two disk replicas are located + List replicaZones = new ArrayList<>(); + replicaZones.add(String.format("projects/%s/zones/%s", projectId, "us-central1-a")); + replicaZones.add(String.format("projects/%s/zones/%s", projectId, "us-central1-b")); + // Name of the disk you want to create. + String diskName = "YOUR_DISK_NAME"; + // Size of the new disk in gigabytes. + int diskSizeGb = 100; + // The type of replicated disk. This value uses the following format: + // "regions/{region}/diskTypes/(pd-standard|pd-ssd|pd-balanced|pd-extreme)". + // For example: "regions/us-west3/diskTypes/pd-ssd" + String diskType = String.format("regions/%s/diskTypes/%s", region, "pd-standard"); + + createReplicatedDisk(projectId, region, replicaZones, diskName, diskSizeGb, diskType); + } + + // Create a disk for synchronous data replication between two zones in the same region + public static Status createReplicatedDisk(String projectId, String region, + List replicaZones, String diskName, int diskSizeGb, String diskType) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (RegionDisksClient regionDisksClient = RegionDisksClient.create()) { + Disk disk = Disk.newBuilder() + .setSizeGb(diskSizeGb) + .setName(diskName) + .setType(diskType) + .addAllReplicaZones(replicaZones) + .build(); + + InsertRegionDiskRequest insertRegionDiskRequest = InsertRegionDiskRequest.newBuilder() + .setProject(projectId) + .setRegion(region) + .setDiskResource(disk) + .build(); + + Operation response = regionDisksClient.insertAsync(insertRegionDiskRequest) + .get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error creating disk! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_disk_regional_replicated] diff --git a/compute/cloud-client/src/main/java/compute/disks/CreateSecondaryCustomDisk.java b/compute/cloud-client/src/main/java/compute/disks/CreateSecondaryCustomDisk.java new file mode 100644 index 00000000000..cf952c3e522 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/CreateSecondaryCustomDisk.java @@ -0,0 +1,111 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +//[START compute_disk_create_secondary_custom] +import com.google.cloud.compute.v1.Disk; +import com.google.cloud.compute.v1.DiskAsyncReplication; +import com.google.cloud.compute.v1.DisksClient; +import com.google.cloud.compute.v1.GuestOsFeature; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateSecondaryCustomDisk { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // The project that contains the primary disk. + String primaryProjectId = "PRIMARY_PROJECT_ID"; + // The project that contains the secondary disk. + String secondaryProjectId = "SECONDARY_PROJECT_ID"; + // Name of the primary disk you want to use. + String primaryDiskName = "PRIMARY_DISK_NAME"; + // Name of the zone in which your primary disk is located. + // Learn more about zones and regions: + // https://cloud.google.com/compute/docs/disks/async-pd/about#supported_region_pairs + String primaryDiskZone = "us-central1-a"; + // Name of the disk you want to create. + String secondaryDiskName = "SECONDARY_DISK_NAME"; + // Name of the zone in which you want to create the secondary disk. + String secondaryDiskZone = "us-east1-c"; + // Size of the new disk in gigabytes. + long diskSizeGb = 30L; + // The type of the disk you want to create. This value uses the following format: + // "projects/{projectId}/zones/{zone}/diskTypes/ + // (pd-standard|pd-ssd|pd-balanced|pd-extreme)". + String diskType = String.format( + "projects/%s/zones/%s/diskTypes/pd-balanced", secondaryProjectId, secondaryDiskZone); + + createSecondaryCustomDisk(primaryProjectId, secondaryProjectId, primaryDiskName, + secondaryDiskName, primaryDiskZone, secondaryDiskZone, diskSizeGb, diskType); + } + + // Creates a secondary disk with specified custom parameters. + public static Status createSecondaryCustomDisk(String primaryProjectId, String secondaryProjectId, + String primaryDiskName, String secondaryDiskName, String primaryDiskZone, + String secondaryDiskZone, long diskSizeGb, String diskType) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (DisksClient disksClient = DisksClient.create()) { + String primaryDiskSource = String.format("projects/%s/zones/%s/disks/%s", + primaryProjectId, primaryDiskZone, primaryDiskName); + + DiskAsyncReplication asyncReplication = DiskAsyncReplication.newBuilder() + .setDisk(primaryDiskSource) + .build(); + + // Define the guest OS features. + List guestOsFeatures = Arrays.asList( + GuestOsFeature.newBuilder().setType("UEFI_COMPATIBLE").build(), + GuestOsFeature.newBuilder().setType("GVNIC").build(), + GuestOsFeature.newBuilder().setType("MULTI_IP_SUBNET").build()); + + // Define the labels. + Map labels = new HashMap<>(); + labels.put("secondary-disk-for-replication", "yes"); + + Disk disk = Disk.newBuilder() + .setName(secondaryDiskName) + .setSizeGb(diskSizeGb) + .setType(diskType) + .setZone(secondaryDiskZone) + .addAllGuestOsFeatures(guestOsFeatures) + .putAllLabels(labels) + .setAsyncPrimaryDisk(asyncReplication) + .build(); + + // Wait for the create disk operation to complete. + Operation response = disksClient.insertAsync(secondaryProjectId, secondaryDiskZone, disk) + .get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error creating secondary custom disks! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_disk_create_secondary_custom] diff --git a/compute/cloud-client/src/main/java/compute/disks/StartRegionalDiskReplication.java b/compute/cloud-client/src/main/java/compute/disks/StartRegionalDiskReplication.java new file mode 100644 index 00000000000..428a417ff24 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/StartRegionalDiskReplication.java @@ -0,0 +1,82 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +// [START compute_regional_disk_start_replication] +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.RegionDisksClient; +import com.google.cloud.compute.v1.RegionDisksStartAsyncReplicationRequest; +import com.google.cloud.compute.v1.StartAsyncReplicationRegionDiskRequest; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class StartRegionalDiskReplication { + + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // The project that contains the primary disk. + String projectId = "YOUR_PROJECT_ID"; + // Name of the primary disk. + String primaryDiskName = "PRIMARY_DISK_NAME"; + // Name of the secondary disk. + String secondaryDiskName = "SECONDARY_DISK_NAME"; + // Name of the region in which your primary disk is located. + // Learn more about zones and regions: + // https://cloud.google.com/compute/docs/disks/async-pd/about#supported_region_pairs + String primaryDiskLocation = "us-central1-a"; + // Name of the region in which your secondary disk is located. + String secondaryDiskLocation = "us-east1-b"; + + startRegionalDiskAsyncReplication(projectId, primaryDiskName, primaryDiskLocation, + secondaryDiskName, secondaryDiskLocation); + } + + // Starts asynchronous replication for the specified regional disk. + public static Status startRegionalDiskAsyncReplication(String projectId, String primaryDiskName, + String primaryDiskLocation, String secondaryDiskName, String secondaryDiskLocation) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + String secondaryDiskPath = String.format("projects/%s/regions/%s/disks/%s", + projectId, secondaryDiskLocation, secondaryDiskName); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (RegionDisksClient disksClient = RegionDisksClient.create()) { + RegionDisksStartAsyncReplicationRequest diskRequest = + RegionDisksStartAsyncReplicationRequest.newBuilder() + .setAsyncSecondaryDisk(secondaryDiskPath) + .build(); + StartAsyncReplicationRegionDiskRequest request = + StartAsyncReplicationRegionDiskRequest.newBuilder() + .setDisk(primaryDiskName) + .setRegionDisksStartAsyncReplicationRequestResource(diskRequest) + .setProject(projectId) + .setRegion(primaryDiskLocation) + .build(); + Operation response = disksClient.startAsyncReplicationAsync(request).get(1, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error starting replication! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_regional_disk_start_replication] \ No newline at end of file diff --git a/compute/cloud-client/src/main/java/compute/disks/StartZonalDiskReplication.java b/compute/cloud-client/src/main/java/compute/disks/StartZonalDiskReplication.java new file mode 100644 index 00000000000..06b6ee067c9 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/StartZonalDiskReplication.java @@ -0,0 +1,82 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +// [START compute_disk_start_replication] +import com.google.cloud.compute.v1.DisksClient; +import com.google.cloud.compute.v1.DisksStartAsyncReplicationRequest; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.StartAsyncReplicationDiskRequest; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class StartZonalDiskReplication { + + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // The project that contains the primary disk. + String projectId = "YOUR_PROJECT_ID"; + // Name of the primary disk. + String primaryDiskName = "PRIMARY_DISK_NAME"; + // Name of the secondary disk. + String secondaryDiskName = "SECONDARY_DISK_NAME"; + // Name of the zone in which your primary disk is located. + // Learn more about zones and regions: + // https://cloud.google.com/compute/docs/disks/async-pd/about#supported_region_pairs + String primaryDiskLocation = "us-central1-a"; + // Name of the zone in which your secondary disk is located. + String secondaryDiskLocation = "us-east1-b"; + + startZonalDiskAsyncReplication(projectId, primaryDiskName, primaryDiskLocation, + secondaryDiskName, secondaryDiskLocation); + } + + // Starts asynchronous replication for the specified zonal disk. + public static Status startZonalDiskAsyncReplication(String projectId, String primaryDiskName, + String primaryDiskLocation, String secondaryDiskName, String secondaryDiskLocation) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + String secondaryDiskPath = String.format("projects/%s/zones/%s/disks/%s", + projectId, secondaryDiskLocation, secondaryDiskName); + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (DisksClient disksClient = DisksClient.create()) { + DisksStartAsyncReplicationRequest diskRequest = + DisksStartAsyncReplicationRequest.newBuilder() + .setAsyncSecondaryDisk(secondaryDiskPath) + .build(); + + StartAsyncReplicationDiskRequest request = + StartAsyncReplicationDiskRequest.newBuilder() + .setDisk(primaryDiskName) + .setDisksStartAsyncReplicationRequestResource(diskRequest) + .setProject(projectId) + .setZone(primaryDiskLocation) + .build(); + Operation response = disksClient.startAsyncReplicationAsync(request).get(1, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error starting replication! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_disk_start_replication] diff --git a/compute/cloud-client/src/main/java/compute/disks/StopRegionalDiskReplication.java b/compute/cloud-client/src/main/java/compute/disks/StopRegionalDiskReplication.java new file mode 100644 index 00000000000..1fe5232e812 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/StopRegionalDiskReplication.java @@ -0,0 +1,67 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +// [START compute_regional_disk_stop_replication] +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.RegionDisksClient; +import com.google.cloud.compute.v1.StopAsyncReplicationRegionDiskRequest; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class StopRegionalDiskReplication { + + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // The project that contains the primary disk. + String projectId = "YOUR_PROJECT_ID"; + // Name of the region or zone in which your secondary disk is located. + String secondaryDiskLocation = "us-east1-b"; + // Name of the secondary disk. + String secondaryDiskName = "SECONDARY_DISK_NAME"; + + stopRegionalDiskAsyncReplication(projectId, secondaryDiskLocation, secondaryDiskName); + } + + // Stops asynchronous replication for the specified disk. + public static Status stopRegionalDiskAsyncReplication( + String project, String secondaryDiskLocation, String secondaryDiskName) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (RegionDisksClient disksClient = RegionDisksClient.create()) { + StopAsyncReplicationRegionDiskRequest stopReplicationDiskRequest = + StopAsyncReplicationRegionDiskRequest.newBuilder() + .setDisk(secondaryDiskName) + .setProject(project) + .setRegion(secondaryDiskLocation) + .build(); + Operation response = disksClient.stopAsyncReplicationAsync(stopReplicationDiskRequest) + .get(1, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error stopping replication! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_regional_disk_stop_replication] \ No newline at end of file diff --git a/compute/cloud-client/src/main/java/compute/disks/StopZonalDiskReplication.java b/compute/cloud-client/src/main/java/compute/disks/StopZonalDiskReplication.java new file mode 100644 index 00000000000..1377169e5c2 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/StopZonalDiskReplication.java @@ -0,0 +1,67 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +// [START compute_disk_stop_replication] +import com.google.cloud.compute.v1.DisksClient; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.StopAsyncReplicationDiskRequest; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class StopZonalDiskReplication { + + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // The project that contains the primary disk. + String projectId = "YOUR_PROJECT_ID"; + // Name of the region or zone in which your secondary disk is located. + String secondaryDiskLocation = "us-east1-b"; + // Name of the secondary disk. + String secondaryDiskName = "SECONDARY_DISK_NAME"; + + stopZonalDiskAsyncReplication(projectId, secondaryDiskLocation, secondaryDiskName); + } + + // Stops asynchronous replication for the specified disk. + public static Status stopZonalDiskAsyncReplication( + String project, String secondaryDiskLocation, String secondaryDiskName) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (DisksClient disksClient = DisksClient.create()) { + StopAsyncReplicationDiskRequest stopReplicationDiskRequest = + StopAsyncReplicationDiskRequest.newBuilder() + .setProject(project) + .setDisk(secondaryDiskName) + .setZone(secondaryDiskLocation) + .build(); + Operation response = disksClient.stopAsyncReplicationAsync(stopReplicationDiskRequest) + .get(1, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error stopping replication! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_disk_stop_replication] diff --git a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/AddDiskToConsistencyGroup.java b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/AddDiskToConsistencyGroup.java index 7c4650fad09..e4a7ca9842e 100644 --- a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/AddDiskToConsistencyGroup.java +++ b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/AddDiskToConsistencyGroup.java @@ -22,6 +22,7 @@ import com.google.cloud.compute.v1.DisksAddResourcePoliciesRequest; import com.google.cloud.compute.v1.DisksClient; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.RegionDisksAddResourcePoliciesRequest; import com.google.cloud.compute.v1.RegionDisksClient; import java.io.IOException; @@ -50,7 +51,7 @@ public static void main(String[] args) } // Adds a disk to a consistency group. - public static Operation.Status addDiskToConsistencyGroup( + public static Status addDiskToConsistencyGroup( String project, String location, String diskName, String consistencyGroupName, String consistencyGroupLocation) throws IOException, ExecutionException, InterruptedException, TimeoutException { diff --git a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/CloneRegionalDisksFromConsistencyGroup.java b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/CloneRegionalDisksFromConsistencyGroup.java new file mode 100644 index 00000000000..b7b0585902d --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/CloneRegionalDisksFromConsistencyGroup.java @@ -0,0 +1,73 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks.consistencygroup; + +// [START compute_consistency_group_clone_regional_disk] +import com.google.cloud.compute.v1.BulkInsertDiskResource; +import com.google.cloud.compute.v1.BulkInsertRegionDiskRequest; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.RegionDisksClient; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CloneRegionalDisksFromConsistencyGroup { + + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String project = "YOUR_PROJECT_ID"; + // Region in which your disks and consistency group are located. + String region = "us-central1"; + // Name of the consistency group you want to clone disks from. + String consistencyGroupName = "YOUR_CONSISTENCY_GROUP_NAME"; + + cloneRegionalDisksFromConsistencyGroup(project, region, consistencyGroupName); + } + + // Clones regional disks from a consistency group. + public static Status cloneRegionalDisksFromConsistencyGroup( + String project, String region, String consistencyGroupName) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + String sourceConsistencyGroupPolicy = String.format( + "projects/%s/regions/%s/resourcePolicies/%s", project, region, consistencyGroupName); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (RegionDisksClient disksClient = RegionDisksClient.create()) { + BulkInsertRegionDiskRequest request = BulkInsertRegionDiskRequest.newBuilder() + .setProject(project) + .setRegion(region) + .setBulkInsertDiskResourceResource( + BulkInsertDiskResource.newBuilder() + .setSourceConsistencyGroupPolicy(sourceConsistencyGroupPolicy) + .build()) + .build(); + + Operation response = disksClient.bulkInsertAsync(request).get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error cloning regional disks! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_consistency_group_clone_regional_disk] diff --git a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/CloneZonalDisksFromConsistencyGroup.java b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/CloneZonalDisksFromConsistencyGroup.java new file mode 100644 index 00000000000..b819829a100 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/CloneZonalDisksFromConsistencyGroup.java @@ -0,0 +1,73 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks.consistencygroup; + +// [START compute_consistency_group_clone] +import com.google.cloud.compute.v1.BulkInsertDiskRequest; +import com.google.cloud.compute.v1.BulkInsertDiskResource; +import com.google.cloud.compute.v1.DisksClient; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CloneZonalDisksFromConsistencyGroup { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String project = "YOUR_PROJECT_ID"; + // Zone in which your disks are located. + String zone = "us-central1-a"; + // Name of the consistency group you want to clone disks from. + String consistencyGroupName = "YOUR_CONSISTENCY_GROUP_NAME"; + + cloneZonalDisksFromConsistencyGroup(project, zone, consistencyGroupName); + } + + // Clones zonal disks from a consistency group. + public static Status cloneZonalDisksFromConsistencyGroup( + String project, String zone, String consistencyGroupName) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + String region = zone.substring(0, zone.lastIndexOf('-')); + String sourceConsistencyGroupPolicy = String.format( + "projects/%s/regions/%s/resourcePolicies/%s", project, region, consistencyGroupName); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (DisksClient disksClient = DisksClient.create()) { + BulkInsertDiskRequest request = BulkInsertDiskRequest.newBuilder() + .setProject(project) + .setZone(zone) + .setBulkInsertDiskResourceResource( + BulkInsertDiskResource.newBuilder() + .setSourceConsistencyGroupPolicy(sourceConsistencyGroupPolicy) + .build()) + .build(); + + Operation response = disksClient.bulkInsertAsync(request).get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error cloning zonal disks! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_consistency_group_clone] diff --git a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/CreateConsistencyGroup.java b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/CreateConsistencyGroup.java index df6c324d8d5..b1769f6fd1b 100644 --- a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/CreateConsistencyGroup.java +++ b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/CreateConsistencyGroup.java @@ -19,6 +19,7 @@ // [START compute_consistency_group_create] import com.google.cloud.compute.v1.InsertResourcePolicyRequest; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.ResourcePoliciesClient; import com.google.cloud.compute.v1.ResourcePolicy; import java.io.IOException; @@ -42,7 +43,7 @@ public static void main(String[] args) } // Creates a new consistency group resource policy in the specified project and region. - public static Operation.Status createConsistencyGroup( + public static Status createConsistencyGroup( String project, String region, String consistencyGroupName) throws IOException, ExecutionException, InterruptedException, TimeoutException { // Initialize client that will be used to send requests. This client only needs to be created diff --git a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/DeleteConsistencyGroup.java b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/DeleteConsistencyGroup.java index 89ab6f756e0..89eaae58e01 100644 --- a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/DeleteConsistencyGroup.java +++ b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/DeleteConsistencyGroup.java @@ -18,6 +18,7 @@ // [START compute_consistency_group_delete] import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.ResourcePoliciesClient; import java.io.IOException; import java.util.concurrent.ExecutionException; @@ -40,7 +41,7 @@ public static void main(String[] args) } // Deletes a consistency group resource policy in the specified project and region. - public static Operation.Status deleteConsistencyGroup( + public static Status deleteConsistencyGroup( String project, String region, String consistencyGroupName) throws IOException, ExecutionException, InterruptedException, TimeoutException { // Initialize client that will be used to send requests. This client only needs to be created diff --git a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/RemoveDiskFromConsistencyGroup.java b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/RemoveDiskFromConsistencyGroup.java index b791125b0dd..fd877947d51 100644 --- a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/RemoveDiskFromConsistencyGroup.java +++ b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/RemoveDiskFromConsistencyGroup.java @@ -20,6 +20,7 @@ import com.google.cloud.compute.v1.DisksClient; import com.google.cloud.compute.v1.DisksRemoveResourcePoliciesRequest; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.RegionDisksClient; import com.google.cloud.compute.v1.RegionDisksRemoveResourcePoliciesRequest; import com.google.cloud.compute.v1.RemoveResourcePoliciesDiskRequest; @@ -51,7 +52,7 @@ public static void main(String[] args) } // Removes a disk from a consistency group. - public static Operation.Status removeDiskFromConsistencyGroup( + public static Status removeDiskFromConsistencyGroup( String project, String location, String diskName, String consistencyGroupName, String consistencyGroupLocation) throws IOException, ExecutionException, InterruptedException, TimeoutException { diff --git a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/StopRegionalDiskReplicationConsistencyGroup.java b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/StopRegionalDiskReplicationConsistencyGroup.java new file mode 100644 index 00000000000..6e293eef0cf --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/StopRegionalDiskReplicationConsistencyGroup.java @@ -0,0 +1,72 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks.consistencygroup; + +// [START compute_consistency_group_regional_stop_replication] +import com.google.cloud.compute.v1.DisksStopGroupAsyncReplicationResource; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.RegionDisksClient; +import com.google.cloud.compute.v1.StopGroupAsyncReplicationRegionDiskRequest; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class StopRegionalDiskReplicationConsistencyGroup { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project that contains the disk. + String project = "YOUR_PROJECT_ID"; + // Region of the disk. + String region = "us-central1"; + // Name of the consistency group. + String consistencyGroupName = "CONSISTENCY_GROUP"; + + stopRegionalDiskReplicationConsistencyGroup(project, region, consistencyGroupName); + } + + // Stops replication of a consistency group for a project in a given region. + public static Status stopRegionalDiskReplicationConsistencyGroup( + String project, String region, String consistencyGroupName) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + String resourcePolicy = String.format("projects/%s/regions/%s/resourcePolicies/%s", + project, region, consistencyGroupName); + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (RegionDisksClient disksClient = RegionDisksClient.create()) { + StopGroupAsyncReplicationRegionDiskRequest request = + StopGroupAsyncReplicationRegionDiskRequest.newBuilder() + .setProject(project) + .setRegion(region) + .setDisksStopGroupAsyncReplicationResourceResource( + DisksStopGroupAsyncReplicationResource.newBuilder() + .setResourcePolicy(resourcePolicy).build()) + .build(); + Operation response = disksClient.stopGroupAsyncReplicationAsync(request) + .get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error stopping disk replication! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_consistency_group_regional_stop_replication] diff --git a/compute/cloud-client/src/main/java/compute/disks/consistencygroup/StopZonalDiskReplicationConsistencyGroup.java b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/StopZonalDiskReplicationConsistencyGroup.java new file mode 100644 index 00000000000..38c31e1850d --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/disks/consistencygroup/StopZonalDiskReplicationConsistencyGroup.java @@ -0,0 +1,73 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks.consistencygroup; + +// [START compute_consistency_group_stop_replication] +import com.google.cloud.compute.v1.DisksClient; +import com.google.cloud.compute.v1.DisksStopGroupAsyncReplicationResource; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.StopGroupAsyncReplicationDiskRequest; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class StopZonalDiskReplicationConsistencyGroup { + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project that contains the disk. + String project = "YOUR_PROJECT_ID"; + // Zone of the disk. + String zone = "us-central1-a"; + // Name of the consistency group. + String consistencyGroupName = "CONSISTENCY_GROUP"; + + stopZonalDiskReplicationConsistencyGroup(project, zone, consistencyGroupName); + } + + // Stops replication of a consistency group for a project in a given zone. + public static Status stopZonalDiskReplicationConsistencyGroup( + String project, String zone, String consistencyGroupName) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + String region = zone.substring(0, zone.lastIndexOf('-')); + + String resourcePolicy = String.format("projects/%s/regions/%s/resourcePolicies/%s", + project, region, consistencyGroupName); + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (DisksClient disksClient = DisksClient.create()) { + StopGroupAsyncReplicationDiskRequest request = + StopGroupAsyncReplicationDiskRequest.newBuilder() + .setProject(project) + .setZone(zone) + .setDisksStopGroupAsyncReplicationResourceResource( + DisksStopGroupAsyncReplicationResource.newBuilder() + .setResourcePolicy(resourcePolicy).build()) + .build(); + Operation response = disksClient.stopGroupAsyncReplicationAsync(request) + .get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error stopping disk replication! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_consistency_group_stop_replication] diff --git a/compute/cloud-client/src/main/java/compute/reservation/CreateSharedReservation.java b/compute/cloud-client/src/main/java/compute/reservation/CreateSharedReservation.java index 53052ee4d25..624965554a9 100644 --- a/compute/cloud-client/src/main/java/compute/reservation/CreateSharedReservation.java +++ b/compute/cloud-client/src/main/java/compute/reservation/CreateSharedReservation.java @@ -18,7 +18,9 @@ // [START compute_reservation_create_shared] import com.google.cloud.compute.v1.AllocationSpecificSKUReservation; +import com.google.cloud.compute.v1.InsertReservationRequest; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.Reservation; import com.google.cloud.compute.v1.ReservationsClient; import com.google.cloud.compute.v1.ShareSettings; @@ -29,12 +31,6 @@ import java.util.concurrent.TimeoutException; public class CreateSharedReservation { - private final ReservationsClient reservationsClient; - - // Constructor to inject the ReservationsClient - public CreateSharedReservation(ReservationsClient reservationsClient) { - this.reservationsClient = reservationsClient; - } public static void main(String[] args) throws IOException, ExecutionException, InterruptedException, TimeoutException { @@ -48,62 +44,66 @@ public static void main(String[] args) // For more information visit this page: // https://cloud.google.com/compute/docs/instances/reservations-shared#shared_reservation_constraint String projectId = "YOUR_PROJECT_ID"; - // Zone in which the reservation resides. + // Zone in which to reserve resources. String zone = "us-central1-a"; // Name of the reservation to be created. String reservationName = "YOUR_RESERVATION_NAME"; // The URI of the global instance template to be used for creating the reservation. String instanceTemplateUri = String.format( - "projects/%s/global/instanceTemplates/YOUR_INSTANCE_TEMPLATE_NAME", projectId); + "projects/%s/global/instanceTemplates/%s", projectId, "YOUR_INSTANCE_TEMPLATE_NAME"); // Number of instances for which capacity needs to be reserved. int vmCount = 3; - // In your main method, create ReservationsClient - ReservationsClient client = ReservationsClient.create(); - // Create an instance of your class, passing in the client - CreateSharedReservation creator = new CreateSharedReservation(client); - creator.createSharedReservation(projectId, zone, reservationName, instanceTemplateUri, vmCount); + createSharedReservation(projectId, zone, reservationName, instanceTemplateUri, vmCount); } // Creates a shared reservation with the given name in the given zone. - public void createSharedReservation( - String projectId, String zone, - String reservationName, String instanceTemplateUri, int vmCount) - throws ExecutionException, InterruptedException, TimeoutException { + public static Status createSharedReservation( + String projectId, String zone, + String reservationName, String instanceTemplateUri, int vmCount) + throws ExecutionException, InterruptedException, TimeoutException, IOException { + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (ReservationsClient reservationsClient = ReservationsClient.create()) { + ShareSettings shareSettings = ShareSettings.newBuilder() + .setShareType(String.valueOf(ShareSettings.ShareType.SPECIFIC_PROJECTS)) + // The IDs of projects that can consume this reservation. You can include up to + // 100 consumer projects. These projects must be in the same organization as + // the owner project. Don't include the owner project. + // By default, it is already allowed to consume the reservation. + .putProjectMap("CONSUMER_PROJECT_1", ShareSettingsProjectConfig.newBuilder().build()) + .putProjectMap("CONSUMER_PROJECT_2", ShareSettingsProjectConfig.newBuilder().build()) + .build(); - ShareSettings shareSettings = ShareSettings.newBuilder() - .setShareType(String.valueOf(ShareSettings.ShareType.SPECIFIC_PROJECTS)) - // The IDs of projects that can consume this reservation. You can include up to 100 - // consumer projects. These projects must be in the same organization as - // the owner project. Don't include the owner project. By default, it is already allowed - // to consume the reservation. - .putProjectMap("CONSUMER_PROJECT_ID_1", ShareSettingsProjectConfig.newBuilder().build()) - .putProjectMap("CONSUMER_PROJECT_ID_2", ShareSettingsProjectConfig.newBuilder().build()) - .build(); + Reservation reservationResource = + Reservation.newBuilder() + .setName(reservationName) + .setZone(zone) + .setSpecificReservationRequired(true) + .setShareSettings(shareSettings) + .setSpecificReservation( + AllocationSpecificSKUReservation.newBuilder() + .setCount(vmCount) + .setSourceInstanceTemplate(instanceTemplateUri) + .build()) + .build(); - // Create the reservation. - Reservation reservation = - Reservation.newBuilder() - .setName(reservationName) - .setZone(zone) - .setSpecificReservationRequired(true) - .setShareSettings(shareSettings) - .setSpecificReservation( - AllocationSpecificSKUReservation.newBuilder() - .setCount(vmCount) - .setSourceInstanceTemplate(instanceTemplateUri) - .build()) - .build(); + InsertReservationRequest request = + InsertReservationRequest.newBuilder() + .setProject(projectId) + .setZone(zone) + .setReservationResource(reservationResource) + .build(); - // Wait for the create reservation operation to complete. - Operation response = - this.reservationsClient.insertAsync(projectId, zone, reservation).get(3, TimeUnit.MINUTES); + Operation response = reservationsClient.insertAsync(request) + .get(3, TimeUnit.MINUTES); - if (response.hasError()) { - System.out.println("Reservation creation failed!" + response); - return; + if (response.hasError()) { + throw new Error("Reservation creation failed!!" + response); + } + return response.getStatus(); } - System.out.println("Reservation created. Operation Status: " + response.getStatus()); } } // [END compute_reservation_create_shared] diff --git a/compute/cloud-client/src/main/java/compute/snapshotschedule/AttachSnapshotScheduleToDisk.java b/compute/cloud-client/src/main/java/compute/snapshotschedule/AttachSnapshotScheduleToDisk.java new file mode 100644 index 00000000000..c68603f3ab6 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/snapshotschedule/AttachSnapshotScheduleToDisk.java @@ -0,0 +1,77 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.snapshotschedule; + +// [START compute_snapshot_schedule_attach] +import com.google.cloud.compute.v1.AddResourcePoliciesDiskRequest; +import com.google.cloud.compute.v1.DisksAddResourcePoliciesRequest; +import com.google.cloud.compute.v1.DisksClient; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class AttachSnapshotScheduleToDisk { + public static void main(String[] args) throws Exception { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String projectId = "YOUR_PROJECT_ID"; + // Name of the zone where your disk is located. + String zone = "us-central1-a"; + // Name of the disk you want to attach the snapshot schedule to. + String diskName = "YOUR_DISK_NAME"; + // Name of the snapshot schedule you want to attach. + String snapshotScheduleName = "YOUR_SNAPSHOT_SCHEDULE_NAME"; + // Name of the region where your snapshot schedule is located. + String region = "us-central1"; + + attachSnapshotScheduleToDisk(projectId, zone, diskName, snapshotScheduleName, region); + } + + // Attaches a snapshot schedule to a disk. + public static Status attachSnapshotScheduleToDisk( + String projectId, String zone, String diskName, String snapshotScheduleName, String region) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + + String resourcePolicyLink = String.format( + "projects/%s/regions/%s/resourcePolicies/%s", projectId, region, snapshotScheduleName); + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (DisksClient disksClient = DisksClient.create()) { + + AddResourcePoliciesDiskRequest request = AddResourcePoliciesDiskRequest.newBuilder() + .setProject(projectId) + .setZone(zone) + .setDisk(diskName) + .setDisksAddResourcePoliciesRequestResource( + DisksAddResourcePoliciesRequest.newBuilder() + .addResourcePolicies(resourcePolicyLink) + .build()) + .build(); + + Operation response = disksClient.addResourcePoliciesAsync(request).get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Error attaching snapshot schedule to disk: " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_snapshot_schedule_attach] \ No newline at end of file diff --git a/compute/cloud-client/src/main/java/compute/snapshotschedule/CreateSnapshotSchedule.java b/compute/cloud-client/src/main/java/compute/snapshotschedule/CreateSnapshotSchedule.java new file mode 100644 index 00000000000..29c9e4aa38b --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/snapshotschedule/CreateSnapshotSchedule.java @@ -0,0 +1,116 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.snapshotschedule; + +// [START compute_snapshot_schedule_create] +import com.google.cloud.compute.v1.InsertResourcePolicyRequest; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.ResourcePoliciesClient; +import com.google.cloud.compute.v1.ResourcePolicy; +import com.google.cloud.compute.v1.ResourcePolicyHourlyCycle; +import com.google.cloud.compute.v1.ResourcePolicySnapshotSchedulePolicy; +import com.google.cloud.compute.v1.ResourcePolicySnapshotSchedulePolicyRetentionPolicy; +import com.google.cloud.compute.v1.ResourcePolicySnapshotSchedulePolicyRetentionPolicy.OnSourceDiskDelete; +import com.google.cloud.compute.v1.ResourcePolicySnapshotSchedulePolicySchedule; +import com.google.cloud.compute.v1.ResourcePolicySnapshotSchedulePolicySnapshotProperties; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateSnapshotSchedule { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String projectId = "YOUR_PROJECT_ID"; + // Name of the region in which you want to create the snapshot schedule. + String region = "us-central1"; + // Name of the snapshot schedule you want to create. + String snapshotScheduleName = "YOUR_SCHEDULE_NAME"; + // Description of the snapshot schedule. + String scheduleDescription = "YOUR_SCHEDULE_DESCRIPTION"; + // Maximum number of days to retain snapshots. + int maxRetentionDays = 10; + // Storage location for the snapshots. + // More about storage locations: + // https://cloud.google.com/compute/docs/disks/snapshots?authuser=0#selecting_a_storage_location + String storageLocation = "US"; + + createSnapshotSchedule(projectId, region, snapshotScheduleName, scheduleDescription, + maxRetentionDays, storageLocation); + } + + // Creates a snapshot schedule policy. + public static Status createSnapshotSchedule(String projectId, String region, + String snapshotScheduleName, String scheduleDescription, int maxRetentionDays, + String storageLocation) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (ResourcePoliciesClient resourcePoliciesClient = ResourcePoliciesClient.create()) { + int snapshotInterval = 10; // Create a snapshot every 10 hours + String startTime = "08:00"; // Define the hourly schedule + + ResourcePolicyHourlyCycle hourlyCycle = ResourcePolicyHourlyCycle.newBuilder() + .setHoursInCycle(snapshotInterval) + .setStartTime(startTime) + .build(); + + ResourcePolicySnapshotSchedulePolicyRetentionPolicy retentionPolicy = + ResourcePolicySnapshotSchedulePolicyRetentionPolicy.newBuilder() + .setMaxRetentionDays(maxRetentionDays) + .setOnSourceDiskDelete(OnSourceDiskDelete.KEEP_AUTO_SNAPSHOTS.toString()) + .build(); + + ResourcePolicySnapshotSchedulePolicySnapshotProperties snapshotProperties = + ResourcePolicySnapshotSchedulePolicySnapshotProperties.newBuilder() + .addStorageLocations(storageLocation) + .build(); + + ResourcePolicySnapshotSchedulePolicy snapshotSchedulePolicy = + ResourcePolicySnapshotSchedulePolicy.newBuilder() + .setRetentionPolicy(retentionPolicy) + .setSchedule(ResourcePolicySnapshotSchedulePolicySchedule.newBuilder() + .setHourlySchedule(hourlyCycle) + .build()) + .setSnapshotProperties(snapshotProperties) + .build(); + + ResourcePolicy resourcePolicy = ResourcePolicy.newBuilder() + .setName(snapshotScheduleName) + .setDescription(scheduleDescription) + .setSnapshotSchedulePolicy(snapshotSchedulePolicy) + .build(); + InsertResourcePolicyRequest request = InsertResourcePolicyRequest.newBuilder() + .setProject(projectId) + .setRegion(region) + .setResourcePolicyResource(resourcePolicy) + .build(); + + Operation response = resourcePoliciesClient.insertAsync(request) + .get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Snapshot schedule creation failed! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_snapshot_schedule_create] \ No newline at end of file diff --git a/compute/cloud-client/src/main/java/compute/snapshotschedule/DeleteSnapshotSchedule.java b/compute/cloud-client/src/main/java/compute/snapshotschedule/DeleteSnapshotSchedule.java new file mode 100644 index 00000000000..9a0dea6815b --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/snapshotschedule/DeleteSnapshotSchedule.java @@ -0,0 +1,64 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.snapshotschedule; + +// [START compute_snapshot_schedule_delete] +import com.google.cloud.compute.v1.DeleteResourcePolicyRequest; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.ResourcePoliciesClient; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class DeleteSnapshotSchedule { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String projectId = "YOUR_PROJECT_ID"; + // Name of the region where your snapshot schedule is located. + String region = "us-central1"; + // Name of the snapshot schedule you want to delete. + String snapshotScheduleName = "YOUR_SCHEDULE_NAME"; + + deleteSnapshotSchedule(projectId, region, snapshotScheduleName); + } + + // Deletes a snapshot schedule policy. + public static Status deleteSnapshotSchedule( + String projectId, String region, String snapshotScheduleName) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (ResourcePoliciesClient resourcePoliciesClient = ResourcePoliciesClient.create()) { + DeleteResourcePolicyRequest request = DeleteResourcePolicyRequest.newBuilder() + .setProject(projectId) + .setRegion(region) + .setResourcePolicy(snapshotScheduleName) + .build(); + Operation response = resourcePoliciesClient.deleteAsync(request).get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Snapshot schedule deletion failed! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_snapshot_schedule_delete] \ No newline at end of file diff --git a/compute/cloud-client/src/main/java/compute/snapshotschedule/EditSnapshotSchedule.java b/compute/cloud-client/src/main/java/compute/snapshotschedule/EditSnapshotSchedule.java new file mode 100644 index 00000000000..5b91a299b58 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/snapshotschedule/EditSnapshotSchedule.java @@ -0,0 +1,113 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.snapshotschedule; + +// [START compute_snapshot_schedule_edit] +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.PatchResourcePolicyRequest; +import com.google.cloud.compute.v1.ResourcePoliciesClient; +import com.google.cloud.compute.v1.ResourcePolicy; +import com.google.cloud.compute.v1.ResourcePolicySnapshotSchedulePolicy; +import com.google.cloud.compute.v1.ResourcePolicySnapshotSchedulePolicyRetentionPolicy; +import com.google.cloud.compute.v1.ResourcePolicySnapshotSchedulePolicyRetentionPolicy.OnSourceDiskDelete; +import com.google.cloud.compute.v1.ResourcePolicySnapshotSchedulePolicySchedule; +import com.google.cloud.compute.v1.ResourcePolicySnapshotSchedulePolicySnapshotProperties; +import com.google.cloud.compute.v1.ResourcePolicyWeeklyCycle; +import com.google.cloud.compute.v1.ResourcePolicyWeeklyCycleDayOfWeek; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class EditSnapshotSchedule { + + public static void main(String[] args) throws Exception { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String projectId = "YOUR_PROJECT_ID"; + // Name of the region where your snapshot schedule is located. + String region = "us-central1"; + // Name of the snapshot schedule you want to update. + String snapshotScheduleName = "YOUR_SCHEDULE_NAME"; + + editSnapshotSchedule(projectId, region, snapshotScheduleName); + } + + // Edits a snapshot schedule. + public static Status editSnapshotSchedule( + String projectId, String region, String snapshotScheduleName) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (ResourcePoliciesClient resourcePoliciesClient = ResourcePoliciesClient.create()) { + Map snapshotLabels = new HashMap<>(); + snapshotLabels.put("key", "value"); + + ResourcePolicySnapshotSchedulePolicySnapshotProperties.Builder snapshotProperties = + ResourcePolicySnapshotSchedulePolicySnapshotProperties.newBuilder(); + snapshotProperties.putAllLabels(snapshotLabels); + + ResourcePolicyWeeklyCycleDayOfWeek dayOfWeek = ResourcePolicyWeeklyCycleDayOfWeek.newBuilder() + .setDay("Tuesday") + .setStartTime("09:00") + .build(); + ResourcePolicyWeeklyCycle weeklySchedule = ResourcePolicyWeeklyCycle.newBuilder() + .addDayOfWeeks(dayOfWeek) + .build(); + + int maxRetentionDays = 3; + + ResourcePolicySnapshotSchedulePolicyRetentionPolicy.Builder retentionPolicy = + ResourcePolicySnapshotSchedulePolicyRetentionPolicy.newBuilder(); + retentionPolicy.setOnSourceDiskDelete(OnSourceDiskDelete.APPLY_RETENTION_POLICY.toString()); + retentionPolicy.setMaxRetentionDays(maxRetentionDays); + + String description = "Updated description"; + + ResourcePolicy updatedSchedule = ResourcePolicy.newBuilder() + .setName(snapshotScheduleName) + .setDescription(description) + .setSnapshotSchedulePolicy( + ResourcePolicySnapshotSchedulePolicy.newBuilder() + .setSchedule(ResourcePolicySnapshotSchedulePolicySchedule.newBuilder() + .setWeeklySchedule(weeklySchedule)) + .setSnapshotProperties(snapshotProperties) + .setRetentionPolicy(retentionPolicy.build()) + .build()) + .build(); + + PatchResourcePolicyRequest request = PatchResourcePolicyRequest.newBuilder() + .setProject(projectId) + .setRegion(region) + .setResourcePolicy(snapshotScheduleName) + .setResourcePolicyResource(updatedSchedule) + .build(); + + Operation response = resourcePoliciesClient.patchAsync(request).get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Failed to update snapshot schedule! " + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_snapshot_schedule_edit] \ No newline at end of file diff --git a/compute/cloud-client/src/main/java/compute/snapshotschedule/GetSnapshotSchedule.java b/compute/cloud-client/src/main/java/compute/snapshotschedule/GetSnapshotSchedule.java new file mode 100644 index 00000000000..fc425899617 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/snapshotschedule/GetSnapshotSchedule.java @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.snapshotschedule; + +// [START compute_snapshot_schedule_get] +import com.google.cloud.compute.v1.GetResourcePolicyRequest; +import com.google.cloud.compute.v1.ResourcePoliciesClient; +import com.google.cloud.compute.v1.ResourcePolicy; +import java.io.IOException; + +public class GetSnapshotSchedule { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String projectId = "YOUR_PROJECT_ID"; + // Name of the region in which your snapshot schedule is located. + String region = "us-central1"; + // Name of your snapshot schedule. + String snapshotScheduleName = "YOUR_SCHEDULE_NAME"; + + getSnapshotSchedule(projectId, region, snapshotScheduleName); + } + + // Retrieves the details of a snapshot schedule. + public static ResourcePolicy getSnapshotSchedule( + String projectId, String region, String snapshotScheduleName) throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (ResourcePoliciesClient resourcePoliciesClient = ResourcePoliciesClient.create()) { + GetResourcePolicyRequest request = GetResourcePolicyRequest.newBuilder() + .setProject(projectId) + .setRegion(region) + .setResourcePolicy(snapshotScheduleName) + .build(); + ResourcePolicy resourcePolicy = resourcePoliciesClient.get(request); + System.out.println(resourcePolicy); + + return resourcePolicy; + } + } +} +// [END compute_snapshot_schedule_get] diff --git a/compute/cloud-client/src/main/java/compute/snapshotschedule/ListSnapshotSchedules.java b/compute/cloud-client/src/main/java/compute/snapshotschedule/ListSnapshotSchedules.java new file mode 100644 index 00000000000..c299f9361f5 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/snapshotschedule/ListSnapshotSchedules.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.snapshotschedule; + +// [START compute_snapshot_schedule_list] +import com.google.cloud.compute.v1.ListResourcePoliciesRequest; +import com.google.cloud.compute.v1.ResourcePoliciesClient; +import com.google.cloud.compute.v1.ResourcePoliciesClient.ListPagedResponse; +import com.google.cloud.compute.v1.ResourcePolicy; +import java.io.IOException; + +public class ListSnapshotSchedules { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String projectId = "YOUR_PROJECT_ID"; + // Name of the region you want to list snapshot schedules from. + String region = "us-central1"; + // Name of the snapshot schedule you want to list. + String snapshotScheduleName = "YOUR_SCHEDULE_NAME"; + + listSnapshotSchedules(projectId, region, snapshotScheduleName); + } + + // Lists snapshot schedules in a specified region, optionally filtered. + public static ListPagedResponse listSnapshotSchedules( + String projectId, String region, String snapshotScheduleName) throws IOException { + String filter = String.format("name = %s", snapshotScheduleName); + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (ResourcePoliciesClient resourcePoliciesClient = ResourcePoliciesClient.create()) { + + ListResourcePoliciesRequest request = ListResourcePoliciesRequest.newBuilder() + .setProject(projectId) + .setRegion(region) + .setFilter(filter) + .build(); + ListPagedResponse response = resourcePoliciesClient.list(request); + for (ResourcePolicy resourcePolicy : response.iterateAll()) { + System.out.println(resourcePolicy); + } + return response; + } + } +} +// [END compute_snapshot_schedule_list] \ No newline at end of file diff --git a/compute/cloud-client/src/main/java/compute/snapshotschedule/RemoveSnapshotScheduleFromDisk.java b/compute/cloud-client/src/main/java/compute/snapshotschedule/RemoveSnapshotScheduleFromDisk.java new file mode 100644 index 00000000000..5fee20934b4 --- /dev/null +++ b/compute/cloud-client/src/main/java/compute/snapshotschedule/RemoveSnapshotScheduleFromDisk.java @@ -0,0 +1,81 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.snapshotschedule; + +// [START compute_snapshot_schedule_remove] +import com.google.cloud.compute.v1.DisksClient; +import com.google.cloud.compute.v1.DisksRemoveResourcePoliciesRequest; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.RemoveResourcePoliciesDiskRequest; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class RemoveSnapshotScheduleFromDisk { + + public static void main(String[] args) throws Exception { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String projectId = "YOUR_PROJECT_ID"; + // Name of the zone where your disk is located. + String zone = "us-central1-a"; + // Name of the disk you want to remove the snapshot schedule from. + String diskName = "YOUR_DISK_NAME"; + // Name of the region where your snapshot schedule is located. + String region = "us-central1"; + // Name of the snapshot schedule you want to remove. + String snapshotScheduleName = "YOUR_SNAPSHOT_SCHEDULE_NAME"; + + removeSnapshotScheduleFromDisk(projectId, zone, diskName, region, snapshotScheduleName); + } + + // Removes snapshot schedule from a zonal disk. + public static Status removeSnapshotScheduleFromDisk( + String project, String zone, String diskName, String region, String snapshotScheduleName) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + String snapshotSchedulePath = String.format("projects/%s/regions/%s/resourcePolicies/%s", + project, region, snapshotScheduleName); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (DisksClient disksClient = DisksClient.create()) { + DisksRemoveResourcePoliciesRequest disksRequest = + DisksRemoveResourcePoliciesRequest.newBuilder() + .addResourcePolicies(snapshotSchedulePath) + .build(); + + RemoveResourcePoliciesDiskRequest request = + RemoveResourcePoliciesDiskRequest.newBuilder() + .setProject(project) + .setZone(zone) + .setDisk(diskName) + .setDisksRemoveResourcePoliciesRequestResource(disksRequest) + .build(); + + Operation response = disksClient.removeResourcePoliciesAsync(request) + .get(3, TimeUnit.MINUTES); + + if (response.hasError()) { + throw new Error("Failed to remove resource policies from disk!" + response.getError()); + } + return response.getStatus(); + } + } +} +// [END compute_snapshot_schedule_remove] \ No newline at end of file diff --git a/compute/cloud-client/src/test/java/compute/InstanceOperationsIT.java b/compute/cloud-client/src/test/java/compute/InstanceOperationsIT.java index 625464b11a9..90ea8bfa729 100644 --- a/compute/cloud-client/src/test/java/compute/InstanceOperationsIT.java +++ b/compute/cloud-client/src/test/java/compute/InstanceOperationsIT.java @@ -20,27 +20,34 @@ import static com.google.common.truth.Truth.assertWithMessage; import static compute.Util.getZone; +import com.google.cloud.compute.v1.CreateSnapshotRegionDiskRequest; import com.google.cloud.compute.v1.Disk; import com.google.cloud.compute.v1.Instance; import com.google.cloud.compute.v1.Instance.Status; import com.google.cloud.compute.v1.InstancesClient; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.RegionDisksClient; +import com.google.cloud.compute.v1.Snapshot; import compute.disks.CloneEncryptedDisk; import compute.disks.CreateEncryptedDisk; import compute.disks.DeleteDisk; +import compute.disks.DeleteSnapshot; +import compute.disks.RegionalCreateFromSource; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.junit.Assert; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import org.junit.runner.RunWith; @@ -52,13 +59,21 @@ public class InstanceOperationsIT { private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); private static final String ZONE = getZone(); + private static final String REGION = ZONE.substring(0, ZONE.length() - 2); private static String MACHINE_NAME; private static String MACHINE_NAME_ENCRYPTED; private static String DISK_NAME; private static String ENCRYPTED_DISK_NAME; private static String RAW_KEY; - - private ByteArrayOutputStream stdOut; + private static String INSTANCE_NAME; + private static final String DISK_TYPE = String.format("regions/%s/diskTypes/pd-standard", REGION); + private static String REPLICATED_DISK_NAME; + private static String SNAPSHOT_NAME; + private static final String DISK_SNAPSHOT_LINK = + String.format("projects/%s/global/snapshots/%s", PROJECT_ID, SNAPSHOT_NAME); + private static final List REPLICA_ZONES = Arrays.asList( + String.format("projects/%s/zones/%s-a", PROJECT_ID, REGION), + String.format("projects/%s/zones/%s-b", PROJECT_ID, REGION)); // Check if the required environment variables are set. public static void requireEnvVar(String envVarName) { @@ -72,47 +87,42 @@ public static void setUp() requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); requireEnvVar("GOOGLE_CLOUD_PROJECT"); - final PrintStream out = System.out; - ByteArrayOutputStream stdOut = new ByteArrayOutputStream(); - System.setOut(new PrintStream(stdOut)); - MACHINE_NAME = "test-instance-operation-" + UUID.randomUUID(); MACHINE_NAME_ENCRYPTED = "test-instance-encrypted-" + UUID.randomUUID(); DISK_NAME = "test-clone-disk-enc-" + UUID.randomUUID(); ENCRYPTED_DISK_NAME = "test-disk-enc-" + UUID.randomUUID(); RAW_KEY = Util.getBase64EncodedKey(); - - // Cleanup existing stale resources. - Util.cleanUpExistingInstances("test-instance-", PROJECT_ID, ZONE); - Util.cleanUpExistingDisks("test-clone-disk-enc-", PROJECT_ID, ZONE); - Util.cleanUpExistingDisks("test-disk-enc-", PROJECT_ID, ZONE); + INSTANCE_NAME = "test-instance-" + UUID.randomUUID(); + REPLICATED_DISK_NAME = "test-disk-replicated-" + UUID.randomUUID(); + SNAPSHOT_NAME = "test-snapshot-" + UUID.randomUUID().toString().split("-")[0]; compute.CreateInstance.createInstance(PROJECT_ID, ZONE, MACHINE_NAME); compute.CreateEncryptedInstance .createEncryptedInstance(PROJECT_ID, ZONE, MACHINE_NAME_ENCRYPTED, RAW_KEY); + RegionalCreateFromSource.createRegionalDisk(PROJECT_ID, REGION, REPLICA_ZONES, + REPLICATED_DISK_NAME, DISK_TYPE, 200, Optional.empty(), Optional.empty()); + createDiskSnapshot(PROJECT_ID, REGION, REPLICATED_DISK_NAME, SNAPSHOT_NAME); TimeUnit.SECONDS.sleep(30); - - stdOut.close(); - System.setOut(out); } - @AfterAll public static void cleanup() throws IOException, InterruptedException, ExecutionException, TimeoutException { - final PrintStream out = System.out; - ByteArrayOutputStream stdOut = new ByteArrayOutputStream(); - System.setOut(new PrintStream(stdOut)); + // Cleanup existing stale resources. + Util.cleanUpExistingInstances("test-instance-", PROJECT_ID, ZONE); + Util.cleanUpExistingDisks("test-clone-disk-enc-", PROJECT_ID, ZONE); + Util.cleanUpExistingDisks("test-disk-enc-", PROJECT_ID, ZONE); + Util.cleanUpExistingRegionalDisks("test-disk-replicated-", PROJECT_ID, REGION); + Util.cleanUpExistingSnapshots("test-snapshot-", PROJECT_ID); // Delete all instances created for testing. compute.DeleteInstance.deleteInstance(PROJECT_ID, ZONE, MACHINE_NAME_ENCRYPTED); compute.DeleteInstance.deleteInstance(PROJECT_ID, ZONE, MACHINE_NAME); + compute.DeleteInstance.deleteInstance(PROJECT_ID, ZONE, INSTANCE_NAME); DeleteDisk.deleteDisk(PROJECT_ID, ZONE, DISK_NAME); DeleteDisk.deleteDisk(PROJECT_ID, ZONE, ENCRYPTED_DISK_NAME); - - stdOut.close(); - System.setOut(out); + DeleteSnapshot.deleteSnapshot(PROJECT_ID, SNAPSHOT_NAME); } private static Instance getInstance(String machineName) throws IOException { @@ -121,16 +131,28 @@ private static Instance getInstance(String machineName) throws IOException { } } - @BeforeEach - public void beforeEach() { - stdOut = new ByteArrayOutputStream(); - System.setOut(new PrintStream(stdOut)); - } - - @AfterEach - public void afterEach() { - stdOut = null; - System.setOut(null); + public static void createDiskSnapshot(String project, String region, String diskName, + String snapshotName) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + try (RegionDisksClient disksClient = RegionDisksClient.create()) { + + CreateSnapshotRegionDiskRequest createSnapshotDiskRequest = + CreateSnapshotRegionDiskRequest.newBuilder() + .setProject(project) + .setRegion(region) + .setDisk(diskName) + .setSnapshotResource(Snapshot.newBuilder() + .setName(snapshotName) + .build()) + .build(); + + Operation operation = disksClient.createSnapshotAsync(createSnapshotDiskRequest) + .get(3, TimeUnit.MINUTES); + + if (operation.hasError()) { + throw new Error("Failed to create the snapshot"); + } + } } @Test @@ -204,14 +226,17 @@ public void testEncryptedInstanceOperations() @Test public void testCloneEncryptedDisk() throws IOException, ExecutionException, InterruptedException, TimeoutException { - Assert.assertEquals(Util.getInstanceStatus(PROJECT_ID, ZONE, MACHINE_NAME_ENCRYPTED), - "RUNNING"); + ByteArrayOutputStream stdOut = new ByteArrayOutputStream(); + System.setOut(new PrintStream(stdOut)); + Instance instance = getInstance(MACHINE_NAME_ENCRYPTED); String diskType = String.format("zones/%s/diskTypes/pd-standard", ZONE); CloneEncryptedDisk.createDiskFromCustomerEncryptedKey(PROJECT_ID, ZONE, DISK_NAME, diskType, 10, instance.getDisks(0).getSource(), RAW_KEY.getBytes( StandardCharsets.UTF_8)); assertThat(stdOut.toString()).contains("Disk cloned with customer encryption key."); + + stdOut.close(); } @Test @@ -228,4 +253,15 @@ public void testCreateEncryptedDisk() Assert.assertNotNull(encryptedDisk.getDiskEncryptionKey()); Assert.assertNotNull(encryptedDisk.getDiskEncryptionKey().getSha256()); } + + @Test + public void testCreateInstanceWithRegionalDiskFromSnapshot() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + Operation.Status status = CreateInstanceWithRegionalDiskFromSnapshot + .createInstanceWithRegionalDiskFromSnapshot( + PROJECT_ID, ZONE, INSTANCE_NAME, REPLICATED_DISK_NAME, + DISK_TYPE, DISK_SNAPSHOT_LINK, REPLICA_ZONES); + + assertThat(status).isEqualTo(Operation.Status.DONE); + } } diff --git a/compute/cloud-client/src/test/java/compute/Util.java b/compute/cloud-client/src/test/java/compute/Util.java index 5c89de8faa8..dffec7f5f41 100644 --- a/compute/cloud-client/src/test/java/compute/Util.java +++ b/compute/cloud-client/src/test/java/compute/Util.java @@ -30,6 +30,8 @@ import com.google.cloud.compute.v1.RegionInstanceTemplatesClient; import com.google.cloud.compute.v1.Reservation; import com.google.cloud.compute.v1.ReservationsClient; +import com.google.cloud.compute.v1.ResourcePoliciesClient; +import com.google.cloud.compute.v1.ResourcePolicy; import com.google.cloud.compute.v1.Snapshot; import com.google.cloud.compute.v1.SnapshotsClient; import com.google.cloud.compute.v1.StoragePool; @@ -37,8 +39,11 @@ import compute.deleteprotection.SetDeleteProtection; import compute.disks.DeleteDisk; import compute.disks.DeleteSnapshot; +import compute.disks.RegionalDelete; import compute.reservation.DeleteReservation; +import compute.snapshotschedule.DeleteSnapshotSchedule; import java.io.IOException; +import java.lang.Error; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.time.Instant; @@ -217,6 +222,22 @@ && isCreatedBeforeThresholdTime(disk.getCreationTimestamp())) { } } + // Delete regional disks which starts with the given prefixToDelete and + // has creation timestamp >24 hours. + public static void cleanUpExistingRegionalDisks( + String prefixToDelete, String projectId, String region) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + try (RegionDisksClient disksClient = RegionDisksClient.create()) { + for (Disk disk : disksClient.list(projectId, region).iterateAll()) { + if (disk.getName().contains(prefixToDelete) + && disk.getRegion().equals(region) + && isCreatedBeforeThresholdTime(disk.getCreationTimestamp())) { + RegionalDelete.deleteRegionalDisk(projectId, region, disk.getName()); + } + } + } + } + // Delete snapshots which starts with the given prefixToDelete and // has creation timestamp >24 hours. public static void cleanUpExistingSnapshots(String prefixToDelete, String projectId) @@ -266,6 +287,21 @@ public static void deleteStoragePool(String project, String zone, String storage } } + // Delete snapshot schedule which starts with the given prefixToDelete and + // has creation timestamp >24 hours. + public static void cleanUpExistingSnapshotSchedule( + String prefixToDelete, String projectId, String region) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + try (ResourcePoliciesClient resourcePoliciesClient = ResourcePoliciesClient.create()) { + for (ResourcePolicy resource : resourcePoliciesClient.list(projectId, region).iterateAll()) { + if (containPrefixToDeleteAndZone(resource, prefixToDelete, region) + && isCreatedBeforeThresholdTime(resource.getCreationTimestamp())) { + DeleteSnapshotSchedule.deleteSnapshotSchedule(projectId, region, resource.getName()); + } + } + } + } + public static boolean containPrefixToDeleteAndZone( Object resource, String prefixToDelete, String zone) { boolean containPrefixAndZone = false; @@ -291,6 +327,11 @@ public static boolean containPrefixToDeleteAndZone( containPrefixAndZone = ((StoragePool) resource).getName().contains(prefixToDelete) && ((StoragePool) resource).getZone().contains(zone); } + if (resource instanceof ResourcePolicy) { + containPrefixAndZone = ((ResourcePolicy) resource).getName().contains(prefixToDelete) + && ((ResourcePolicy) resource).getRegion() + .contains(zone.substring(0, zone.lastIndexOf('-'))); + } } catch (NullPointerException e) { System.out.println("Resource not found, skipping deletion:"); } diff --git a/compute/cloud-client/src/test/java/compute/disks/ConsistencyGroupIT.java b/compute/cloud-client/src/test/java/compute/disks/ConsistencyGroupIT.java index 61d4ec81940..7f96e34dfd8 100644 --- a/compute/cloud-client/src/test/java/compute/disks/ConsistencyGroupIT.java +++ b/compute/cloud-client/src/test/java/compute/disks/ConsistencyGroupIT.java @@ -27,20 +27,29 @@ import com.google.api.gax.longrunning.OperationFuture; import com.google.cloud.compute.v1.AddResourcePoliciesRegionDiskRequest; +import com.google.cloud.compute.v1.BulkInsertDiskRequest; +import com.google.cloud.compute.v1.BulkInsertRegionDiskRequest; import com.google.cloud.compute.v1.DisksClient; import com.google.cloud.compute.v1.InsertResourcePolicyRequest; import com.google.cloud.compute.v1.ListDisksRequest; import com.google.cloud.compute.v1.ListRegionDisksRequest; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.RegionDisksClient; import com.google.cloud.compute.v1.RemoveResourcePoliciesRegionDiskRequest; import com.google.cloud.compute.v1.ResourcePoliciesClient; +import com.google.cloud.compute.v1.StopGroupAsyncReplicationDiskRequest; +import com.google.cloud.compute.v1.StopGroupAsyncReplicationRegionDiskRequest; import compute.disks.consistencygroup.AddDiskToConsistencyGroup; +import compute.disks.consistencygroup.CloneRegionalDisksFromConsistencyGroup; +import compute.disks.consistencygroup.CloneZonalDisksFromConsistencyGroup; import compute.disks.consistencygroup.CreateConsistencyGroup; import compute.disks.consistencygroup.DeleteConsistencyGroup; import compute.disks.consistencygroup.ListRegionalDisksInConsistencyGroup; import compute.disks.consistencygroup.ListZonalDisksInConsistencyGroup; import compute.disks.consistencygroup.RemoveDiskFromConsistencyGroup; +import compute.disks.consistencygroup.StopRegionalDiskReplicationConsistencyGroup; +import compute.disks.consistencygroup.StopZonalDiskReplicationConsistencyGroup; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; @@ -53,6 +62,7 @@ public class ConsistencyGroupIT { private static final String PROJECT_ID = "project-id"; private static final String REGION = "asia-east1"; + private static final String ZONE = "asia-east1-c"; private static final String CONSISTENCY_GROUP_NAME = "consistency-group"; private static final String DISK_NAME = "disk-for-consistency"; @@ -68,14 +78,14 @@ public void testCreateConsistencyGroupResourcePolicy() throws Exception { when(mockClient.insertAsync(any(InsertResourcePolicyRequest.class))) .thenReturn(mockFuture); when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); - when(operation.getStatus()).thenReturn(Operation.Status.DONE); + when(operation.getStatus()).thenReturn(Status.DONE); - Operation.Status status = CreateConsistencyGroup.createConsistencyGroup( + Status status = CreateConsistencyGroup.createConsistencyGroup( PROJECT_ID, REGION, CONSISTENCY_GROUP_NAME); verify(mockClient, times(1)).insertAsync(any(InsertResourcePolicyRequest.class)); verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); - assertEquals(Operation.Status.DONE, status); + assertEquals(Status.DONE, status); } } @@ -91,15 +101,15 @@ public void testAddRegionalDiskToConsistencyGroup() throws Exception { when(mockClient.addResourcePoliciesAsync(any(AddResourcePoliciesRegionDiskRequest.class))) .thenReturn(mockFuture); when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); - when(operation.getStatus()).thenReturn(Operation.Status.DONE); + when(operation.getStatus()).thenReturn(Status.DONE); - Operation.Status status = AddDiskToConsistencyGroup.addDiskToConsistencyGroup( + Status status = AddDiskToConsistencyGroup.addDiskToConsistencyGroup( PROJECT_ID, REGION, DISK_NAME, CONSISTENCY_GROUP_NAME, REGION); verify(mockClient, times(1)) .addResourcePoliciesAsync(any(AddResourcePoliciesRegionDiskRequest.class)); verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); - assertEquals(Operation.Status.DONE, status); + assertEquals(Status.DONE, status); } } @@ -115,15 +125,15 @@ public void testRemoveDiskFromConsistencyGroup() throws Exception { when(mockClient.removeResourcePoliciesAsync( any(RemoveResourcePoliciesRegionDiskRequest.class))).thenReturn(mockFuture); when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); - when(operation.getStatus()).thenReturn(Operation.Status.DONE); + when(operation.getStatus()).thenReturn(Status.DONE); - Operation.Status status = RemoveDiskFromConsistencyGroup.removeDiskFromConsistencyGroup( + Status status = RemoveDiskFromConsistencyGroup.removeDiskFromConsistencyGroup( PROJECT_ID, REGION, DISK_NAME, CONSISTENCY_GROUP_NAME, REGION); verify(mockClient, times(1)) .removeResourcePoliciesAsync(any(RemoveResourcePoliciesRegionDiskRequest.class)); verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); - assertEquals(Operation.Status.DONE, status); + assertEquals(Status.DONE, status); } } @@ -139,15 +149,15 @@ public void testDeleteConsistencyGroup() throws Exception { when(mockClient.deleteAsync(PROJECT_ID, REGION, CONSISTENCY_GROUP_NAME)) .thenReturn(mockFuture); when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); - when(operation.getStatus()).thenReturn(Operation.Status.DONE); + when(operation.getStatus()).thenReturn(Status.DONE); - Operation.Status status = DeleteConsistencyGroup.deleteConsistencyGroup( + Status status = DeleteConsistencyGroup.deleteConsistencyGroup( PROJECT_ID, REGION, CONSISTENCY_GROUP_NAME); verify(mockClient, times(1)) .deleteAsync(PROJECT_ID, REGION, CONSISTENCY_GROUP_NAME); verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); - assertEquals(Operation.Status.DONE, status); + assertEquals(Status.DONE, status); } } @@ -192,4 +202,103 @@ public void testListZonalDisksInConsistencyGroup() throws Exception { verify(mockResponse, times(1)).iterateAll(); } } + + @Test + public void testStopRegionalDiskReplicationConsistencyGroup() throws Exception { + try (MockedStatic mockedRegionDisksClient = + mockStatic(RegionDisksClient.class)) { + Operation operation = mock(Operation.class); + RegionDisksClient mockClient = mock(RegionDisksClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedRegionDisksClient.when(RegionDisksClient::create).thenReturn(mockClient); + when(mockClient.stopGroupAsyncReplicationAsync( + any(StopGroupAsyncReplicationRegionDiskRequest.class))).thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status status = StopRegionalDiskReplicationConsistencyGroup + .stopRegionalDiskReplicationConsistencyGroup( + PROJECT_ID, REGION, CONSISTENCY_GROUP_NAME); + + verify(mockClient, times(1)).stopGroupAsyncReplicationAsync( + any(StopGroupAsyncReplicationRegionDiskRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + } + } + + @Test + public void testStopZonalDiskReplicationConsistencyGroup() throws Exception { + try (MockedStatic mockedDisksClient = + mockStatic(DisksClient.class)) { + Operation operation = mock(Operation.class); + DisksClient mockClient = mock(DisksClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedDisksClient.when(DisksClient::create).thenReturn(mockClient); + when(mockClient.stopGroupAsyncReplicationAsync( + any(StopGroupAsyncReplicationDiskRequest.class))).thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status status = StopZonalDiskReplicationConsistencyGroup + .stopZonalDiskReplicationConsistencyGroup( + PROJECT_ID, ZONE, CONSISTENCY_GROUP_NAME); + + verify(mockClient, times(1)).stopGroupAsyncReplicationAsync( + any(StopGroupAsyncReplicationDiskRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + } + } + + @Test + public void testCloneRegionalDisksFromConsistencyGroup() throws Exception { + try (MockedStatic mockedRegionDisksClient = + mockStatic(RegionDisksClient.class)) { + Operation operation = mock(Operation.class); + RegionDisksClient mockClient = mock(RegionDisksClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedRegionDisksClient.when(RegionDisksClient::create).thenReturn(mockClient); + when(mockClient.bulkInsertAsync(any(BulkInsertRegionDiskRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status status = CloneRegionalDisksFromConsistencyGroup + .cloneRegionalDisksFromConsistencyGroup( + PROJECT_ID, REGION, CONSISTENCY_GROUP_NAME); + + verify(mockClient, times(1)) + .bulkInsertAsync(any(BulkInsertRegionDiskRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + } + } + + @Test + public void testCloneZonalDisksFromConsistencyGroup() throws Exception { + try (MockedStatic mockedRegionDisksClient = + mockStatic(DisksClient.class)) { + Operation operation = mock(Operation.class); + DisksClient mockClient = mock(DisksClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedRegionDisksClient.when(DisksClient::create).thenReturn(mockClient); + when(mockClient.bulkInsertAsync(any(BulkInsertDiskRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status status = CloneZonalDisksFromConsistencyGroup + .cloneZonalDisksFromConsistencyGroup(PROJECT_ID, REGION, CONSISTENCY_GROUP_NAME); + + verify(mockClient, times(1)) + .bulkInsertAsync(any(BulkInsertDiskRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + } + } } \ No newline at end of file diff --git a/compute/cloud-client/src/test/java/compute/disks/DiskReplicationIT.java b/compute/cloud-client/src/test/java/compute/disks/DiskReplicationIT.java new file mode 100644 index 00000000000..8f0dfd92901 --- /dev/null +++ b/compute/cloud-client/src/test/java/compute/disks/DiskReplicationIT.java @@ -0,0 +1,151 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.compute.v1.DisksClient; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.RegionDisksClient; +import com.google.cloud.compute.v1.StartAsyncReplicationDiskRequest; +import com.google.cloud.compute.v1.StartAsyncReplicationRegionDiskRequest; +import com.google.cloud.compute.v1.StopAsyncReplicationDiskRequest; +import com.google.cloud.compute.v1.StopAsyncReplicationRegionDiskRequest; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.MockedStatic; + +@RunWith(JUnit4.class) +@Timeout(value = 2, unit = TimeUnit.MINUTES) +public class DiskReplicationIT { + + private static final String PROJECT_ID = "project-id"; + private static final String PRIMARY_REGION = "us-central1"; + private static final String SECONDARY_REGION = "us-east1"; + private static final String PRIMARY_ZONE = "us-central1-a"; + private static final String SECONDARY_ZONE = "us-east1-c"; + private static final String PRIMARY_DISK_NAME = "test-disk-primary"; + private static final String SECONDARY_DISK_NAME = "test-disk-secondary"; + + @Test + public void testStartRegionalDiskAsyncReplication() throws Exception { + try (MockedStatic mockedRegionDisksClient = + mockStatic(RegionDisksClient.class)) { + Operation operation = mock(Operation.class); + RegionDisksClient mockClient = mock(RegionDisksClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedRegionDisksClient.when(RegionDisksClient::create).thenReturn(mockClient); + when(mockClient.startAsyncReplicationAsync(any(StartAsyncReplicationRegionDiskRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status status = StartRegionalDiskReplication.startRegionalDiskAsyncReplication( + PROJECT_ID, PRIMARY_DISK_NAME, PRIMARY_REGION, SECONDARY_DISK_NAME, SECONDARY_REGION); + + verify(mockClient, times(1)) + .startAsyncReplicationAsync(any(StartAsyncReplicationRegionDiskRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + } + } + + @Test + public void testStartZonalDiskAsyncReplication() throws Exception { + try (MockedStatic mockedDisksClient = + mockStatic(DisksClient.class)) { + Operation operation = mock(Operation.class); + DisksClient mockClient = mock(DisksClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedDisksClient.when(DisksClient::create).thenReturn(mockClient); + when(mockClient.startAsyncReplicationAsync(any(StartAsyncReplicationDiskRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status status = StartZonalDiskReplication.startZonalDiskAsyncReplication( + PROJECT_ID, PRIMARY_DISK_NAME, PRIMARY_ZONE, SECONDARY_DISK_NAME, SECONDARY_ZONE); + + verify(mockClient, times(1)) + .startAsyncReplicationAsync(any(StartAsyncReplicationDiskRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + } + } + + @Test + public void testStopRegionalDiskAsyncReplication() throws Exception { + try (MockedStatic mockedRegionDisksClient = + mockStatic(RegionDisksClient.class)) { + Operation operation = mock(Operation.class); + RegionDisksClient mockClient = mock(RegionDisksClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedRegionDisksClient.when(RegionDisksClient::create).thenReturn(mockClient); + when(mockClient.stopAsyncReplicationAsync(any(StopAsyncReplicationRegionDiskRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status status = StopRegionalDiskReplication.stopRegionalDiskAsyncReplication(PROJECT_ID, + SECONDARY_REGION, SECONDARY_DISK_NAME); + + verify(mockClient, times(1)) + .stopAsyncReplicationAsync(any(StopAsyncReplicationRegionDiskRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + } + } + + @Test + public void testStopZonalDiskAsyncReplication() throws Exception { + try (MockedStatic mockedDisksClient = + mockStatic(DisksClient.class)) { + Operation operation = mock(Operation.class); + DisksClient mockClient = mock(DisksClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedDisksClient.when(DisksClient::create).thenReturn(mockClient); + when(mockClient.stopAsyncReplicationAsync(any(StopAsyncReplicationDiskRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status status = StopZonalDiskReplication.stopZonalDiskAsyncReplication(PROJECT_ID, + SECONDARY_ZONE, SECONDARY_DISK_NAME); + + verify(mockClient, times(1)) + .stopAsyncReplicationAsync(any(StopAsyncReplicationDiskRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + } + } +} \ No newline at end of file diff --git a/compute/cloud-client/src/test/java/compute/disks/DisksIT.java b/compute/cloud-client/src/test/java/compute/disks/DisksIT.java index 07dfc9cd3dd..f5458eedbfd 100644 --- a/compute/cloud-client/src/test/java/compute/disks/DisksIT.java +++ b/compute/cloud-client/src/test/java/compute/disks/DisksIT.java @@ -18,6 +18,8 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import com.google.cloud.compute.v1.AttachedDisk; import com.google.cloud.compute.v1.AttachedDiskInitializeParams; @@ -31,13 +33,17 @@ import com.google.cloud.compute.v1.InstancesClient; import com.google.cloud.compute.v1.NetworkInterface; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.Snapshot; import com.google.cloud.compute.v1.SnapshotsClient; import compute.DeleteInstance; import compute.Util; +import compute.snapshotschedule.CreateSnapshotSchedule; +import compute.snapshotschedule.DeleteSnapshotSchedule; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.lang.Error; import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -45,7 +51,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import org.junit.Assert; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; @@ -69,11 +74,18 @@ public class DisksIT { private static String EMPTY_DISK_NAME; private static String SNAPSHOT_NAME; private static String DISK_TYPE; - private static String ZONAL_BLANK_DISK; - private static String REGIONAL_BLANK_DISK; - + private static String REGIONAL_REPLICATED_DISK; + private static final List replicaZones = Arrays.asList( + String.format("projects/%s/zones/%s-a", PROJECT_ID, REGION), + String.format("projects/%s/zones/%s-b", PROJECT_ID, REGION)); + private static String SECONDARY_REGIONAL_DISK; + private static String SECONDARY_DISK; + private static final long DISK_SIZE = 10L; + private static String SECONDARY_CUSTOM_DISK; + private static String DISK_WITH_SNAPSHOT_SCHEDULE; + private static String SNAPSHOT_SCHEDULE; private ByteArrayOutputStream stdOut; // Check if the required environment variables are set. @@ -101,35 +113,47 @@ public static void setup() DISK_TYPE = String.format("zones/%s/diskTypes/pd-ssd", ZONE); ZONAL_BLANK_DISK = "gcloud-test-disk-zattach-" + uuid; REGIONAL_BLANK_DISK = "gcloud-test-disk-rattach-" + uuid; - - // Cleanup existing stale instances. + REGIONAL_REPLICATED_DISK = "gcloud-test-disk-replicated-" + uuid; + SECONDARY_REGIONAL_DISK = "gcloud-test-disk-secondary-regional-" + uuid; + SECONDARY_DISK = "gcloud-test-disk-secondary-" + uuid; + SECONDARY_CUSTOM_DISK = "gcloud-test-disk-custom-" + uuid; + DISK_WITH_SNAPSHOT_SCHEDULE = "gcloud-test-disk-shapshot-" + uuid; + SNAPSHOT_SCHEDULE = "gcloud-test-snapshot-schedule-" + uuid; + + // Cleanup existing stale resources. Util.cleanUpExistingInstances("test-disks", PROJECT_ID, ZONE); Util.cleanUpExistingDisks("gcloud-test-", PROJECT_ID, ZONE); + Util.cleanUpExistingDisks("gcloud-test-", PROJECT_ID, "us-central1-c"); + Util.cleanUpExistingRegionalDisks( + "gcloud-test-disk-secondary-regional-", PROJECT_ID, "us-central1"); + Util.cleanUpExistingRegionalDisks("gcloud-test-disk-", PROJECT_ID, REGION); Util.cleanUpExistingSnapshots("gcloud-test-snapshot-", PROJECT_ID); + Util.cleanUpExistingSnapshotSchedule("gcloud-test-snapshot-schedule-", PROJECT_ID, REGION); // Create disk from image. Image debianImage = null; try (ImagesClient imagesClient = ImagesClient.create()) { debianImage = imagesClient.getFromFamily("debian-cloud", "debian-11"); } - CreateDiskFromImage.createDiskFromImage(PROJECT_ID, ZONE, DISK_NAME, DISK_TYPE, 10, + CreateDiskFromImage.createDiskFromImage(PROJECT_ID, ZONE, DISK_NAME, DISK_TYPE, DISK_SIZE, debianImage.getSelfLink()); assertThat(stdOut.toString()).contains("Disk created from image."); // Create disk from snapshot. - CreateDiskFromImage.createDiskFromImage(PROJECT_ID, ZONE, DISK_NAME_DUMMY, DISK_TYPE, 10, + CreateDiskFromImage.createDiskFromImage(PROJECT_ID, ZONE, DISK_NAME_DUMMY, DISK_TYPE, DISK_SIZE, debianImage.getSelfLink()); TimeUnit.SECONDS.sleep(10); createDiskSnapshot(PROJECT_ID, ZONE, DISK_NAME_DUMMY, SNAPSHOT_NAME); String diskSnapshotLink = String.format("projects/%s/global/snapshots/%s", PROJECT_ID, SNAPSHOT_NAME); TimeUnit.SECONDS.sleep(5); - CreateDiskFromSnapshot.createDiskFromSnapshot(PROJECT_ID, ZONE, DISK_NAME_2, DISK_TYPE, 10, + CreateDiskFromSnapshot.createDiskFromSnapshot( + PROJECT_ID, ZONE, DISK_NAME_2, DISK_TYPE, DISK_SIZE, diskSnapshotLink); assertThat(stdOut.toString()).contains("Disk created."); // Create empty disk. - CreateEmptyDisk.createEmptyDisk(PROJECT_ID, ZONE, EMPTY_DISK_NAME, DISK_TYPE, 10); + CreateEmptyDisk.createEmptyDisk(PROJECT_ID, ZONE, EMPTY_DISK_NAME, DISK_TYPE, DISK_SIZE); assertThat(stdOut.toString()).contains("Empty disk created."); // Set Disk autodelete. @@ -137,7 +161,8 @@ public static void setup() TimeUnit.SECONDS.sleep(10); SetDiskAutodelete.setDiskAutodelete(PROJECT_ID, ZONE, INSTANCE_NAME, DISK_NAME, true); assertThat(stdOut.toString()).contains("Disk autodelete field updated."); - + CreateSnapshotSchedule.createSnapshotSchedule(PROJECT_ID, REGION, SNAPSHOT_SCHEDULE, + "description", 10, "US"); // Create zonal and regional blank disks for testing attach and resize. createZonalDisk(); createRegionalDisk(); @@ -170,6 +195,12 @@ public static void cleanUp() DeleteDisk.deleteDisk(PROJECT_ID, ZONE, EMPTY_DISK_NAME); DeleteDisk.deleteDisk(PROJECT_ID, ZONE, ZONAL_BLANK_DISK); RegionalDelete.deleteRegionalDisk(PROJECT_ID, REGION, REGIONAL_BLANK_DISK); + RegionalDelete.deleteRegionalDisk(PROJECT_ID, REGION, REGIONAL_REPLICATED_DISK); + RegionalDelete.deleteRegionalDisk(PROJECT_ID, "us-central1", SECONDARY_REGIONAL_DISK); + DeleteDisk.deleteDisk(PROJECT_ID, "us-central1-c", SECONDARY_DISK); + DeleteDisk.deleteDisk(PROJECT_ID, "us-central1-c", SECONDARY_CUSTOM_DISK); + DeleteDisk.deleteDisk(PROJECT_ID, ZONE, DISK_WITH_SNAPSHOT_SCHEDULE); + DeleteSnapshotSchedule.deleteSnapshotSchedule(PROJECT_ID, REGION, SNAPSHOT_SCHEDULE); stdOut.close(); System.setOut(out); @@ -210,7 +241,7 @@ public static void createInstance(String projectId, String zone, String instance .setAutoDelete(false) .setBoot(true) .setInitializeParams(AttachedDiskInitializeParams.newBuilder() - .setDiskSizeGb(10) + .setDiskSizeGb(DISK_SIZE) .setSourceImage(sourceImage) .setDiskName(diskName) .build()) @@ -239,17 +270,15 @@ public static void createInstance(String projectId, String zone, String instance public static void createZonalDisk() throws IOException, ExecutionException, InterruptedException, TimeoutException { String diskType = String.format("zones/%s/diskTypes/pd-standard", ZONE); - CreateEmptyDisk.createEmptyDisk(PROJECT_ID, ZONE, ZONAL_BLANK_DISK, diskType, 12); + CreateEmptyDisk.createEmptyDisk(PROJECT_ID, ZONE, ZONAL_BLANK_DISK, diskType, DISK_SIZE); } public static void createRegionalDisk() throws IOException, ExecutionException, InterruptedException, TimeoutException { String diskType = String.format("regions/%s/diskTypes/pd-balanced", REGION); - List replicaZones = Arrays.asList( - String.format("projects/%s/zones/%s-a", PROJECT_ID, REGION), - String.format("projects/%s/zones/%s-b", PROJECT_ID, REGION)); + RegionalCreateFromSource.createRegionalDisk(PROJECT_ID, REGION, replicaZones, - REGIONAL_BLANK_DISK, diskType, 11, Optional.empty(), Optional.empty()); + REGIONAL_BLANK_DISK, diskType, 10, Optional.empty(), Optional.empty()); } @BeforeEach @@ -276,7 +305,7 @@ public void testDiskAttachResize() throws IOException, ExecutionException, InterruptedException, TimeoutException { // Test disk attach. Instance instance = Util.getInstance(PROJECT_ID, ZONE, INSTANCE_NAME); - Assert.assertEquals(1, instance.getDisksCount()); + assertEquals(1, instance.getDisksCount()); Disk zonalDisk = Util.getDisk(PROJECT_ID, ZONE, ZONAL_BLANK_DISK); Disk regionalDisk = Util.getRegionalDisk(PROJECT_ID, REGION, REGIONAL_BLANK_DISK); @@ -296,9 +325,82 @@ public void testDiskAttachResize() ResizeRegionalDisk.resizeRegionalDisk(PROJECT_ID, regionalDisk.getRegion().split("regions/")[1], regionalDisk.getName(), 23); - Assert.assertEquals(22, Util.getDisk(PROJECT_ID, ZONE, ZONAL_BLANK_DISK).getSizeGb()); - Assert.assertEquals(23, + assertEquals(22, Util.getDisk(PROJECT_ID, ZONE, ZONAL_BLANK_DISK).getSizeGb()); + assertEquals(23, Util.getRegionalDisk(PROJECT_ID, REGION, REGIONAL_BLANK_DISK).getSizeGb()); } + @Test + public void testCreateReplicatedDisk() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + Status status = CreateReplicatedDisk.createReplicatedDisk(PROJECT_ID, REGION, + replicaZones, REGIONAL_REPLICATED_DISK, 100, DISK_TYPE); + + assertThat(status).isEqualTo(Status.DONE); + assertDoesNotThrow(() -> { + Disk disk = Util.getRegionalDisk(PROJECT_ID, REGION, REGIONAL_REPLICATED_DISK); + assertEquals(REGIONAL_REPLICATED_DISK, disk.getName()); + }); + } + + @Test + public void testCreateDiskSecondaryRegional() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + String diskType = String.format( + "projects/%s/regions/%s/diskTypes/pd-balanced", PROJECT_ID, REGION); + Status status = CreateDiskSecondaryRegional.createDiskSecondaryRegional( + PROJECT_ID, PROJECT_ID, REGIONAL_BLANK_DISK, SECONDARY_REGIONAL_DISK, + REGION, "us-central1", DISK_SIZE, diskType); + + assertThat(status).isEqualTo(Status.DONE); + assertDoesNotThrow(() -> { + Disk disk = Util.getRegionalDisk(PROJECT_ID, "us-central1", SECONDARY_REGIONAL_DISK); + assertEquals(SECONDARY_REGIONAL_DISK, disk.getName()); + }); + } + + @Test + public void testCreateDiskSecondaryZonal() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + String diskType = String.format( + "projects/%s/zones/%s/diskTypes/pd-ssd", PROJECT_ID, ZONE); + Status status = CreateDiskSecondaryZonal.createDiskSecondaryZonal( + PROJECT_ID, PROJECT_ID, EMPTY_DISK_NAME, SECONDARY_DISK, ZONE, + "us-central1-c", DISK_SIZE, diskType); + + assertThat(status).isEqualTo(Status.DONE); + assertDoesNotThrow(() -> { + Disk disk = Util.getDisk(PROJECT_ID, "us-central1-c", SECONDARY_DISK); + assertEquals(SECONDARY_DISK, disk.getName()); + }); + } + + @Test + public void testCreateSecondaryCustomDisk() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + String diskType = String.format( + "projects/%s/zones/%s/diskTypes/pd-ssd", PROJECT_ID, ZONE); + Status status = CreateSecondaryCustomDisk.createSecondaryCustomDisk( + PROJECT_ID, PROJECT_ID, EMPTY_DISK_NAME, SECONDARY_CUSTOM_DISK, ZONE, + "us-central1-c", DISK_SIZE, diskType); + + assertThat(status).isEqualTo(Status.DONE); + assertDoesNotThrow(() -> { + Disk disk = Util.getDisk(PROJECT_ID, "us-central1-c", SECONDARY_CUSTOM_DISK); + assertEquals(SECONDARY_CUSTOM_DISK, disk.getName()); + }); + } + + @Test + void testCreateDiskWithSnapshotSchedule() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + Status status = CreateDiskWithSnapshotSchedule.createDiskWithSnapshotSchedule( + PROJECT_ID, ZONE, DISK_WITH_SNAPSHOT_SCHEDULE, SNAPSHOT_SCHEDULE); + + assertThat(status).isEqualTo(Status.DONE); + assertDoesNotThrow(() -> { + Disk disk = Util.getDisk(PROJECT_ID, ZONE, DISK_WITH_SNAPSHOT_SCHEDULE); + assertEquals(DISK_WITH_SNAPSHOT_SCHEDULE, disk.getName()); + }); + } } diff --git a/compute/cloud-client/src/test/java/compute/disks/HyperdiskIT.java b/compute/cloud-client/src/test/java/compute/disks/HyperdiskIT.java index d8fac41a64b..4ad74ce4dff 100644 --- a/compute/cloud-client/src/test/java/compute/disks/HyperdiskIT.java +++ b/compute/cloud-client/src/test/java/compute/disks/HyperdiskIT.java @@ -32,6 +32,7 @@ import com.google.cloud.compute.v1.InsertDiskRequest; import com.google.cloud.compute.v1.InsertStoragePoolRequest; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.StoragePool; import com.google.cloud.compute.v1.StoragePoolsClient; import compute.disks.storagepool.CreateDiskInStoragePool; @@ -78,7 +79,7 @@ public void testCreateHyperdiskStoragePool() throws Exception { when(mockClient.insertAsync(any(InsertStoragePoolRequest.class))) .thenReturn(mockFuture); when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); - when(operation.getStatus()).thenReturn(Operation.Status.DONE); + when(operation.getStatus()).thenReturn(Status.DONE); when(mockClient.get(PROJECT_ID, ZONE, STORAGE_POOL_NAME)).thenReturn(storagePool); @@ -116,7 +117,7 @@ public void testCreateDiskInStoragePool() throws Exception { mockedDisksClient.when(DisksClient::create).thenReturn(mockClient); when(mockClient.insertAsync(any(InsertDiskRequest.class))).thenReturn(mockFuture); when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); - when(operation.getStatus()).thenReturn(Operation.Status.DONE); + when(operation.getStatus()).thenReturn(Status.DONE); when(mockClient.get(PROJECT_ID, ZONE, HYPERDISK_IN_POOL_NAME)).thenReturn(expectedHyperdisk); diff --git a/compute/cloud-client/src/test/java/compute/disks/InstanceAttachDiskIT.java b/compute/cloud-client/src/test/java/compute/disks/InstanceAttachDiskIT.java new file mode 100644 index 00000000000..47ba47b66df --- /dev/null +++ b/compute/cloud-client/src/test/java/compute/disks/InstanceAttachDiskIT.java @@ -0,0 +1,75 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.disks; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.compute.v1.AttachDiskInstanceRequest; +import com.google.cloud.compute.v1.InstancesClient; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.MockedStatic; + +@RunWith(JUnit4.class) +@Timeout(value = 4, unit = TimeUnit.MINUTES) +public class InstanceAttachDiskIT { + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private static final String ZONE = "us-west1-a"; + private static final String REGION = "us-west1"; + private static final String ATTACHED_DISK = "disk-regional"; + private static final String INSTANCE_NAME = "instance"; + + @Test + public void testAttachRegionalDiskForceAttach() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + try (MockedStatic mockedResourcePoliciesClient = + mockStatic(InstancesClient.class)) { + Operation operation = mock(Operation.class); + InstancesClient mockClient = mock(InstancesClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedResourcePoliciesClient.when(InstancesClient::create).thenReturn(mockClient); + when(mockClient.attachDiskAsync(any(AttachDiskInstanceRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status status = AttachRegionalDiskForce + .attachRegionalDiskForce(PROJECT_ID, ZONE, INSTANCE_NAME, REGION, ATTACHED_DISK); + + verify(mockClient, times(1)).attachDiskAsync(any(AttachDiskInstanceRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + } + } +} diff --git a/compute/cloud-client/src/test/java/compute/reservation/CrudOperationsReservationIT.java b/compute/cloud-client/src/test/java/compute/reservation/CrudOperationsReservationIT.java index 0dd9209ae5f..4c92b4b020d 100644 --- a/compute/cloud-client/src/test/java/compute/reservation/CrudOperationsReservationIT.java +++ b/compute/cloud-client/src/test/java/compute/reservation/CrudOperationsReservationIT.java @@ -22,6 +22,7 @@ import com.google.api.gax.rpc.NotFoundException; import com.google.cloud.compute.v1.Reservation; +import compute.Util; import java.io.IOException; import java.util.List; import java.util.UUID; @@ -63,6 +64,8 @@ public static void setUp() @AfterAll public static void cleanup() throws IOException, ExecutionException, InterruptedException, TimeoutException { + Util.cleanUpExistingReservations("test-reservation", PROJECT_ID, ZONE); + DeleteReservation.deleteReservation(PROJECT_ID, ZONE, RESERVATION_NAME); // Test that reservation is deleted diff --git a/compute/cloud-client/src/test/java/compute/reservation/ReservationIT.java b/compute/cloud-client/src/test/java/compute/reservation/ReservationIT.java index 22be75ea98a..e94d2fee8b3 100644 --- a/compute/cloud-client/src/test/java/compute/reservation/ReservationIT.java +++ b/compute/cloud-client/src/test/java/compute/reservation/ReservationIT.java @@ -18,24 +18,28 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.google.api.gax.longrunning.OperationFuture; import com.google.api.gax.rpc.NotFoundException; -import com.google.cloud.compute.v1.AllocationSpecificSKUReservation; +import com.google.cloud.compute.v1.InsertReservationRequest; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.Reservation; import com.google.cloud.compute.v1.ReservationsClient; -import com.google.cloud.compute.v1.ShareSettings; -import com.google.cloud.compute.v1.ShareSettingsProjectConfig; import compute.CreateInstanceTemplate; import compute.CreateRegionalInstanceTemplate; import compute.DeleteInstanceTemplate; import compute.DeleteRegionalInstanceTemplate; +import compute.Util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; @@ -51,6 +55,7 @@ import org.junit.jupiter.api.Timeout; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.MockedStatic; @RunWith(JUnit4.class) @Timeout(value = 6, unit = TimeUnit.MINUTES) @@ -113,6 +118,8 @@ public static void cleanup() final PrintStream out = System.out; System.setOut(new PrintStream(stdOut)); + Util.cleanUpExistingReservations("test-reservation", PROJECT_ID, ZONE); + // Delete instance template with GLOBAL location. DeleteInstanceTemplate.deleteInstanceTemplate(PROJECT_ID, GLOBAL_INSTANCE_TEMPLATE_NAME); assertThat(stdOut.toString()) @@ -180,50 +187,26 @@ public void testCreateReservationWithRegionInstanceTemplate() @Test public void testCreateSharedReservation() - throws ExecutionException, InterruptedException, TimeoutException { - // Mock the ReservationsClient - ReservationsClient mockReservationsClient = mock(ReservationsClient.class); - - // This test require projects in the test environment to share reservation with, - // therefore the operation should be mocked. If you want to make a real test, - // please set the CONSUMER_PROJECT_ID_1 and CONSUMER_PROJECT_ID_2 accordingly. - // Make sure that base project has proper permissions to share reservations. - // See: https://cloud.google.com/compute/docs/instances/reservations-shared#shared_reservation_constraint - ShareSettings shareSettings = ShareSettings.newBuilder() - .setShareType(String.valueOf(ShareSettings.ShareType.SPECIFIC_PROJECTS)) - .putProjectMap("CONSUMER_PROJECT_ID_1", ShareSettingsProjectConfig.newBuilder().build()) - .putProjectMap("CONSUMER_PROJECT_ID_2", ShareSettingsProjectConfig.newBuilder().build()) - .build(); - - Reservation reservation = - Reservation.newBuilder() - .setName(RESERVATION_NAME_SHARED) - .setZone(ZONE) - .setSpecificReservationRequired(true) - .setShareSettings(shareSettings) - .setSpecificReservation( - AllocationSpecificSKUReservation.newBuilder() - .setCount(NUMBER_OF_VMS) - .setSourceInstanceTemplate(INSTANCE_TEMPLATE_SHARED_RESERV_URI) - .build()) - .build(); - - OperationFuture mockFuture = mock(OperationFuture.class); - when(mockReservationsClient.insertAsync(PROJECT_ID, ZONE, reservation)) - .thenReturn(mockFuture); - Operation mockOperation = mock(Operation.class); - when(mockFuture.get(3, TimeUnit.MINUTES)).thenReturn(mockOperation); - when(mockOperation.hasError()).thenReturn(false); - when(mockOperation.getStatus()).thenReturn(Operation.Status.DONE); - - // Create an instance, passing in the mock client - CreateSharedReservation creator = new CreateSharedReservation(mockReservationsClient); - - creator.createSharedReservation(PROJECT_ID, ZONE, - RESERVATION_NAME_SHARED, INSTANCE_TEMPLATE_SHARED_RESERV_URI, NUMBER_OF_VMS); - - verify(mockReservationsClient, times(1)) - .insertAsync(PROJECT_ID, ZONE, reservation); - assertThat(stdOut.toString()).contains("Reservation created. Operation Status: DONE"); + throws ExecutionException, InterruptedException, TimeoutException, IOException { + try (MockedStatic mockReservationsClient = + mockStatic(ReservationsClient.class)) { + ReservationsClient mockClient = mock(ReservationsClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + Operation mockOperation = mock(Operation.class); + + mockReservationsClient.when(ReservationsClient::create).thenReturn(mockClient); + when(mockClient.insertAsync(any(InsertReservationRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(3, TimeUnit.MINUTES)).thenReturn(mockOperation); + when(mockOperation.getStatus()).thenReturn(Status.DONE); + + Status status = CreateSharedReservation.createSharedReservation(PROJECT_ID, ZONE, + RESERVATION_NAME_SHARED, INSTANCE_TEMPLATE_SHARED_RESERV_URI, NUMBER_OF_VMS); + + verify(mockClient, times(1)).insertAsync(any(InsertReservationRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + + } } } \ No newline at end of file diff --git a/compute/cloud-client/src/test/java/compute/snapshotschedule/SnapshotScheduleIT.java b/compute/cloud-client/src/test/java/compute/snapshotschedule/SnapshotScheduleIT.java new file mode 100644 index 00000000000..f22c9ee4ddd --- /dev/null +++ b/compute/cloud-client/src/test/java/compute/snapshotschedule/SnapshotScheduleIT.java @@ -0,0 +1,228 @@ +/* + * Copyright 2024 Google LLC + * + * 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 compute.snapshotschedule; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.compute.v1.AddResourcePoliciesDiskRequest; +import com.google.cloud.compute.v1.DeleteResourcePolicyRequest; +import com.google.cloud.compute.v1.DisksClient; +import com.google.cloud.compute.v1.GetResourcePolicyRequest; +import com.google.cloud.compute.v1.InsertResourcePolicyRequest; +import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.RemoveResourcePoliciesDiskRequest; +import com.google.cloud.compute.v1.ResourcePoliciesClient; +import com.google.cloud.compute.v1.ResourcePoliciesClient.ListPagedResponse; +import com.google.cloud.compute.v1.ResourcePolicy; +import com.google.cloud.compute.v1.ResourcePolicySnapshotSchedulePolicyRetentionPolicy.OnSourceDiskDelete; +import java.io.IOException; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.MockedStatic; + +@RunWith(JUnit4.class) +@Timeout(value = 6, unit = TimeUnit.MINUTES) +public class SnapshotScheduleIT { + private static final String PROJECT_ID = System.getenv("GOOGLE_CLOUD_PROJECT"); + private static final String ZONE = "asia-south1-a"; + private static final String REGION = ZONE.substring(0, ZONE.lastIndexOf('-')); + private static final String DISK_NAME = "gcloud-test-disk"; + private static final String SCHEDULE_NAME = "test-schedule-" + UUID.randomUUID(); + private static final String SCHEDULE_DESCRIPTION = "Test hourly snapshot schedule"; + private static final int MAX_RETENTION_DAYS = 2; + private static final String STORAGE_LOCATION = "US"; + + // Check if the required environment variables are set. + public static void requireEnvVar(String envVarName) { + assertWithMessage(String.format("Missing environment variable '%s' ", envVarName)) + .that(System.getenv(envVarName)).isNotEmpty(); + } + + @BeforeAll + public static void setUp() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("GOOGLE_CLOUD_PROJECT"); + CreateSnapshotSchedule.createSnapshotSchedule(PROJECT_ID, REGION, SCHEDULE_NAME, + SCHEDULE_DESCRIPTION, MAX_RETENTION_DAYS, STORAGE_LOCATION); + } + + @AfterAll + public static void cleanup() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + DeleteSnapshotSchedule.deleteSnapshotSchedule(PROJECT_ID, REGION, SCHEDULE_NAME); + } + + @Test + public void testEditSnapshotSchedule() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + EditSnapshotSchedule.editSnapshotSchedule(PROJECT_ID, REGION, SCHEDULE_NAME); + + ResourcePolicy resourcePolicy = GetSnapshotSchedule + .getSnapshotSchedule(PROJECT_ID, REGION, SCHEDULE_NAME); + + assertThat(resourcePolicy.getDescription()).isEqualTo("Updated description"); + assertThat(resourcePolicy.getSnapshotSchedulePolicy() + .getRetentionPolicy() + .getOnSourceDiskDelete()) + .isEqualTo(OnSourceDiskDelete.APPLY_RETENTION_POLICY.toString()); + } + + @Test + public void testListSnapshotSchedules() throws IOException { + ListPagedResponse listPagedResponse = ListSnapshotSchedules.listSnapshotSchedules( + PROJECT_ID, REGION, SCHEDULE_NAME); + + ResourcePolicy firstPolicy = listPagedResponse.iterateAll().iterator().next(); + + assertThat(listPagedResponse.iterateAll()).hasSize(1); + assertEquals(SCHEDULE_NAME, firstPolicy.getName()); + } + + @Test + public void testCreateSnapshotScheduleHourly() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + try (MockedStatic mockedResourcePoliciesClient = + mockStatic(ResourcePoliciesClient.class)) { + Operation operation = mock(Operation.class); + ResourcePoliciesClient mockClient = mock(ResourcePoliciesClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedResourcePoliciesClient.when(ResourcePoliciesClient::create).thenReturn(mockClient); + when(mockClient.insertAsync(any(InsertResourcePolicyRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status status = CreateSnapshotSchedule.createSnapshotSchedule(PROJECT_ID, REGION, + SCHEDULE_NAME, SCHEDULE_DESCRIPTION, MAX_RETENTION_DAYS, STORAGE_LOCATION); + + verify(mockClient, times(1)) + .insertAsync(any(InsertResourcePolicyRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + } + } + + @Test + public void testAttachSnapshotScheduleToDisk() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + try (MockedStatic mockedDisksClient = mockStatic(DisksClient.class)) { + DisksClient mockClient = mock(DisksClient.class); + Operation operation = mock(Operation.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedDisksClient.when(DisksClient::create).thenReturn(mockClient); + when(mockClient.addResourcePoliciesAsync(any(AddResourcePoliciesDiskRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status actualStatus = AttachSnapshotScheduleToDisk.attachSnapshotScheduleToDisk( + PROJECT_ID, ZONE, DISK_NAME, SCHEDULE_NAME, REGION); + + verify(mockClient, times(1)).addResourcePoliciesAsync(any()); + assertEquals(Status.DONE, actualStatus); + } + } + + @Test + public void testRemoveSnapshotScheduleFromDisk() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + try (MockedStatic mockedDisksClient = mockStatic(DisksClient.class)) { + DisksClient mockClient = mock(DisksClient.class); + Operation operation = mock(Operation.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedDisksClient.when(DisksClient::create).thenReturn(mockClient); + when(mockClient.removeResourcePoliciesAsync(any(RemoveResourcePoliciesDiskRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status actualStatus = RemoveSnapshotScheduleFromDisk.removeSnapshotScheduleFromDisk( + PROJECT_ID, ZONE, DISK_NAME, REGION, SCHEDULE_NAME); + + verify(mockClient, times(1)).removeResourcePoliciesAsync(any()); + assertEquals(Status.DONE, actualStatus); + } + } + + @Test + public void testGetSnapshotSchedule() throws IOException { + try (MockedStatic mockedResourcePoliciesClient = + mockStatic(ResourcePoliciesClient.class)) { + ResourcePoliciesClient mockClient = mock(ResourcePoliciesClient.class); + ResourcePolicy mockResourcePolicy = mock(ResourcePolicy.class); + + mockedResourcePoliciesClient.when(ResourcePoliciesClient::create).thenReturn(mockClient); + when(mockClient.get(any(GetResourcePolicyRequest.class))) + .thenReturn(mockResourcePolicy); + + ResourcePolicy resourcePolicy = GetSnapshotSchedule.getSnapshotSchedule( + PROJECT_ID, REGION, SCHEDULE_NAME); + + verify(mockClient, times(1)) + .get(any(GetResourcePolicyRequest.class)); + assertEquals(mockResourcePolicy, resourcePolicy); + } + } + + @Test + public void testDeleteSnapshotSchedule() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + try (MockedStatic mockedResourcePoliciesClient = + mockStatic(ResourcePoliciesClient.class)) { + Operation operation = mock(Operation.class); + ResourcePoliciesClient mockClient = mock(ResourcePoliciesClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedResourcePoliciesClient.when(ResourcePoliciesClient::create).thenReturn(mockClient); + when(mockClient.deleteAsync(any(DeleteResourcePolicyRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(operation); + when(operation.getStatus()).thenReturn(Status.DONE); + + Status status = DeleteSnapshotSchedule + .deleteSnapshotSchedule(PROJECT_ID, REGION, SCHEDULE_NAME); + + verify(mockClient, times(1)) + .deleteAsync(any(DeleteResourcePolicyRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(Status.DONE, status); + } + } +} \ No newline at end of file diff --git a/endpoints/getting-started/k8s/esp_echo_http.yaml b/endpoints/getting-started/k8s/esp_echo_http.yaml index a9b0bb56c66..4e575b59ebd 100644 --- a/endpoints/getting-started/k8s/esp_echo_http.yaml +++ b/endpoints/getting-started/k8s/esp_echo_http.yaml @@ -38,12 +38,15 @@ spec: labels: app: esp-echo spec: + # [START endpoints_secret_1_java] # [START secret-1] volumes: - name: service-account-creds secret: secretName: service-account-creds # [END secret-1] + # [END endpoints_secret_1_java] + # [START endpoints_service_java] # [START service] containers: - name: esp @@ -56,14 +59,17 @@ spec: "--service_account_key", "/etc/nginx/creds/service-account-creds.json", ] # [END service] + # [END endpoints_service_java] ports: - containerPort: 8080 + # [START endpoints_secret_2_java] # [START secret-2] volumeMounts: - mountPath: /etc/nginx/creds name: service-account-creds readOnly: true # [END secret-2] + # [END endpoints_secret_2_java] - name: echo image: gcr.io/endpoints-release/echo:latest ports: diff --git a/endpoints/multiple-versions/openapi-v1.yaml b/endpoints/multiple-versions/openapi-v1.yaml index 3a939f9cec6..f78f3895197 100644 --- a/endpoints/multiple-versions/openapi-v1.yaml +++ b/endpoints/multiple-versions/openapi-v1.yaml @@ -12,14 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -# [START swagger] swagger: "2.0" info: description: "A simple Google Cloud Endpoints API example." title: "Endpoints Example" version: "1.0.0" host: "echo-api.endpoints.YOUR-PROJECT-ID.cloud.goog" -# [END swagger] basePath: "/v1" consumes: - "application/json" diff --git a/endpoints/multiple-versions/openapi-v2.yaml b/endpoints/multiple-versions/openapi-v2.yaml index d80ff233952..dfe56f52949 100644 --- a/endpoints/multiple-versions/openapi-v2.yaml +++ b/endpoints/multiple-versions/openapi-v2.yaml @@ -12,14 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -# [START swagger] swagger: "2.0" info: description: "A simple Google Cloud Endpoints API example." title: "Endpoints Example" version: "2.0.0" host: "echo-api.endpoints.YOUR-PROJECT-ID.cloud.goog" -# [END swagger] basePath: "/v2" consumes: - "application/json" diff --git a/jobs/v3/src/main/java/com/google/samples/BasicCompanySample.java b/jobs/v3/src/main/java/com/google/samples/BasicCompanySample.java index 052c82dd541..812183db77d 100644 --- a/jobs/v3/src/main/java/com/google/samples/BasicCompanySample.java +++ b/jobs/v3/src/main/java/com/google/samples/BasicCompanySample.java @@ -46,8 +46,6 @@ public final class BasicCompanySample { private static CloudTalentSolution talentSolutionClient = JobServiceQuickstart.getTalentSolutionClient(); - // [START basic_company] - /** Generate a company */ public static Company generateCompany() { // distributor company id should be a unique Id in your system. @@ -61,9 +59,8 @@ public static Company generateCompany() { System.out.println("Company generated: " + company); return company; } - // [END basic_company] - // [START create_company] + // [START job_create_company] /** Create a company. */ public static Company createCompany(Company companyToBeCreated) throws IOException { @@ -83,9 +80,9 @@ public static Company createCompany(Company companyToBeCreated) throws IOExcepti throw e; } } - // [END create_company] + // [END job_create_company] - // [START get_company] + // [START job_get_company] /** Get a company. */ public static Company getCompany(String companyName) throws IOException { @@ -99,9 +96,9 @@ public static Company getCompany(String companyName) throws IOException { throw e; } } - // [END get_company] + // [END job_get_company] - // [START update_company] + // [START job_update_company] /** Updates a company. */ public static Company updateCompany(String companyName, Company companyToBeUpdated) @@ -124,9 +121,9 @@ public static Company updateCompany(String companyName, Company companyToBeUpdat throw e; } } - // [END update_company] + // [END job_update_company] - // [START update_company_with_field_mask] + // [START job_update_company_with_field_mask] /** Updates a company. */ public static Company updateCompanyWithFieldMask( @@ -150,9 +147,7 @@ public static Company updateCompanyWithFieldMask( throw e; } } - // [END update_company_with_field_mask] - - // [START delete_company] + // [END job_update_company_with_field_mask] /** Delete a company. */ public static void deleteCompany(String companyName) throws IOException { @@ -164,7 +159,6 @@ public static void deleteCompany(String companyName) throws IOException { throw e; } } - // [END delete_company] public static void main(String... args) throws Exception { // Construct a company diff --git a/jobs/v3/src/main/java/com/google/samples/BasicJobSample.java b/jobs/v3/src/main/java/com/google/samples/BasicJobSample.java index 69c373ea3ca..f5c0ded1e67 100644 --- a/jobs/v3/src/main/java/com/google/samples/BasicJobSample.java +++ b/jobs/v3/src/main/java/com/google/samples/BasicJobSample.java @@ -73,7 +73,6 @@ public static Job generateJobWithRequiredFields(String companyName) { // [END job_basic_job] // [START job_create_job] - // [START create_job] /** Create a job. */ public static Job createJob(Job jobToBeCreated) throws IOException { @@ -93,7 +92,6 @@ public static Job createJob(Job jobToBeCreated) throws IOException { throw e; } } - // [END create_job] // [END job_create_job] // [START job_get_job] @@ -132,7 +130,6 @@ public static Job updateJob(String jobName, Job jobToBeUpdated) throws IOExcepti // [END job_update_job] // [START job_update_job_with_field_mask] - // [START update_job_with_field_mask] /** Update a job. */ public static Job updateJobWithFieldMask(String jobName, String fieldMask, Job jobToBeUpdated) @@ -149,7 +146,6 @@ public static Job updateJobWithFieldMask(String jobName, String fieldMask, Job j throw e; } } - // [END update_job_with_field_mask] // [END job_update_job_with_field_mask] // [START job_delete_job] diff --git a/jobs/v3/src/main/java/com/google/samples/LocationSearchSample.java b/jobs/v3/src/main/java/com/google/samples/LocationSearchSample.java index 2f8f4a1ab79..6fb5b7402d2 100644 --- a/jobs/v3/src/main/java/com/google/samples/LocationSearchSample.java +++ b/jobs/v3/src/main/java/com/google/samples/LocationSearchSample.java @@ -48,6 +48,7 @@ public final class LocationSearchSample { private static CloudTalentSolution talentSolutionClient = JobServiceQuickstart.getTalentSolutionClient(); + // [START job_basic_location_search] // [START basic_location_search] /** Basic location Search */ @@ -80,7 +81,9 @@ public static void basicLocationSearch(String companyName, String location, doub } // [END basic_location_search] + // [END job_basic_location_search] + // [START job_keyword_location_search] // [START keyword_location_search] /** Keyword location Search */ @@ -114,7 +117,9 @@ public static void keywordLocationSearch( System.out.printf("Keyword location search results: %s", response); } // [END keyword_location_search] + // [END job_keyword_location_search] + // [START job_city_location_search] // [START city_location_search] /** City location Search */ @@ -145,7 +150,9 @@ public static void cityLocationSearch(String companyName, String location) System.out.printf("City locations search results: %s", response); } // [END city_location_search] + // [END job_city_location_search] + // [START job_multi_locations_search] // [START multi_locations_search] /** Multiple locations Search */ @@ -181,8 +188,10 @@ public static void multiLocationsSearch( System.out.printf("Multiple locations search results: %s", response); } + // [END job_multi_locations_search] // [END multi_locations_search] + // [START job_broadening_location_search] // [START broadening_location_search] /** Broadening location Search */ @@ -214,6 +223,7 @@ public static void broadeningLocationsSearch(String companyName, String location System.out.printf("Broadening locations search results: %s", response); } // [END broadening_location_search] + // [END job_broadening_location_search] public static void main(String... args) throws Exception { String location = args.length >= 1 ? args[0] : "Mountain View, CA"; diff --git a/jobs/v4/pom.xml b/jobs/v4/pom.xml index c009d657d34..b27fe160cb5 100644 --- a/jobs/v4/pom.xml +++ b/jobs/v4/pom.xml @@ -40,24 +40,20 @@ - com.google.cloud google-cloud-talent - - com.google.apis google-api-services-jobs - v4-rev20230822-2.0.0 + v4-rev20240614-2.0.0 com.google.http-client google-http-client-jackson2 - - + com.google.truth diff --git a/secretmanager/src/main/java/secretmanager/CreateSecret.java b/secretmanager/src/main/java/secretmanager/CreateSecret.java index a5f6f79439b..0a025daf088 100644 --- a/secretmanager/src/main/java/secretmanager/CreateSecret.java +++ b/secretmanager/src/main/java/secretmanager/CreateSecret.java @@ -21,6 +21,7 @@ import com.google.cloud.secretmanager.v1.Replication; import com.google.cloud.secretmanager.v1.Secret; import com.google.cloud.secretmanager.v1.SecretManagerServiceClient; +import com.google.protobuf.Duration; import java.io.IOException; public class CreateSecret { @@ -41,6 +42,12 @@ public static void createSecret(String projectId, String secretId) throws IOExce // Build the parent name from the project. ProjectName projectName = ProjectName.of(projectId); + // Optionally set a TTL for the secret. This demonstrates how to configure + // a secret to be automatically deleted after a certain period. The TTL is + // specified in seconds (e.g., 900 for 15 minutes). This can be useful + // for managing sensitive data and reducing storage costs. + Duration ttl = Duration.newBuilder().setSeconds(900).build(); + // Build the secret to create. Secret secret = Secret.newBuilder() @@ -48,6 +55,7 @@ public static void createSecret(String projectId, String secretId) throws IOExce Replication.newBuilder() .setAutomatic(Replication.Automatic.newBuilder().build()) .build()) + .setTtl(ttl) .build(); // Create the secret. diff --git a/security-command-center/snippets/src/main/java/management/api/CreateEventThreatDetectionCustomModule.java b/security-command-center/snippets/src/main/java/management/api/CreateEventThreatDetectionCustomModule.java new file mode 100644 index 00000000000..4615ed39331 --- /dev/null +++ b/security-command-center/snippets/src/main/java/management/api/CreateEventThreatDetectionCustomModule.java @@ -0,0 +1,99 @@ +/* + * Copyright 2024 Google LLC + * + * 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 management.api; + +// [START securitycenter_create_event_threat_detection_custom_module] +import com.google.cloud.securitycentermanagement.v1.CreateEventThreatDetectionCustomModuleRequest; +import com.google.cloud.securitycentermanagement.v1.EventThreatDetectionCustomModule; +import com.google.cloud.securitycentermanagement.v1.EventThreatDetectionCustomModule.EnablementState; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient; +import com.google.protobuf.ListValue; +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CreateEventThreatDetectionCustomModule { + + public static void main(String[] args) throws IOException { + // https://cloud.google.com/security-command-center/docs/reference/security-center-management/rest/v1/organizations.locations.eventThreatDetectionCustomModules/create + // TODO: Developer should replace project_id with a real project ID before running this code + String projectId = "project_id"; + + String customModuleDisplayName = "custom_module_display_name"; + + createEventThreatDetectionCustomModule(projectId, customModuleDisplayName); + } + + public static EventThreatDetectionCustomModule createEventThreatDetectionCustomModule( + String projectId, String customModuleDisplayName) throws IOException { + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecurityCenterManagementClient client = SecurityCenterManagementClient.create()) { + + String parent = String.format("projects/%s/locations/global", projectId); + + // define the metadata and other config parameters severity, description, + // recommendation and ips below + Map metadata = new HashMap<>(); + metadata.put("severity", Value.newBuilder().setStringValue("MEDIUM").build()); + metadata.put( + "description", Value.newBuilder().setStringValue("add your description here").build()); + metadata.put( + "recommendation", + Value.newBuilder().setStringValue("add your recommendation here").build()); + List ips = Arrays.asList(Value.newBuilder().setStringValue("0.0.0.0").build()); + + Value metadataVal = + Value.newBuilder() + .setStructValue(Struct.newBuilder().putAllFields(metadata).build()) + .build(); + Value ipsValue = + Value.newBuilder().setListValue(ListValue.newBuilder().addAllValues(ips).build()).build(); + + Struct configStruct = + Struct.newBuilder().putFields("metadata", metadataVal).putFields("ips", ipsValue).build(); + + // define the Event Threat Detection custom module configuration, update the EnablementState + // below + EventThreatDetectionCustomModule eventThreatDetectionCustomModule = + EventThreatDetectionCustomModule.newBuilder() + .setConfig(configStruct) + .setDisplayName(customModuleDisplayName) + .setEnablementState(EnablementState.ENABLED) + .setType("CONFIGURABLE_BAD_IP") + .build(); + + CreateEventThreatDetectionCustomModuleRequest request = + CreateEventThreatDetectionCustomModuleRequest.newBuilder() + .setParent(parent) + .setEventThreatDetectionCustomModule(eventThreatDetectionCustomModule) + .build(); + + EventThreatDetectionCustomModule response = + client.createEventThreatDetectionCustomModule(request); + + return response; + } + } +} +// [END securitycenter_create_event_threat_detection_custom_module] diff --git a/security-command-center/snippets/src/main/java/management/api/DeleteEventThreatDetectionCustomModule.java b/security-command-center/snippets/src/main/java/management/api/DeleteEventThreatDetectionCustomModule.java new file mode 100644 index 00000000000..688cdbca5af --- /dev/null +++ b/security-command-center/snippets/src/main/java/management/api/DeleteEventThreatDetectionCustomModule.java @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Google LLC + * + * 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 management.api; + +// [START securitycenter_delete_event_threat_detection_custom_module] +import com.google.cloud.securitycentermanagement.v1.DeleteEventThreatDetectionCustomModuleRequest; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient; +import java.io.IOException; + +public class DeleteEventThreatDetectionCustomModule { + + public static void main(String[] args) throws IOException { + // https://cloud.google.com/security-command-center/docs/reference/security-center-management/rest/v1/organizations.locations.eventThreatDetectionCustomModules/delete + // TODO: Developer should replace project_id with a real project ID before running this code + String projectId = "project_id"; + + String customModuleId = "custom_module_id"; + + deleteEventThreatDetectionCustomModule(projectId, customModuleId); + } + + public static boolean deleteEventThreatDetectionCustomModule( + String projectId, String customModuleId) throws IOException { + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecurityCenterManagementClient client = SecurityCenterManagementClient.create()) { + + String qualifiedModuleName = + String.format( + "projects/%s/locations/global/eventThreatDetectionCustomModules/%s", + projectId, customModuleId); + + DeleteEventThreatDetectionCustomModuleRequest request = + DeleteEventThreatDetectionCustomModuleRequest.newBuilder() + .setName(qualifiedModuleName) + .build(); + + client.deleteEventThreatDetectionCustomModule(request); + + return true; + } + } +} +// [END securitycenter_delete_event_threat_detection_custom_module] diff --git a/security-command-center/snippets/src/main/java/management/api/GetEffectiveEventThreatDetectionCustomModule.java b/security-command-center/snippets/src/main/java/management/api/GetEffectiveEventThreatDetectionCustomModule.java new file mode 100644 index 00000000000..c9b8a8d0ec5 --- /dev/null +++ b/security-command-center/snippets/src/main/java/management/api/GetEffectiveEventThreatDetectionCustomModule.java @@ -0,0 +1,62 @@ +/* + * Copyright 2025 Google LLC + * + * 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 management.api; + +// [START securitycenter_get_effective_event_threat_detection_custom_module] +import com.google.cloud.securitycentermanagement.v1.EffectiveEventThreatDetectionCustomModule; +import com.google.cloud.securitycentermanagement.v1.GetEffectiveEventThreatDetectionCustomModuleRequest; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient; +import java.io.IOException; + +public class GetEffectiveEventThreatDetectionCustomModule { + + public static void main(String[] args) throws IOException { + // TODO: Developer should replace project_id with a real project ID before running this code + String projectId = "project_id"; + + String customModuleId = "custom_module_id"; + + getEffectiveEventThreatDetectionCustomModule(projectId, customModuleId); + } + + public static EffectiveEventThreatDetectionCustomModule + getEffectiveEventThreatDetectionCustomModule(String projectId, String customModuleId) + throws IOException { + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecurityCenterManagementClient client = SecurityCenterManagementClient.create()) { + + String qualifiedModuleName = + String.format( + "projects/%s/locations/global/effectiveEventThreatDetectionCustomModules/%s", + projectId, customModuleId); + + GetEffectiveEventThreatDetectionCustomModuleRequest request = + GetEffectiveEventThreatDetectionCustomModuleRequest.newBuilder() + .setName(qualifiedModuleName) + .build(); + + EffectiveEventThreatDetectionCustomModule response = + client.getEffectiveEventThreatDetectionCustomModule(request); + + return response; + } + } +} +// [END securitycenter_get_effective_event_threat_detection_custom_module] diff --git a/security-command-center/snippets/src/main/java/management/api/GetEventThreatDetectionCustomModule.java b/security-command-center/snippets/src/main/java/management/api/GetEventThreatDetectionCustomModule.java new file mode 100644 index 00000000000..cd8b5ee3519 --- /dev/null +++ b/security-command-center/snippets/src/main/java/management/api/GetEventThreatDetectionCustomModule.java @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Google LLC + * + * 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 management.api; + +// [START securitycenter_get_event_threat_detection_custom_module] +import com.google.cloud.securitycentermanagement.v1.EventThreatDetectionCustomModule; +import com.google.cloud.securitycentermanagement.v1.GetEventThreatDetectionCustomModuleRequest; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient; +import java.io.IOException; + +public class GetEventThreatDetectionCustomModule { + + public static void main(String[] args) throws IOException { + // https://cloud.google.com/security-command-center/docs/reference/security-center-management/rest/v1/organizations.locations.eventThreatDetectionCustomModules/get + // TODO: Developer should replace project_id with a real project ID before running this code + String projectId = "project_id"; + + String customModuleId = "custom_module_id"; + + getEventThreatDetectionCustomModule(projectId, customModuleId); + } + + public static EventThreatDetectionCustomModule getEventThreatDetectionCustomModule( + String projectId, String customModuleId) throws IOException { + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecurityCenterManagementClient client = SecurityCenterManagementClient.create()) { + + String qualifiedModuleName = + String.format( + "projects/%s/locations/global/eventThreatDetectionCustomModules/%s", + projectId, customModuleId); + + GetEventThreatDetectionCustomModuleRequest request = + GetEventThreatDetectionCustomModuleRequest.newBuilder() + .setName(qualifiedModuleName) + .build(); + + EventThreatDetectionCustomModule response = + client.getEventThreatDetectionCustomModule(request); + + return response; + } + } +} +// [END securitycenter_get_event_threat_detection_custom_module] diff --git a/security-command-center/snippets/src/main/java/management/api/ListDescendantEventThreatDetectionCustomModules.java b/security-command-center/snippets/src/main/java/management/api/ListDescendantEventThreatDetectionCustomModules.java new file mode 100644 index 00000000000..1aeccbd4582 --- /dev/null +++ b/security-command-center/snippets/src/main/java/management/api/ListDescendantEventThreatDetectionCustomModules.java @@ -0,0 +1,56 @@ +/* + * Copyright 2025 Google LLC + * + * 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 management.api; + +// [START securitycenter_list_descendant_event_threat_detection_custom_module] +import com.google.cloud.securitycentermanagement.v1.ListDescendantEventThreatDetectionCustomModulesRequest; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient.ListDescendantEventThreatDetectionCustomModulesPagedResponse; +import java.io.IOException; + +public class ListDescendantEventThreatDetectionCustomModules { + + public static void main(String[] args) throws IOException { + // TODO: Developer should replace project_id with a real project ID before running this code + String projectId = "project_id"; + + listDescendantEventThreatDetectionCustomModules(projectId); + } + + public static ListDescendantEventThreatDetectionCustomModulesPagedResponse + listDescendantEventThreatDetectionCustomModules(String projectId) throws IOException { + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecurityCenterManagementClient client = SecurityCenterManagementClient.create()) { + + String parent = String.format("projects/%s/locations/global", projectId); + + ListDescendantEventThreatDetectionCustomModulesRequest request = + ListDescendantEventThreatDetectionCustomModulesRequest.newBuilder() + .setParent(parent) + .build(); + + ListDescendantEventThreatDetectionCustomModulesPagedResponse response = + client.listDescendantEventThreatDetectionCustomModules(request); + + return response; + } + } +} +// [END securitycenter_list_descendant_event_threat_detection_custom_module] diff --git a/security-command-center/snippets/src/main/java/management/api/ListEffectiveEventThreatDetectionCustomModules.java b/security-command-center/snippets/src/main/java/management/api/ListEffectiveEventThreatDetectionCustomModules.java new file mode 100644 index 00000000000..e44490bc436 --- /dev/null +++ b/security-command-center/snippets/src/main/java/management/api/ListEffectiveEventThreatDetectionCustomModules.java @@ -0,0 +1,56 @@ +/* + * Copyright 2025 Google LLC + * + * 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 management.api; + +// [START securitycenter_list_effective_event_threat_detection_custom_module] +import com.google.cloud.securitycentermanagement.v1.ListEffectiveEventThreatDetectionCustomModulesRequest; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient.ListEffectiveEventThreatDetectionCustomModulesPagedResponse; +import java.io.IOException; + +public class ListEffectiveEventThreatDetectionCustomModules { + + public static void main(String[] args) throws IOException { + // TODO: Developer should replace project_id with a real project ID before running this code + String projectId = "project_id"; + + listEffectiveEventThreatDetectionCustomModules(projectId); + } + + public static ListEffectiveEventThreatDetectionCustomModulesPagedResponse + listEffectiveEventThreatDetectionCustomModules(String projectId) throws IOException { + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecurityCenterManagementClient client = SecurityCenterManagementClient.create()) { + + String parent = String.format("projects/%s/locations/global", projectId); + + ListEffectiveEventThreatDetectionCustomModulesRequest request = + ListEffectiveEventThreatDetectionCustomModulesRequest.newBuilder() + .setParent(parent) + .build(); + + ListEffectiveEventThreatDetectionCustomModulesPagedResponse response = + client.listEffectiveEventThreatDetectionCustomModules(request); + + return response; + } + } +} +// [END securitycenter_list_effective_event_threat_detection_custom_module] diff --git a/security-command-center/snippets/src/main/java/management/api/ListEventThreatDetectionCustomModules.java b/security-command-center/snippets/src/main/java/management/api/ListEventThreatDetectionCustomModules.java new file mode 100644 index 00000000000..4e4b0340a1a --- /dev/null +++ b/security-command-center/snippets/src/main/java/management/api/ListEventThreatDetectionCustomModules.java @@ -0,0 +1,55 @@ +/* + * Copyright 2024 Google LLC + * + * 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 management.api; + +// [START securitycenter_list_event_threat_detection_custom_module] +import com.google.cloud.securitycentermanagement.v1.ListEventThreatDetectionCustomModulesRequest; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient.ListEventThreatDetectionCustomModulesPagedResponse; +import java.io.IOException; + +public class ListEventThreatDetectionCustomModules { + + public static void main(String[] args) throws IOException { + // https://cloud.google.com/security-command-center/docs/reference/security-center-management/rest/v1/organizations.locations.eventThreatDetectionCustomModules/list + // TODO: Developer should replace project_id with a real project ID before running this code + String projectId = "project_id"; + + listEventThreatDetectionCustomModules(projectId); + } + + public static ListEventThreatDetectionCustomModulesPagedResponse + listEventThreatDetectionCustomModules(String projectId) throws IOException { + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecurityCenterManagementClient client = SecurityCenterManagementClient.create()) { + + String parent = String.format("projects/%s/locations/global", projectId); + + ListEventThreatDetectionCustomModulesRequest request = + ListEventThreatDetectionCustomModulesRequest.newBuilder().setParent(parent).build(); + + ListEventThreatDetectionCustomModulesPagedResponse response = + client.listEventThreatDetectionCustomModules(request); + + return response; + } + } +} +// [END securitycenter_list_event_threat_detection_custom_module] diff --git a/security-command-center/snippets/src/main/java/management/api/UpdateEventThreatDetectionCustomModule.java b/security-command-center/snippets/src/main/java/management/api/UpdateEventThreatDetectionCustomModule.java new file mode 100644 index 00000000000..a350554dfd5 --- /dev/null +++ b/security-command-center/snippets/src/main/java/management/api/UpdateEventThreatDetectionCustomModule.java @@ -0,0 +1,80 @@ +/* + * Copyright 2025 Google LLC + * + * 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 management.api; + +// [START securitycenter_update_event_threat_detection_custom_module] +import com.google.cloud.securitycentermanagement.v1.EventThreatDetectionCustomModule; +import com.google.cloud.securitycentermanagement.v1.EventThreatDetectionCustomModule.EnablementState; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient; +import com.google.cloud.securitycentermanagement.v1.UpdateEventThreatDetectionCustomModuleRequest; +import com.google.protobuf.FieldMask; +import java.io.IOException; + +public class UpdateEventThreatDetectionCustomModule { + + public static void main(String[] args) throws IOException { + // TODO: Developer should replace project_id with a real project ID before running this code + String projectId = "project_id"; + + String customModuleId = "custom_module_id"; + + updateEventThreatDetectionCustomModule(projectId, customModuleId); + } + + public static EventThreatDetectionCustomModule updateEventThreatDetectionCustomModule( + String projectId, String customModuleId) throws IOException { + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecurityCenterManagementClient client = SecurityCenterManagementClient.create()) { + + String qualifiedModuleName = + String.format( + "projects/%s/locations/global/eventThreatDetectionCustomModules/%s", + projectId, customModuleId); + + // Define the event threat detection custom module configuration, update the + // DisplayName and EnablementState accordingly. + EventThreatDetectionCustomModule eventThreatDetectionCustomModule = + EventThreatDetectionCustomModule.newBuilder() + .setName(qualifiedModuleName) + .setDisplayName("updated_custom_module_name") + .setEnablementState(EnablementState.DISABLED) + .build(); + + // Set the field mask to specify which properties should be updated. In the below example we + // are updating displayName and EnablementState + // https://cloud.google.com/security-command-center/docs/reference/security-center-management/rest/v1/organizations.locations.eventThreatDetectionCustomModules/patch#query-parameters + // https://protobuf.dev/reference/protobuf/google.protobuf/#field-mask + FieldMask fieldMask = + FieldMask.newBuilder().addPaths("display_name").addPaths("enablement_state").build(); + + UpdateEventThreatDetectionCustomModuleRequest request = + UpdateEventThreatDetectionCustomModuleRequest.newBuilder() + .setEventThreatDetectionCustomModule(eventThreatDetectionCustomModule) + .setUpdateMask(fieldMask) + .build(); + + EventThreatDetectionCustomModule response = + client.updateEventThreatDetectionCustomModule(request); + + return response; + } + } +} +// [END securitycenter_update_event_threat_detection_custom_module] diff --git a/security-command-center/snippets/src/main/java/management/api/ValidateEventThreatDetectionCustomModule.java b/security-command-center/snippets/src/main/java/management/api/ValidateEventThreatDetectionCustomModule.java new file mode 100644 index 00000000000..41ae1d8b129 --- /dev/null +++ b/security-command-center/snippets/src/main/java/management/api/ValidateEventThreatDetectionCustomModule.java @@ -0,0 +1,82 @@ +/* + * Copyright 2025 Google LLC + * + * 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 management.api; + +// [START securitycenter_validate_event_threat_detection_custom_module] +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient; +import com.google.cloud.securitycentermanagement.v1.ValidateEventThreatDetectionCustomModuleRequest; +import com.google.cloud.securitycentermanagement.v1.ValidateEventThreatDetectionCustomModuleResponse; +import com.google.cloud.securitycentermanagement.v1.ValidateEventThreatDetectionCustomModuleResponse.CustomModuleValidationError; +import java.io.IOException; + +public class ValidateEventThreatDetectionCustomModule { + + public static void main(String[] args) throws IOException { + // TODO: Developer should replace project_id with a real project ID before running this code + String projectId = "project_id"; + + validateEventThreatDetectionCustomModule(projectId); + } + + public static ValidateEventThreatDetectionCustomModuleResponse + validateEventThreatDetectionCustomModule(String projectId) throws IOException { + + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + try (SecurityCenterManagementClient client = SecurityCenterManagementClient.create()) { + + String parent = String.format("projects/%s/locations/global", projectId); + + // Define the raw JSON configuration for the Event Threat Detection custom module + String rawText = + "{" + + "\"ips\": [\"192.0.2.1\"]," + + "\"metadata\": {" + + " \"properties\": {" + + " \"someProperty\": \"someValue\"" + + " }," + + " \"severity\": \"MEDIUM\"" + + "}" + + "}"; + + ValidateEventThreatDetectionCustomModuleRequest request = + ValidateEventThreatDetectionCustomModuleRequest.newBuilder() + .setParent(parent) + .setRawText(rawText) // Use JSON as a string for validation + .setType("CONFIGURABLE_BAD_IP") + .build(); + + // Perform validation + ValidateEventThreatDetectionCustomModuleResponse response = + client.validateEventThreatDetectionCustomModule(request); + + // Handle the response and output validation results + if (response.getErrorsCount() > 0) { + for (CustomModuleValidationError module : response.getErrorsList()) { + System.out.printf( + "FieldPath : %s, Description : %s \n", + module.getFieldPath(), module.getDescription()); + } + } else { + System.out.println("Validation successful: No errors found."); + } + return response; + } + } +} +// [END securitycenter_validate_event_threat_detection_custom_module] diff --git a/security-command-center/snippets/src/test/java/management/api/EventThreatDetectionCustomModuleTest.java b/security-command-center/snippets/src/test/java/management/api/EventThreatDetectionCustomModuleTest.java new file mode 100644 index 00000000000..158bff1b63e --- /dev/null +++ b/security-command-center/snippets/src/test/java/management/api/EventThreatDetectionCustomModuleTest.java @@ -0,0 +1,236 @@ +/* + * Copyright 2024 Google LLC + * + * 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 management.api; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.cloud.securitycentermanagement.v1.EffectiveEventThreatDetectionCustomModule; +import com.google.cloud.securitycentermanagement.v1.EventThreatDetectionCustomModule; +import com.google.cloud.securitycentermanagement.v1.EventThreatDetectionCustomModule.EnablementState; +import com.google.cloud.securitycentermanagement.v1.ListEventThreatDetectionCustomModulesRequest; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient.ListDescendantEventThreatDetectionCustomModulesPagedResponse; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient.ListEffectiveEventThreatDetectionCustomModulesPagedResponse; +import com.google.cloud.securitycentermanagement.v1.SecurityCenterManagementClient.ListEventThreatDetectionCustomModulesPagedResponse; +import com.google.cloud.securitycentermanagement.v1.ValidateEventThreatDetectionCustomModuleResponse; +import com.google.cloud.testing.junit4.MultipleAttemptsRule; +import com.google.common.base.Strings; +import java.io.IOException; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.StreamSupport; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class EventThreatDetectionCustomModuleTest { + // TODO(Developer): Replace the below variable + private static final String PROJECT_ID = System.getenv("SCC_PROJECT_ID"); + private static final String CUSTOM_MODULE_DISPLAY_NAME = + "java_sample_etd_custom_module_test_" + UUID.randomUUID(); + private static final int MAX_ATTEMPT_COUNT = 3; + private static final int INITIAL_BACKOFF_MILLIS = 120000; // 2 minutes + + @Rule + public final MultipleAttemptsRule multipleAttemptsRule = + new MultipleAttemptsRule(MAX_ATTEMPT_COUNT, INITIAL_BACKOFF_MILLIS); + + // Check if the required environment variables are set. + public static void requireEnvVar(String envVarName) { + assertWithMessage(String.format("Missing environment variable '%s' ", envVarName)) + .that(System.getenv(envVarName)) + .isNotEmpty(); + } + + @BeforeClass + public static void setUp() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("SCC_PROJECT_ID"); + } + + @AfterClass + public static void cleanUp() throws IOException { + // Perform cleanup after running tests + cleanupExistingCustomModules(); + } + + // cleanupExistingCustomModules clean up all the existing custom module + private static void cleanupExistingCustomModules() throws IOException { + try (SecurityCenterManagementClient client = SecurityCenterManagementClient.create()) { + ListEventThreatDetectionCustomModulesRequest request = + ListEventThreatDetectionCustomModulesRequest.newBuilder() + .setParent(String.format("projects/%s/locations/global", PROJECT_ID)) + .build(); + ListEventThreatDetectionCustomModulesPagedResponse response = + client.listEventThreatDetectionCustomModules(request); + // Iterate over the response and delete custom module one by one which start with + // java_sample_custom_module + for (EventThreatDetectionCustomModule module : response.iterateAll()) { + try { + if (module.getDisplayName().startsWith("java_sample_etd_custom_module")) { + String customModuleId = extractCustomModuleId(module.getName()); + deleteCustomModule(PROJECT_ID, customModuleId); + } + } catch (Exception e) { + System.err.println("Failed to delete module: " + module.getDisplayName()); + e.printStackTrace(); + } + } + } catch (Exception e) { + System.err.println("Failed to process cleanupExistingCustomModules."); + e.printStackTrace(); + } + } + + // extractCustomModuleID extracts the custom module Id from the full name and below regex will + // parses suffix after the last slash character. + private static String extractCustomModuleId(String customModuleFullName) { + if (!Strings.isNullOrEmpty(customModuleFullName)) { + Pattern pattern = Pattern.compile(".*/([^/]+)$"); + Matcher matcher = pattern.matcher(customModuleFullName); + if (matcher.find()) { + return matcher.group(1); + } + } + return ""; + } + + // deleteCustomModule method is for deleting the custom module + private static void deleteCustomModule(String projectId, String customModuleId) + throws IOException { + if (!Strings.isNullOrEmpty(projectId) && !Strings.isNullOrEmpty(customModuleId)) { + DeleteEventThreatDetectionCustomModule.deleteEventThreatDetectionCustomModule( + projectId, customModuleId); + } + } + + @Test + public void testCreateEventThreatDetectionCustomModule() throws IOException { + EventThreatDetectionCustomModule response = + CreateEventThreatDetectionCustomModule.createEventThreatDetectionCustomModule( + PROJECT_ID, CUSTOM_MODULE_DISPLAY_NAME); + assertNotNull(response); + assertThat(response.getDisplayName()).isEqualTo(CUSTOM_MODULE_DISPLAY_NAME); + } + + @Test + public void testDeleteEventThreatDetectionCustomModule() throws IOException { + EventThreatDetectionCustomModule response = + CreateEventThreatDetectionCustomModule.createEventThreatDetectionCustomModule( + PROJECT_ID, CUSTOM_MODULE_DISPLAY_NAME); + String customModuleId = extractCustomModuleId(response.getName()); + assertTrue( + DeleteEventThreatDetectionCustomModule.deleteEventThreatDetectionCustomModule( + PROJECT_ID, customModuleId)); + } + + @Test + public void testListEventThreatDetectionCustomModules() throws IOException { + CreateEventThreatDetectionCustomModule.createEventThreatDetectionCustomModule( + PROJECT_ID, CUSTOM_MODULE_DISPLAY_NAME); + ListEventThreatDetectionCustomModulesPagedResponse response = + ListEventThreatDetectionCustomModules.listEventThreatDetectionCustomModules(PROJECT_ID); + assertTrue( + StreamSupport.stream(response.iterateAll().spliterator(), false) + .anyMatch(module -> CUSTOM_MODULE_DISPLAY_NAME.equals(module.getDisplayName()))); + } + + @Test + public void testGetEventThreatDetectionCustomModule() throws IOException { + EventThreatDetectionCustomModule response = + CreateEventThreatDetectionCustomModule.createEventThreatDetectionCustomModule( + PROJECT_ID, CUSTOM_MODULE_DISPLAY_NAME); + String customModuleId = extractCustomModuleId(response.getName()); + EventThreatDetectionCustomModule getCustomModuleResponse = + GetEventThreatDetectionCustomModule.getEventThreatDetectionCustomModule( + PROJECT_ID, customModuleId); + + assertThat(getCustomModuleResponse.getDisplayName()).isEqualTo(CUSTOM_MODULE_DISPLAY_NAME); + assertThat(extractCustomModuleId(getCustomModuleResponse.getName())).isEqualTo(customModuleId); + } + + @Test + public void testUpdateEventThreatDetectionCustomModule() throws IOException { + EventThreatDetectionCustomModule createCustomModuleResponse = + CreateEventThreatDetectionCustomModule.createEventThreatDetectionCustomModule( + PROJECT_ID, CUSTOM_MODULE_DISPLAY_NAME); + String customModuleId = extractCustomModuleId(createCustomModuleResponse.getName()); + EventThreatDetectionCustomModule response = + UpdateEventThreatDetectionCustomModule.updateEventThreatDetectionCustomModule( + PROJECT_ID, customModuleId); + assertNotNull(response); + assertThat(response.getEnablementState().equals(EnablementState.DISABLED)); + } + + @Test + public void testGetEffectiveEventThreatDetectionCustomModule() throws IOException { + EventThreatDetectionCustomModule createCustomModuleResponse = + CreateEventThreatDetectionCustomModule.createEventThreatDetectionCustomModule( + PROJECT_ID, CUSTOM_MODULE_DISPLAY_NAME); + String customModuleId = extractCustomModuleId(createCustomModuleResponse.getName()); + EffectiveEventThreatDetectionCustomModule getEffectiveCustomModuleResponse = + GetEffectiveEventThreatDetectionCustomModule.getEffectiveEventThreatDetectionCustomModule( + PROJECT_ID, customModuleId); + + assertThat(getEffectiveCustomModuleResponse.getDisplayName()) + .isEqualTo(CUSTOM_MODULE_DISPLAY_NAME); + assertThat(extractCustomModuleId(getEffectiveCustomModuleResponse.getName())) + .isEqualTo(customModuleId); + } + + @Test + public void testListEffectiveEventThreatDetectionCustomModules() throws IOException { + CreateEventThreatDetectionCustomModule.createEventThreatDetectionCustomModule( + PROJECT_ID, CUSTOM_MODULE_DISPLAY_NAME); + ListEffectiveEventThreatDetectionCustomModulesPagedResponse response = + ListEffectiveEventThreatDetectionCustomModules + .listEffectiveEventThreatDetectionCustomModules(PROJECT_ID); + assertTrue( + StreamSupport.stream(response.iterateAll().spliterator(), false) + .anyMatch(module -> CUSTOM_MODULE_DISPLAY_NAME.equals(module.getDisplayName()))); + } + + @Test + public void testListDescendantEventThreatDetectionCustomModules() throws IOException { + CreateEventThreatDetectionCustomModule.createEventThreatDetectionCustomModule( + PROJECT_ID, CUSTOM_MODULE_DISPLAY_NAME); + ListDescendantEventThreatDetectionCustomModulesPagedResponse response = + ListDescendantEventThreatDetectionCustomModules + .listDescendantEventThreatDetectionCustomModules(PROJECT_ID); + assertTrue( + StreamSupport.stream(response.iterateAll().spliterator(), false) + .anyMatch(module -> CUSTOM_MODULE_DISPLAY_NAME.equals(module.getDisplayName()))); + } + + @Test + public void testValidateEventThreatDetectionCustomModule() throws IOException { + + ValidateEventThreatDetectionCustomModuleResponse response = + ValidateEventThreatDetectionCustomModule.validateEventThreatDetectionCustomModule( + PROJECT_ID); + assertNotNull(response); + assertThat(response.getErrorsCount()).isEqualTo(0); + } +} diff --git a/storage-transfer/src/test/java/com/google/cloud/storage/storagetransfer/samples/test/util/TransferJobUtils.java b/storage-transfer/src/test/java/com/google/cloud/storage/storagetransfer/samples/test/util/TransferJobUtils.java index c2fedcab472..af8b2044be9 100644 --- a/storage-transfer/src/test/java/com/google/cloud/storage/storagetransfer/samples/test/util/TransferJobUtils.java +++ b/storage-transfer/src/test/java/com/google/cloud/storage/storagetransfer/samples/test/util/TransferJobUtils.java @@ -14,6 +14,7 @@ * limitations under the License. */ +// [START storagetransfer_transfer_all] // [START all] package com.google.cloud.storage.storagetransfer.samples.test.util; @@ -68,3 +69,4 @@ public static TimeOfDay createTimeOfDay(String timeString) } } // [END all] +// [END storagetransfer_transfer_all] \ No newline at end of file diff --git a/tpu/src/main/java/tpu/CreateQueuedResource.java b/tpu/src/main/java/tpu/CreateQueuedResource.java new file mode 100644 index 00000000000..421acff2d04 --- /dev/null +++ b/tpu/src/main/java/tpu/CreateQueuedResource.java @@ -0,0 +1,98 @@ +/* + * Copyright 2024 Google LLC + * + * 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 tpu; + +//[START tpu_queued_resources_create] +import com.google.cloud.tpu.v2alpha1.CreateQueuedResourceRequest; +import com.google.cloud.tpu.v2alpha1.Node; +import com.google.cloud.tpu.v2alpha1.QueuedResource; +import com.google.cloud.tpu.v2alpha1.TpuClient; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateQueuedResource { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Google Cloud project you want to create a node. + String projectId = "YOUR_PROJECT_ID"; + // The zone in which to create the TPU. + // For more information about supported TPU types for specific zones, + // see https://cloud.google.com/tpu/docs/regions-zones + String zone = "us-central1-f"; + // The name for your TPU. + String nodeName = "YOUR_NODE_ID"; + // The accelerator type that specifies the version and size of the Cloud TPU you want to create. + // For more information about supported accelerator types for each TPU version, + // see https://cloud.google.com/tpu/docs/system-architecture-tpu-vm#versions. + String tpuType = "v2-8"; + // Software version that specifies the version of the TPU runtime to install. + // For more information see https://cloud.google.com/tpu/docs/runtimes + String tpuSoftwareVersion = "tpu-vm-tf-2.14.1"; + // The name for your Queued Resource. + String queuedResourceId = "QUEUED_RESOURCE_ID"; + + createQueuedResource( + projectId, zone, queuedResourceId, nodeName, tpuType, tpuSoftwareVersion); + } + + // Creates a Queued Resource + public static QueuedResource createQueuedResource(String projectId, String zone, + String queuedResourceId, String nodeName, String tpuType, String tpuSoftwareVersion) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + String resource = String.format("projects/%s/locations/%s/queuedResources/%s", + projectId, zone, queuedResourceId); + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (TpuClient tpuClient = TpuClient.create()) { + String parent = String.format("projects/%s/locations/%s", projectId, zone); + Node node = + Node.newBuilder() + .setName(nodeName) + .setAcceleratorType(tpuType) + .setRuntimeVersion(tpuSoftwareVersion) + .setQueuedResource(resource) + .build(); + + QueuedResource queuedResource = + QueuedResource.newBuilder() + .setName(queuedResourceId) + .setTpu( + QueuedResource.Tpu.newBuilder() + .addNodeSpec( + QueuedResource.Tpu.NodeSpec.newBuilder() + .setParent(parent) + .setNode(node) + .setNodeId(nodeName) + .build()) + .build()) + .build(); + + CreateQueuedResourceRequest request = + CreateQueuedResourceRequest.newBuilder() + .setParent(parent) + .setQueuedResourceId(queuedResourceId) + .setQueuedResource(queuedResource) + .build(); + + return tpuClient.createQueuedResourceAsync(request).get(1, TimeUnit.MINUTES); + } + } +} +//[END tpu_queued_resources_create] \ No newline at end of file diff --git a/tpu/src/main/java/tpu/CreateSpotQueuedResource.java b/tpu/src/main/java/tpu/CreateSpotQueuedResource.java new file mode 100644 index 00000000000..b281d87abd9 --- /dev/null +++ b/tpu/src/main/java/tpu/CreateSpotQueuedResource.java @@ -0,0 +1,103 @@ +/* + * Copyright 2024 Google LLC + * + * 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 tpu; + +// [START tpu_queued_resources_create_spot] +import com.google.cloud.tpu.v2alpha1.CreateQueuedResourceRequest; +import com.google.cloud.tpu.v2alpha1.Node; +import com.google.cloud.tpu.v2alpha1.QueuedResource; +import com.google.cloud.tpu.v2alpha1.SchedulingConfig; +import com.google.cloud.tpu.v2alpha1.TpuClient; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class CreateSpotQueuedResource { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Google Cloud project you want to create a node. + String projectId = "YOUR_PROJECT_ID"; + // The zone in which to create the TPU. + // For more information about supported TPU types for specific zones, + // see https://cloud.google.com/tpu/docs/regions-zones + String zone = "us-central1-f"; + // The name for your TPU. + String nodeName = "YOUR_TPU_NAME"; + // The accelerator type that specifies the version and size of the Cloud TPU you want to create. + // For more information about supported accelerator types for each TPU version, + // see https://cloud.google.com/tpu/docs/system-architecture-tpu-vm#versions. + String tpuType = "v2-8"; + // Software version that specifies the version of the TPU runtime to install. + // For more information see https://cloud.google.com/tpu/docs/runtimes + String tpuSoftwareVersion = "tpu-vm-tf-2.14.1"; + // The name for your Queued Resource. + String queuedResourceId = "QUEUED_RESOURCE_ID"; + + createQueuedResource( + projectId, zone, queuedResourceId, nodeName, tpuType, tpuSoftwareVersion); + } + + // Creates a Queued Resource with --preemptible flag. + public static QueuedResource createQueuedResource( + String projectId, String zone, String queuedResourceId, + String nodeName, String tpuType, String tpuSoftwareVersion) + throws IOException, ExecutionException, InterruptedException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (TpuClient tpuClient = TpuClient.create()) { + String parent = String.format("projects/%s/locations/%s", projectId, zone); + String resourceName = String.format("projects/%s/locations/%s/queuedResources/%s", + projectId, zone, queuedResourceId); + SchedulingConfig schedulingConfig = SchedulingConfig.newBuilder() + .setPreemptible(true) + .build(); + + Node node = + Node.newBuilder() + .setName(nodeName) + .setAcceleratorType(tpuType) + .setRuntimeVersion(tpuSoftwareVersion) + .setSchedulingConfig(schedulingConfig) + .setQueuedResource(resourceName) + .build(); + + QueuedResource queuedResource = + QueuedResource.newBuilder() + .setName(queuedResourceId) + .setTpu( + QueuedResource.Tpu.newBuilder() + .addNodeSpec( + QueuedResource.Tpu.NodeSpec.newBuilder() + .setParent(parent) + .setNode(node) + .setNodeId(nodeName) + .build()) + .build()) + .build(); + + CreateQueuedResourceRequest request = + CreateQueuedResourceRequest.newBuilder() + .setParent(parent) + .setQueuedResourceId(queuedResourceId) + .setQueuedResource(queuedResource) + .build(); + + return tpuClient.createQueuedResourceAsync(request).get(); + } + } +} +// [END tpu_queued_resources_create_spot] diff --git a/tpu/src/main/java/tpu/CreateSpotTpuVm.java b/tpu/src/main/java/tpu/CreateSpotTpuVm.java new file mode 100644 index 00000000000..d129f8c4b34 --- /dev/null +++ b/tpu/src/main/java/tpu/CreateSpotTpuVm.java @@ -0,0 +1,80 @@ +/* + * Copyright 2024 Google LLC + * + * 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 tpu; + +//[START tpu_vm_create_spot] +import com.google.cloud.tpu.v2.CreateNodeRequest; +import com.google.cloud.tpu.v2.Node; +import com.google.cloud.tpu.v2.SchedulingConfig; +import com.google.cloud.tpu.v2.TpuClient; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class CreateSpotTpuVm { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Google Cloud project you want to create a node. + String projectId = "YOUR_PROJECT_ID"; + // The zone in which to create the TPU. + // For more information about supported TPU types for specific zones, + // see https://cloud.google.com/tpu/docs/regions-zones + String zone = "us-central1-f"; + // The name for your TPU. + String nodeName = "YOUR_TPY_NAME"; + // The accelerator type that specifies the version and size of the Cloud TPU you want to create. + // For more information about supported accelerator types for each TPU version, + // see https://cloud.google.com/tpu/docs/system-architecture-tpu-vm#versions. + String tpuType = "v2-8"; + // Software version that specifies the version of the TPU runtime to install. + // For more information see https://cloud.google.com/tpu/docs/runtimes + String tpuSoftwareVersion = "tpu-vm-tf-2.14.1"; + + createSpotTpuVm(projectId, zone, nodeName, tpuType, tpuSoftwareVersion); + } + + // Creates a preemptible TPU VM with the specified name, zone, accelerator type, and version. + public static Node createSpotTpuVm( + String projectId, String zone, String nodeName, String tpuType, String tpuSoftwareVersion) + throws IOException, ExecutionException, InterruptedException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (TpuClient tpuClient = TpuClient.create()) { + String parent = String.format("projects/%s/locations/%s", projectId, zone); + // TODO: Wait for update of library to change preemptible to spot=True + SchedulingConfig schedulingConfig = SchedulingConfig.newBuilder() + .setPreemptible(true) + .build(); + + Node tpuVm = Node.newBuilder() + .setName(nodeName) + .setAcceleratorType(tpuType) + .setRuntimeVersion(tpuSoftwareVersion) + .setSchedulingConfig(schedulingConfig) + .build(); + + CreateNodeRequest request = CreateNodeRequest.newBuilder() + .setParent(parent) + .setNodeId(nodeName) + .setNode(tpuVm) + .build(); + + return tpuClient.createNodeAsync(request).get(); + } + } +} +//[END tpu_vm_create_spot] \ No newline at end of file diff --git a/tpu/src/main/java/tpu/CreateTimeBoundQueuedResource.java b/tpu/src/main/java/tpu/CreateTimeBoundQueuedResource.java new file mode 100644 index 00000000000..b1b1b927300 --- /dev/null +++ b/tpu/src/main/java/tpu/CreateTimeBoundQueuedResource.java @@ -0,0 +1,110 @@ +/* + * Copyright 2024 Google LLC + * + * 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 tpu; + +// [START tpu_queued_resources_time_bound] +import com.google.cloud.tpu.v2alpha1.CreateQueuedResourceRequest; +import com.google.cloud.tpu.v2alpha1.Node; +import com.google.cloud.tpu.v2alpha1.QueuedResource; +import com.google.cloud.tpu.v2alpha1.TpuClient; +import com.google.protobuf.Duration; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class CreateTimeBoundQueuedResource { + + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Google Cloud project you want to create a node. + String projectId = "YOUR_PROJECT_ID"; + // The zone in which to create the TPU. + // For more information about supported TPU types for specific zones, + // see https://cloud.google.com/tpu/docs/regions-zones + String zone = "us-central2-b"; + // The name of your node. + String nodeId = "YOUR_NODE_ID"; + // The accelerator type that specifies the version and size of the Cloud TPU you want to create. + // For more information about supported accelerator types for each TPU version, + // see https://cloud.google.com/tpu/docs/system-architecture-tpu-vm#versions. + String acceleratorType = "v2-8"; + // Software version that specifies the version of the TPU runtime to install. + // For more information see https://cloud.google.com/tpu/docs/runtimes + String runtimeVersion = "tpu-vm-tf-2.14.1"; + // The name of your Queued Resource. + String queuedResourceId = "YOUR_QUEUED_RESOURCE_ID"; + + createTimeBoundQueuedResource(projectId, nodeId, + queuedResourceId, zone, acceleratorType, runtimeVersion); + } + + // Creates a Queued Resource with time bound configuration. + public static QueuedResource createTimeBoundQueuedResource( + String projectId, String nodeId, String queuedResourceId, + String zone, String acceleratorType, String runtimeVersion) + throws IOException, ExecutionException, InterruptedException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (TpuClient tpuClient = TpuClient.create()) { + String parent = String.format("projects/%s/locations/%s", projectId, zone); + // Create a Duration object representing 6 hours. + Duration validAfterDuration = Duration.newBuilder().setSeconds(6 * 3600).build(); + // You could also use timestamps like this: + // Timestamp validAfterTime = Timestamps.parse("2024-10-14T09:00:00Z"); + + Node node = + Node.newBuilder() + .setName(nodeId) + .setAcceleratorType(acceleratorType) + .setRuntimeVersion(runtimeVersion) + .setQueuedResource( + String.format( + "projects/%s/locations/%s/queuedResources/%s", + projectId, zone, queuedResourceId)) + .build(); + + QueuedResource queuedResource = + QueuedResource.newBuilder() + .setName(queuedResourceId) + .setTpu( + QueuedResource.Tpu.newBuilder() + .addNodeSpec( + QueuedResource.Tpu.NodeSpec.newBuilder() + .setParent(parent) + .setNode(node) + .setNodeId(nodeId) + .build()) + .build()) + .setQueueingPolicy( + QueuedResource.QueueingPolicy.newBuilder() + .setValidAfterDuration(validAfterDuration) + // .setValidAfterTime(validAfterTime) + .build()) + .build(); + + CreateQueuedResourceRequest request = + CreateQueuedResourceRequest.newBuilder() + .setParent(parent) + .setQueuedResource(queuedResource) + .setQueuedResourceId(queuedResourceId) + .build(); + + return tpuClient.createQueuedResourceAsync(request).get(); + } + } +} +// [END tpu_queued_resources_time_bound] \ No newline at end of file diff --git a/tpu/src/main/java/tpu/CreateTpuVmWithStartupScript.java b/tpu/src/main/java/tpu/CreateTpuVmWithStartupScript.java new file mode 100644 index 00000000000..87c2115dea6 --- /dev/null +++ b/tpu/src/main/java/tpu/CreateTpuVmWithStartupScript.java @@ -0,0 +1,84 @@ +/* +* Copyright 2024 Google LLC +* +* 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 tpu; + +//[START tpu_vm_create_startup_script] +import com.google.cloud.tpu.v2.CreateNodeRequest; +import com.google.cloud.tpu.v2.Node; +import com.google.cloud.tpu.v2.TpuClient; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +public class CreateTpuVmWithStartupScript { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Google Cloud project you want to create a node. + String projectId = "YOUR_PROJECT_ID"; + // The zone in which to create the TPU. + // For more information about supported TPU types for specific zones, + // see https://cloud.google.com/tpu/docs/regions-zones + String zone = "us-central1-f"; + // The name for your TPU. + String nodeName = "YOUR_TPU_NAME"; + // The accelerator type that specifies the version and size of the Cloud TPU you want to create. + // For more information about supported accelerator types for each TPU version, + // see https://cloud.google.com/tpu/docs/system-architecture-tpu-vm#versions. + String acceleratorType = "v2-8"; + // Software version that specifies the version of the TPU runtime to install. + // For more information, see https://cloud.google.com/tpu/docs/runtimes + String tpuSoftwareVersion = "tpu-vm-tf-2.14.1"; + + createTpuVmWithStartupScript(projectId, zone, nodeName, acceleratorType, tpuSoftwareVersion); + } + + // Create a TPU VM with a startup script. + public static Node createTpuVmWithStartupScript(String projectId, String zone, + String nodeName, String acceleratorType, String tpuSoftwareVersion) + throws IOException, ExecutionException, InterruptedException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (TpuClient tpuClient = TpuClient.create()) { + String parent = String.format("projects/%s/locations/%s", projectId, zone); + + String startupScriptContent = "#!/bin/bash\necho \"Hello from the startup script!\""; + // Add startup script to metadata + Map metadata = new HashMap<>(); + metadata.put("startup-script", startupScriptContent); + + Node tpuVm = + Node.newBuilder() + .setName(nodeName) + .setAcceleratorType(acceleratorType) + .setRuntimeVersion(tpuSoftwareVersion) + .putAllMetadata(metadata) + .build(); + + CreateNodeRequest request = + CreateNodeRequest.newBuilder() + .setParent(parent) + .setNodeId(nodeName) + .setNode(tpuVm) + .build(); + + return tpuClient.createNodeAsync(request).get(); + } + } +} +//[END tpu_vm_create_startup_script] \ No newline at end of file diff --git a/tpu/src/main/java/tpu/DeleteForceQueuedResource.java b/tpu/src/main/java/tpu/DeleteForceQueuedResource.java index f619889001c..f05e11fd57d 100644 --- a/tpu/src/main/java/tpu/DeleteForceQueuedResource.java +++ b/tpu/src/main/java/tpu/DeleteForceQueuedResource.java @@ -74,4 +74,4 @@ public static void deleteForceQueuedResource( } } } -//[END tpu_queued_resources_delete_force] +//[END tpu_queued_resources_delete_force] \ No newline at end of file diff --git a/tpu/src/main/java/tpu/DeleteQueuedResource.java b/tpu/src/main/java/tpu/DeleteQueuedResource.java new file mode 100644 index 00000000000..9f0e123a43e --- /dev/null +++ b/tpu/src/main/java/tpu/DeleteQueuedResource.java @@ -0,0 +1,58 @@ +/* + * Copyright 2024 Google LLC + * + * 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 tpu; + +//[START tpu_queued_resources_delete] +import com.google.cloud.tpu.v2alpha1.DeleteQueuedResourceRequest; +import com.google.cloud.tpu.v2alpha1.TpuClient; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class DeleteQueuedResource { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Google Cloud project. + String projectId = "YOUR_PROJECT_ID"; + // The zone in which the TPU was created. + String zone = "us-central1-f"; + // The name for your Queued Resource. + String queuedResourceId = "QUEUED_RESOURCE_ID"; + + deleteQueuedResource(projectId, zone, queuedResourceId); + } + + // Deletes a Queued Resource asynchronously. + public static void deleteQueuedResource(String projectId, String zone, String queuedResourceId) + throws ExecutionException, InterruptedException, IOException { + String name = String.format("projects/%s/locations/%s/queuedResources/%s", + projectId, zone, queuedResourceId); + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (TpuClient tpuClient = TpuClient.create()) { + // Before deleting the queued resource it is required to delete the TPU VM. + // For more information about deleting TPU + // see https://cloud.google.com/tpu/docs/managing-tpus-tpu-vm + + DeleteQueuedResourceRequest request = + DeleteQueuedResourceRequest.newBuilder().setName(name).build(); + + tpuClient.deleteQueuedResourceAsync(request).get(); + } + } +} +//[END tpu_queued_resources_delete] diff --git a/tpu/src/main/java/tpu/GetQueuedResource.java b/tpu/src/main/java/tpu/GetQueuedResource.java index a17c2b41f79..588987a25f0 100644 --- a/tpu/src/main/java/tpu/GetQueuedResource.java +++ b/tpu/src/main/java/tpu/GetQueuedResource.java @@ -28,7 +28,7 @@ public static void main(String[] args) throws IOException { // Project ID or project number of the Google Cloud project. String projectId = "YOUR_PROJECT_ID"; // The zone in which the TPU was created. - String zone = "europe-west4-a"; + String zone = "us-central1-f"; // The name for your Queued Resource. String queuedResourceId = "QUEUED_RESOURCE_ID"; @@ -50,4 +50,4 @@ public static QueuedResource getQueuedResource( } } } -//[END tpu_queued_resources_get] +//[END tpu_queued_resources_get] \ No newline at end of file diff --git a/tpu/src/main/java/tpu/ListQueuedResources.java b/tpu/src/main/java/tpu/ListQueuedResources.java new file mode 100644 index 00000000000..1d38c988892 --- /dev/null +++ b/tpu/src/main/java/tpu/ListQueuedResources.java @@ -0,0 +1,55 @@ +/* + * Copyright 2024 Google LLC + * + * 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 tpu; + +//[START tpu_queued_resources_list] +import com.google.cloud.tpu.v2alpha1.ListQueuedResourcesRequest; +import com.google.cloud.tpu.v2alpha1.QueuedResource; +import com.google.cloud.tpu.v2alpha1.TpuClient; +import com.google.cloud.tpu.v2alpha1.TpuClient.ListQueuedResourcesPage; +import java.io.IOException; + +public class ListQueuedResources { + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Google Cloud project. + String projectId = "YOUR_PROJECT_ID"; + // The zone in which the TPU was created. + String zone = "us-central1-a"; + + listQueuedResources(projectId, zone); + } + + // List Queued Resources. + public static ListQueuedResourcesPage listQueuedResources( + String projectId, String zone) throws IOException { + String parent = String.format("projects/%s/locations/%s", projectId, zone); + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + try (TpuClient tpuClient = TpuClient.create()) { + ListQueuedResourcesRequest request = + ListQueuedResourcesRequest.newBuilder().setParent(parent).build(); + ListQueuedResourcesPage response = tpuClient.listQueuedResources(request).getPage(); + + for (QueuedResource queuedResource : response.iterateAll()) { + System.out.println(queuedResource.getName()); + } + return response; + } + } +} +//[END tpu_queued_resources_list] diff --git a/tpu/src/test/java/tpu/QueuedResourceIT.java b/tpu/src/test/java/tpu/QueuedResourceIT.java index 15dd2e768cc..0cb6bafcd4d 100644 --- a/tpu/src/test/java/tpu/QueuedResourceIT.java +++ b/tpu/src/test/java/tpu/QueuedResourceIT.java @@ -16,7 +16,9 @@ package tpu; +import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; @@ -28,11 +30,17 @@ import com.google.cloud.tpu.v2alpha1.CreateQueuedResourceRequest; import com.google.cloud.tpu.v2alpha1.DeleteQueuedResourceRequest; import com.google.cloud.tpu.v2alpha1.GetQueuedResourceRequest; +import com.google.cloud.tpu.v2alpha1.ListQueuedResourcesRequest; import com.google.cloud.tpu.v2alpha1.QueuedResource; import com.google.cloud.tpu.v2alpha1.TpuClient; +import com.google.cloud.tpu.v2alpha1.TpuClient.ListQueuedResourcesPage; +import com.google.cloud.tpu.v2alpha1.TpuClient.ListQueuedResourcesPagedResponse; import com.google.cloud.tpu.v2alpha1.TpuSettings; import java.io.IOException; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import org.junit.runner.RunWith; @@ -40,7 +48,7 @@ import org.mockito.MockedStatic; @RunWith(JUnit4.class) -@Timeout(value = 10) +@Timeout(value = 2, unit = TimeUnit.MINUTES) public class QueuedResourceIT { private static final String PROJECT_ID = "project-id"; private static final String ZONE = "europe-west4-a"; @@ -50,6 +58,30 @@ public class QueuedResourceIT { private static final String QUEUED_RESOURCE_NAME = "queued-resource"; private static final String NETWORK_NAME = "default"; + @Test + public void testCreateQueuedResource() throws Exception { + try (MockedStatic mockedTpuClient = mockStatic(TpuClient.class)) { + QueuedResource mockQueuedResource = mock(QueuedResource.class); + TpuClient mockTpuClient = mock(TpuClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedTpuClient.when(TpuClient::create).thenReturn(mockTpuClient); + when(mockTpuClient.createQueuedResourceAsync(any(CreateQueuedResourceRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get(anyLong(), any(TimeUnit.class))).thenReturn(mockQueuedResource); + + QueuedResource returnedQueuedResource = + CreateQueuedResource.createQueuedResource( + PROJECT_ID, ZONE, QUEUED_RESOURCE_NAME, NODE_NAME, + TPU_TYPE, TPU_SOFTWARE_VERSION); + + verify(mockTpuClient, times(1)) + .createQueuedResourceAsync(any(CreateQueuedResourceRequest.class)); + verify(mockFuture, times(1)).get(anyLong(), any(TimeUnit.class)); + assertEquals(returnedQueuedResource, mockQueuedResource); + } + } + @Test public void testCreateQueuedResourceWithSpecifiedNetwork() throws Exception { try (MockedStatic mockedTpuClient = mockStatic(TpuClient.class)) { @@ -94,6 +126,33 @@ public void testGetQueuedResource() throws IOException { } } + @Test + public void testListTpuVm() throws IOException { + try (MockedStatic mockedTpuClient = mockStatic(TpuClient.class)) { + QueuedResource queuedResource1 = mock(QueuedResource.class); + QueuedResource queuedResource2 = mock(QueuedResource.class); + List mockListQueuedResources = + Arrays.asList(queuedResource1, queuedResource2); + + TpuClient mockClient = mock(TpuClient.class); + mockedTpuClient.when(TpuClient::create).thenReturn(mockClient); + ListQueuedResourcesPagedResponse mockListQueuedResourcesResponse = + mock(ListQueuedResourcesPagedResponse.class); + when(mockClient.listQueuedResources(any(ListQueuedResourcesRequest.class))) + .thenReturn(mockListQueuedResourcesResponse); + ListQueuedResourcesPage mockQueuedResourcesPage = + mock(ListQueuedResourcesPage.class); + when(mockListQueuedResourcesResponse.getPage()).thenReturn(mockQueuedResourcesPage); + when(mockQueuedResourcesPage.getValues()).thenReturn(mockListQueuedResources); + + ListQueuedResourcesPage returnedList = + ListQueuedResources.listQueuedResources(PROJECT_ID, ZONE); + + assertThat(returnedList.getValues()).isEqualTo(mockListQueuedResources); + verify(mockClient, times(1)).listQueuedResources(any(ListQueuedResourcesRequest.class)); + } + } + @Test public void testDeleteForceQueuedResource() throws IOException, InterruptedException, ExecutionException { @@ -113,6 +172,25 @@ public void testDeleteForceQueuedResource() } } + @Test + public void testDeleteQueuedResource() + throws IOException, ExecutionException, InterruptedException { + try (MockedStatic mockedTpuClient = mockStatic(TpuClient.class)) { + TpuClient mockTpuClient = mock(TpuClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedTpuClient.when(TpuClient::create).thenReturn(mockTpuClient); + when(mockTpuClient.deleteQueuedResourceAsync(any(DeleteQueuedResourceRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get()).thenReturn(null); + + DeleteQueuedResource.deleteQueuedResource(PROJECT_ID, ZONE, QUEUED_RESOURCE_NAME); + + verify(mockTpuClient, times(1)) + .deleteQueuedResourceAsync(any(DeleteQueuedResourceRequest.class)); + } + } + @Test public void testCreateQueuedResourceWithStartupScript() throws Exception { try (MockedStatic mockedTpuClient = mockStatic(TpuClient.class)) { @@ -136,4 +214,56 @@ public void testCreateQueuedResourceWithStartupScript() throws Exception { assertEquals(returnedQueuedResource, mockQueuedResource); } } + + @Test + public void testCreateSpotQueuedResource() throws Exception { + try (MockedStatic mockedTpuClient = mockStatic(TpuClient.class)) { + QueuedResource mockQueuedResource = QueuedResource.newBuilder() + .setName("QueuedResourceName") + .build(); + TpuClient mockedClientInstance = mock(TpuClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedTpuClient.when(TpuClient::create).thenReturn(mockedClientInstance); + when(mockedClientInstance.createQueuedResourceAsync(any(CreateQueuedResourceRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get()).thenReturn(mockQueuedResource); + + QueuedResource returnedQueuedResource = + CreateSpotQueuedResource.createQueuedResource( + PROJECT_ID, ZONE, QUEUED_RESOURCE_NAME, NODE_NAME, + TPU_TYPE, TPU_SOFTWARE_VERSION); + + verify(mockedClientInstance, times(1)) + .createQueuedResourceAsync(any(CreateQueuedResourceRequest.class)); + verify(mockFuture, times(1)).get(); + assertEquals(returnedQueuedResource.getName(), mockQueuedResource.getName()); + } + } + + @Test + public void testCreateTimeBoundQueuedResource() throws Exception { + try (MockedStatic mockedTpuClient = mockStatic(TpuClient.class)) { + QueuedResource mockQueuedResource = QueuedResource.newBuilder() + .setName("QueuedResourceName") + .build(); + TpuClient mockTpuClient = mock(TpuClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedTpuClient.when(TpuClient::create).thenReturn(mockTpuClient); + when(mockTpuClient.createQueuedResourceAsync(any(CreateQueuedResourceRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get()).thenReturn(mockQueuedResource); + + QueuedResource returnedQueuedResource = + CreateTimeBoundQueuedResource.createTimeBoundQueuedResource( + PROJECT_ID, ZONE, QUEUED_RESOURCE_NAME, NODE_NAME, + TPU_TYPE, TPU_SOFTWARE_VERSION); + + verify(mockTpuClient, times(1)) + .createQueuedResourceAsync(any(CreateQueuedResourceRequest.class)); + verify(mockFuture, times(1)).get(); + assertEquals(returnedQueuedResource.getName(), mockQueuedResource.getName()); + } + } } \ No newline at end of file diff --git a/tpu/src/test/java/tpu/TpuVmIT.java b/tpu/src/test/java/tpu/TpuVmIT.java index e40e220fec8..bdf76a955b6 100644 --- a/tpu/src/test/java/tpu/TpuVmIT.java +++ b/tpu/src/test/java/tpu/TpuVmIT.java @@ -210,4 +210,57 @@ public void testStopTpuVm() throws IOException, ExecutionException, InterruptedE assertEquals(returnedNode, mockNode); } } + + @Test + public void testCreateSpotTpuVm() throws Exception { + try (MockedStatic mockedTpuClient = mockStatic(TpuClient.class)) { + Node mockNode = mock(Node.class); + TpuClient mockTpuClient = mock(TpuClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedTpuClient.when(TpuClient::create).thenReturn(mockTpuClient); + when(mockTpuClient.createNodeAsync(any(CreateNodeRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get()).thenReturn(mockNode); + + Node returnedNode = CreateSpotTpuVm.createSpotTpuVm( + PROJECT_ID, ZONE, NODE_NAME, + TPU_TYPE, TPU_SOFTWARE_VERSION); + + verify(mockTpuClient, times(1)) + .createNodeAsync(any(CreateNodeRequest.class)); + verify(mockFuture, times(1)).get(); + assertEquals(returnedNode, mockNode); + } + } + + @Test + public void testCreateTpuVmWithStartupScript() throws Exception { + try (MockedStatic mockedTpuClient = mockStatic(TpuClient.class)) { + Node mockNode = Node.newBuilder() + .setName("nodeName") + .setAcceleratorType("acceleratorType") + .setRuntimeVersion("runtimeVersion") + .build(); + + TpuClient mockTpuClient = mock(TpuClient.class); + OperationFuture mockFuture = mock(OperationFuture.class); + + mockedTpuClient.when(TpuClient::create).thenReturn(mockTpuClient); + when(mockTpuClient.createNodeAsync(any(CreateNodeRequest.class))) + .thenReturn(mockFuture); + when(mockFuture.get()).thenReturn(mockNode); + + Node returnedNode = CreateTpuVmWithStartupScript.createTpuVmWithStartupScript( + PROJECT_ID, ZONE, NODE_NAME, + TPU_TYPE, TPU_SOFTWARE_VERSION); + + verify(mockTpuClient, times(1)) + .createNodeAsync(any(CreateNodeRequest.class)); + verify(mockFuture, times(1)).get(); + assertEquals(returnedNode.getName(), mockNode.getName()); + assertEquals(returnedNode.getAcceleratorType(), mockNode.getAcceleratorType()); + assertEquals(returnedNode.getRuntimeVersion(), mockNode.getRuntimeVersion()); + } + } } \ No newline at end of file