Skip to content

Commit d2ba844

Browse files
committed
Add consistency group clone sample + updated tests
1 parent b424d9e commit d2ba844

File tree

5 files changed

+271
-1
lines changed

5 files changed

+271
-1
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_name, group_region):
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_name (str): The name of the consistency group.
30+
group_region (str): The region where the consistency group is located.
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>
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_name, group_region):
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_name (str): The name of the consistency group.
86+
group_region (str): The region where the consistency group is located.
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_consistency_groups.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
# limitations under the License.
1414
import os
1515

16+
from unittest.mock import patch
17+
1618
import uuid
1719

1820
import pytest
@@ -21,6 +23,9 @@
2123
from ..disks.сonsistency_groups.add_disk_consistency_group import (
2224
add_disk_consistency_group,
2325
)
26+
from ..disks.сonsistency_groups.clone_disks_consistency_group import (
27+
clone_disks_to_consistency_group,
28+
)
2429
from ..disks.сonsistency_groups.create_consistency_group import create_consistency_group
2530
from ..disks.сonsistency_groups.delete_consistency_group import delete_consistency_group
2631
from ..disks.сonsistency_groups.list_disks_consistency_group import (
@@ -94,3 +99,10 @@ def test_add_remove_and_list_disks_consistency_group(
9499
consistency_group_region=REGION,
95100
)
96101
assert not disks
102+
103+
104+
def test_clone_disk_consistency_group():
105+
with patch("google.cloud.compute_v1.RegionDisksClient") as mock_client:
106+
client = mock_client.return_value
107+
clone_disks_to_consistency_group(PROJECT_ID, "group-4", "us-east1")
108+
client.bulk_insert.assert_called_once()

compute/client_library/snippets/tests/test_disks.py

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@
3838
from ..disks.replication_disk_start import start_disk_replication
3939
from ..disks.replication_disk_stop import stop_disk_replication
4040
from ..disks.resize_disk import resize_disk
41+
from ..disks.сonsistency_groups.add_disk_consistency_group import (
42+
add_disk_consistency_group,
43+
)
44+
from ..disks.сonsistency_groups.clone_disks_consistency_group import (
45+
clone_disks_to_consistency_group,
46+
)
47+
from ..disks.сonsistency_groups.create_consistency_group import create_consistency_group
48+
from ..disks.сonsistency_groups.delete_consistency_group import delete_consistency_group
49+
from ..disks.сonsistency_groups.remove_disk_consistency_group import remove_disk_consistency_group
4150
from ..images.get import get_image_from_family
4251
from ..instances.create import create_instance, disk_from_image
4352
from ..instances.delete import delete_instance
@@ -50,7 +59,7 @@
5059
ZONE = "europe-west2-c"
5160
ZONE_SECONDARY = "europe-west1-c"
5261
REGION = "europe-west2"
53-
REGION_SECONDARY = "europe-central2"
62+
REGION_SECONDARY = "europe-west3"
5463
KMS_KEYRING_NAME = "compute-test-keyring"
5564
KMS_KEY_NAME = "compute-test-key"
5665
DISK_SIZE = 11
@@ -499,3 +508,69 @@ def test_start_stop_zone_replication(test_empty_pd_balanced_disk, autodelete_dis
499508
)
500509
# Wait for the replication to stop
501510
time.sleep(20)
511+
512+
513+
def test_clone_disks_in_consistency_group(
514+
autodelete_regional_disk_name,
515+
autodelete_regional_blank_disk,
516+
):
517+
first = "first-group" + uuid.uuid4().hex[:5]
518+
create_consistency_group(PROJECT, REGION, first, "description")
519+
520+
add_disk_consistency_group(
521+
project_id=PROJECT,
522+
disk_name=autodelete_regional_blank_disk.name,
523+
disk_location=REGION,
524+
consistency_group_name=first,
525+
consistency_group_region=REGION,
526+
)
527+
528+
second_disk = create_secondary_region_disk(
529+
autodelete_regional_blank_disk.name,
530+
PROJECT,
531+
REGION,
532+
autodelete_regional_disk_name,
533+
PROJECT,
534+
REGION_SECONDARY,
535+
DISK_SIZE,
536+
)
537+
538+
second = "second-group" + uuid.uuid4().hex[:5]
539+
create_consistency_group(PROJECT, REGION_SECONDARY, second, "description")
540+
541+
add_disk_consistency_group(
542+
project_id=PROJECT,
543+
disk_name=second_disk.name,
544+
disk_location=REGION_SECONDARY,
545+
consistency_group_name=second,
546+
consistency_group_region=REGION_SECONDARY,
547+
)
548+
549+
start_disk_replication(
550+
project_id=PROJECT,
551+
primary_disk_location=REGION,
552+
primary_disk_name=autodelete_regional_blank_disk.name,
553+
secondary_disk_location=REGION_SECONDARY,
554+
secondary_disk_name=autodelete_regional_disk_name,
555+
)
556+
time.sleep(45)
557+
try:
558+
assert clone_disks_to_consistency_group(PROJECT, second, REGION_SECONDARY)
559+
finally:
560+
stop_disk_replication(
561+
project_id=PROJECT,
562+
primary_disk_location=REGION,
563+
primary_disk_name=autodelete_regional_blank_disk.name,
564+
)
565+
# Wait for the replication to stop
566+
time.sleep(30)
567+
disks = compute_v1.RegionDisksClient().list(
568+
project=PROJECT, region=REGION_SECONDARY
569+
)
570+
if disks:
571+
for disk in disks:
572+
delete_regional_disk(PROJECT, REGION_SECONDARY, disk.name)
573+
time.sleep(20)
574+
remove_disk_consistency_group(PROJECT, autodelete_regional_blank_disk.name, REGION, first, REGION)
575+
delete_consistency_group(PROJECT, REGION, first)
576+
delete_consistency_group(PROJECT, REGION_SECONDARY, second)

0 commit comments

Comments
 (0)