Skip to content

Commit f9fddc3

Browse files
feat: Consistency group clone sample (GoogleCloudPlatform#12984)
* Add consistency group clone sample + updated tests * Deleted mock tests * Updated time shifts * Updated dependencies * Updated arguments and test
1 parent b061822 commit f9fddc3

File tree

5 files changed

+263
-2
lines changed

5 files changed

+263
-2
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# This is an ingredient file. It is not meant to be run directly. Check the samples/snippets
16+
# folder for complete code samples that are ready to be used.
17+
# Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check.
18+
# flake8: noqa
19+
20+
from google.cloud import compute_v1
21+
22+
23+
# <INGREDIENT consistency_group_clone_disks>
24+
def clone_disks_to_consistency_group(project_id, group_region, group_name):
25+
"""
26+
Clones disks to a consistency group in the specified region.
27+
Args:
28+
project_id (str): The ID of the Google Cloud project.
29+
group_region (str): The region where the consistency group is located.
30+
group_name (str): The name of the consistency group.
31+
Returns:
32+
bool: True if the disks were successfully cloned to the consistency group.
33+
"""
34+
consistency_group_policy = (
35+
f"projects/{project_id}/regions/{group_region}/resourcePolicies/{group_name}"
36+
)
37+
38+
resource = compute_v1.BulkInsertDiskResource(
39+
source_consistency_group_policy=consistency_group_policy
40+
)
41+
client = compute_v1.RegionDisksClient()
42+
request = compute_v1.BulkInsertRegionDiskRequest(
43+
project=project_id,
44+
region=group_region,
45+
bulk_insert_disk_resource_resource=resource,
46+
)
47+
operation = client.bulk_insert(request=request)
48+
wait_for_extended_operation(operation, verbose_name="bulk insert disk")
49+
return True
50+
51+
52+
# </INGREDIENT>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# flake8: noqa
15+
16+
# <REGION compute_consistency_group_clone>
17+
# <IMPORTS/>
18+
19+
# <INGREDIENT wait_for_extended_operation />
20+
21+
# <INGREDIENT consistency_group_clone_disks />
22+
23+
# </REGION compute_consistency_group_clone>

compute/client_library/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ isort==5.13.2; python_version > "3.7"
22
isort==5.11.5; python_version <= "3.7"
33
black==24.8.0; python_version < "3.9"
44
black==24.10.0; python_version >= "3.9"
5-
google-cloud-compute==1.19.1
5+
google-cloud-compute==1.19.1
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# flake8: noqa
15+
16+
17+
# This file is automatically generated. Please do not modify it directly.
18+
# Find the relevant recipe file in the samples/recipes or samples/ingredients
19+
# directory and apply your changes there.
20+
21+
22+
# [START compute_consistency_group_clone]
23+
from __future__ import annotations
24+
25+
import sys
26+
from typing import Any
27+
28+
from google.api_core.extended_operation import ExtendedOperation
29+
from google.cloud import compute_v1
30+
31+
32+
def wait_for_extended_operation(
33+
operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300
34+
) -> Any:
35+
"""
36+
Waits for the extended (long-running) operation to complete.
37+
38+
If the operation is successful, it will return its result.
39+
If the operation ends with an error, an exception will be raised.
40+
If there were any warnings during the execution of the operation
41+
they will be printed to sys.stderr.
42+
43+
Args:
44+
operation: a long-running operation you want to wait on.
45+
verbose_name: (optional) a more verbose name of the operation,
46+
used only during error and warning reporting.
47+
timeout: how long (in seconds) to wait for operation to finish.
48+
If None, wait indefinitely.
49+
50+
Returns:
51+
Whatever the operation.result() returns.
52+
53+
Raises:
54+
This method will raise the exception received from `operation.exception()`
55+
or RuntimeError if there is no exception set, but there is an `error_code`
56+
set for the `operation`.
57+
58+
In case of an operation taking longer than `timeout` seconds to complete,
59+
a `concurrent.futures.TimeoutError` will be raised.
60+
"""
61+
result = operation.result(timeout=timeout)
62+
63+
if operation.error_code:
64+
print(
65+
f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}",
66+
file=sys.stderr,
67+
flush=True,
68+
)
69+
print(f"Operation ID: {operation.name}", file=sys.stderr, flush=True)
70+
raise operation.exception() or RuntimeError(operation.error_message)
71+
72+
if operation.warnings:
73+
print(f"Warnings during {verbose_name}:\n", file=sys.stderr, flush=True)
74+
for warning in operation.warnings:
75+
print(f" - {warning.code}: {warning.message}", file=sys.stderr, flush=True)
76+
77+
return result
78+
79+
80+
def clone_disks_to_consistency_group(project_id, group_region, group_name):
81+
"""
82+
Clones disks to a consistency group in the specified region.
83+
Args:
84+
project_id (str): The ID of the Google Cloud project.
85+
group_region (str): The region where the consistency group is located.
86+
group_name (str): The name of the consistency group.
87+
Returns:
88+
bool: True if the disks were successfully cloned to the consistency group.
89+
"""
90+
consistency_group_policy = (
91+
f"projects/{project_id}/regions/{group_region}/resourcePolicies/{group_name}"
92+
)
93+
94+
resource = compute_v1.BulkInsertDiskResource(
95+
source_consistency_group_policy=consistency_group_policy
96+
)
97+
client = compute_v1.RegionDisksClient()
98+
request = compute_v1.BulkInsertRegionDiskRequest(
99+
project=project_id,
100+
region=group_region,
101+
bulk_insert_disk_resource_resource=resource,
102+
)
103+
operation = client.bulk_insert(request=request)
104+
wait_for_extended_operation(operation, verbose_name="bulk insert disk")
105+
return True
106+
107+
108+
# [END compute_consistency_group_clone]

