diff --git a/samples/ingredients/disks/autodelete_change.py b/samples/ingredients/disks/autodelete_change.py index 589fe75bf..4238c3094 100644 --- a/samples/ingredients/disks/autodelete_change.py +++ b/samples/ingredients/disks/autodelete_change.py @@ -46,16 +46,8 @@ def set_disk_autodelete(project_id: str, zone: str, instance_name: str, disk_nam disk.auto_delete = autodelete - operation = instance_client.update_unary(project=project_id, zone=zone, instance=instance_name, instance_resource=instance) - operation_client = compute_v1.ZoneOperationsClient() - operation = operation_client.wait(project=project_id, zone=zone, operation=operation.name) - - if operation.error: - print("Error during instance update:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during instance update:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + operation = instance_client.update(project=project_id, zone=zone, instance=instance_name, instance_resource=instance) + + wait_for_extended_operation(operation, "disk update") return # diff --git a/samples/ingredients/disks/create_empty_disk.py b/samples/ingredients/disks/create_empty_disk.py index 7422caf45..b06f283f0 100644 --- a/samples/ingredients/disks/create_empty_disk.py +++ b/samples/ingredients/disks/create_empty_disk.py @@ -47,17 +47,9 @@ def create_empty_disk( disk.type_ = disk_type disk_client = compute_v1.DisksClient() - operation = disk_client.insert_unary(project=project_id, zone=zone, disk_resource=disk) - operation_client = compute_v1.ZoneOperationsClient() - operation = operation_client.wait(project=project_id, zone=zone, operation=operation.name) - - if operation.error: - print("Error during disk creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during disk creation:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + operation = disk_client.insert(project=project_id, zone=zone, disk_resource=disk) + + wait_for_extended_operation(operation, "disk creation") return disk_client.get(project=project_id, zone=zone, disk=disk.name) # diff --git a/samples/ingredients/disks/create_from_image.py b/samples/ingredients/disks/create_from_image.py index c8e1bdce1..ab6ebf28e 100644 --- a/samples/ingredients/disks/create_from_image.py +++ b/samples/ingredients/disks/create_from_image.py @@ -51,17 +51,9 @@ def create_disk_from_image( disk.source_image = source_image disk_client = compute_v1.DisksClient() - operation = disk_client.insert_unary(project=project_id, zone=zone, disk_resource=disk) - operation_client = compute_v1.ZoneOperationsClient() - operation = operation_client.wait(project=project_id, zone=zone, operation=operation.name) + operation = disk_client.insert(project=project_id, zone=zone, disk_resource=disk) - if operation.error: - print("Error during disk creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during disk creation:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + wait_for_extended_operation(operation, "disk creation") return disk_client.get(project=project_id, zone=zone, disk=disk.name) # diff --git a/samples/ingredients/disks/create_from_snapshot.py b/samples/ingredients/disks/create_from_snapshot.py index 059ab0180..88a797512 100644 --- a/samples/ingredients/disks/create_from_snapshot.py +++ b/samples/ingredients/disks/create_from_snapshot.py @@ -48,18 +48,9 @@ def create_disk_from_snapshot(project_id: str, zone: str, disk_name: str, disk_t disk.source_snapshot = snapshot_link disk.type_ = disk_type disk.name = disk_name - operation = disk_client.insert_unary(project=project_id, zone=zone, disk_resource=disk) - operation_client = compute_v1.ZoneOperationsClient() - operation = operation_client.wait(project=project_id, zone=zone, operation=operation.name) + operation = disk_client.insert(project=project_id, zone=zone, disk_resource=disk) - if operation.error: - print("Error during disk creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - - if operation.warnings: - print("Warnings during disk creation:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + wait_for_extended_operation(operation, "disk creation") return disk_client.get(project=project_id, zone=zone, disk=disk_name) # diff --git a/samples/ingredients/disks/delete.py b/samples/ingredients/disks/delete.py index d66294ece..6b3788b94 100644 --- a/samples/ingredients/disks/delete.py +++ b/samples/ingredients/disks/delete.py @@ -33,16 +33,7 @@ def delete_disk(project_id: str, zone: str, disk_name: str) -> NoReturn: disk_name: name of the disk you want to delete. """ disk_client = compute_v1.DisksClient() - operation = disk_client.delete_unary(project=project_id, zone=zone, disk=disk_name) - operation_client = compute_v1.ZoneOperationsClient() - operation = operation_client.wait(project=project_id, zone=zone, operation=operation.name) - - if operation.error: - print("Error during disk delete operation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during disk delete operation:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + operation = disk_client.delete(project=project_id, zone=zone, disk=disk_name) + wait_for_extended_operation(operation, "disk deletion") return # diff --git a/samples/ingredients/firewall/create.py b/samples/ingredients/firewall/create.py index e6e9f0008..d6f17b090 100644 --- a/samples/ingredients/firewall/create.py +++ b/samples/ingredients/firewall/create.py @@ -16,6 +16,7 @@ # folder for complete code samples that are ready to be used. # Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check. # flake8: noqa + from google.cloud import compute_v1 @@ -61,12 +62,11 @@ def create_firewall_rule( # firewall_rule.priority = 0 firewall_client = compute_v1.FirewallsClient() - op = firewall_client.insert_unary( + operation = firewall_client.insert( project=project_id, firewall_resource=firewall_rule ) - op_client = compute_v1.GlobalOperationsClient() - op_client.wait(project=project_id, operation=op.name) + wait_for_extended_operation(operation, "firewall rule creation") return firewall_client.get(project=project_id, firewall=firewall_rule_name) # diff --git a/samples/ingredients/firewall/delete.py b/samples/ingredients/firewall/delete.py index fc6a42150..1f4b87031 100644 --- a/samples/ingredients/firewall/delete.py +++ b/samples/ingredients/firewall/delete.py @@ -16,6 +16,7 @@ # folder for complete code samples that are ready to be used. # Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check. # flake8: noqa + from google.cloud import compute_v1 @@ -29,11 +30,10 @@ def delete_firewall_rule(project_id: str, firewall_rule_name: str) -> None: firewall_rule_name: name of the firewall rule you want to delete. """ firewall_client = compute_v1.FirewallsClient() - operation = firewall_client.delete_unary( + operation = firewall_client.delete( project=project_id, firewall=firewall_rule_name ) - operation_client = compute_v1.GlobalOperationsClient() - operation_client.wait(project=project_id, operation=operation.name) + wait_for_extended_operation(operation, "firewall rule deletion") return # diff --git a/samples/ingredients/firewall/patch.py b/samples/ingredients/firewall/patch.py index 5017114a3..0c44979cd 100644 --- a/samples/ingredients/firewall/patch.py +++ b/samples/ingredients/firewall/patch.py @@ -16,6 +16,7 @@ # folder for complete code samples that are ready to be used. # Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check. # flake8: noqa + from google.cloud import compute_v1 @@ -35,12 +36,11 @@ def patch_firewall_priority(project_id: str, firewall_rule_name: str, priority: # The patch operation doesn't require the full definition of a Firewall object. It will only update # the values that were set in it, in this case it will only change the priority. firewall_client = compute_v1.FirewallsClient() - operation = firewall_client.patch_unary( + operation = firewall_client.patch( project=project_id, firewall=firewall_rule_name, firewall_resource=firewall_rule ) - operation_client = compute_v1.GlobalOperationsClient() - operation_client.wait(project=project_id, operation=operation.name) + wait_for_extended_operation(operation, "firewall rule patching") return # diff --git a/samples/ingredients/instance-templates/create.py b/samples/ingredients/instance-templates/create.py index ca56e99a8..9c79f8c76 100644 --- a/samples/ingredients/instance-templates/create.py +++ b/samples/ingredients/instance-templates/create.py @@ -16,6 +16,7 @@ # folder for complete code samples that are ready to be used. # Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check. # flake8: noqa +import sys from google.cloud import compute_v1 @@ -64,11 +65,11 @@ def create_template(project_id: str, template_name: str) -> compute_v1.InstanceT template.properties.network_interfaces = [network_interface] template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.insert_unary( + operation = template_client.insert( project=project_id, instance_template_resource=template ) - operation_client.wait(project=project_id, operation=op.name) + + wait_for_extended_operation(operation, "instance template creation") return template_client.get(project=project_id, instance_template=template_name) # diff --git a/samples/ingredients/instance-templates/create_from_instance.py b/samples/ingredients/instance-templates/create_from_instance.py index 584e2f177..1450cf02f 100644 --- a/samples/ingredients/instance-templates/create_from_instance.py +++ b/samples/ingredients/instance-templates/create_from_instance.py @@ -54,11 +54,11 @@ def create_template_from_instance( template.source_instance_params.disk_configs = [disk] template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.insert_unary( + operation = template_client.insert( project=project_id, instance_template_resource=template ) - operation_client.wait(project=project_id, operation=op.name) + + wait_for_extended_operation(operation, "instance template creation") return template_client.get(project=project_id, instance_template=template_name) # diff --git a/samples/ingredients/instance-templates/create_with_subnet.py b/samples/ingredients/instance-templates/create_with_subnet.py index fb80d2510..fd91bb3c9 100644 --- a/samples/ingredients/instance-templates/create_with_subnet.py +++ b/samples/ingredients/instance-templates/create_with_subnet.py @@ -63,11 +63,10 @@ def create_template_with_subnet( template.properties.network_interfaces = [network_interface] template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.insert_unary( + operation = template_client.insert( project=project_id, instance_template_resource=template ) - operation_client.wait(project=project_id, operation=op.name) + wait_for_extended_operation(operation, "instance template creation") return template_client.get(project=project_id, instance_template=template_name) # diff --git a/samples/ingredients/instance-templates/delete.py b/samples/ingredients/instance-templates/delete.py index 23bd929ee..f37206660 100644 --- a/samples/ingredients/instance-templates/delete.py +++ b/samples/ingredients/instance-templates/delete.py @@ -30,10 +30,9 @@ def delete_instance_template(project_id: str, template_name: str): template_name: name of the template to delete. """ template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.delete_unary( + operation = template_client.delete( project=project_id, instance_template=template_name ) - operation_client.wait(project=project_id, operation=op.name) + wait_for_extended_operation(operation, "instance template deletion") return # diff --git a/samples/ingredients/instances/create_instance.py b/samples/ingredients/instances/create_instance.py index 17ab8319b..f49fa6a98 100644 --- a/samples/ingredients/instances/create_instance.py +++ b/samples/ingredients/instances/create_instance.py @@ -18,11 +18,10 @@ # flake8: noqa import re -import sys -from google.cloud import compute_v1 -import time from typing import List +from google.cloud import compute_v1 + # def create_instance( @@ -79,7 +78,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -135,19 +133,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) # diff --git a/samples/ingredients/instances/create_instance_from_template.py b/samples/ingredients/instances/create_instance_from_template.py index 73ff814f4..b007f4f40 100644 --- a/samples/ingredients/instances/create_instance_from_template.py +++ b/samples/ingredients/instances/create_instance_from_template.py @@ -41,7 +41,6 @@ def create_instance_from_template( Returns: Instance object. """ - operation_client = compute_v1.ZoneOperationsClient() instance_client = compute_v1.InstancesClient() instance_insert_request = compute_v1.InsertInstanceRequest() @@ -50,8 +49,8 @@ def create_instance_from_template( instance_insert_request.source_instance_template = instance_template_url instance_insert_request.instance_resource.name = instance_name - op = instance_client.insert_unary(instance_insert_request) - operation_client.wait(project=project_id, zone=zone, operation=op.name) + operation = instance_client.insert(instance_insert_request) + wait_for_extended_operation(operation, "instance creation") return instance_client.get(project=project_id, zone=zone, instance=instance_name) # diff --git a/samples/ingredients/instances/create_instance_from_template_with_overrides.py b/samples/ingredients/instances/create_instance_from_template_with_overrides.py index 001cb5179..5920a0648 100644 --- a/samples/ingredients/instances/create_instance_from_template_with_overrides.py +++ b/samples/ingredients/instances/create_instance_from_template_with_overrides.py @@ -53,7 +53,6 @@ def create_instance_from_template_with_overrides( Returns: Instance object. """ - operation_client = compute_v1.ZoneOperationsClient() instance_client = compute_v1.InstancesClient() instance_template_client = compute_v1.InstanceTemplatesClient() @@ -90,8 +89,8 @@ def create_instance_from_template_with_overrides( instance_insert_request.instance_resource = instance instance_insert_request.source_instance_template = instance_template.self_link - op = instance_client.insert_unary(instance_insert_request) - operation_client.wait(project=project_id, zone=zone, operation=op.name) + operation = instance_client.insert(instance_insert_request) + wait_for_extended_operation(operation, "instance creation") return instance_client.get(project=project_id, zone=zone, instance=instance_name) # \ No newline at end of file diff --git a/samples/ingredients/instances/custom_machine_types/update_memory.py b/samples/ingredients/instances/custom_machine_types/update_memory.py index ee9ed2a75..fd1afac89 100644 --- a/samples/ingredients/instances/custom_machine_types/update_memory.py +++ b/samples/ingredients/instances/custom_machine_types/update_memory.py @@ -38,7 +38,6 @@ def add_extended_memory_to_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() instance = instance_client.get( project=project_id, zone=zone, instance=instance_name ) @@ -51,10 +50,10 @@ def add_extended_memory_to_instance( instance.Status.TERMINATED.name, instance.Status.STOPPED.name, ): - op = instance_client.stop_unary( + operation = instance_client.stop( project=project_id, zone=zone, instance=instance_name ) - operation_client.wait(project=project_id, zone=zone, operation=op.name) + wait_for_extended_operation(operation, "instance stopping") start = time.time() while instance.status not in ( instance.Status.TERMINATED.name, @@ -77,13 +76,13 @@ def add_extended_memory_to_instance( # cmt.memory_mb = new_memory # cmt.extra_memory_used = True # instance.machine_type = str(cmt) - op = instance_client.update_unary( + operation = instance_client.update( project=project_id, zone=zone, instance=instance_name, instance_resource=instance, ) - operation_client.wait(project=project_id, zone=zone, operation=op.name) + wait_for_extended_operation(operation, "instance update") return instance_client.get(project=project_id, zone=zone, instance=instance_name) # diff --git a/samples/ingredients/instances/delete.py b/samples/ingredients/instances/delete.py index ee84a349c..bd16d439a 100644 --- a/samples/ingredients/instances/delete.py +++ b/samples/ingredients/instances/delete.py @@ -33,24 +33,12 @@ def delete_instance(project_id: str, zone: str, machine_name: str) -> None: machine_name: name of the machine you want to delete. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() print(f"Deleting {machine_name} from {zone}...") - operation = instance_client.delete_unary( + operation = instance_client.delete( project=project_id, zone=zone, instance=machine_name ) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during deletion:", operation.error, file=sys.stderr) - return - if operation.warnings: - print("Warning during deletion:", operation.warnings, file=sys.stderr) + wait_for_extended_operation(operation, "instance deletion") print(f"Instance {machine_name} deleted.") return # diff --git a/samples/ingredients/instances/delete_protection/set.py b/samples/ingredients/instances/delete_protection/set.py index fd7bd4ca9..4d3a73a5b 100644 --- a/samples/ingredients/instances/delete_protection/set.py +++ b/samples/ingredients/instances/delete_protection/set.py @@ -33,7 +33,6 @@ def set_delete_protection( protected against deletion or not. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() request = compute_v1.SetDeletionProtectionInstanceRequest() request.project = project_id @@ -41,7 +40,7 @@ def set_delete_protection( request.resource = instance_name request.deletion_protection = delete_protection - operation = instance_client.set_deletion_protection_unary(request) - operation_client.wait(project=project_id, zone=zone, operation=operation.name) + operation = instance_client.set_deletion_protection(request) + wait_for_extended_operation(operation, "changing delete protection setting") return # diff --git a/samples/ingredients/instances/reset.py b/samples/ingredients/instances/reset.py index a0d29a1d9..f784e4b91 100644 --- a/samples/ingredients/instances/reset.py +++ b/samples/ingredients/instances/reset.py @@ -31,16 +31,12 @@ def reset_instance(project_id: str, zone: str, instance_name: str) -> None: instance_name: name of the instance your want to reset. """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() - op = instance_client.reset_unary( + operation = instance_client.reset( project=project_id, zone=zone, instance=instance_name ) - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance reset") + return # diff --git a/samples/ingredients/instances/resume.py b/samples/ingredients/instances/resume.py index 5762797b3..2dcfcd325 100644 --- a/samples/ingredients/instances/resume.py +++ b/samples/ingredients/instances/resume.py @@ -31,22 +31,17 @@ def resume_instance(project_id: str, zone: str, instance_name: str) -> None: instance_name: name of the instance your want to resume. """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() instance = instance_client.get(project=project_id, zone=zone, instance=instance_name) if instance.status != compute_v1.Instance.Status.SUSPENDED.name: raise RuntimeError(f"Only suspended instances can be resumed. " f"Instance {instance_name} is in {instance.status} state.") - op = instance_client.resume_unary( + operation = instance_client.resume( project=project_id, zone=zone, instance=instance_name ) - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance resumption") return # diff --git a/samples/ingredients/instances/start.py b/samples/ingredients/instances/start.py index a57359b10..eeba32eb7 100644 --- a/samples/ingredients/instances/start.py +++ b/samples/ingredients/instances/start.py @@ -31,16 +31,11 @@ def start_instance(project_id: str, zone: str, instance_name: str) -> None: instance_name: name of the instance your want to start. """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() - op = instance_client.start_unary( + operation = instance_client.start( project=project_id, zone=zone, instance=instance_name ) - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance start") return # diff --git a/samples/ingredients/instances/start_encrypted.py b/samples/ingredients/instances/start_encrypted.py index e90c56f2a..201d2233d 100644 --- a/samples/ingredients/instances/start_encrypted.py +++ b/samples/ingredients/instances/start_encrypted.py @@ -36,7 +36,6 @@ def start_instance_with_encryption_key( https://cloud.google.com/compute/docs/disks/customer-supplied-encryption#specifications """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() instance_data = instance_client.get( project=project_id, zone=zone, instance=instance_name @@ -52,17 +51,13 @@ def start_instance_with_encryption_key( enc_data = compute_v1.InstancesStartWithEncryptionKeyRequest() enc_data.disks = [disk_data] - op = instance_client.start_with_encryption_key_unary( + operation = instance_client.start_with_encryption_key( project=project_id, zone=zone, instance=instance_name, instances_start_with_encryption_key_request_resource=enc_data, ) - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance start (with encrypted disk)") return # diff --git a/samples/ingredients/instances/stop.py b/samples/ingredients/instances/stop.py index 903053348..ea1b532f8 100644 --- a/samples/ingredients/instances/stop.py +++ b/samples/ingredients/instances/stop.py @@ -31,16 +31,10 @@ def stop_instance(project_id: str, zone: str, instance_name: str) -> None: instance_name: name of the instance your want to stop. """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() - op = instance_client.stop_unary( + operation = instance_client.stop( project=project_id, zone=zone, instance=instance_name ) - - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance stopping") return # diff --git a/samples/ingredients/instances/suspend.py b/samples/ingredients/instances/suspend.py index 50550d112..d38cac81e 100644 --- a/samples/ingredients/instances/suspend.py +++ b/samples/ingredients/instances/suspend.py @@ -31,17 +31,12 @@ def suspend_instance(project_id: str, zone: str, instance_name: str) -> None: instance_name: name of the instance your want to suspend. """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() - op = instance_client.suspend_unary( + operation = instance_client.suspend( project=project_id, zone=zone, instance=instance_name ) - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance suspend") return # diff --git a/samples/ingredients/operations/handle_extended_operation.py b/samples/ingredients/operations/handle_extended_operation.py new file mode 100644 index 000000000..7c75c17f7 --- /dev/null +++ b/samples/ingredients/operations/handle_extended_operation.py @@ -0,0 +1,68 @@ +# Copyright 2022 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. + +# This is an ingredient file. It is not meant to be run directly. Check the samples/snippets +# folder for complete code samples that are ready to be used. +# Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check. +# flake8: noqa +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation + + +# +def wait_for_extended_operation( + operation: ExtendedOperation, + verbose_name: str = "operation", + timeout: int = 300) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print(f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", file=sys.stderr) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result +# diff --git a/samples/ingredients/operations/list_zone_operations.py b/samples/ingredients/operations/list_zone_operations.py index 7089f023f..472e893d5 100644 --- a/samples/ingredients/operations/list_zone_operations.py +++ b/samples/ingredients/operations/list_zone_operations.py @@ -43,4 +43,4 @@ def list_zone_operations( request.filter = filter return operation_client.list(request) -# \ No newline at end of file +# diff --git a/samples/ingredients/snapshots/create.py b/samples/ingredients/snapshots/create.py index 3e3b2a97c..1c876a206 100644 --- a/samples/ingredients/snapshots/create.py +++ b/samples/ingredients/snapshots/create.py @@ -16,7 +16,6 @@ # folder for complete code samples that are ready to be used. # Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check. # flake8: noqa -import sys from google.cloud import compute_v1 @@ -43,17 +42,9 @@ def create_snapshot(project_id: str, zone: str, disk_name: str, snapshot_name: s snapshot.name = snapshot_name snapshot_client = compute_v1.SnapshotsClient() - operation = snapshot_client.insert_unary(project=project_id, snapshot_resource=snapshot) - op_client = compute_v1.GlobalOperationsClient() - operation = op_client.wait(project=project_id, operation=operation.name) - - if operation.error: - print("Error during snapshot creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during snapshot creation:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + operation = snapshot_client.insert(project=project_id, snapshot_resource=snapshot) + + wait_for_extended_operation(operation, "snapshot creation") return snapshot_client.get(project=project_id, snapshot=snapshot_name) diff --git a/samples/ingredients/snapshots/delete.py b/samples/ingredients/snapshots/delete.py index dd3f1f29c..e7f5af9bc 100644 --- a/samples/ingredients/snapshots/delete.py +++ b/samples/ingredients/snapshots/delete.py @@ -16,7 +16,6 @@ # folder for complete code samples that are ready to be used. # Disabling flake8 for the ingredients file, as it would fail F821 - undefined name check. # flake8: noqa -import sys from typing import NoReturn from google.cloud import compute_v1 @@ -33,17 +32,9 @@ def delete_snapshot(project_id: str, snapshot_name: str) -> NoReturn: """ snapshot_client = compute_v1.SnapshotsClient() - operation = snapshot_client.delete_unary(project=project_id, snapshot=snapshot_name) - op_client = compute_v1.GlobalOperationsClient() - operation = op_client.wait(project=project_id, operation=operation.name) - - if operation.error: - print("Error during snapshot deletion:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during snapshot deletion:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + operation = snapshot_client.delete(project=project_id, snapshot=snapshot_name) + + wait_for_extended_operation(operation, "snapshot deletion") return # diff --git a/samples/ingredients/usage_report/disable.py b/samples/ingredients/usage_report/disable.py index e8d1464cb..4fc7ad6c1 100644 --- a/samples/ingredients/usage_report/disable.py +++ b/samples/ingredients/usage_report/disable.py @@ -31,13 +31,10 @@ def disable_usage_export(project_id: str) -> None: # Setting `usage_export_location_resource` to an # empty object will disable the usage report generation. - operation = projects_client.set_usage_export_bucket_unary( + operation = projects_client.set_usage_export_bucket( project=project_id, usage_export_location_resource={} ) - op_client = compute_v1.GlobalOperationsClient() - - while operation.status != compute_v1.Operation.Status.DONE: - operation = op_client.wait(operation=operation.name, project=project_id) + wait_for_extended_operation(operation, "disabling GCE usage bucket") # diff --git a/samples/ingredients/usage_report/set_bucket.py b/samples/ingredients/usage_report/set_bucket.py index 7a948c8b7..f308257df 100644 --- a/samples/ingredients/usage_report/set_bucket.py +++ b/samples/ingredients/usage_report/set_bucket.py @@ -49,13 +49,10 @@ def set_usage_export_bucket( ) projects_client = compute_v1.ProjectsClient() - operation = projects_client.set_usage_export_bucket_unary( + operation = projects_client.set_usage_export_bucket( project=project_id, usage_export_location_resource=usage_export_location ) - op_client = compute_v1.GlobalOperationsClient() - - while operation.status != compute_v1.Operation.Status.DONE: - operation = op_client.wait(operation=operation.name, project=project_id) + wait_for_extended_operation(operation, "setting GCE usage bucket") # diff --git a/samples/recipes/disks/autodelete_change.py b/samples/recipes/disks/autodelete_change.py index 33120f897..62465ac91 100644 --- a/samples/recipes/disks/autodelete_change.py +++ b/samples/recipes/disks/autodelete_change.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/disks/create_empty_disk.py b/samples/recipes/disks/create_empty_disk.py index 923f79d07..c044d56f3 100644 --- a/samples/recipes/disks/create_empty_disk.py +++ b/samples/recipes/disks/create_empty_disk.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/disks/create_from_image.py b/samples/recipes/disks/create_from_image.py index 407b4aa0d..a1aa318af 100644 --- a/samples/recipes/disks/create_from_image.py +++ b/samples/recipes/disks/create_from_image.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/disks/create_from_snapshot.py b/samples/recipes/disks/create_from_snapshot.py index c33060ca2..efc3e29cc 100644 --- a/samples/recipes/disks/create_from_snapshot.py +++ b/samples/recipes/disks/create_from_snapshot.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/disks/delete.py b/samples/recipes/disks/delete.py index e319a075c..c8bf1d904 100644 --- a/samples/recipes/disks/delete.py +++ b/samples/recipes/disks/delete.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/firewall/create.py b/samples/recipes/firewall/create.py index 8d76598fa..b4770f78a 100644 --- a/samples/recipes/firewall/create.py +++ b/samples/recipes/firewall/create.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/firewall/delete.py b/samples/recipes/firewall/delete.py index 6c3752fa6..ed25d5d1f 100644 --- a/samples/recipes/firewall/delete.py +++ b/samples/recipes/firewall/delete.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/firewall/patch.py b/samples/recipes/firewall/patch.py index 543157e1a..48b717308 100644 --- a/samples/recipes/firewall/patch.py +++ b/samples/recipes/firewall/patch.py @@ -16,5 +16,7 @@ # # +# + # # diff --git a/samples/recipes/instance_templates/create.py b/samples/recipes/instance_templates/create.py index 6c313c2d2..f3fe9d797 100644 --- a/samples/recipes/instance_templates/create.py +++ b/samples/recipes/instance_templates/create.py @@ -16,5 +16,7 @@ # # +# + # # diff --git a/samples/recipes/instance_templates/create_from_instance.py b/samples/recipes/instance_templates/create_from_instance.py index 751416fe3..2059793f3 100644 --- a/samples/recipes/instance_templates/create_from_instance.py +++ b/samples/recipes/instance_templates/create_from_instance.py @@ -16,5 +16,7 @@ # # +# + # # diff --git a/samples/recipes/instance_templates/create_with_subnet.py b/samples/recipes/instance_templates/create_with_subnet.py index 85639db00..0aeba05dd 100644 --- a/samples/recipes/instance_templates/create_with_subnet.py +++ b/samples/recipes/instance_templates/create_with_subnet.py @@ -16,5 +16,7 @@ # # +# + # # diff --git a/samples/recipes/instance_templates/delete.py b/samples/recipes/instance_templates/delete.py index bf774c57d..8a9743b61 100644 --- a/samples/recipes/instance_templates/delete.py +++ b/samples/recipes/instance_templates/delete.py @@ -16,5 +16,7 @@ # # +# + # # diff --git a/samples/recipes/instances/create.py b/samples/recipes/instances/create.py index b51a2e737..3f35a1e4c 100644 --- a/samples/recipes/instances/create.py +++ b/samples/recipes/instances/create.py @@ -20,6 +20,8 @@ # +# + # # diff --git a/samples/recipes/instances/create_start_instance/create_from_custom_image.py b/samples/recipes/instances/create_start_instance/create_from_custom_image.py index e50d60367..a093f8cb3 100644 --- a/samples/recipes/instances/create_start_instance/create_from_custom_image.py +++ b/samples/recipes/instances/create_start_instance/create_from_custom_image.py @@ -21,6 +21,8 @@ # +# + # diff --git a/samples/recipes/instances/create_start_instance/create_from_public_image.py b/samples/recipes/instances/create_start_instance/create_from_public_image.py index 6f6f0ee04..ac6f2d9bd 100644 --- a/samples/recipes/instances/create_start_instance/create_from_public_image.py +++ b/samples/recipes/instances/create_start_instance/create_from_public_image.py @@ -21,6 +21,8 @@ # +# + # diff --git a/samples/recipes/instances/create_start_instance/create_from_snapshot.py b/samples/recipes/instances/create_start_instance/create_from_snapshot.py index 2047eeb57..34d3e9a9b 100644 --- a/samples/recipes/instances/create_start_instance/create_from_snapshot.py +++ b/samples/recipes/instances/create_start_instance/create_from_snapshot.py @@ -18,6 +18,8 @@ # +# + # diff --git a/samples/recipes/instances/create_start_instance/create_with_additional_disk.py b/samples/recipes/instances/create_start_instance/create_with_additional_disk.py index ab9baa6e4..097cc1cf2 100644 --- a/samples/recipes/instances/create_start_instance/create_with_additional_disk.py +++ b/samples/recipes/instances/create_start_instance/create_with_additional_disk.py @@ -25,6 +25,8 @@ # +# + # diff --git a/samples/recipes/instances/create_start_instance/create_with_existing_disks.py b/samples/recipes/instances/create_start_instance/create_with_existing_disks.py index 3f6bf6ac2..dfa59eb36 100644 --- a/samples/recipes/instances/create_start_instance/create_with_existing_disks.py +++ b/samples/recipes/instances/create_start_instance/create_with_existing_disks.py @@ -19,6 +19,8 @@ # +# + # diff --git a/samples/recipes/instances/create_start_instance/create_with_snapshotted_data_disk.py b/samples/recipes/instances/create_start_instance/create_with_snapshotted_data_disk.py index 858e61884..19aec72dc 100644 --- a/samples/recipes/instances/create_start_instance/create_with_snapshotted_data_disk.py +++ b/samples/recipes/instances/create_start_instance/create_with_snapshotted_data_disk.py @@ -25,6 +25,8 @@ # +# + # diff --git a/samples/recipes/instances/create_with_subnet.py b/samples/recipes/instances/create_with_subnet.py index 906edca50..989e64483 100644 --- a/samples/recipes/instances/create_with_subnet.py +++ b/samples/recipes/instances/create_with_subnet.py @@ -21,6 +21,8 @@ # +# + # diff --git a/samples/recipes/instances/custom_hostname/create.py b/samples/recipes/instances/custom_hostname/create.py index 55f3b47e6..588c60382 100644 --- a/samples/recipes/instances/custom_hostname/create.py +++ b/samples/recipes/instances/custom_hostname/create.py @@ -21,6 +21,8 @@ # +# + # diff --git a/samples/recipes/instances/custom_machine_types/create_shared_with_helper.py b/samples/recipes/instances/custom_machine_types/create_shared_with_helper.py index 6adc80098..a4d355d4d 100644 --- a/samples/recipes/instances/custom_machine_types/create_shared_with_helper.py +++ b/samples/recipes/instances/custom_machine_types/create_shared_with_helper.py @@ -24,6 +24,8 @@ # +# + # diff --git a/samples/recipes/instances/custom_machine_types/create_with_helper.py b/samples/recipes/instances/custom_machine_types/create_with_helper.py index 0ea883cf5..8619e6822 100644 --- a/samples/recipes/instances/custom_machine_types/create_with_helper.py +++ b/samples/recipes/instances/custom_machine_types/create_with_helper.py @@ -25,6 +25,8 @@ # +# + # diff --git a/samples/recipes/instances/custom_machine_types/create_without_helper.py b/samples/recipes/instances/custom_machine_types/create_without_helper.py index e88388a82..6b99722f2 100644 --- a/samples/recipes/instances/custom_machine_types/create_without_helper.py +++ b/samples/recipes/instances/custom_machine_types/create_without_helper.py @@ -21,6 +21,8 @@ # +# + # diff --git a/samples/recipes/instances/custom_machine_types/extra_mem_no_helper.py b/samples/recipes/instances/custom_machine_types/extra_mem_no_helper.py index 68fdc2759..3b998965d 100644 --- a/samples/recipes/instances/custom_machine_types/extra_mem_no_helper.py +++ b/samples/recipes/instances/custom_machine_types/extra_mem_no_helper.py @@ -21,6 +21,8 @@ # +# + # diff --git a/samples/recipes/instances/custom_machine_types/update_memory.py b/samples/recipes/instances/custom_machine_types/update_memory.py index 5817cd987..4d6b2ced8 100644 --- a/samples/recipes/instances/custom_machine_types/update_memory.py +++ b/samples/recipes/instances/custom_machine_types/update_memory.py @@ -16,5 +16,7 @@ # # +# + # # diff --git a/samples/recipes/instances/delete.py b/samples/recipes/instances/delete.py index 68fc7f554..99cff9e25 100644 --- a/samples/recipes/instances/delete.py +++ b/samples/recipes/instances/delete.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/instances/delete_protection/create.py b/samples/recipes/instances/delete_protection/create.py index f1bb3a9b3..c45d757ea 100644 --- a/samples/recipes/instances/delete_protection/create.py +++ b/samples/recipes/instances/delete_protection/create.py @@ -21,6 +21,8 @@ # +# + # diff --git a/samples/recipes/instances/delete_protection/set.py b/samples/recipes/instances/delete_protection/set.py index 785e8f781..ebd5b5970 100644 --- a/samples/recipes/instances/delete_protection/set.py +++ b/samples/recipes/instances/delete_protection/set.py @@ -16,5 +16,7 @@ # # +# + # # diff --git a/samples/recipes/instances/from_instance_template/create_from_template.py b/samples/recipes/instances/from_instance_template/create_from_template.py index c296366cc..9a07cd10c 100644 --- a/samples/recipes/instances/from_instance_template/create_from_template.py +++ b/samples/recipes/instances/from_instance_template/create_from_template.py @@ -16,5 +16,7 @@ # # +# + # # diff --git a/samples/recipes/instances/from_instance_template/create_from_template_with_overrides.py b/samples/recipes/instances/from_instance_template/create_from_template_with_overrides.py index 27d1b2ae0..c4d5ca109 100644 --- a/samples/recipes/instances/from_instance_template/create_from_template_with_overrides.py +++ b/samples/recipes/instances/from_instance_template/create_from_template_with_overrides.py @@ -16,5 +16,7 @@ # # +# + # # diff --git a/samples/recipes/instances/preemptible/create_preemptible.py b/samples/recipes/instances/preemptible/create_preemptible.py index a61615412..18791d35d 100644 --- a/samples/recipes/instances/preemptible/create_preemptible.py +++ b/samples/recipes/instances/preemptible/create_preemptible.py @@ -21,6 +21,8 @@ # +# + # diff --git a/samples/recipes/instances/reset.py b/samples/recipes/instances/reset.py index 0842ed544..ce09f66e7 100644 --- a/samples/recipes/instances/reset.py +++ b/samples/recipes/instances/reset.py @@ -16,6 +16,7 @@ # # +# # # diff --git a/samples/recipes/instances/resume.py b/samples/recipes/instances/resume.py index 0165ccb9a..4cc8d7ef5 100644 --- a/samples/recipes/instances/resume.py +++ b/samples/recipes/instances/resume.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/instances/start.py b/samples/recipes/instances/start.py index 9ea6be08a..913680aa9 100644 --- a/samples/recipes/instances/start.py +++ b/samples/recipes/instances/start.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/instances/start_encrypted.py b/samples/recipes/instances/start_encrypted.py index 6833c644e..d6a0194bd 100644 --- a/samples/recipes/instances/start_encrypted.py +++ b/samples/recipes/instances/start_encrypted.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/instances/stop.py b/samples/recipes/instances/stop.py index 7dda8bcfa..49abe79a0 100644 --- a/samples/recipes/instances/stop.py +++ b/samples/recipes/instances/stop.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/instances/suspend.py b/samples/recipes/instances/suspend.py index 5f3baa0be..59c5b75f0 100644 --- a/samples/recipes/instances/suspend.py +++ b/samples/recipes/instances/suspend.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/snapshots/create.py b/samples/recipes/snapshots/create.py index b77eb7a98..5b54951b1 100644 --- a/samples/recipes/snapshots/create.py +++ b/samples/recipes/snapshots/create.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/snapshots/delete.py b/samples/recipes/snapshots/delete.py index ff8e89c8e..a9686d6d3 100644 --- a/samples/recipes/snapshots/delete.py +++ b/samples/recipes/snapshots/delete.py @@ -16,6 +16,8 @@ # # +# + # # diff --git a/samples/recipes/usage_report/usage_reports.py b/samples/recipes/usage_report/usage_reports.py index 4a293b800..d153b48d9 100644 --- a/samples/recipes/usage_report/usage_reports.py +++ b/samples/recipes/usage_report/usage_reports.py @@ -28,6 +28,9 @@ # + +# + # # @@ -40,6 +43,9 @@ # + +# + # # diff --git a/samples/snippets/disks/autodelete_change.py b/samples/snippets/disks/autodelete_change.py index 943564cd1..197e275d6 100644 --- a/samples/snippets/disks/autodelete_change.py +++ b/samples/snippets/disks/autodelete_change.py @@ -21,11 +21,58 @@ # [START compute_disk_autodelete_change] import sys -from typing import NoReturn +from typing import Any, NoReturn +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def set_disk_autodelete( project_id: str, zone: str, instance_name: str, disk_name: str, autodelete: bool ) -> NoReturn: @@ -54,24 +101,14 @@ def set_disk_autodelete( disk.auto_delete = autodelete - operation = instance_client.update_unary( + operation = instance_client.update( project=project_id, zone=zone, instance=instance_name, instance_resource=instance, ) - operation_client = compute_v1.ZoneOperationsClient() - operation = operation_client.wait( - project=project_id, zone=zone, operation=operation.name - ) - if operation.error: - print("Error during instance update:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during instance update:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + wait_for_extended_operation(operation, "disk update") return diff --git a/samples/snippets/disks/create_empty_disk.py b/samples/snippets/disks/create_empty_disk.py index d1352f861..ff86b77d0 100644 --- a/samples/snippets/disks/create_empty_disk.py +++ b/samples/snippets/disks/create_empty_disk.py @@ -21,10 +21,58 @@ # [START compute_disk_create_empty_disk] import sys +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_empty_disk( project_id: str, zone: str, disk_name: str, disk_type: str, disk_size_gb: int ) -> compute_v1.Disk: @@ -50,21 +98,9 @@ def create_empty_disk( disk.type_ = disk_type disk_client = compute_v1.DisksClient() - operation = disk_client.insert_unary( - project=project_id, zone=zone, disk_resource=disk - ) - operation_client = compute_v1.ZoneOperationsClient() - operation = operation_client.wait( - project=project_id, zone=zone, operation=operation.name - ) - - if operation.error: - print("Error during disk creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during disk creation:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + operation = disk_client.insert(project=project_id, zone=zone, disk_resource=disk) + + wait_for_extended_operation(operation, "disk creation") return disk_client.get(project=project_id, zone=zone, disk=disk.name) diff --git a/samples/snippets/disks/create_from_image.py b/samples/snippets/disks/create_from_image.py index 74e998ada..51ccb8e8c 100644 --- a/samples/snippets/disks/create_from_image.py +++ b/samples/snippets/disks/create_from_image.py @@ -21,10 +21,58 @@ # [START compute_disk_create_from_image] import sys +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_disk_from_image( project_id: str, zone: str, @@ -59,21 +107,9 @@ def create_disk_from_image( disk.source_image = source_image disk_client = compute_v1.DisksClient() - operation = disk_client.insert_unary( - project=project_id, zone=zone, disk_resource=disk - ) - operation_client = compute_v1.ZoneOperationsClient() - operation = operation_client.wait( - project=project_id, zone=zone, operation=operation.name - ) - - if operation.error: - print("Error during disk creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during disk creation:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + operation = disk_client.insert(project=project_id, zone=zone, disk_resource=disk) + + wait_for_extended_operation(operation, "disk creation") return disk_client.get(project=project_id, zone=zone, disk=disk.name) diff --git a/samples/snippets/disks/create_from_snapshot.py b/samples/snippets/disks/create_from_snapshot.py index 2421adb0f..8aef45ade 100644 --- a/samples/snippets/disks/create_from_snapshot.py +++ b/samples/snippets/disks/create_from_snapshot.py @@ -21,10 +21,58 @@ # [START compute_disk_create_from_snapshot] import sys +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_disk_from_snapshot( project_id: str, zone: str, @@ -57,22 +105,9 @@ def create_disk_from_snapshot( disk.source_snapshot = snapshot_link disk.type_ = disk_type disk.name = disk_name - operation = disk_client.insert_unary( - project=project_id, zone=zone, disk_resource=disk - ) - operation_client = compute_v1.ZoneOperationsClient() - operation = operation_client.wait( - project=project_id, zone=zone, operation=operation.name - ) - - if operation.error: - print("Error during disk creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) + operation = disk_client.insert(project=project_id, zone=zone, disk_resource=disk) - if operation.warnings: - print("Warnings during disk creation:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + wait_for_extended_operation(operation, "disk creation") return disk_client.get(project=project_id, zone=zone, disk=disk_name) diff --git a/samples/snippets/disks/delete.py b/samples/snippets/disks/delete.py index 0b5ea3cb3..f5c21d6fe 100644 --- a/samples/snippets/disks/delete.py +++ b/samples/snippets/disks/delete.py @@ -21,11 +21,58 @@ # [START compute_disk_delete] import sys -from typing import NoReturn +from typing import Any, NoReturn +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def delete_disk(project_id: str, zone: str, disk_name: str) -> NoReturn: """ Deletes a disk from a project. @@ -36,19 +83,8 @@ def delete_disk(project_id: str, zone: str, disk_name: str) -> NoReturn: disk_name: name of the disk you want to delete. """ disk_client = compute_v1.DisksClient() - operation = disk_client.delete_unary(project=project_id, zone=zone, disk=disk_name) - operation_client = compute_v1.ZoneOperationsClient() - operation = operation_client.wait( - project=project_id, zone=zone, operation=operation.name - ) - - if operation.error: - print("Error during disk delete operation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during disk delete operation:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + operation = disk_client.delete(project=project_id, zone=zone, disk=disk_name) + wait_for_extended_operation(operation, "disk deletion") return diff --git a/samples/snippets/firewall/create.py b/samples/snippets/firewall/create.py index 1eb230dea..8d80a08d8 100644 --- a/samples/snippets/firewall/create.py +++ b/samples/snippets/firewall/create.py @@ -20,9 +20,59 @@ # [START compute_firewall_create] +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_firewall_rule( project_id: str, firewall_rule_name: str, network: str = "global/networks/default" ) -> compute_v1.Firewall: @@ -64,12 +114,11 @@ def create_firewall_rule( # firewall_rule.priority = 0 firewall_client = compute_v1.FirewallsClient() - op = firewall_client.insert_unary( + operation = firewall_client.insert( project=project_id, firewall_resource=firewall_rule ) - op_client = compute_v1.GlobalOperationsClient() - op_client.wait(project=project_id, operation=op.name) + wait_for_extended_operation(operation, "firewall rule creation") return firewall_client.get(project=project_id, firewall=firewall_rule_name) diff --git a/samples/snippets/firewall/delete.py b/samples/snippets/firewall/delete.py index d606912a5..fe2c7c08e 100644 --- a/samples/snippets/firewall/delete.py +++ b/samples/snippets/firewall/delete.py @@ -20,9 +20,59 @@ # [START compute_firewall_delete] +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def delete_firewall_rule(project_id: str, firewall_rule_name: str) -> None: """ Deletes a firewall rule from the project. @@ -32,12 +82,9 @@ def delete_firewall_rule(project_id: str, firewall_rule_name: str) -> None: firewall_rule_name: name of the firewall rule you want to delete. """ firewall_client = compute_v1.FirewallsClient() - operation = firewall_client.delete_unary( - project=project_id, firewall=firewall_rule_name - ) + operation = firewall_client.delete(project=project_id, firewall=firewall_rule_name) - operation_client = compute_v1.GlobalOperationsClient() - operation_client.wait(project=project_id, operation=operation.name) + wait_for_extended_operation(operation, "firewall rule deletion") return diff --git a/samples/snippets/firewall/main.py b/samples/snippets/firewall/main.py index b53e677e0..b506328df 100644 --- a/samples/snippets/firewall/main.py +++ b/samples/snippets/firewall/main.py @@ -65,12 +65,11 @@ def create_firewall_rule( # firewall_rule.priority = 0 firewall_client = compute_v1.FirewallsClient() - op = firewall_client.insert_unary( + operation = firewall_client.insert( project=project_id, firewall_resource=firewall_rule ) - op_client = compute_v1.GlobalOperationsClient() - op_client.wait(project=project_id, operation=op.name) + wait_for_extended_operation(operation, "firewall rule creation") return firewall_client.get(project=project_id, firewall=firewall_rule_name) @@ -84,12 +83,9 @@ def delete_firewall_rule(project_id: str, firewall_rule_name: str) -> None: firewall_rule_name: name of the firewall rule you want to delete. """ firewall_client = compute_v1.FirewallsClient() - operation = firewall_client.delete_unary( - project=project_id, firewall=firewall_rule_name - ) + operation = firewall_client.delete(project=project_id, firewall=firewall_rule_name) - operation_client = compute_v1.GlobalOperationsClient() - operation_client.wait(project=project_id, operation=operation.name) + wait_for_extended_operation(operation, "firewall rule deletion") return @@ -145,12 +141,11 @@ def patch_firewall_priority( # The patch operation doesn't require the full definition of a Firewall object. It will only update # the values that were set in it, in this case it will only change the priority. firewall_client = compute_v1.FirewallsClient() - operation = firewall_client.patch_unary( + operation = firewall_client.patch( project=project_id, firewall=firewall_rule_name, firewall_resource=firewall_rule ) - operation_client = compute_v1.GlobalOperationsClient() - operation_client.wait(project=project_id, operation=operation.name) + wait_for_extended_operation(operation, "firewall rule patching") return diff --git a/samples/snippets/firewall/patch.py b/samples/snippets/firewall/patch.py index 9dbb823da..e81624dc9 100644 --- a/samples/snippets/firewall/patch.py +++ b/samples/snippets/firewall/patch.py @@ -20,9 +20,59 @@ # [START compute_firewall_patch] +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def patch_firewall_priority( project_id: str, firewall_rule_name: str, priority: int ) -> None: @@ -40,12 +90,11 @@ def patch_firewall_priority( # The patch operation doesn't require the full definition of a Firewall object. It will only update # the values that were set in it, in this case it will only change the priority. firewall_client = compute_v1.FirewallsClient() - operation = firewall_client.patch_unary( + operation = firewall_client.patch( project=project_id, firewall=firewall_rule_name, firewall_resource=firewall_rule ) - operation_client = compute_v1.GlobalOperationsClient() - operation_client.wait(project=project_id, operation=operation.name) + wait_for_extended_operation(operation, "firewall rule patching") return diff --git a/samples/snippets/instance_templates/create.py b/samples/snippets/instance_templates/create.py index f328bbfc1..4b63601c8 100644 --- a/samples/snippets/instance_templates/create.py +++ b/samples/snippets/instance_templates/create.py @@ -20,9 +20,59 @@ # [START compute_template_create] +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_template(project_id: str, template_name: str) -> compute_v1.InstanceTemplate: """ Create a new instance template with the provided name and a specific @@ -66,11 +116,11 @@ def create_template(project_id: str, template_name: str) -> compute_v1.InstanceT template.properties.network_interfaces = [network_interface] template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.insert_unary( + operation = template_client.insert( project=project_id, instance_template_resource=template ) - operation_client.wait(project=project_id, operation=op.name) + + wait_for_extended_operation(operation, "instance template creation") return template_client.get(project=project_id, instance_template=template_name) diff --git a/samples/snippets/instance_templates/create_from_instance.py b/samples/snippets/instance_templates/create_from_instance.py index 20afc7154..7ceff5074 100644 --- a/samples/snippets/instance_templates/create_from_instance.py +++ b/samples/snippets/instance_templates/create_from_instance.py @@ -20,9 +20,59 @@ # [START compute_template_create_from_instance] +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_template_from_instance( project_id: str, instance: str, template_name: str ) -> compute_v1.InstanceTemplate: @@ -56,11 +106,11 @@ def create_template_from_instance( template.source_instance_params.disk_configs = [disk] template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.insert_unary( + operation = template_client.insert( project=project_id, instance_template_resource=template ) - operation_client.wait(project=project_id, operation=op.name) + + wait_for_extended_operation(operation, "instance template creation") return template_client.get(project=project_id, instance_template=template_name) diff --git a/samples/snippets/instance_templates/create_with_subnet.py b/samples/snippets/instance_templates/create_with_subnet.py index ea6ddc191..922a0ec27 100644 --- a/samples/snippets/instance_templates/create_with_subnet.py +++ b/samples/snippets/instance_templates/create_with_subnet.py @@ -20,9 +20,59 @@ # [START compute_template_create_with_subnet] +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_template_with_subnet( project_id: str, network: str, subnetwork: str, template_name: str ) -> compute_v1.InstanceTemplate: @@ -65,11 +115,10 @@ def create_template_with_subnet( template.properties.network_interfaces = [network_interface] template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.insert_unary( + operation = template_client.insert( project=project_id, instance_template_resource=template ) - operation_client.wait(project=project_id, operation=op.name) + wait_for_extended_operation(operation, "instance template creation") return template_client.get(project=project_id, instance_template=template_name) diff --git a/samples/snippets/instance_templates/delete.py b/samples/snippets/instance_templates/delete.py index b0700c9ab..d024f70c9 100644 --- a/samples/snippets/instance_templates/delete.py +++ b/samples/snippets/instance_templates/delete.py @@ -20,9 +20,59 @@ # [START compute_template_delete] +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def delete_instance_template(project_id: str, template_name: str): """ Delete an instance template. @@ -32,11 +82,10 @@ def delete_instance_template(project_id: str, template_name: str): template_name: name of the template to delete. """ template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.delete_unary( + operation = template_client.delete( project=project_id, instance_template=template_name ) - operation_client.wait(project=project_id, operation=op.name) + wait_for_extended_operation(operation, "instance template deletion") return diff --git a/samples/snippets/instances/create.py b/samples/snippets/instances/create.py index efa0de173..512ed6176 100644 --- a/samples/snippets/instances/create.py +++ b/samples/snippets/instances/create.py @@ -22,9 +22,9 @@ # [START compute_instances_create] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -83,6 +83,52 @@ def disk_from_image( return boot_disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -137,7 +183,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -193,19 +238,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/create_start_instance/create_from_custom_image.py b/samples/snippets/instances/create_start_instance/create_from_custom_image.py index 59d32f08c..16dfa1b86 100644 --- a/samples/snippets/instances/create_start_instance/create_from_custom_image.py +++ b/samples/snippets/instances/create_start_instance/create_from_custom_image.py @@ -22,9 +22,9 @@ # [START compute_instances_create_from_custom_image] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -83,6 +83,52 @@ def disk_from_image( return boot_disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -137,7 +183,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -193,19 +238,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/create_start_instance/create_from_public_image.py b/samples/snippets/instances/create_start_instance/create_from_public_image.py index bfe848afa..881aa2c85 100644 --- a/samples/snippets/instances/create_start_instance/create_from_public_image.py +++ b/samples/snippets/instances/create_start_instance/create_from_public_image.py @@ -22,9 +22,9 @@ # [START compute_instances_create_from_image] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -83,6 +83,52 @@ def disk_from_image( return boot_disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -137,7 +183,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -193,19 +238,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/create_start_instance/create_from_snapshot.py b/samples/snippets/instances/create_start_instance/create_from_snapshot.py index 2c6996ed8..f7397b0ad 100644 --- a/samples/snippets/instances/create_start_instance/create_from_snapshot.py +++ b/samples/snippets/instances/create_start_instance/create_from_snapshot.py @@ -22,9 +22,9 @@ # [START compute_instances_create_from_snapshot] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -65,6 +65,52 @@ def disk_from_snapshot( return disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -119,7 +165,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -175,19 +220,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/create_start_instance/create_with_additional_disk.py b/samples/snippets/instances/create_start_instance/create_with_additional_disk.py index a14005eb5..b506a9f09 100644 --- a/samples/snippets/instances/create_start_instance/create_with_additional_disk.py +++ b/samples/snippets/instances/create_start_instance/create_with_additional_disk.py @@ -22,9 +22,9 @@ # [START compute_instances_create_from_image_plus_empty_disk] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -113,6 +113,52 @@ def empty_disk( return disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -167,7 +213,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -223,19 +268,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/create_start_instance/create_with_existing_disks.py b/samples/snippets/instances/create_start_instance/create_with_existing_disks.py index df36012ea..121582d91 100644 --- a/samples/snippets/instances/create_start_instance/create_with_existing_disks.py +++ b/samples/snippets/instances/create_start_instance/create_with_existing_disks.py @@ -22,9 +22,9 @@ # [START compute_instances_create_with_existing_disks] import re import sys -import time -from typing import Iterable, List, NoReturn +from typing import Any, Iterable, List, NoReturn +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -41,6 +41,52 @@ def get_disk(project_id: str, zone: str, disk_name: str) -> compute_v1.Disk: return disk_client.get(project=project_id, zone=zone, disk=disk_name) +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -95,7 +141,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -151,19 +196,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/create_start_instance/create_with_snapshotted_data_disk.py b/samples/snippets/instances/create_start_instance/create_with_snapshotted_data_disk.py index 0385c17ab..dbffbb174 100644 --- a/samples/snippets/instances/create_start_instance/create_with_snapshotted_data_disk.py +++ b/samples/snippets/instances/create_start_instance/create_with_snapshotted_data_disk.py @@ -22,9 +22,9 @@ # [START compute_instances_create_from_image_plus_snapshot_disk] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -120,6 +120,52 @@ def disk_from_snapshot( return disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -174,7 +220,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -230,19 +275,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/create_with_subnet.py b/samples/snippets/instances/create_with_subnet.py index 27a52a9f7..3c28b8470 100644 --- a/samples/snippets/instances/create_with_subnet.py +++ b/samples/snippets/instances/create_with_subnet.py @@ -22,9 +22,9 @@ # [START compute_instances_create_with_subnet] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -83,6 +83,52 @@ def disk_from_image( return boot_disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -137,7 +183,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -193,19 +238,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/custom_hostname/create.py b/samples/snippets/instances/custom_hostname/create.py index 699f6397e..377a3169f 100644 --- a/samples/snippets/instances/custom_hostname/create.py +++ b/samples/snippets/instances/custom_hostname/create.py @@ -22,9 +22,9 @@ # [START compute_instances_create_custom_hostname] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -83,6 +83,52 @@ def disk_from_image( return boot_disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -137,7 +183,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -193,19 +238,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/custom_machine_types/create_shared_with_helper.py b/samples/snippets/instances/custom_machine_types/create_shared_with_helper.py index 7674013d4..4f37ae2a2 100644 --- a/samples/snippets/instances/custom_machine_types/create_shared_with_helper.py +++ b/samples/snippets/instances/custom_machine_types/create_shared_with_helper.py @@ -25,9 +25,9 @@ from enum import unique import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -277,6 +277,52 @@ def disk_from_image( return boot_disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -331,7 +377,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -387,19 +432,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/custom_machine_types/create_with_helper.py b/samples/snippets/instances/custom_machine_types/create_with_helper.py index 5821f160b..499c63059 100644 --- a/samples/snippets/instances/custom_machine_types/create_with_helper.py +++ b/samples/snippets/instances/custom_machine_types/create_with_helper.py @@ -25,9 +25,9 @@ from enum import unique import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -277,6 +277,52 @@ def disk_from_image( return boot_disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -331,7 +377,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -387,19 +432,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/custom_machine_types/create_without_helper.py b/samples/snippets/instances/custom_machine_types/create_without_helper.py index 54e208b6d..d7e13d8c1 100644 --- a/samples/snippets/instances/custom_machine_types/create_without_helper.py +++ b/samples/snippets/instances/custom_machine_types/create_without_helper.py @@ -22,9 +22,9 @@ # [START compute_custom_machine_type_create_without_helper] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -83,6 +83,52 @@ def disk_from_image( return boot_disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -137,7 +183,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -193,19 +238,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/custom_machine_types/extra_mem_no_helper.py b/samples/snippets/instances/custom_machine_types/extra_mem_no_helper.py index 9449ef11f..059750328 100644 --- a/samples/snippets/instances/custom_machine_types/extra_mem_no_helper.py +++ b/samples/snippets/instances/custom_machine_types/extra_mem_no_helper.py @@ -22,9 +22,9 @@ # [START compute_custom_machine_type_extra_mem_no_helper] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -83,6 +83,52 @@ def disk_from_image( return boot_disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -137,7 +183,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -193,19 +238,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/custom_machine_types/update_memory.py b/samples/snippets/instances/custom_machine_types/update_memory.py index b65c94344..b61a2a2b5 100644 --- a/samples/snippets/instances/custom_machine_types/update_memory.py +++ b/samples/snippets/instances/custom_machine_types/update_memory.py @@ -20,11 +20,60 @@ # [START compute_custom_machine_type_update_memory] +import sys import time +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def add_extended_memory_to_instance( project_id: str, zone: str, instance_name: str, new_memory: int ): @@ -41,7 +90,6 @@ def add_extended_memory_to_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() instance = instance_client.get( project=project_id, zone=zone, instance=instance_name ) @@ -58,10 +106,10 @@ def add_extended_memory_to_instance( instance.Status.TERMINATED.name, instance.Status.STOPPED.name, ): - op = instance_client.stop_unary( + operation = instance_client.stop( project=project_id, zone=zone, instance=instance_name ) - operation_client.wait(project=project_id, zone=zone, operation=op.name) + wait_for_extended_operation(operation, "instance stopping") start = time.time() while instance.status not in ( instance.Status.TERMINATED.name, @@ -84,13 +132,13 @@ def add_extended_memory_to_instance( # cmt.memory_mb = new_memory # cmt.extra_memory_used = True # instance.machine_type = str(cmt) - op = instance_client.update_unary( + operation = instance_client.update( project=project_id, zone=zone, instance=instance_name, instance_resource=instance, ) - operation_client.wait(project=project_id, zone=zone, operation=op.name) + wait_for_extended_operation(operation, "instance update") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/delete.py b/samples/snippets/instances/delete.py index 55cdfe9c7..af8474558 100644 --- a/samples/snippets/instances/delete.py +++ b/samples/snippets/instances/delete.py @@ -22,10 +22,58 @@ # [START compute_instances_delete] import sys import time +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def delete_instance(project_id: str, zone: str, machine_name: str) -> None: """ Send an instance deletion request to the Compute Engine API and wait for it to complete. @@ -36,24 +84,12 @@ def delete_instance(project_id: str, zone: str, machine_name: str) -> None: machine_name: name of the machine you want to delete. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() print(f"Deleting {machine_name} from {zone}...") - operation = instance_client.delete_unary( + operation = instance_client.delete( project=project_id, zone=zone, instance=machine_name ) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during deletion:", operation.error, file=sys.stderr) - return - if operation.warnings: - print("Warning during deletion:", operation.warnings, file=sys.stderr) + wait_for_extended_operation(operation, "instance deletion") print(f"Instance {machine_name} deleted.") return diff --git a/samples/snippets/instances/delete_protection/create.py b/samples/snippets/instances/delete_protection/create.py index 15d31f102..fe9d26e60 100644 --- a/samples/snippets/instances/delete_protection/create.py +++ b/samples/snippets/instances/delete_protection/create.py @@ -22,9 +22,9 @@ # [START compute_delete_protection_create] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -83,6 +83,52 @@ def disk_from_image( return boot_disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -137,7 +183,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -193,19 +238,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/delete_protection/set.py b/samples/snippets/instances/delete_protection/set.py index 47c3b35ba..3a6008306 100644 --- a/samples/snippets/instances/delete_protection/set.py +++ b/samples/snippets/instances/delete_protection/set.py @@ -20,9 +20,59 @@ # [START compute_delete_protection_set] +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def set_delete_protection( project_id: str, zone: str, instance_name: str, delete_protection: bool ) -> None: @@ -36,7 +86,6 @@ def set_delete_protection( protected against deletion or not. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() request = compute_v1.SetDeletionProtectionInstanceRequest() request.project = project_id @@ -44,8 +93,8 @@ def set_delete_protection( request.resource = instance_name request.deletion_protection = delete_protection - operation = instance_client.set_deletion_protection_unary(request) - operation_client.wait(project=project_id, zone=zone, operation=operation.name) + operation = instance_client.set_deletion_protection(request) + wait_for_extended_operation(operation, "changing delete protection setting") return diff --git a/samples/snippets/instances/from_instance_template/create_from_template.py b/samples/snippets/instances/from_instance_template/create_from_template.py index 6310cfd11..3abd6cc46 100644 --- a/samples/snippets/instances/from_instance_template/create_from_template.py +++ b/samples/snippets/instances/from_instance_template/create_from_template.py @@ -20,9 +20,59 @@ # [START compute_instances_create_from_template] +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance_from_template( project_id: str, zone: str, instance_name: str, instance_template_url: str ) -> compute_v1.Instance: @@ -43,7 +93,6 @@ def create_instance_from_template( Returns: Instance object. """ - operation_client = compute_v1.ZoneOperationsClient() instance_client = compute_v1.InstancesClient() instance_insert_request = compute_v1.InsertInstanceRequest() @@ -52,8 +101,8 @@ def create_instance_from_template( instance_insert_request.source_instance_template = instance_template_url instance_insert_request.instance_resource.name = instance_name - op = instance_client.insert_unary(instance_insert_request) - operation_client.wait(project=project_id, zone=zone, operation=op.name) + operation = instance_client.insert(instance_insert_request) + wait_for_extended_operation(operation, "instance creation") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/from_instance_template/create_from_template_with_overrides.py b/samples/snippets/instances/from_instance_template/create_from_template_with_overrides.py index 6f76d3290..eca6f0a49 100644 --- a/samples/snippets/instances/from_instance_template/create_from_template_with_overrides.py +++ b/samples/snippets/instances/from_instance_template/create_from_template_with_overrides.py @@ -20,9 +20,59 @@ # [START compute_instances_create_from_template_with_overrides] +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance_from_template_with_overrides( project_id: str, zone: str, @@ -55,7 +105,6 @@ def create_instance_from_template_with_overrides( Returns: Instance object. """ - operation_client = compute_v1.ZoneOperationsClient() instance_client = compute_v1.InstancesClient() instance_template_client = compute_v1.InstanceTemplatesClient() @@ -92,8 +141,8 @@ def create_instance_from_template_with_overrides( instance_insert_request.instance_resource = instance instance_insert_request.source_instance_template = instance_template.self_link - op = instance_client.insert_unary(instance_insert_request) - operation_client.wait(project=project_id, zone=zone, operation=op.name) + operation = instance_client.insert(instance_insert_request) + wait_for_extended_operation(operation, "instance creation") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/preemptible/create_preemptible.py b/samples/snippets/instances/preemptible/create_preemptible.py index 5cc7ff47d..3e2ef4b89 100644 --- a/samples/snippets/instances/preemptible/create_preemptible.py +++ b/samples/snippets/instances/preemptible/create_preemptible.py @@ -22,9 +22,9 @@ # [START compute_preemptible_create] import re import sys -import time -from typing import List +from typing import Any, List +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -83,6 +83,52 @@ def disk_from_image( return boot_disk +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_instance( project_id: str, zone: str, @@ -137,7 +183,6 @@ def create_instance( Instance object. """ instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() @@ -193,19 +238,10 @@ def create_instance( # Wait for the create operation to complete. print(f"Creating the {instance_name} instance in {zone}...") - operation = instance_client.insert_unary(request=request) - start = time.time() - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) + operation = instance_client.insert(request=request) + + wait_for_extended_operation(operation, "instance creation") + print(f"Instance {instance_name} created.") return instance_client.get(project=project_id, zone=zone, instance=instance_name) diff --git a/samples/snippets/instances/reset.py b/samples/snippets/instances/reset.py index a04003f17..1764ab632 100644 --- a/samples/snippets/instances/reset.py +++ b/samples/snippets/instances/reset.py @@ -20,11 +20,60 @@ # [START compute_reset_instance] +import sys import time +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def reset_instance(project_id: str, zone: str, instance_name: str) -> None: """ Resets a stopped Google Compute Engine instance (with unencrypted disks). @@ -34,17 +83,13 @@ def reset_instance(project_id: str, zone: str, instance_name: str) -> None: instance_name: name of the instance your want to reset. """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() - op = instance_client.reset_unary( + operation = instance_client.reset( project=project_id, zone=zone, instance=instance_name ) - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance reset") + return diff --git a/samples/snippets/instances/resume.py b/samples/snippets/instances/resume.py index a55b2fafe..2c6cf68cb 100644 --- a/samples/snippets/instances/resume.py +++ b/samples/snippets/instances/resume.py @@ -20,11 +20,60 @@ # [START compute_resume_instance] +import sys import time +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def resume_instance(project_id: str, zone: str, instance_name: str) -> None: """ Resume a suspended Google Compute Engine instance (with unencrypted disks). @@ -34,7 +83,6 @@ def resume_instance(project_id: str, zone: str, instance_name: str) -> None: instance_name: name of the instance your want to resume. """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() instance = instance_client.get( project=project_id, zone=zone, instance=instance_name @@ -45,15 +93,11 @@ def resume_instance(project_id: str, zone: str, instance_name: str) -> None: f"Instance {instance_name} is in {instance.status} state." ) - op = instance_client.resume_unary( + operation = instance_client.resume( project=project_id, zone=zone, instance=instance_name ) - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance resumption") return diff --git a/samples/snippets/instances/start.py b/samples/snippets/instances/start.py index 4548a8cd9..9dbf039ae 100644 --- a/samples/snippets/instances/start.py +++ b/samples/snippets/instances/start.py @@ -20,11 +20,60 @@ # [START compute_start_instance] +import sys import time +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def start_instance(project_id: str, zone: str, instance_name: str) -> None: """ Starts a stopped Google Compute Engine instance (with unencrypted disks). @@ -34,17 +83,12 @@ def start_instance(project_id: str, zone: str, instance_name: str) -> None: instance_name: name of the instance your want to start. """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() - op = instance_client.start_unary( + operation = instance_client.start( project=project_id, zone=zone, instance=instance_name ) - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance start") return diff --git a/samples/snippets/instances/start_encrypted.py b/samples/snippets/instances/start_encrypted.py index 401b2b0cc..ef08fb1dd 100644 --- a/samples/snippets/instances/start_encrypted.py +++ b/samples/snippets/instances/start_encrypted.py @@ -20,11 +20,60 @@ # [START compute_start_enc_instance] +import sys import time +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def start_instance_with_encryption_key( project_id: str, zone: str, instance_name: str, key: bytes ): @@ -39,7 +88,6 @@ def start_instance_with_encryption_key( https://cloud.google.com/compute/docs/disks/customer-supplied-encryption#specifications """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() instance_data = instance_client.get( project=project_id, zone=zone, instance=instance_name @@ -55,18 +103,14 @@ def start_instance_with_encryption_key( enc_data = compute_v1.InstancesStartWithEncryptionKeyRequest() enc_data.disks = [disk_data] - op = instance_client.start_with_encryption_key_unary( + operation = instance_client.start_with_encryption_key( project=project_id, zone=zone, instance=instance_name, instances_start_with_encryption_key_request_resource=enc_data, ) - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance start (with encrypted disk)") return diff --git a/samples/snippets/instances/stop.py b/samples/snippets/instances/stop.py index b8b2f8b4e..7cbaeb16b 100644 --- a/samples/snippets/instances/stop.py +++ b/samples/snippets/instances/stop.py @@ -20,11 +20,60 @@ # [START compute_stop_instance] +import sys import time +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def stop_instance(project_id: str, zone: str, instance_name: str) -> None: """ Stops a running Google Compute Engine instance. @@ -34,17 +83,11 @@ def stop_instance(project_id: str, zone: str, instance_name: str) -> None: instance_name: name of the instance your want to stop. """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() - op = instance_client.stop_unary( + operation = instance_client.stop( project=project_id, zone=zone, instance=instance_name ) - - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance stopping") return diff --git a/samples/snippets/instances/suspend.py b/samples/snippets/instances/suspend.py index 4427176a0..bf4a4c30d 100644 --- a/samples/snippets/instances/suspend.py +++ b/samples/snippets/instances/suspend.py @@ -20,11 +20,60 @@ # [START compute_suspend_instance] +import sys import time +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def suspend_instance(project_id: str, zone: str, instance_name: str) -> None: """ Suspend a running Google Compute Engine instance. @@ -34,17 +83,12 @@ def suspend_instance(project_id: str, zone: str, instance_name: str) -> None: instance_name: name of the instance your want to suspend. """ instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() - op = instance_client.suspend_unary( + operation = instance_client.suspend( project=project_id, zone=zone, instance=instance_name ) - start = time.time() - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - if time.time() - start >= 300: # 5 minutes - raise TimeoutError() + wait_for_extended_operation(operation, "instance suspend") return diff --git a/samples/snippets/snapshots/create.py b/samples/snippets/snapshots/create.py index adfdf8e28..0e9a472df 100644 --- a/samples/snippets/snapshots/create.py +++ b/samples/snippets/snapshots/create.py @@ -21,10 +21,58 @@ # [START compute_snapshot_create] import sys +from typing import Any +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def create_snapshot( project_id: str, zone: str, disk_name: str, snapshot_name: str ) -> compute_v1.Snapshot: @@ -47,19 +95,9 @@ def create_snapshot( snapshot.name = snapshot_name snapshot_client = compute_v1.SnapshotsClient() - operation = snapshot_client.insert_unary( - project=project_id, snapshot_resource=snapshot - ) - op_client = compute_v1.GlobalOperationsClient() - operation = op_client.wait(project=project_id, operation=operation.name) - - if operation.error: - print("Error during snapshot creation:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during snapshot creation:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + operation = snapshot_client.insert(project=project_id, snapshot_resource=snapshot) + + wait_for_extended_operation(operation, "snapshot creation") return snapshot_client.get(project=project_id, snapshot=snapshot_name) diff --git a/samples/snippets/snapshots/delete.py b/samples/snippets/snapshots/delete.py index ffa0abab5..ebbf0e04b 100644 --- a/samples/snippets/snapshots/delete.py +++ b/samples/snippets/snapshots/delete.py @@ -21,11 +21,58 @@ # [START compute_snapshot_delete] import sys -from typing import NoReturn +from typing import Any, NoReturn +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def delete_snapshot(project_id: str, snapshot_name: str) -> NoReturn: """ Delete a snapshot of a disk. @@ -36,17 +83,9 @@ def delete_snapshot(project_id: str, snapshot_name: str) -> NoReturn: """ snapshot_client = compute_v1.SnapshotsClient() - operation = snapshot_client.delete_unary(project=project_id, snapshot=snapshot_name) - op_client = compute_v1.GlobalOperationsClient() - operation = op_client.wait(project=project_id, operation=operation.name) + operation = snapshot_client.delete(project=project_id, snapshot=snapshot_name) - if operation.error: - print("Error during snapshot deletion:", operation.error, file=sys.stderr) - raise RuntimeError(operation.error) - if operation.warnings: - print("Warnings during snapshot deletion:\n", file=sys.stderr) - for warning in operation.warnings: - print(f" - {warning.code}: {warning.message}", file=sys.stderr) + wait_for_extended_operation(operation, "snapshot deletion") return diff --git a/samples/snippets/tests/test_create_vm.py b/samples/snippets/tests/test_create_vm.py index fbda262ea..58382ed92 100644 --- a/samples/snippets/tests/test_create_vm.py +++ b/samples/snippets/tests/test_create_vm.py @@ -230,9 +230,6 @@ def test_create_with_existing_disks(boot_disk, empty_disk): [boot_disk.name, empty_disk.name]) try: - print(instance.disks) - for disk in instance.disks: - print(disk, dir(disk), type(disk), disk.disk_size_gb) assert any( disk.disk_size_gb == 13 for disk in instance.disks ) diff --git a/samples/snippets/usage_report/usage_reports.py b/samples/snippets/usage_report/usage_reports.py index 85e5ea9cd..1c89bf3e8 100644 --- a/samples/snippets/usage_report/usage_reports.py +++ b/samples/snippets/usage_report/usage_reports.py @@ -26,6 +26,10 @@ # [START compute_usage_report_set] # [START compute_usage_report_get] # [START compute_usage_report_disable] +import sys +from typing import Any + +from google.api_core.extended_operation import ExtendedOperation from google.cloud import compute_v1 @@ -35,6 +39,54 @@ # [START compute_usage_report_set] + + +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def set_usage_export_bucket( project_id: str, bucket_name: str, report_name_prefix: str = "" ) -> None: @@ -64,14 +116,11 @@ def set_usage_export_bucket( ) projects_client = compute_v1.ProjectsClient() - operation = projects_client.set_usage_export_bucket_unary( + operation = projects_client.set_usage_export_bucket( project=project_id, usage_export_location_resource=usage_export_location ) - op_client = compute_v1.GlobalOperationsClient() - - while operation.status != compute_v1.Operation.Status.DONE: - operation = op_client.wait(operation=operation.name, project=project_id) + wait_for_extended_operation(operation, "setting GCE usage bucket") # [END compute_usage_report_set] @@ -115,6 +164,54 @@ def get_usage_export_bucket(project_id: str) -> compute_v1.UsageExportLocation: # [START compute_usage_report_disable] + + +def wait_for_extended_operation( + operation: ExtendedOperation, verbose_name: str = "operation", timeout: int = 300 +) -> Any: + """ + This method will wait for the extended (long-running) operation to + complete. If the operation is successful, it will return its result. + If the operation ends with an error, an exception will be raised. + If there were any warnings during the execution of the operation + they will be printed to sys.stderr. + + Args: + operation: a long-running operation you want to wait on. + verbose_name: (optional) a more verbose name of the operation, + used only during error and warning reporting. + timeout: how long (in seconds) to wait for operation to finish. + If None, wait indefinitely. + + Returns: + Whatever the operation.result() returns. + + Raises: + This method will raise the exception received from `operation.exception()` + or RuntimeError if there is no exception set, but there is an `error_code` + set for the `operation`. + + In case of an operation taking longer than `timeout` seconds to complete, + a `concurrent.futures.TimeoutError` will be raised. + """ + result = operation.result(timeout=timeout) + + if operation.error_code: + print( + f"Error during {verbose_name}: [Code: {operation.error_code}]: {operation.error_message}", + file=sys.stderr, + ) + print(f"Operation ID: {operation.name}") + raise operation.exception() or RuntimeError(operation.error_message) + + if operation.warnings: + print(f"Warnings during {verbose_name}:\n", file=sys.stderr) + for warning in operation.warnings: + print(f" - {warning.code}: {warning.message}", file=sys.stderr) + + return result + + def disable_usage_export(project_id: str) -> None: """ Disable Compute Engine usage export bucket for the Cloud Project. @@ -126,14 +223,11 @@ def disable_usage_export(project_id: str) -> None: # Setting `usage_export_location_resource` to an # empty object will disable the usage report generation. - operation = projects_client.set_usage_export_bucket_unary( + operation = projects_client.set_usage_export_bucket( project=project_id, usage_export_location_resource={} ) - op_client = compute_v1.GlobalOperationsClient() - - while operation.status != compute_v1.Operation.Status.DONE: - operation = op_client.wait(operation=operation.name, project=project_id) + wait_for_extended_operation(operation, "disabling GCE usage bucket") # [END compute_usage_report_disable]