diff --git a/compute/compute/ingredients/disks/create_empty_disk.py b/compute/compute/ingredients/disks/create_empty_disk.py new file mode 100644 index 000000000000..7422caf45e61 --- /dev/null +++ b/compute/compute/ingredients/disks/create_empty_disk.py @@ -0,0 +1,63 @@ +# 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 google.cloud import compute_v1 + + +# +def create_empty_disk( + project_id: str, zone: str, disk_name: str, disk_type: str, disk_size_gb: int +) -> compute_v1.Disk: + """ + Creates a new empty disk in a project in given zone. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + zone: name of the zone in which you want to create the disk. + disk_name: name of the disk you want to create. + disk_type: the type of disk you want to create. This value uses the following format: + "zones/{zone}/diskTypes/(pd-standard|pd-ssd|pd-balanced|pd-extreme)". + For example: "zones/us-west3-b/diskTypes/pd-ssd" + disk_size_gb: size of the new disk in gigabytes + + Returns: + An unattached Disk instance. + """ + disk = compute_v1.Disk() + disk.size_gb = disk_size_gb + disk.name = disk_name + disk.zone = zone + 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) + + return disk_client.get(project=project_id, zone=zone, disk=disk.name) +# diff --git a/compute/compute/ingredients/disks/disk_from_snapshot.py b/compute/compute/ingredients/disks/disk_from_snapshot.py index e0271c47bc46..f7abd0c5a68d 100644 --- a/compute/compute/ingredients/disks/disk_from_snapshot.py +++ b/compute/compute/ingredients/disks/disk_from_snapshot.py @@ -21,7 +21,7 @@ # def disk_from_snapshot( - disk_type: str, disk_size_gb: int, boot: bool, source_snapshot: str, auto_delete: bool = False + disk_type: str, disk_size_gb: int, boot: bool, source_snapshot: str, auto_delete: bool = True ) -> compute_v1.AttachedDisk(): """ Create an AttachedDisk object to be used in VM instance creation. Uses a disk snapshot as the diff --git a/compute/compute/ingredients/disks/empty_disk.py b/compute/compute/ingredients/disks/empty_disk.py index 570292fde9ee..70c677b7da37 100644 --- a/compute/compute/ingredients/disks/empty_disk.py +++ b/compute/compute/ingredients/disks/empty_disk.py @@ -20,7 +20,7 @@ # -def empty_disk(disk_type: str, disk_size_gb: int, boot: bool = False, auto_delete: bool = False) -> compute_v1.AttachedDisk(): +def empty_disk(disk_type: str, disk_size_gb: int, boot: bool = False, auto_delete: bool = True) -> compute_v1.AttachedDisk(): """ Create an AttachedDisk object to be used in VM instance creation. The created disk contains no data and requires formatting before it can be used. @@ -43,7 +43,7 @@ def empty_disk(disk_type: str, disk_size_gb: int, boot: bool = False, auto_delet disk.initialize_params = initialize_params # Remember to set auto_delete to True if you want the disk to be deleted when you delete # your VM instance. - disk.auto_delete = True - disk.boot = False + disk.auto_delete = auto_delete + disk.boot = boot return disk # diff --git a/compute/compute/ingredients/disks/from_image.py b/compute/compute/ingredients/disks/from_image.py index 5f22f4e61760..945b018b9f8c 100644 --- a/compute/compute/ingredients/disks/from_image.py +++ b/compute/compute/ingredients/disks/from_image.py @@ -21,7 +21,7 @@ # def disk_from_image( - disk_type: str, disk_size_gb: int, boot: bool, source_image: str, auto_delete: bool = False + disk_type: str, disk_size_gb: int, boot: bool, source_image: str, auto_delete: bool = True ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the diff --git a/compute/compute/ingredients/disks/get.py b/compute/compute/ingredients/disks/get.py new file mode 100644 index 000000000000..54b68d9d4ae3 --- /dev/null +++ b/compute/compute/ingredients/disks/get.py @@ -0,0 +1,37 @@ +# 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 NoReturn, Iterable + +from google.cloud import compute_v1 + + +# +def get_disk(project_id: str, zone: str, disk_name: str) -> compute_v1.Disk: + """ + Gets a disk from a project. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + zone: name of the zone where the disk exists. + disk_name: name of the disk you want to retrieve. + """ + disk_client = compute_v1.DisksClient() + return disk_client.get(project=project_id, zone=zone, disk=disk_name) +# diff --git a/compute/compute/ingredients/instances/create_instance.py b/compute/compute/ingredients/instances/create_instance.py index 99fad23e4144..17ab8319b13d 100644 --- a/compute/compute/ingredients/instances/create_instance.py +++ b/compute/compute/ingredients/instances/create_instance.py @@ -149,5 +149,5 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) # diff --git a/compute/compute/ingredients/instances/create_start_instance/create_from_custom_image.py b/compute/compute/ingredients/instances/create_start_instance/create_from_custom_image.py index 2d297cbca986..1195b75872f0 100644 --- a/compute/compute/ingredients/instances/create_start_instance/create_from_custom_image.py +++ b/compute/compute/ingredients/instances/create_start_instance/create_from_custom_image.py @@ -1,22 +1,3 @@ -# 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 -# # 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 @@ -55,7 +36,7 @@ def create_from_custom_image( Instance object. """ disk_type = f"zones/{zone}/diskTypes/pd-standard" - disks = [disk_from_image(disk_type, 10, True, custom_image_link)] + disks = [disk_from_image(disk_type, 10, True, custom_image_link, True)] instance = create_instance(project_id, zone, instance_name, disks) return instance # diff --git a/compute/compute/ingredients/instances/create_start_instance/create_from_public_image.py b/compute/compute/ingredients/instances/create_start_instance/create_from_public_image.py index 2eb8e3c2e157..fdf2e35f748e 100644 --- a/compute/compute/ingredients/instances/create_start_instance/create_from_public_image.py +++ b/compute/compute/ingredients/instances/create_start_instance/create_from_public_image.py @@ -36,7 +36,7 @@ def create_from_public_image(project_id: str, zone: str, instance_name: str) -> project="debian-cloud", family="debian-10" ) disk_type = f"zones/{zone}/diskTypes/pd-standard" - disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)] + disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link, True)] instance = create_instance(project_id, zone, instance_name, disks) return instance # diff --git a/compute/compute/ingredients/instances/create_start_instance/create_with_existing_disks.py b/compute/compute/ingredients/instances/create_start_instance/create_with_existing_disks.py new file mode 100644 index 000000000000..2affc851d478 --- /dev/null +++ b/compute/compute/ingredients/instances/create_start_instance/create_with_existing_disks.py @@ -0,0 +1,50 @@ +# 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 +from typing import List + +from google.cloud import compute_v1 + + +# +def create_with_existing_disks(project_id: str, zone: str, instance_name: str, disk_names: List[str]) -> compute_v1.Instance: + """ + Create a new VM instance using selected disks. The first disk in disk_names will + be used as boot disk. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + zone: name of the zone to create the instance in. For example: "us-west3-b" + instance_name: name of the new virtual machine (VM) instance. + disk_names: list of disk names to be attached to the new virtual machine. + First disk in this list will be used as the boot device. + + Returns: + Instance object. + """ + assert(len(disk_names) >= 1) + disks = [get_disk(project_id, zone, disk_name) for disk_name in disk_names] + attached_disks = [] + for disk in disks: + adisk = compute_v1.AttachedDisk() + adisk.source = disk.self_link + attached_disks.append(adisk) + attached_disks[0].boot = True + instance = create_instance(project_id, zone, instance_name, attached_disks) + return instance +# diff --git a/compute/compute/ingredients/instances/get.py b/compute/compute/ingredients/instances/get.py new file mode 100644 index 000000000000..702696ad7896 --- /dev/null +++ b/compute/compute/ingredients/instances/get.py @@ -0,0 +1,39 @@ +# 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 +from google.cloud import compute_v1 + + +# +def get_instance(project_id: str, zone: str, instance_name: str) -> compute_v1.Instance: + """ + Get information about a VM instance in the given zone in the specified project. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + zone: name of the zone you want to use. For example: “us-west3-b” + instance_name: name of the VM instance you want to query. + Returns: + An Instance object. + """ + instance_client = compute_v1.InstancesClient() + instance = instance_client.get(project=project_id, zone=zone, instance=instance_name) + + return instance +# + diff --git a/compute/compute/recipes/disks/create_empty_disk.py b/compute/compute/recipes/disks/create_empty_disk.py new file mode 100644 index 000000000000..923f79d076cf --- /dev/null +++ b/compute/compute/recipes/disks/create_empty_disk.py @@ -0,0 +1,21 @@ +# 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. +# flake8: noqa + +# +# + +# + +# diff --git a/compute/compute/recipes/instances/create_start_instance/create_with_existing_disks.py b/compute/compute/recipes/instances/create_start_instance/create_with_existing_disks.py new file mode 100644 index 000000000000..3f6bf6ac20fa --- /dev/null +++ b/compute/compute/recipes/instances/create_start_instance/create_with_existing_disks.py @@ -0,0 +1,27 @@ +# 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. +# flake8: noqa + + +# +# + +# + + +# + + +# +# diff --git a/compute/compute/recipes/instances/get.py b/compute/compute/recipes/instances/get.py new file mode 100644 index 000000000000..2dcc5c8849ed --- /dev/null +++ b/compute/compute/recipes/instances/get.py @@ -0,0 +1,20 @@ +# 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. +# flake8: noqa + +# +# + +# +# diff --git a/compute/compute/snippets/disks/create_empty_disk.py b/compute/compute/snippets/disks/create_empty_disk.py new file mode 100644 index 000000000000..d1352f861ede --- /dev/null +++ b/compute/compute/snippets/disks/create_empty_disk.py @@ -0,0 +1,72 @@ +# 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. +# flake8: noqa + + +# This file is automatically generated. Please do not modify it directly. +# Find the relevant recipe file in the samples/recipes or samples/ingredients +# directory and apply your changes there. + + +# [START compute_disk_create_empty_disk] +import sys + +from google.cloud import compute_v1 + + +def create_empty_disk( + project_id: str, zone: str, disk_name: str, disk_type: str, disk_size_gb: int +) -> compute_v1.Disk: + """ + Creates a new empty disk in a project in given zone. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + zone: name of the zone in which you want to create the disk. + disk_name: name of the disk you want to create. + disk_type: the type of disk you want to create. This value uses the following format: + "zones/{zone}/diskTypes/(pd-standard|pd-ssd|pd-balanced|pd-extreme)". + For example: "zones/us-west3-b/diskTypes/pd-ssd" + disk_size_gb: size of the new disk in gigabytes + + Returns: + An unattached Disk instance. + """ + disk = compute_v1.Disk() + disk.size_gb = disk_size_gb + disk.name = disk_name + disk.zone = zone + 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) + + return disk_client.get(project=project_id, zone=zone, disk=disk.name) + + +# [END compute_disk_create_empty_disk] diff --git a/compute/compute/snippets/instances/create.py b/compute/compute/snippets/instances/create.py index a4df25156e25..efa0de1735a0 100644 --- a/compute/compute/snippets/instances/create.py +++ b/compute/compute/snippets/instances/create.py @@ -50,7 +50,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -207,7 +207,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) # [END compute_instances_create] diff --git a/compute/compute/snippets/instances/create_start_instance/create_from_custom_image.py b/compute/compute/snippets/instances/create_start_instance/create_from_custom_image.py index 203633f02fde..59d32f08c14a 100644 --- a/compute/compute/snippets/instances/create_start_instance/create_from_custom_image.py +++ b/compute/compute/snippets/instances/create_start_instance/create_from_custom_image.py @@ -50,7 +50,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -207,7 +207,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_from_custom_image( @@ -227,7 +227,7 @@ def create_from_custom_image( Instance object. """ disk_type = f"zones/{zone}/diskTypes/pd-standard" - disks = [disk_from_image(disk_type, 10, True, custom_image_link)] + disks = [disk_from_image(disk_type, 10, True, custom_image_link, True)] instance = create_instance(project_id, zone, instance_name, disks) return instance diff --git a/compute/compute/snippets/instances/create_start_instance/create_from_public_image.py b/compute/compute/snippets/instances/create_start_instance/create_from_public_image.py index 28d762a86a72..bfe848afaf80 100644 --- a/compute/compute/snippets/instances/create_start_instance/create_from_public_image.py +++ b/compute/compute/snippets/instances/create_start_instance/create_from_public_image.py @@ -50,7 +50,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -207,7 +207,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_from_public_image( @@ -226,7 +226,7 @@ def create_from_public_image( """ newest_debian = get_image_from_family(project="debian-cloud", family="debian-10") disk_type = f"zones/{zone}/diskTypes/pd-standard" - disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)] + disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link, True)] instance = create_instance(project_id, zone, instance_name, disks) return instance diff --git a/compute/compute/snippets/instances/create_start_instance/create_from_snapshot.py b/compute/compute/snippets/instances/create_start_instance/create_from_snapshot.py index 92880c972ae9..2c6996ed89a3 100644 --- a/compute/compute/snippets/instances/create_start_instance/create_from_snapshot.py +++ b/compute/compute/snippets/instances/create_start_instance/create_from_snapshot.py @@ -33,7 +33,7 @@ def disk_from_snapshot( disk_size_gb: int, boot: bool, source_snapshot: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk(): """ Create an AttachedDisk object to be used in VM instance creation. Uses a disk snapshot as the @@ -189,7 +189,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_from_snapshot( diff --git a/compute/compute/snippets/instances/create_start_instance/create_with_additional_disk.py b/compute/compute/snippets/instances/create_start_instance/create_with_additional_disk.py index bffe080107b8..a14005eb5d9d 100644 --- a/compute/compute/snippets/instances/create_start_instance/create_with_additional_disk.py +++ b/compute/compute/snippets/instances/create_start_instance/create_with_additional_disk.py @@ -50,7 +50,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -84,7 +84,7 @@ def disk_from_image( def empty_disk( - disk_type: str, disk_size_gb: int, boot: bool = False, auto_delete: bool = False + disk_type: str, disk_size_gb: int, boot: bool = False, auto_delete: bool = True ) -> compute_v1.AttachedDisk(): """ Create an AttachedDisk object to be used in VM instance creation. The created disk contains @@ -108,8 +108,8 @@ def empty_disk( disk.initialize_params = initialize_params # Remember to set auto_delete to True if you want the disk to be deleted when you delete # your VM instance. - disk.auto_delete = True - disk.boot = False + disk.auto_delete = auto_delete + disk.boot = boot return disk @@ -237,7 +237,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_with_additional_disk( diff --git a/compute/compute/snippets/instances/create_start_instance/create_with_existing_disks.py b/compute/compute/snippets/instances/create_start_instance/create_with_existing_disks.py new file mode 100644 index 000000000000..62a118ee850d --- /dev/null +++ b/compute/compute/snippets/instances/create_start_instance/create_with_existing_disks.py @@ -0,0 +1,200 @@ +# 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. +# flake8: noqa + + +# This file is automatically generated. Please do not modify it directly. +# Find the relevant recipe file in the samples/recipes or samples/ingredients +# directory and apply your changes there. + + +# [START compute_instances_create_with_existing_disks] +import re +import sys +import time +from typing import Iterable, List, NoReturn + +from google.cloud import compute_v1 + + +def get_disk(project_id: str, zone: str, disk_name: str) -> compute_v1.Disk: + """ + Deletes a disk from a project. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + zone: name of the zone in which is the disk you want to delete. + disk_name: name of the disk you want to retrieve. + """ + disk_client = compute_v1.DisksClient() + return disk_client.get(project=project_id, zone=zone, disk=disk_name) + + +def create_instance( + project_id: str, + zone: str, + instance_name: str, + disks: List[compute_v1.AttachedDisk], + machine_type: str = "n1-standard-1", + network_link: str = "global/networks/default", + subnetwork_link: str = None, + internal_ip: str = None, + external_access: bool = False, + external_ipv4: str = None, + accelerators: List[compute_v1.AcceleratorConfig] = None, + preemptible: bool = False, + custom_hostname: str = None, + delete_protection: bool = False, +) -> compute_v1.Instance: + """ + Send an instance creation request to the Compute Engine API and wait for it to complete. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + zone: name of the zone to create the instance in. For example: "us-west3-b" + instance_name: name of the new virtual machine (VM) instance. + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + machine_type: machine type of the VM being created. This value uses the + following format: "zones/{zone}/machineTypes/{type_name}". + For example: "zones/europe-west3-c/machineTypes/f1-micro" + network_link: name of the network you want the new instance to use. + For example: "global/networks/default" represents the network + named "default", which is created automatically for each project. + subnetwork_link: name of the subnetwork you want the new instance to use. + This value uses the following format: + "regions/{region}/subnetworks/{subnetwork_name}" + internal_ip: internal IP address you want to assign to the new instance. + By default, a free address from the pool of available internal IP addresses of + used subnet will be used. + external_access: boolean flag indicating if the instance should have an external IPv4 + address assigned. + external_ipv4: external IPv4 address to be assigned to this instance. If you specify + an external IP address, it must live in the same region as the zone of the instance. + This setting requires `external_access` to be set to True to work. + accelerators: a list of AcceleratorConfig objects describing the accelerators that will + be attached to the new instance. + preemptible: boolean value indicating if the new instance should be preemptible + or not. + custom_hostname: Custom hostname of the new VM instance. + Custom hostnames must conform to RFC 1035 requirements for valid hostnames. + delete_protection: boolean value indicating if the new virtual machine should be + protected against deletion or not. + Returns: + 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() + network_interface.name = network_link + if subnetwork_link: + network_interface.subnetwork = subnetwork_link + + if internal_ip: + network_interface.network_i_p = internal_ip + + if external_access: + access = compute_v1.AccessConfig() + access.type_ = compute_v1.AccessConfig.Type.ONE_TO_ONE_NAT.name + access.name = "External NAT" + access.network_tier = access.NetworkTier.PREMIUM.name + if external_ipv4: + access.nat_i_p = external_ipv4 + network_interface.access_configs = [access] + + # Collect information into the Instance object. + instance = compute_v1.Instance() + instance.name = instance_name + instance.disks = disks + if re.match(r"^zones/[a-z\d\-]+/machineTypes/[a-z\d\-]+$", machine_type): + instance.machine_type = machine_type + else: + instance.machine_type = f"zones/{zone}/machineTypes/{machine_type}" + + if accelerators: + instance.guest_accelerators = accelerators + + instance.network_interfaces = [network_interface] + + if preemptible: + # Set the preemptible setting + instance.scheduling = compute_v1.Scheduling() + instance.scheduling.preemptible = True + + if custom_hostname is not None: + # Set the custom hostname for the instance + instance.hostname = custom_hostname + + if delete_protection: + # Set the delete protection bit + instance.deletion_protection = True + + # Prepare the request to insert an instance. + request = compute_v1.InsertInstanceRequest() + request.zone = zone + request.project = project_id + request.instance_resource = 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) + print(f"Instance {instance_name} created.") + return instance_client.get(project=project_id, zone=zone, instance=instance_name) + + +def create_with_existing_disks( + project_id: str, zone: str, instance_name: str, disk_names: List[str] +) -> compute_v1.Instance: + """ + Create a new VM instance using selected disks. The first disk in disk_names will + be used as boot disk. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + zone: name of the zone to create the instance in. For example: "us-west3-b" + instance_name: name of the new virtual machine (VM) instance. + disk_names: list of disk names to be attached to the new virtual machine. + First disk in this list will be used as the boot device. + + Returns: + Instance object. + """ + assert len(disk_names) >= 1 + disks = [get_disk(project_id, zone, disk_name) for disk_name in disk_names] + attached_disks = [] + for disk in disks: + adisk = compute_v1.AttachedDisk() + adisk.source = disk.self_link + attached_disks.append(adisk) + attached_disks[0].boot = True + instance = create_instance(project_id, zone, instance_name, attached_disks) + return instance + + +# [END compute_instances_create_with_existing_disks] diff --git a/compute/compute/snippets/instances/create_start_instance/create_with_snapshotted_data_disk.py b/compute/compute/snippets/instances/create_start_instance/create_with_snapshotted_data_disk.py index f1c904d09907..0385c17abc48 100644 --- a/compute/compute/snippets/instances/create_start_instance/create_with_snapshotted_data_disk.py +++ b/compute/compute/snippets/instances/create_start_instance/create_with_snapshotted_data_disk.py @@ -50,7 +50,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -88,7 +88,7 @@ def disk_from_snapshot( disk_size_gb: int, boot: bool, source_snapshot: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk(): """ Create an AttachedDisk object to be used in VM instance creation. Uses a disk snapshot as the @@ -244,7 +244,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_with_snapshotted_data_disk( diff --git a/compute/compute/snippets/instances/create_with_subnet.py b/compute/compute/snippets/instances/create_with_subnet.py index 6c4be0122843..27a52a9f75c7 100644 --- a/compute/compute/snippets/instances/create_with_subnet.py +++ b/compute/compute/snippets/instances/create_with_subnet.py @@ -50,7 +50,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -207,7 +207,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_with_subnet( diff --git a/compute/compute/snippets/instances/custom_hostname/create.py b/compute/compute/snippets/instances/custom_hostname/create.py index 9ede42b7b734..699f6397e758 100644 --- a/compute/compute/snippets/instances/custom_hostname/create.py +++ b/compute/compute/snippets/instances/custom_hostname/create.py @@ -50,7 +50,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -207,7 +207,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_instance_custom_hostname( diff --git a/compute/compute/snippets/instances/custom_machine_types/create_shared_with_helper.py b/compute/compute/snippets/instances/custom_machine_types/create_shared_with_helper.py index f699228b998d..7674013d44e3 100644 --- a/compute/compute/snippets/instances/custom_machine_types/create_shared_with_helper.py +++ b/compute/compute/snippets/instances/custom_machine_types/create_shared_with_helper.py @@ -244,7 +244,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -401,7 +401,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_custom_shared_core_instance( diff --git a/compute/compute/snippets/instances/custom_machine_types/create_with_helper.py b/compute/compute/snippets/instances/custom_machine_types/create_with_helper.py index 700ccdcea223..5821f160b59c 100644 --- a/compute/compute/snippets/instances/custom_machine_types/create_with_helper.py +++ b/compute/compute/snippets/instances/custom_machine_types/create_with_helper.py @@ -244,7 +244,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -401,7 +401,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_custom_instance( diff --git a/compute/compute/snippets/instances/custom_machine_types/create_without_helper.py b/compute/compute/snippets/instances/custom_machine_types/create_without_helper.py index ae79f9fb7f9e..54e208b6df7f 100644 --- a/compute/compute/snippets/instances/custom_machine_types/create_without_helper.py +++ b/compute/compute/snippets/instances/custom_machine_types/create_without_helper.py @@ -50,7 +50,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -207,7 +207,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_custom_instances_no_helper( diff --git a/compute/compute/snippets/instances/custom_machine_types/extra_mem_no_helper.py b/compute/compute/snippets/instances/custom_machine_types/extra_mem_no_helper.py index e4b1abd1198e..9449ef11f516 100644 --- a/compute/compute/snippets/instances/custom_machine_types/extra_mem_no_helper.py +++ b/compute/compute/snippets/instances/custom_machine_types/extra_mem_no_helper.py @@ -50,7 +50,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -207,7 +207,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_custom_instances_extra_mem( diff --git a/compute/compute/snippets/instances/delete_protection/create.py b/compute/compute/snippets/instances/delete_protection/create.py index 32148a25fcc0..15d31f102a86 100644 --- a/compute/compute/snippets/instances/delete_protection/create.py +++ b/compute/compute/snippets/instances/delete_protection/create.py @@ -50,7 +50,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -207,7 +207,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_protected_instance( diff --git a/compute/compute/snippets/instances/get.py b/compute/compute/snippets/instances/get.py new file mode 100644 index 000000000000..427ea19a1d81 --- /dev/null +++ b/compute/compute/snippets/instances/get.py @@ -0,0 +1,45 @@ +# 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. +# flake8: noqa + + +# This file is automatically generated. Please do not modify it directly. +# Find the relevant recipe file in the samples/recipes or samples/ingredients +# directory and apply your changes there. + + +# [START compute_instances_get] +from google.cloud import compute_v1 + + +def get_instance(project_id: str, zone: str, instance_name: str) -> compute_v1.Instance: + """ + Get information about a VM instance in the given zone in the specified project. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + zone: name of the zone you want to use. For example: “us-west3-b” + instance_name: name of the VM instance you want to query. + Returns: + An Instance object. + """ + instance_client = compute_v1.InstancesClient() + instance = instance_client.get( + project=project_id, zone=zone, instance=instance_name + ) + + return instance + + +# [END compute_instances_get] diff --git a/compute/compute/snippets/instances/preemptible/create_preemptible.py b/compute/compute/snippets/instances/preemptible/create_preemptible.py index 3fd4de32d730..5cc7ff47d4a4 100644 --- a/compute/compute/snippets/instances/preemptible/create_preemptible.py +++ b/compute/compute/snippets/instances/preemptible/create_preemptible.py @@ -50,7 +50,7 @@ def disk_from_image( disk_size_gb: int, boot: bool, source_image: str, - auto_delete: bool = False, + auto_delete: bool = True, ) -> compute_v1.AttachedDisk: """ Create an AttachedDisk object to be used in VM instance creation. Uses an image as the @@ -207,7 +207,7 @@ def create_instance( if operation.warnings: print("Warning during creation:", operation.warnings, file=sys.stderr) print(f"Instance {instance_name} created.") - return instance + return instance_client.get(project=project_id, zone=zone, instance=instance_name) def create_preemptible_instance( diff --git a/compute/compute/snippets/tests/test_create_vm.py b/compute/compute/snippets/tests/test_create_vm.py index 5497f233bb16..fbda262ea25c 100644 --- a/compute/compute/snippets/tests/test_create_vm.py +++ b/compute/compute/snippets/tests/test_create_vm.py @@ -17,6 +17,10 @@ from google.cloud import compute_v1 import pytest +from ..disks.create_empty_disk import create_empty_disk +from ..disks.create_from_image import create_disk_from_image +from ..disks.delete import delete_disk + from ..instances.create_start_instance.create_from_custom_image import ( create_from_custom_image, ) @@ -27,6 +31,7 @@ from ..instances.create_start_instance.create_with_additional_disk import ( create_with_additional_disk, ) +from ..instances.create_start_instance.create_with_existing_disks import create_with_existing_disks from ..instances.create_start_instance.create_with_snapshotted_data_disk import ( create_with_snapshotted_data_disk, ) @@ -108,89 +113,132 @@ def image(src_disk): wait_for_operation(op, PROJECT) -class TestCreation: - def test_create_from_custom_image(self, image): - instance_name = "i" + uuid.uuid4().hex[:10] - instance = create_from_custom_image( - PROJECT, INSTANCE_ZONE, instance_name, image.self_link +@pytest.fixture() +def boot_disk(): + debian_image = get_active_debian() + disk_name = "test-disk-" + uuid.uuid4().hex[:10] + disk = create_disk_from_image(PROJECT, INSTANCE_ZONE, disk_name, + f"zones/{INSTANCE_ZONE}/diskTypes/pd-standard", + 13, debian_image.self_link) + yield disk + delete_disk(PROJECT, INSTANCE_ZONE, disk_name) + + +@pytest.fixture() +def empty_disk(): + disk_name = "test-disk-" + uuid.uuid4().hex[:10] + disk = create_empty_disk(PROJECT, INSTANCE_ZONE, disk_name, + f"zones/{INSTANCE_ZONE}/diskTypes/pd-standard", + 14) + + yield disk + delete_disk(PROJECT, INSTANCE_ZONE, disk_name) + + +def test_create_from_custom_image(image): + instance_name = "i" + uuid.uuid4().hex[:10] + instance = create_from_custom_image( + PROJECT, INSTANCE_ZONE, instance_name, image.self_link + ) + try: + assert ( + instance.disks[0].disk_size_gb == 10 + ) + finally: + delete_instance(PROJECT, INSTANCE_ZONE, instance_name) + + +def test_create_from_public_image(): + instance_name = "i" + uuid.uuid4().hex[:10] + instance = create_from_public_image( + PROJECT, + INSTANCE_ZONE, + instance_name, + ) + try: + assert instance.disks[0].disk_size_gb == 10 + finally: + delete_instance(PROJECT, INSTANCE_ZONE, instance_name) + + +def test_create_from_snapshot(snapshot): + instance_name = "i" + uuid.uuid4().hex[:10] + instance = create_from_snapshot( + PROJECT, INSTANCE_ZONE, instance_name, snapshot.self_link + ) + try: + assert ( + instance.disks[0].disk_size_gb == 20 + ) + finally: + delete_instance(PROJECT, INSTANCE_ZONE, instance_name) + + +def test_create_with_additional_disk(): + instance_name = "i" + uuid.uuid4().hex[:10] + instance = create_with_additional_disk(PROJECT, INSTANCE_ZONE, instance_name) + try: + assert any( + disk.disk_size_gb == 20 for disk in instance.disks + ) + assert any( + disk.disk_size_gb == 25 for disk in instance.disks + ) + assert len(instance.disks) == 2 + finally: + delete_instance(PROJECT, INSTANCE_ZONE, instance_name) + + +def test_create_with_snapshotted_data_disk(snapshot): + instance_name = "i" + uuid.uuid4().hex[:10] + instance = create_with_snapshotted_data_disk( + PROJECT, INSTANCE_ZONE, instance_name, snapshot.self_link + ) + try: + assert any( + disk.disk_size_gb == 11 for disk in instance.disks ) - try: - assert ( - instance.disks[0].initialize_params.source_image == image.self_link - ) - finally: - delete_instance(PROJECT, INSTANCE_ZONE, instance_name) - - def test_create_from_public_image(self): - instance_name = "i" + uuid.uuid4().hex[:10] - instance = create_from_public_image( - PROJECT, - INSTANCE_ZONE, - instance_name, + assert any( + disk.disk_size_gb == 10 for disk in instance.disks ) - try: - assert "debian-cloud" in instance.disks[0].initialize_params.source_image - assert "debian-10" in instance.disks[0].initialize_params.source_image - finally: - delete_instance(PROJECT, INSTANCE_ZONE, instance_name) - - def test_create_from_snapshot(self, snapshot): - instance_name = "i" + uuid.uuid4().hex[:10] - instance = create_from_snapshot( - PROJECT, INSTANCE_ZONE, instance_name, snapshot.self_link + assert len(instance.disks) == 2 + finally: + delete_instance(PROJECT, INSTANCE_ZONE, instance_name) + + +def test_create_with_subnet(): + instance_name = "i" + uuid.uuid4().hex[:10] + instance = create_with_subnet( + PROJECT, + INSTANCE_ZONE, + instance_name, + "global/networks/default", + f"regions/{REGION}/subnetworks/default", + ) + try: + assert instance.network_interfaces[0].network.endswith("global/networks/default") + assert ( + instance.network_interfaces[0].subnetwork.endswith(f"regions/{REGION}/subnetworks/default") ) - try: - assert ( - instance.disks[0].initialize_params.source_snapshot - == snapshot.self_link - ) - finally: - delete_instance(PROJECT, INSTANCE_ZONE, instance_name) - - def test_create_with_additional_disk(self): - instance_name = "i" + uuid.uuid4().hex[:10] - instance = create_with_additional_disk(PROJECT, INSTANCE_ZONE, instance_name) - try: - assert any( - disk.initialize_params.disk_size_gb == 20 for disk in instance.disks - ) - assert any( - disk.initialize_params.disk_size_gb == 25 for disk in instance.disks - ) - assert len(instance.disks) == 2 - finally: - delete_instance(PROJECT, INSTANCE_ZONE, instance_name) - - def test_create_with_snapshotted_data_disk(self, snapshot): - instance_name = "i" + uuid.uuid4().hex[:10] - instance = create_with_snapshotted_data_disk( - PROJECT, INSTANCE_ZONE, instance_name, snapshot.self_link + finally: + delete_instance(PROJECT, INSTANCE_ZONE, instance_name) + + +def test_create_with_existing_disks(boot_disk, empty_disk): + instance_name = "i" + uuid.uuid4().hex[:10] + instance = create_with_existing_disks(PROJECT, INSTANCE_ZONE, instance_name, + [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 ) - try: - assert any( - disk.initialize_params.disk_size_gb == 11 for disk in instance.disks - ) - assert any( - disk.initialize_params.disk_size_gb == 10 for disk in instance.disks - ) - assert len(instance.disks) == 2 - finally: - delete_instance(PROJECT, INSTANCE_ZONE, instance_name) - - def test_create_with_subnet(self): - instance_name = "i" + uuid.uuid4().hex[:10] - instance = create_with_subnet( - PROJECT, - INSTANCE_ZONE, - instance_name, - "global/networks/default", - f"regions/{REGION}/subnetworks/default", + assert any( + disk.disk_size_gb == 14 for disk in instance.disks ) - try: - assert instance.network_interfaces[0].name == "global/networks/default" - assert ( - instance.network_interfaces[0].subnetwork - == f"regions/{REGION}/subnetworks/default" - ) - finally: - delete_instance(PROJECT, INSTANCE_ZONE, instance_name) + assert len(instance.disks) == 2 + finally: + delete_instance(PROJECT, INSTANCE_ZONE, instance_name)