compute/client_library/snippets/tests/test_disks.py

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@
3939
from ..disks.replication_disk_start import start_disk_replication
4040
from ..disks.replication_disk_stop import stop_disk_replication
4141
from ..disks.resize_disk import resize_disk
42+
from ..disks.сonsistency_groups.add_disk_consistency_group import (
43+
add_disk_consistency_group,
44+
)
45+
from ..disks.сonsistency_groups.clone_disks_consistency_group import (
46+
clone_disks_to_consistency_group,
47+
)
48+
from ..disks.сonsistency_groups.create_consistency_group import create_consistency_group
49+
from ..disks.сonsistency_groups.delete_consistency_group import delete_consistency_group
50+
from ..disks.сonsistency_groups.remove_disk_consistency_group import (
51+
remove_disk_consistency_group,
52+
)
4253
from ..images.get import get_image_from_family
4354
from ..instances.create import create_instance, disk_from_image
4455
from ..instances.delete import delete_instance
@@ -51,7 +62,7 @@
5162
ZONE = "europe-west2-c"
5263
ZONE_SECONDARY = "europe-west1-c"
5364
REGION = "europe-west2"
54-
REGION_SECONDARY = "europe-central2"
65+
REGION_SECONDARY = "europe-west3"
5566
KMS_KEYRING_NAME = "compute-test-keyring"
5667
KMS_KEY_NAME = "compute-test-key"
5768
DISK_SIZE = 11
@@ -511,3 +522,70 @@ def test_start_stop_zone_replication(test_empty_pd_balanced_disk, autodelete_dis
511522
)
512523
# Wait for the replication to stop
513524
time.sleep(20)
525+
526+
527+
def test_clone_disks_in_consistency_group(
528+
autodelete_regional_disk_name,
529+
autodelete_regional_blank_disk,
530+
):
531+
group_name1 = "first-group" + uuid.uuid4().hex[:5]
532+
group_name2 = "second-group" + uuid.uuid4().hex[:5]
533+
create_consistency_group(PROJECT, REGION, group_name1, "description")
534+
create_consistency_group(PROJECT, REGION_SECONDARY, group_name2, "description")
535+
536+
add_disk_consistency_group(
537+
project_id=PROJECT,
538+
disk_name=autodelete_regional_blank_disk.name,
539+
disk_location=REGION,
540+
consistency_group_name=group_name1,
541+
consistency_group_region=REGION,
542+
)
543+
544+
second_disk = create_secondary_region_disk(
545+
autodelete_regional_blank_disk.name,
546+
PROJECT,
547+
REGION,
548+
autodelete_regional_disk_name,
549+
PROJECT,
550+
REGION_SECONDARY,
551+
DISK_SIZE,
552+
)
553+
554+
add_disk_consistency_group(
555+
project_id=PROJECT,
556+
disk_name=second_disk.name,
557+
disk_location=REGION_SECONDARY,
558+
consistency_group_name=group_name2,
559+
consistency_group_region=REGION_SECONDARY,
560+
)
561+
562+
start_disk_replication(
563+
project_id=PROJECT,
564+
primary_disk_location=REGION,
565+
primary_disk_name=autodelete_regional_blank_disk.name,
566+
secondary_disk_location=REGION_SECONDARY,
567+
secondary_disk_name=autodelete_regional_disk_name,
568+
)
569+
time.sleep(60)
570+
try:
571+
assert clone_disks_to_consistency_group(PROJECT, REGION_SECONDARY, group_name2)
572+
finally:
573+
stop_disk_replication(
574+
project_id=PROJECT,
575+
primary_disk_location=REGION,
576+
primary_disk_name=autodelete_regional_blank_disk.name,
577+
)
578+
# Wait for the replication to stop
579+
time.sleep(30)
580+
disks = compute_v1.RegionDisksClient().list(
581+
project=PROJECT, region=REGION_SECONDARY
582+
)
583+
if disks:
584+
for disk in disks:
585+
delete_regional_disk(PROJECT, REGION_SECONDARY, disk.name)
586+
time.sleep(25)
587+
remove_disk_consistency_group(
588+
PROJECT, autodelete_regional_blank_disk.name, REGION, group_name1, REGION
589+
)
590+
delete_consistency_group(PROJECT, REGION, group_name1)
591+
delete_consistency_group(PROJECT, REGION_SECONDARY, group_name2)

0 commit comments

Comments
 (0)