diff --git a/samples/__init__.py b/samples/__init__.py new file mode 100644 index 000000000..4bbe0ffdb --- /dev/null +++ b/samples/__init__.py @@ -0,0 +1,13 @@ +# 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. diff --git a/samples/ingredients/__init__.py b/samples/ingredients/__init__.py new file mode 100644 index 000000000..81d8b9be3 --- /dev/null +++ b/samples/ingredients/__init__.py @@ -0,0 +1,18 @@ +# 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 diff --git a/samples/ingredients/disks/disk_from_snapshot.py b/samples/ingredients/disks/disk_from_snapshot.py new file mode 100644 index 000000000..e0271c47b --- /dev/null +++ b/samples/ingredients/disks/disk_from_snapshot.py @@ -0,0 +1,54 @@ +# 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 disk_from_snapshot( + disk_type: str, disk_size_gb: int, boot: bool, source_snapshot: str, auto_delete: bool = False +) -> compute_v1.AttachedDisk(): + """ + Create an AttachedDisk object to be used in VM instance creation. Uses a disk snapshot as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_snapshot: disk snapshot to use when creating this disk. You must have read access to this disk. + This value uses the following format: "projects/{project_name}/global/snapshots/{snapshot_name}" + auto_delete: boolean flag indicating whether this disk should be deleted with the VM that uses it + + Returns: + AttachedDisk object configured to be created using the specified snapshot. + """ + disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_snapshot = source_snapshot + initialize_params.disk_type = disk_type + initialize_params.disk_size_gb = disk_size_gb + 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 = auto_delete + disk.boot = boot + return disk +# diff --git a/samples/ingredients/disks/empty_disk.py b/samples/ingredients/disks/empty_disk.py new file mode 100644 index 000000000..570292fde --- /dev/null +++ b/samples/ingredients/disks/empty_disk.py @@ -0,0 +1,49 @@ +# 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 empty_disk(disk_type: str, disk_size_gb: int, boot: bool = False, auto_delete: bool = False) -> 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. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + auto_delete: boolean flag indicating whether this disk should be deleted with the VM that uses it + + Returns: + AttachedDisk object configured to be created as an empty disk. + """ + disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.disk_type = disk_type + initialize_params.disk_size_gb = disk_size_gb + 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 + return disk +# diff --git a/samples/ingredients/disks/from_image.py b/samples/ingredients/disks/from_image.py new file mode 100644 index 000000000..5f22f4e61 --- /dev/null +++ b/samples/ingredients/disks/from_image.py @@ -0,0 +1,55 @@ +# 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 disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str, auto_delete: bool = False +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + auto_delete: boolean flag indicating whether this disk should be deleted with the VM that uses it + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = auto_delete + boot_disk.boot = boot + return boot_disk +# diff --git a/samples/ingredients/firewall/create.py b/samples/ingredients/firewall/create.py new file mode 100644 index 000000000..e6e9f0008 --- /dev/null +++ b/samples/ingredients/firewall/create.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. + +# 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 create_firewall_rule( + project_id: str, firewall_rule_name: str, network: str = "global/networks/default" +) -> compute_v1.Firewall: + """ + Creates a simple firewall rule allowing for incoming HTTP and HTTPS access from the entire Internet. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + firewall_rule_name: name of the rule that is created. + network: name of the network the rule will be applied to. Available name formats: + * https://www.googleapis.com/compute/v1/projects/{project_id}/global/networks/{network} + * projects/{project_id}/global/networks/{network} + * global/networks/{network} + + Returns: + A Firewall object. + """ + firewall_rule = compute_v1.Firewall() + firewall_rule.name = firewall_rule_name + firewall_rule.direction = "INGRESS" + + allowed_ports = compute_v1.Allowed() + allowed_ports.I_p_protocol = "tcp" + allowed_ports.ports = ["80", "443"] + + firewall_rule.allowed = [allowed_ports] + firewall_rule.source_ranges = ["0.0.0.0/0"] + firewall_rule.network = network + firewall_rule.description = "Allowing TCP traffic on port 80 and 443 from Internet." + + firewall_rule.target_tags = ["web"] + + # Note that the default value of priority for the firewall API is 1000. + # If you check the value of `firewall_rule.priority` at this point it + # will be equal to 0, however it is not treated as "set" by the library and thus + # the default will be applied to the new rule. If you want to create a rule that + # has priority == 0, you need to explicitly set it so: + # TODO: Uncomment to set the priority to 0 + # firewall_rule.priority = 0 + + firewall_client = compute_v1.FirewallsClient() + op = firewall_client.insert_unary( + project=project_id, firewall_resource=firewall_rule + ) + + op_client = compute_v1.GlobalOperationsClient() + op_client.wait(project=project_id, operation=op.name) + + 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 new file mode 100644 index 000000000..fc6a42150 --- /dev/null +++ b/samples/ingredients/firewall/delete.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 delete_firewall_rule(project_id: str, firewall_rule_name: str) -> None: + """ + Deletes a firewall rule from the project. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + 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_client = compute_v1.GlobalOperationsClient() + operation_client.wait(project=project_id, operation=operation.name) + return +# diff --git a/samples/ingredients/firewall/get.py b/samples/ingredients/firewall/get.py new file mode 100644 index 000000000..0a8388d56 --- /dev/null +++ b/samples/ingredients/firewall/get.py @@ -0,0 +1,36 @@ +# 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_firewall_rule(project_id: str, firewall_rule_name: str) -> compute_v1.Firewall: + """ + Retrieve a Firewall from a project. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + firewall_rule_name: name of the firewall rule you want to retrieve. + + Returns: + A Firewall object. + """ + firewall_client = compute_v1.FirewallsClient() + return firewall_client.get(project=project_id, firewall=firewall_rule_name) +# diff --git a/samples/ingredients/firewall/list.py b/samples/ingredients/firewall/list.py new file mode 100644 index 000000000..5deeac4e3 --- /dev/null +++ b/samples/ingredients/firewall/list.py @@ -0,0 +1,44 @@ +# 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 Iterable + +from google.cloud import compute_v1 + + +# +def list_firewall_rules(project_id: str) -> Iterable[compute_v1.Firewall]: + """ + Return a list of all the firewall rules in specified project. Also prints the + list of firewall names and their descriptions. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + + Returns: + A flat list of all firewall rules defined for given project. + """ + firewall_client = compute_v1.FirewallsClient() + firewalls_list = firewall_client.list(project=project_id) + + for firewall in firewalls_list: + print(f" - {firewall.name}: {firewall.description}") + + return firewalls_list +# + diff --git a/samples/ingredients/firewall/patch.py b/samples/ingredients/firewall/patch.py new file mode 100644 index 000000000..5017114a3 --- /dev/null +++ b/samples/ingredients/firewall/patch.py @@ -0,0 +1,46 @@ +# 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 patch_firewall_priority(project_id: str, firewall_rule_name: str, priority: int) -> None: + """ + Modifies the priority of a given firewall rule. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + firewall_rule_name: name of the rule you want to modify. + priority: the new priority to be set for the rule. + """ + firewall_rule = compute_v1.Firewall() + firewall_rule.priority = 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( + 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) + return +# + diff --git a/samples/snippets/sample_images.py b/samples/ingredients/images/get_image.py similarity index 60% rename from samples/snippets/sample_images.py rename to samples/ingredients/images/get_image.py index 96d8bbb83..4dcce0e77 100644 --- a/samples/snippets/sample_images.py +++ b/samples/ingredients/images/get_image.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google LLC +# 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. @@ -12,35 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Iterable +# 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 -# [START compute_images_get] -# [START compute_images_get_list] from google.cloud import compute_v1 -# [END compute_images_get_list] -# [END compute_images_get] - -# [START compute_images_get_list] -def list_images(project_id: str) -> Iterable[compute_v1.Image]: - """ - Retrieve a list of images available in given project. - - Args: - project_id: project ID or project number of the Cloud project you want to list images from. - - Returns: - An iterable collection of compute_v1.Image objects. - """ - image_client = compute_v1.ImagesClient() - return image_client.list(project=project_id) - - -# [END compute_images_get_list] - - -# [START compute_images_get] +# def get_image(project_id: str, image_name: str) -> compute_v1.Image: """ Retrieve detailed information about a single image from a project. @@ -54,6 +34,4 @@ def get_image(project_id: str, image_name: str) -> compute_v1.Image: """ image_client = compute_v1.ImagesClient() return image_client.get(project=project_id, image=image_name) - - -# [END compute_images_get] +# diff --git a/samples/ingredients/images/get_image_from_family.py b/samples/ingredients/images/get_image_from_family.py new file mode 100644 index 000000000..45daec115 --- /dev/null +++ b/samples/ingredients/images/get_image_from_family.py @@ -0,0 +1,42 @@ +# 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_image_from_family(project: str, family: str) -> compute_v1.Image: + """ + Retrieve the newest image that is part of a given family in a project. + + Args: + project: project ID or project number of the Cloud project you want to get image from. + family: name of the image family you want to get image from. + + Returns: + An Image object. + """ + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family( + project=project, family=family + ) + return newest_image +# diff --git a/samples/ingredients/images/list_images.py b/samples/ingredients/images/list_images.py new file mode 100644 index 000000000..b4c191fc3 --- /dev/null +++ b/samples/ingredients/images/list_images.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 +from typing import Iterable + +from google.cloud import compute_v1 + + +# +def list_images(project_id: str) -> Iterable[compute_v1.Image]: + """ + Retrieve a list of images available in given project. + + Args: + project_id: project ID or project number of the Cloud project you want to list images from. + + Returns: + An iterable collection of compute_v1.Image objects. + """ + image_client = compute_v1.ImagesClient() + return image_client.list(project=project_id) +# diff --git a/samples/ingredients/instance-templates/create.py b/samples/ingredients/instance-templates/create.py new file mode 100644 index 000000000..ca56e99a8 --- /dev/null +++ b/samples/ingredients/instance-templates/create.py @@ -0,0 +1,74 @@ +# 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 create_template(project_id: str, template_name: str) -> compute_v1.InstanceTemplate: + """ + Create a new instance template with the provided name and a specific + instance configuration. + + Args: + project_id: project ID or project number of the Cloud project you use. + template_name: name of the new template to create. + + Returns: + InstanceTemplate object that represents the new instance template. + """ + # The template describes the size and source image of the boot disk + # to attach to the instance. + disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = ( + "projects/debian-cloud/global/images/family/debian-11" + ) + initialize_params.disk_size_gb = 250 + disk.initialize_params = initialize_params + disk.auto_delete = True + disk.boot = True + + # The template connects the instance to the `default` network, + # without specifying a subnetwork. + network_interface = compute_v1.NetworkInterface() + network_interface.name = "global/networks/default" + + # The template lets the instance use an external IP address. + access_config = compute_v1.AccessConfig() + access_config.name = "External NAT" + access_config.type_ = "ONE_TO_ONE_NAT" + access_config.network_tier = "PREMIUM" + network_interface.access_configs = [access_config] + + template = compute_v1.InstanceTemplate() + template.name = template_name + template.properties.disks = [disk] + template.properties.machine_type = "e2-standard-4" + template.properties.network_interfaces = [network_interface] + + template_client = compute_v1.InstanceTemplatesClient() + operation_client = compute_v1.GlobalOperationsClient() + op = template_client.insert_unary( + project=project_id, instance_template_resource=template + ) + operation_client.wait(project=project_id, operation=op.name) + + 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 new file mode 100644 index 000000000..584e2f177 --- /dev/null +++ b/samples/ingredients/instance-templates/create_from_instance.py @@ -0,0 +1,64 @@ +# 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 create_template_from_instance( + project_id: str, instance: str, template_name: str +) -> compute_v1.InstanceTemplate: + """ + Create a new instance template based on an existing instance. + This new template specifies a different boot disk. + + Args: + project_id: project ID or project number of the Cloud project you use. + instance: the instance to base the new template on. This value uses + the following format: "projects/{project}/zones/{zone}/instances/{instance_name}" + template_name: name of the new template to create. + + Returns: + InstanceTemplate object that represents the new instance template. + """ + disk = compute_v1.DiskInstantiationConfig() + # Device name must match the name of a disk attached to the instance you are + # basing your template on. + disk.device_name = "disk-1" + # Replace the original boot disk image used in your instance with a Rocky Linux image. + disk.instantiate_from = "CUSTOM_IMAGE" + disk.custom_image = "projects/rocky-linux-cloud/global/images/family/rocky-linux-8" + # Override the auto_delete setting. + disk.auto_delete = True + + template = compute_v1.InstanceTemplate() + template.name = template_name + template.source_instance = instance + template.source_instance_params = compute_v1.SourceInstanceParams() + template.source_instance_params.disk_configs = [disk] + + template_client = compute_v1.InstanceTemplatesClient() + operation_client = compute_v1.GlobalOperationsClient() + op = template_client.insert_unary( + project=project_id, instance_template_resource=template + ) + operation_client.wait(project=project_id, operation=op.name) + + 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 new file mode 100644 index 000000000..fb80d2510 --- /dev/null +++ b/samples/ingredients/instance-templates/create_with_subnet.py @@ -0,0 +1,73 @@ +# 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 create_template_with_subnet( + project_id: str, network: str, subnetwork: str, template_name: str +) -> compute_v1.InstanceTemplate: + """ + Create an instance template that uses a provided subnet. + + Args: + project_id: project ID or project number of the Cloud project you use. + network: the network to be used in the new template. This value uses + the following format: "projects/{project}/global/networks/{network}" + subnetwork: the subnetwork to be used in the new template. This value + uses the following format: "projects/{project}/regions/{region}/subnetworks/{subnetwork}" + template_name: name of the new template to create. + + Returns: + InstanceTemplate object that represents the new instance template. + """ + # The template describes the size and source image of the book disk to + # attach to the instance. + disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = ( + "projects/debian-cloud/global/images/family/debian-11" + ) + initialize_params.disk_size_gb = 250 + disk.initialize_params = initialize_params + disk.auto_delete = True + disk.boot = True + + template = compute_v1.InstanceTemplate() + template.name = template_name + template.properties = compute_v1.InstanceProperties() + template.properties.disks = [disk] + template.properties.machine_type = "e2-standard-4" + + # The template connects the instance to the specified network and subnetwork. + network_interface = compute_v1.NetworkInterface() + network_interface.network = network + network_interface.subnetwork = subnetwork + template.properties.network_interfaces = [network_interface] + + template_client = compute_v1.InstanceTemplatesClient() + operation_client = compute_v1.GlobalOperationsClient() + op = template_client.insert_unary( + project=project_id, instance_template_resource=template + ) + operation_client.wait(project=project_id, operation=op.name) + + 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 new file mode 100644 index 000000000..23bd929ee --- /dev/null +++ b/samples/ingredients/instance-templates/delete.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 delete_instance_template(project_id: str, template_name: str): + """ + Delete an instance template. + + Args: + project_id: project ID or project number of the Cloud project you use. + template_name: name of the template to delete. + """ + template_client = compute_v1.InstanceTemplatesClient() + operation_client = compute_v1.GlobalOperationsClient() + op = template_client.delete_unary( + project=project_id, instance_template=template_name + ) + operation_client.wait(project=project_id, operation=op.name) + return +# diff --git a/samples/ingredients/instance-templates/get.py b/samples/ingredients/instance-templates/get.py new file mode 100644 index 000000000..99aae684d --- /dev/null +++ b/samples/ingredients/instance-templates/get.py @@ -0,0 +1,40 @@ +# 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_template( + project_id: str, template_name: str +) -> compute_v1.InstanceTemplate: + """ + Retrieve an instance template, which you can use to create virtual machine + (VM) instances and managed instance groups (MIGs). + + Args: + project_id: project ID or project number of the Cloud project you use. + template_name: name of the template to retrieve. + + Returns: + InstanceTemplate object that represents the retrieved template. + """ + template_client = compute_v1.InstanceTemplatesClient() + return template_client.get(project=project_id, instance_template=template_name) +# diff --git a/samples/ingredients/instance-templates/list.py b/samples/ingredients/instance-templates/list.py new file mode 100644 index 000000000..851e2c48e --- /dev/null +++ b/samples/ingredients/instance-templates/list.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 + +from typing import Iterable +from google.cloud import compute_v1 + + +# +def list_instance_templates(project_id: str) -> Iterable[compute_v1.InstanceTemplate]: + """ + Get a list of InstanceTemplate objects available in a project. + + Args: + project_id: project ID or project number of the Cloud project you use. + + Returns: + Iterable list of InstanceTemplate objects. + """ + template_client = compute_v1.InstanceTemplatesClient() + return template_client.list(project=project_id) +# diff --git a/samples/ingredients/instances/__init__.py b/samples/ingredients/instances/__init__.py new file mode 100644 index 000000000..81d8b9be3 --- /dev/null +++ b/samples/ingredients/instances/__init__.py @@ -0,0 +1,18 @@ +# 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 diff --git a/samples/ingredients/instances/create_instance.py b/samples/ingredients/instances/create_instance.py new file mode 100644 index 000000000..85c2e4818 --- /dev/null +++ b/samples/ingredients/instances/create_instance.py @@ -0,0 +1,124 @@ +# 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 re +import sys +from google.cloud import compute_v1 +import time +from typing import List + + +# +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, + 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}" + 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 + + # 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}" + + 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 +# diff --git a/samples/ingredients/instances/create_instance_from_template.py b/samples/ingredients/instances/create_instance_from_template.py new file mode 100644 index 000000000..73ff814f4 --- /dev/null +++ b/samples/ingredients/instances/create_instance_from_template.py @@ -0,0 +1,57 @@ +# 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 create_instance_from_template( + project_id: str, zone: str, instance_name: str, instance_template_url: str +) -> compute_v1.Instance: + """ + Creates a Compute Engine VM instance from an instance template. + + Args: + project_id: ID or number of the project you want to use. + zone: Name of the zone you want to check, for example: us-west3-b + instance_name: Name of the new instance. + instance_template_url: URL of the instance template used for creating the new instance. + It can be a full or partial URL. + Examples: + - https://www.googleapis.com/compute/v1/projects/project/global/instanceTemplates/example-instance-template + - projects/project/global/instanceTemplates/example-instance-template + - global/instanceTemplates/example-instance-template + + Returns: + Instance object. + """ + operation_client = compute_v1.ZoneOperationsClient() + instance_client = compute_v1.InstancesClient() + + instance_insert_request = compute_v1.InsertInstanceRequest() + instance_insert_request.project = project_id + instance_insert_request.zone = zone + 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) + + 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 new file mode 100644 index 000000000..001cb5179 --- /dev/null +++ b/samples/ingredients/instances/create_instance_from_template_with_overrides.py @@ -0,0 +1,97 @@ +# 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 create_instance_from_template_with_overrides( + project_id: str, + zone: str, + instance_name: str, + instance_template_name: str, + machine_type: str, + new_disk_source_image: str, +) -> compute_v1.Instance: + """ + Creates a Compute Engine VM instance from an instance template, changing the machine type and + adding a new disk created from a source image. + + Args: + project_id: ID or number of the project you want to use. + zone: Name of the zone you want to check, for example: us-west3-b + instance_name: Name of the new instance. + instance_template_name: Name of the instance template used for creating the new instance. + machine_type: Machine type you want to set in following format: + "zones/{zone}/machineTypes/{type_name}". For example: + - "zones/europe-west3-c/machineTypes/f1-micro" + - You can find the list of available machine types using: + https://cloud.google.com/sdk/gcloud/reference/compute/machine-types/list + new_disk_source_image: Path the the disk image you want to use for your new + disk. This can be one of the public images + (like "projects/debian-cloud/global/images/family/debian-10") + or a private image you have access to. + For a list of available public images, see the documentation: + http://cloud.google.com/compute/docs/images + + Returns: + Instance object. + """ + operation_client = compute_v1.ZoneOperationsClient() + instance_client = compute_v1.InstancesClient() + instance_template_client = compute_v1.InstanceTemplatesClient() + + # Retrieve an instance template by name. + instance_template = instance_template_client.get( + project=project_id, instance_template=instance_template_name + ) + + # Adjust diskType field of the instance template to use the URL formatting required by instances.insert.diskType + # For instance template, there is only a name, not URL. + for disk in instance_template.properties.disks: + if disk.initialize_params.disk_type: + disk.initialize_params.disk_type = ( + f"zones/{zone}/diskTypes/{disk.initialize_params.disk_type}" + ) + + instance = compute_v1.Instance() + instance.name = instance_name + instance.machine_type = machine_type + instance.disks = instance_template.properties.disks + + new_disk = compute_v1.AttachedDisk() + new_disk.initialize_params.disk_size_gb = 50 + new_disk.initialize_params.source_image = new_disk_source_image + new_disk.auto_delete = True + new_disk.boot = False + new_disk.type_ = "PERSISTENT" + + instance.disks.append(new_disk) + + instance_insert_request = compute_v1.InsertInstanceRequest() + instance_insert_request.project = project_id + instance_insert_request.zone = zone + 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) + + return instance_client.get(project=project_id, zone=zone, instance=instance_name) +# \ No newline at end of file diff --git a/samples/ingredients/instances/create_start_instance/create_from_custom_image.py b/samples/ingredients/instances/create_start_instance/create_from_custom_image.py new file mode 100644 index 000000000..2d297cbca --- /dev/null +++ b/samples/ingredients/instances/create_start_instance/create_from_custom_image.py @@ -0,0 +1,61 @@ +# 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 +# +# 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 create_from_custom_image( + project_id: str, zone: str, instance_name: str, custom_image_link: str +) -> compute_v1.Instance: + """ + Create a new VM instance with custom image used as its 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. + custom_image_link: link to the custom image you want to use in the form of: + "projects/{project_name}/global/images/{image_name}" + + Returns: + Instance object. + """ + disk_type = f"zones/{zone}/diskTypes/pd-standard" + disks = [disk_from_image(disk_type, 10, True, custom_image_link)] + instance = create_instance(project_id, zone, instance_name, disks) + return instance +# diff --git a/samples/ingredients/instances/create_start_instance/create_from_public_image.py b/samples/ingredients/instances/create_start_instance/create_from_public_image.py new file mode 100644 index 000000000..2eb8e3c2e --- /dev/null +++ b/samples/ingredients/instances/create_start_instance/create_from_public_image.py @@ -0,0 +1,42 @@ +# 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 create_from_public_image(project_id: str, zone: str, instance_name: str) -> compute_v1.Instance: + """ + Create a new VM instance with Debian 10 operating system. + + 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. + + Returns: + Instance object. + """ + 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)] + instance = create_instance(project_id, zone, instance_name, disks) + return instance +# diff --git a/samples/ingredients/instances/create_start_instance/create_from_snapshot.py b/samples/ingredients/instances/create_start_instance/create_from_snapshot.py new file mode 100644 index 000000000..a2729332c --- /dev/null +++ b/samples/ingredients/instances/create_start_instance/create_from_snapshot.py @@ -0,0 +1,43 @@ +# 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 + + +# +def create_from_snapshot( + project_id: str, zone: str, instance_name: str, snapshot_link: str +): + """ + Create a new VM instance with boot disk created from a snapshot. The + new boot disk will have 20 gigabytes. + + 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. + snapshot_link: link to the snapshot you want to use as the source of your + boot disk in the form of: "projects/{project_name}/global/snapshots/{snapshot_name}" + + Returns: + Instance object. + """ + disk_type = f"zones/{zone}/diskTypes/pd-standard" + disks = [disk_from_snapshot(disk_type, 20, True, snapshot_link)] + instance = create_instance(project_id, zone, instance_name, disks) + return instance +# diff --git a/samples/ingredients/instances/create_start_instance/create_with_additional_disk.py b/samples/ingredients/instances/create_start_instance/create_with_additional_disk.py new file mode 100644 index 000000000..b921f27a3 --- /dev/null +++ b/samples/ingredients/instances/create_start_instance/create_with_additional_disk.py @@ -0,0 +1,46 @@ +# 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 create_with_additional_disk(project_id: str, zone: str, instance_name: str) -> compute_v1.Instance: + """ + Create a new VM instance with Debian 10 operating system on a 20 GB disk + and a 25 GB additional empty 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. + + Returns: + Instance object. + """ + 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, 20, True, newest_debian.self_link), + empty_disk(disk_type, 25), + ] + instance = create_instance(project_id, zone, instance_name, disks) + return instance +# \ No newline at end of file diff --git a/samples/ingredients/instances/create_start_instance/create_with_snapshotted_data_disk.py b/samples/ingredients/instances/create_start_instance/create_with_snapshotted_data_disk.py new file mode 100644 index 000000000..ea87201e5 --- /dev/null +++ b/samples/ingredients/instances/create_start_instance/create_with_snapshotted_data_disk.py @@ -0,0 +1,48 @@ +# 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 + + +# +def create_with_snapshotted_data_disk( + project_id: str, zone: str, instance_name: str, snapshot_link: str +): + """ + Create a new VM instance with Debian 10 operating system and data disk created from snapshot. + + 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. + snapshot_link: link to the snapshot you want to use as the source of your + data disk in the form of: "projects/{project_name}/global/snapshots/{snapshot_name}" + + Returns: + Instance object. + """ + 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), + disk_from_snapshot(disk_type, 11, False, snapshot_link), + ] + instance = create_instance(project_id, zone, instance_name, disks) + return instance +# diff --git a/samples/ingredients/instances/create_with_subnet.py b/samples/ingredients/instances/create_with_subnet.py new file mode 100644 index 000000000..bc39ff223 --- /dev/null +++ b/samples/ingredients/instances/create_with_subnet.py @@ -0,0 +1,57 @@ +# 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 create_with_subnet( + project_id: str, zone: str, instance_name: str, network_link: str, subnet_link: str +) -> compute_v1.Instance: + """ + Create a new VM instance with Debian 10 operating system in specified network and subnetwork. + + 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. + 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}" + + Returns: + Instance object. + """ + 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)] + instance = create_instance( + project_id, + zone, + instance_name, + disks, + network_link=network_link, + subnetwork_link=subnet_link, + ) + return instance +# diff --git a/samples/ingredients/instances/custom_hostname/create.py b/samples/ingredients/instances/custom_hostname/create.py new file mode 100644 index 000000000..9a990cb9f --- /dev/null +++ b/samples/ingredients/instances/custom_hostname/create.py @@ -0,0 +1,43 @@ +# 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 create_instance_custom_hostname(project_id: str, zone: str, instance_name: str, hostname: str) -> compute_v1.Instance: + """ + Create a new VM instance with Debian 10 operating system and a custom hostname. + + 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. + hostname: the hostname you want to use for the new instance. + + Returns: + Instance object. + """ + newest_debian = get_image_from_family( + project="debian-cloud", family="debian-11" + ) + disk_type = f"zones/{zone}/diskTypes/pd-standard" + disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)] + instance = create_instance(project_id, zone, instance_name, disks, custom_hostname=hostname) + return instance +# diff --git a/samples/ingredients/instances/custom_hostname/get.py b/samples/ingredients/instances/custom_hostname/get.py new file mode 100644 index 000000000..b362fce26 --- /dev/null +++ b/samples/ingredients/instances/custom_hostname/get.py @@ -0,0 +1,40 @@ +# 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_hostname(project_id: str, zone: str, instance_name: str) -> str: + """ + Retrieve the hostname of given instance. + + 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 virtual machine to check. + + Returns: + The hostname of an instance. + """ + instance_client = compute_v1.InstancesClient() + instance = instance_client.get( + project=project_id, zone=zone, instance=instance_name + ) + return instance.hostname +# diff --git a/samples/ingredients/instances/custom_machine_types/create_extra_mem_no_helper.py b/samples/ingredients/instances/custom_machine_types/create_extra_mem_no_helper.py new file mode 100644 index 000000000..536455f66 --- /dev/null +++ b/samples/ingredients/instances/custom_machine_types/create_extra_mem_no_helper.py @@ -0,0 +1,71 @@ +# 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_custom_instances_extra_mem( + project_id: str, zone: str, instance_name: str, core_count: int, memory: int +) -> List[compute_v1.Instance]: + """ + Create 3 new VM instances with extra memory without using a CustomMachineType helper class. + + 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. + core_count: number of CPU cores you want to use. + memory: the amount of memory for the VM instance, in megabytes. + + Returns: + List of Instance objects. + """ + 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)] + # The core_count and memory values are not validated anywhere and can be rejected by the API. + instances = [ + create_instance( + project_id, + zone, + f"{instance_name}_n1_extra_mem", + disks, + f"zones/{zone}/machineTypes/custom-{core_count}-{memory}-ext", + ), + create_instance( + project_id, + zone, + f"{instance_name}_n2_extra_mem", + disks, + f"zones/{zone}/machineTypes/n2-custom-{core_count}-{memory}-ext", + ), + create_instance( + project_id, + zone, + f"{instance_name}_n2d_extra_mem", + disks, + f"zones/{zone}/machineTypes/n2d-custom-{core_count}-{memory}-ext", + ), + ] + return instances +# diff --git a/samples/ingredients/instances/custom_machine_types/create_shared_with_helper.py b/samples/ingredients/instances/custom_machine_types/create_shared_with_helper.py new file mode 100644 index 000000000..a29193438 --- /dev/null +++ b/samples/ingredients/instances/custom_machine_types/create_shared_with_helper.py @@ -0,0 +1,60 @@ +# 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 create_custom_shared_core_instance( + project_id: str, + zone: str, + instance_name: str, + cpu_series: CustomMachineType.CPUSeries, + memory: int, +) -> compute_v1.Instance: + """ + Create a new VM instance with a custom type using shared CPUs. + + 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. + cpu_series: the type of CPU you want to use. Pick one value from the CustomMachineType.CPUSeries enum. + For example: CustomMachineType.CPUSeries.E2_MICRO + memory: the amount of memory for the VM instance, in megabytes. + + Return: + Instance object. + """ + assert cpu_series in ( + CustomMachineType.CPUSeries.E2_MICRO, + CustomMachineType.CPUSeries.E2_SMALL, + CustomMachineType.CPUSeries.E2_MEDIUM, + ) + custom_type = CustomMachineType(zone, cpu_series, memory) + + 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)] + + return create_instance(project_id, zone, instance_name, disks, str(custom_type)) +# diff --git a/samples/ingredients/instances/custom_machine_types/create_with_helper.py b/samples/ingredients/instances/custom_machine_types/create_with_helper.py new file mode 100644 index 000000000..2731f40da --- /dev/null +++ b/samples/ingredients/instances/custom_machine_types/create_with_helper.py @@ -0,0 +1,61 @@ +# 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 create_custom_instance( + project_id: str, + zone: str, + instance_name: str, + cpu_series: CustomMachineType.CPUSeries, + core_count: int, + memory: int, +) -> compute_v1.Instance: + """ + Create a new VM instance with a custom machine type. + + 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. + cpu_series: the type of CPU you want to use. Select one value from the CustomMachineType.CPUSeries enum. + For example: CustomMachineType.CPUSeries.N2 + core_count: number of CPU cores you want to use. + memory: the amount of memory for the VM instance, in megabytes. + + Return: + Instance object. + """ + assert cpu_series in ( + CustomMachineType.CPUSeries.E2, + CustomMachineType.CPUSeries.N1, + CustomMachineType.CPUSeries.N2, + CustomMachineType.CPUSeries.N2D, + ) + custom_type = CustomMachineType(zone, cpu_series, memory, core_count) + + 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)] + + return create_instance(project_id, zone, instance_name, disks, str(custom_type)) +# diff --git a/samples/ingredients/instances/custom_machine_types/create_without_helper.py b/samples/ingredients/instances/custom_machine_types/create_without_helper.py new file mode 100644 index 000000000..a17a979bb --- /dev/null +++ b/samples/ingredients/instances/custom_machine_types/create_without_helper.py @@ -0,0 +1,60 @@ +# 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_custom_instances_no_helper( + project_id: str, zone: str, instance_name: str, core_count: int, memory: int +) -> List[compute_v1.Instance]: + """ + Create 7 new VM instances without using a CustomMachineType helper function. + + 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. + core_count: number of CPU cores you want to use. + memory: the amount of memory for the VM instance, in megabytes. + + Returns: + List of Instance objects. + """ + 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)] + params = [ + (f"{instance_name}_n1", f"zones/{zone}/machineTypes/custom-{core_count}-{memory}"), + (f"{instance_name}_n2", f"zones/{zone}/machineTypes/n2-custom-{core_count}-{memory}"), + (f"{instance_name}_n2d", f"zones/{zone}/machineTypes/n2d-custom-{core_count}-{memory}"), + (f"{instance_name}_e2", f"zones/{zone}/machineTypes/e2-custom-{core_count}-{memory}"), + (f"{instance_name}_e2_micro", f"zones/{zone}/machineTypes/e2-custom-micro-{memory}"), + (f"{instance_name}_e2_small", f"zones/{zone}/machineTypes/e2-custom-small-{memory}"), + (f"{instance_name}_e2_medium", f"zones/{zone}/machineTypes/e2-custom-medium-{memory}"), + ] + # The core_count and memory values are not validated anywhere and can be rejected by the API. + instances = [create_instance(project_id, zone, name, disks, type) for name, type in params] + return instances +# diff --git a/samples/ingredients/instances/custom_machine_types/helper_class.py b/samples/ingredients/instances/custom_machine_types/helper_class.py new file mode 100644 index 000000000..616961943 --- /dev/null +++ b/samples/ingredients/instances/custom_machine_types/helper_class.py @@ -0,0 +1,211 @@ +# 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 collections import namedtuple +from enum import Enum, unique + + +# +def gb_to_mb(value: int) -> int: + return value << 10 + + +class CustomMachineType: + """ + Allows to create custom machine types to be used with the VM instances. + """ + + @unique + class CPUSeries(Enum): + N1 = "custom" + N2 = "n2-custom" + N2D = "n2d-custom" + E2 = "e2-custom" + E2_MICRO = "e2-custom-micro" + E2_SMALL = "e2-custom-small" + E2_MEDIUM = "e2-custom-medium" + + TypeLimits = namedtuple( + "TypeLimits", + [ + "allowed_cores", + "min_mem_per_core", + "max_mem_per_core", + "allow_extra_memory", + "extra_memory_limit", + ], + ) + + # The limits for various CPU types are described on: + # https://cloud.google.com/compute/docs/general-purpose-machines + LIMITS = { + CPUSeries.E2: TypeLimits(frozenset(range(2, 33, 2)), 512, 8192, False, 0), + CPUSeries.E2_MICRO: TypeLimits(frozenset(), 1024, 2048, False, 0), + CPUSeries.E2_SMALL: TypeLimits(frozenset(), 2048, 4096, False, 0), + CPUSeries.E2_MEDIUM: TypeLimits(frozenset(), 4096, 8192, False, 0), + CPUSeries.N2: TypeLimits( + frozenset(range(2, 33, 2)).union(set(range(36, 129, 4))), + 512, + 8192, + True, + gb_to_mb(624), + ), + CPUSeries.N2D: TypeLimits( + frozenset({2, 4, 8, 16, 32, 48, 64, 80, 96}), 512, 8192, True, gb_to_mb(768) + ), + CPUSeries.N1: TypeLimits( + frozenset({1}.union(range(2, 97, 2))), 922, 6656, True, gb_to_mb(624) + ), + } + + def __init__( + self, zone: str, cpu_series: CPUSeries, memory_mb: int, core_count: int = 0 + ): + self.zone = zone + self.cpu_series = cpu_series + self.limits = self.LIMITS[self.cpu_series] + # Shared machine types (e2-small, e2-medium and e2-micro) always have + # 2 vCPUs: https://cloud.google.com/compute/docs/general-purpose-machines#e2_limitations + self.core_count = 2 if self.is_shared() else core_count + self.memory_mb = memory_mb + self._checked = False + self._check_parameters() + self.extra_memory_used = self._check_extra_memory() + + def is_shared(self): + return self.cpu_series in ( + CustomMachineType.CPUSeries.E2_SMALL, + CustomMachineType.CPUSeries.E2_MICRO, + CustomMachineType.CPUSeries.E2_MEDIUM, + ) + + def _check_extra_memory(self) -> bool: + if self._checked: + return self.memory_mb > self.core_count * self.limits.max_mem_per_core + else: + raise RuntimeError("You need to call _check_parameters() before calling _check_extra_memory()") + + def _check_parameters(self): + """ + Check whether the requested parameters are allowed. Find more information about limitations of custom machine + types at: https://cloud.google.com/compute/docs/general-purpose-machines#custom_machine_types + """ + # Check the number of cores + if ( + self.limits.allowed_cores + and self.core_count not in self.limits.allowed_cores + ): + raise RuntimeError( + f"Invalid number of cores requested. Allowed number of cores for {self.cpu_series.name} is: {sorted(self.limits.allowed_cores)}" + ) + + # Memory must be a multiple of 256 MB + if self.memory_mb % 256 != 0: + raise RuntimeError("Requested memory must be a multiple of 256 MB.") + + # Check if the requested memory isn't too little + if self.memory_mb < self.core_count * self.limits.min_mem_per_core: + raise RuntimeError( + f"Requested memory is too low. Minimal memory for {self.cpu_series.name} is {self.limits.min_mem_per_core} MB per core." + ) + + # Check if the requested memory isn't too much + if self.memory_mb > self.core_count * self.limits.max_mem_per_core: + if self.limits.allow_extra_memory: + if self.memory_mb > self.limits.extra_memory_limit: + raise RuntimeError( + f"Requested memory is too large.. Maximum memory allowed for {self.cpu_series.name} is {self.limits.extra_memory_limit} MB." + ) + else: + raise RuntimeError( + f"Requested memory is too large.. Maximum memory allowed for {self.cpu_series.name} is {self.limits.max_mem_per_core} MB per core." + ) + + self._checked = True + + def __str__(self) -> str: + """ + Return the custom machine type in form of a string acceptable by Compute Engine API. + """ + if self.cpu_series in { + self.CPUSeries.E2_SMALL, + self.CPUSeries.E2_MICRO, + self.CPUSeries.E2_MEDIUM, + }: + return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.memory_mb}" + + if self.extra_memory_used: + return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.core_count}-{self.memory_mb}-ext" + + return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.core_count}-{self.memory_mb}" + + def short_type_str(self) -> str: + """ + Return machine type in a format without the zone. For example, n2-custom-0-10240. + This format is used to create instance templates. + """ + return str(self).rsplit("/", maxsplit=1)[1] + + @classmethod + def from_str(cls, machine_type: str): + """ + Construct a new object from a string. The string needs to be a valid custom machine type like: + - https://www.googleapis.com/compute/v1/projects/diregapic-mestiv/zones/us-central1-b/machineTypes/e2-custom-4-8192 + - zones/us-central1-b/machineTypes/e2-custom-4-8192 + - e2-custom-4-8192 (in this case, the zone parameter will not be set) + """ + zone = None + if machine_type.startswith("http"): + machine_type = machine_type[machine_type.find("zones/") :] + + if machine_type.startswith("zones/"): + _, zone, _, machine_type = machine_type.split("/") + + extra_mem = machine_type.endswith("-ext") + + if machine_type.startswith("custom"): + cpu = cls.CPUSeries.N1 + _, cores, memory = machine_type.rsplit("-", maxsplit=2) + else: + if extra_mem: + cpu_series, _, cores, memory, _ = machine_type.split("-") + else: + cpu_series, _, cores, memory = machine_type.split("-") + if cpu_series == "n2": + cpu = cls.CPUSeries.N2 + elif cpu_series == "n2d": + cpu = cls.CPUSeries.N2D + elif cpu_series == "e2": + cpu = cls.CPUSeries.E2 + if cores == "micro": + cpu = cls.CPUSeries.E2_MICRO + cores = 2 + elif cores == "small": + cpu = cls.CPUSeries.E2_SMALL + cores = 2 + elif cores == "medium": + cpu = cls.CPUSeries.E2_MEDIUM + cores = 2 + else: + raise RuntimeError("Unknown CPU series.") + + cores = int(cores) + memory = int(memory) + + return cls(zone, cpu, memory, cores) +# diff --git a/samples/ingredients/instances/custom_machine_types/update_memory.py b/samples/ingredients/instances/custom_machine_types/update_memory.py new file mode 100644 index 000000000..ee9ed2a75 --- /dev/null +++ b/samples/ingredients/instances/custom_machine_types/update_memory.py @@ -0,0 +1,89 @@ +# 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 time + +from google.cloud import compute_v1 + + +# +def add_extended_memory_to_instance( + project_id: str, zone: str, instance_name: str, new_memory: int +): + """ + Modify an existing VM to use extended memory. + + 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. + new_memory: the amount of memory for the VM instance, in megabytes. + + Returns: + Instance object. + """ + instance_client = compute_v1.InstancesClient() + operation_client = compute_v1.ZoneOperationsClient() + instance = instance_client.get( + project=project_id, zone=zone, instance=instance_name + ) + + if not ("n1-" in instance.machine_type or "n2-" in instance.machine_type or "n2d-" in instance.machine_type): + raise RuntimeError("Extra memory is available only for N1, N2 and N2D CPUs.") + + # Make sure that the machine is turned off + if instance.status not in ( + instance.Status.TERMINATED.name, + instance.Status.STOPPED.name, + ): + op = instance_client.stop_unary( + project=project_id, zone=zone, instance=instance_name + ) + operation_client.wait(project=project_id, zone=zone, operation=op.name) + start = time.time() + while instance.status not in ( + instance.Status.TERMINATED.name, + instance.Status.STOPPED.name, + ): + # Waiting for the instance to be turned off. + instance = instance_client.get( + project=project_id, zone=zone, instance=instance_name + ) + time.sleep(2) + if time.time() - start >= 300: # 5 minutes + raise TimeoutError() + + # Modify the machine definition, remember that extended memory is available only for N1, N2 and N2D CPUs + start, end = instance.machine_type.rsplit("-", maxsplit=1) + instance.machine_type = start + f"-{new_memory}-ext" + # TODO: If you prefer to use the CustomMachineType helper class, uncomment this code and comment the 2 lines above + # Using CustomMachineType helper + # cmt = CustomMachineType.from_str(instance.machine_type) + # cmt.memory_mb = new_memory + # cmt.extra_memory_used = True + # instance.machine_type = str(cmt) + op = instance_client.update_unary( + project=project_id, + zone=zone, + instance=instance_name, + instance_resource=instance, + ) + operation_client.wait(project=project_id, zone=zone, operation=op.name) + + 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 new file mode 100644 index 000000000..ee84a349c --- /dev/null +++ b/samples/ingredients/instances/delete.py @@ -0,0 +1,56 @@ +# 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 +import time + +from google.cloud import compute_v1 + + +# +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. + + 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” + 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( + 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) + print(f"Instance {machine_name} deleted.") + return +# diff --git a/samples/ingredients/instances/delete_protection/__init__.py b/samples/ingredients/instances/delete_protection/__init__.py new file mode 100644 index 000000000..8fb7cb024 --- /dev/null +++ b/samples/ingredients/instances/delete_protection/__init__.py @@ -0,0 +1,19 @@ +# 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 + diff --git a/samples/ingredients/instances/delete_protection/create.py b/samples/ingredients/instances/delete_protection/create.py new file mode 100644 index 000000000..eb431ec7e --- /dev/null +++ b/samples/ingredients/instances/delete_protection/create.py @@ -0,0 +1,44 @@ +# 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 create_protected_instance(project_id: str, zone: str, instance_name: str) -> compute_v1.Instance: + """ + Create a new VM instance with Debian 10 operating system and delete protection + turned on. + + 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. + + Returns: + Instance object. + """ + newest_debian = get_image_from_family( + project="debian-cloud", family="debian-11" + ) + disk_type = f"zones/{zone}/diskTypes/pd-standard" + disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)] + instance = create_instance(project_id, zone, instance_name, disks, delete_protection=True) + return instance +# \ No newline at end of file diff --git a/samples/ingredients/instances/delete_protection/get.py b/samples/ingredients/instances/delete_protection/get.py new file mode 100644 index 000000000..f57b1624e --- /dev/null +++ b/samples/ingredients/instances/delete_protection/get.py @@ -0,0 +1,38 @@ +# 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_delete_protection(project_id: str, zone: str, instance_name: str) -> bool: + """ + Returns the state of delete protection flag of given instance. + 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 virtual machine to check. + Returns: + The boolean value of the delete protection setting. + """ + instance_client = compute_v1.InstancesClient() + instance = instance_client.get( + project=project_id, zone=zone, instance=instance_name + ) + return instance.deletion_protection +# diff --git a/samples/ingredients/instances/delete_protection/set.py b/samples/ingredients/instances/delete_protection/set.py new file mode 100644 index 000000000..fd7bd4ca9 --- /dev/null +++ b/samples/ingredients/instances/delete_protection/set.py @@ -0,0 +1,47 @@ +# 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 set_delete_protection( + project_id: str, zone: str, instance_name: str, delete_protection: bool +) -> None: + """ + Updates the delete protection setting of given instance. + 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 instance to update. + delete_protection: boolean value indicating if the virtual machine should be + protected against deletion or not. + """ + instance_client = compute_v1.InstancesClient() + operation_client = compute_v1.ZoneOperationsClient() + + request = compute_v1.SetDeletionProtectionInstanceRequest() + request.project = project_id + request.zone = zone + 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) + return +# diff --git a/samples/ingredients/instances/list.py b/samples/ingredients/instances/list.py new file mode 100644 index 000000000..089f7fdab --- /dev/null +++ b/samples/ingredients/instances/list.py @@ -0,0 +1,44 @@ +# 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 Iterable + +from google.cloud import compute_v1 + + +# +def list_instances(project_id: str, zone: str) -> Iterable[compute_v1.Instance]: + """ + List all instances 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” + Returns: + An iterable collection of Instance objects. + """ + instance_client = compute_v1.InstancesClient() + instance_list = instance_client.list(project=project_id, zone=zone) + + print(f"Instances found in zone {zone}:") + for instance in instance_list: + print(f" - {instance.name} ({instance.machine_type})") + + return instance_list +# + diff --git a/samples/ingredients/instances/list_all.py b/samples/ingredients/instances/list_all.py new file mode 100644 index 000000000..ced8e7a1f --- /dev/null +++ b/samples/ingredients/instances/list_all.py @@ -0,0 +1,58 @@ +# 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 Dict, Iterable + +from google.cloud import compute_v1 + + +# +def list_all_instances( + project_id: str, +) -> Dict[str, Iterable[compute_v1.Instance]]: + """ + Returns a dictionary of all instances present in a project, grouped by their zone. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + Returns: + A dictionary with zone names as keys (in form of "zones/{zone_name}") and + iterable collections of Instance objects as values. + """ + instance_client = compute_v1.InstancesClient() + request = compute_v1.AggregatedListInstancesRequest() + request.project = project_id + # Use the `max_results` parameter to limit the number of results that the API returns per response page. + request.max_results = 50 + + agg_list = instance_client.aggregated_list(request=request) + + all_instances = {} + print("Instances found:") + # Despite using the `max_results` parameter, you don't need to handle the pagination + # yourself. The returned `AggregatedListPager` object handles pagination + # automatically, returning separated pages as you iterate over the results. + for zone, response in agg_list: + if response.instances: + all_instances[zone] = response.instances + print(f" {zone}:") + for instance in response.instances: + print(f" - {instance.name} ({instance.machine_type})") + return all_instances +# + diff --git a/samples/ingredients/instances/preemptible/__init__.py b/samples/ingredients/instances/preemptible/__init__.py new file mode 100644 index 000000000..81d8b9be3 --- /dev/null +++ b/samples/ingredients/instances/preemptible/__init__.py @@ -0,0 +1,18 @@ +# 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 diff --git a/samples/ingredients/instances/preemptible/create.py b/samples/ingredients/instances/preemptible/create.py new file mode 100644 index 000000000..46d611a5d --- /dev/null +++ b/samples/ingredients/instances/preemptible/create.py @@ -0,0 +1,60 @@ +# 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 +# +# 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 create_preemptible_instance(project_id: str, zone: str, instance_name: str) -> compute_v1.Instance: + """ + Create a new preemptible VM instance with Debian 10 operating system. + + 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. + + Returns: + Instance object. + """ + newest_debian = get_image_from_family( + project="debian-cloud", family="debian-11" + ) + disk_type = f"zones/{zone}/diskTypes/pd-standard" + disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)] + instance = create_instance(project_id, zone, instance_name, disks, preemptible=True) + return instance +# diff --git a/samples/ingredients/instances/preemptible/get.py b/samples/ingredients/instances/preemptible/get.py new file mode 100644 index 000000000..7ff9fc860 --- /dev/null +++ b/samples/ingredients/instances/preemptible/get.py @@ -0,0 +1,38 @@ +# 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 is_preemptible(project_id: str, zone: str, instance_name: str) -> bool: + """ + Check if a given instance is preemptible or not. + 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 virtual machine to check. + Returns: + The preemptible status of the instance. + """ + instance_client = compute_v1.InstancesClient() + instance = instance_client.get( + project=project_id, zone=zone, instance=instance_name + ) + return instance.scheduling.preemptible +# diff --git a/samples/ingredients/instances/preemptible/preemption_history.py b/samples/ingredients/instances/preemptible/preemption_history.py new file mode 100644 index 000000000..53b6a3da7 --- /dev/null +++ b/samples/ingredients/instances/preemptible/preemption_history.py @@ -0,0 +1,56 @@ +# 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 datetime +from typing import List, Tuple + + +# +def preemption_history( + project_id: str, zone: str, instance_name: str = None +) -> List[Tuple[str, datetime.datetime]]: + """ + Get a list of preemption operations from given zone in a project. Optionally limit + the results to instance name. + 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 virtual machine to look for. + Returns: + List of preemption operations in given zone. + """ + if instance_name: + filter = ( + f'operationType="compute.instances.preempted" ' + f"AND targetLink:instances/{instance_name}" + ) + else: + filter = 'operationType="compute.instances.preempted"' + + history = [] + + for operation in list_zone_operations(project_id, zone, filter): + this_instance_name = operation.target_link.rsplit("/", maxsplit=1)[1] + if instance_name and this_instance_name == instance_name: + # The filter used is not 100% accurate, it's `contains` not `equals` + # So we need to check the name to make sure it's the one we want. + moment = datetime.datetime.fromisoformat(operation.insert_time) + history.append((instance_name, moment)) + + return history +# diff --git a/samples/ingredients/instances/reset.py b/samples/ingredients/instances/reset.py new file mode 100644 index 000000000..a0d29a1d9 --- /dev/null +++ b/samples/ingredients/instances/reset.py @@ -0,0 +1,46 @@ +# 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 time + +from google.cloud import compute_v1 + + +# +def reset_instance(project_id: str, zone: str, instance_name: str) -> None: + """ + Resets a stopped Google Compute Engine instance (with unencrypted disks). + Args: + project_id: project ID or project number of the Cloud project your instance belongs to. + zone: name of the zone your instance belongs to. + 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( + 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() + return +# diff --git a/samples/ingredients/instances/start.py b/samples/ingredients/instances/start.py new file mode 100644 index 000000000..a57359b10 --- /dev/null +++ b/samples/ingredients/instances/start.py @@ -0,0 +1,46 @@ +# 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 time + +from google.cloud import compute_v1 + + +# +def start_instance(project_id: str, zone: str, instance_name: str) -> None: + """ + Starts a stopped Google Compute Engine instance (with unencrypted disks). + Args: + project_id: project ID or project number of the Cloud project your instance belongs to. + zone: name of the zone your instance belongs to. + 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( + 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() + return +# diff --git a/samples/ingredients/instances/start_encrypted.py b/samples/ingredients/instances/start_encrypted.py new file mode 100644 index 000000000..e90c56f2a --- /dev/null +++ b/samples/ingredients/instances/start_encrypted.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 time + +from google.cloud import compute_v1 + + +# +def start_instance_with_encryption_key( + project_id: str, zone: str, instance_name: str, key: bytes +): + """ + Starts a stopped Google Compute Engine instance (with encrypted disks). + Args: + project_id: project ID or project number of the Cloud project your instance belongs to. + zone: name of the zone your instance belongs to. + instance_name: name of the instance your want to start. + key: bytes object representing a raw base64 encoded key to your machines boot disk. + For more information about disk encryption see: + 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 + ) + + # Prepare the information about disk encryption + disk_data = compute_v1.CustomerEncryptionKeyProtectedDisk() + disk_data.source = instance_data.disks[0].source + disk_data.disk_encryption_key = compute_v1.CustomerEncryptionKey() + # Use raw_key to send over the key to unlock the disk + # To use a key stored in KMS, you need to provide `kms_key_name` and `kms_key_service_account` + disk_data.disk_encryption_key.raw_key = key + enc_data = compute_v1.InstancesStartWithEncryptionKeyRequest() + enc_data.disks = [disk_data] + + op = instance_client.start_with_encryption_key_unary( + 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() + return +# diff --git a/samples/ingredients/instances/stop.py b/samples/ingredients/instances/stop.py new file mode 100644 index 000000000..903053348 --- /dev/null +++ b/samples/ingredients/instances/stop.py @@ -0,0 +1,46 @@ +# 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 time + +from google.cloud import compute_v1 + + +# +def stop_instance(project_id: str, zone: str, instance_name: str) -> None: + """ + Stops a running Google Compute Engine instance. + Args: + project_id: project ID or project number of the Cloud project your instance belongs to. + zone: name of the zone your instance belongs to. + 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( + 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() + return +# diff --git a/samples/ingredients/operations/__init__.py b/samples/ingredients/operations/__init__.py new file mode 100644 index 000000000..81d8b9be3 --- /dev/null +++ b/samples/ingredients/operations/__init__.py @@ -0,0 +1,18 @@ +# 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 diff --git a/samples/ingredients/operations/list_zone_operations.py b/samples/ingredients/operations/list_zone_operations.py new file mode 100644 index 000000000..7089f023f --- /dev/null +++ b/samples/ingredients/operations/list_zone_operations.py @@ -0,0 +1,46 @@ +# 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 + +from google.cloud.compute_v1.services.zone_operations import pagers + + +# +def list_zone_operations( + project_id: str, zone: str, filter: str = "" +) -> pagers.ListPager: + """ + List all recent operations the happened in given zone in a project. Optionally filter those + operations by providing a filter. More about using the filter can be found here: + https://cloud.google.com/compute/docs/reference/rest/v1/zoneOperations/list + 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" + filter: filter string to be used for this listing operation. + Returns: + List of preemption operations in given zone. + """ + operation_client = compute_v1.ZoneOperationsClient() + request = compute_v1.ListZoneOperationsRequest() + request.project = project_id + request.zone = zone + request.filter = filter + + return operation_client.list(request) +# \ No newline at end of file diff --git a/samples/ingredients/operations/wait_for_operation.py b/samples/ingredients/operations/wait_for_operation.py new file mode 100644 index 000000000..53913076e --- /dev/null +++ b/samples/ingredients/operations/wait_for_operation.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 google.cloud import compute_v1 + + +# +def wait_for_operation( + operation: compute_v1.Operation, project_id: str +) -> compute_v1.Operation: + """ + This method waits for an operation to be completed. Calling this function + will block until the operation is finished. + + Args: + operation: The Operation object representing the operation you want to + wait on. + project_id: project ID or project number of the Cloud project you want to use. + + Returns: + Finished Operation object. + """ + kwargs = {"project": project_id, "operation": operation.name} + if operation.zone: + client = compute_v1.ZoneOperationsClient() + # Operation.zone is a full URL address of a zone, so we need to extract just the name + kwargs["zone"] = operation.zone.rsplit("/", maxsplit=1)[1] + elif operation.region: + client = compute_v1.RegionOperationsClient() + # Operation.region is a full URL address of a region, so we need to extract just the name + kwargs["region"] = operation.region.rsplit("/", maxsplit=1)[1] + else: + client = compute_v1.GlobalOperationsClient() + return client.wait(**kwargs) +# diff --git a/samples/ingredients/usage_report/disable.py b/samples/ingredients/usage_report/disable.py new file mode 100644 index 000000000..e8d1464cb --- /dev/null +++ b/samples/ingredients/usage_report/disable.py @@ -0,0 +1,43 @@ +# 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 disable_usage_export(project_id: str) -> None: + """ + Disable Compute Engine usage export bucket for the Cloud Project. + + Args: + project_id: project ID or project number of the project to update. + """ + projects_client = compute_v1.ProjectsClient() + + # Setting `usage_export_location_resource` to an + # empty object will disable the usage report generation. + operation = projects_client.set_usage_export_bucket_unary( + 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) +# + diff --git a/samples/ingredients/usage_report/get_bucket.py b/samples/ingredients/usage_report/get_bucket.py new file mode 100644 index 000000000..8b5a3b0b4 --- /dev/null +++ b/samples/ingredients/usage_report/get_bucket.py @@ -0,0 +1,55 @@ +# 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_usage_export_bucket(project_id: str) -> compute_v1.UsageExportLocation: + """ + Retrieve Compute Engine usage export bucket for the Cloud project. + Replaces the empty value returned by the API with the default value used + to generate report file names. + + Args: + project_id: project ID or project number of the project to update. + Returns: + UsageExportLocation object describing the current usage export settings + for project project_id. + """ + projects_client = compute_v1.ProjectsClient() + project_data = projects_client.get(project=project_id) + + uel = project_data.usage_export_location + + if not uel.bucket_name: + # The usage reports are disabled. + return uel + + if not uel.report_name_prefix: + # Although the server sent the empty string value, the next usage report + # generated with these settings still has the default prefix value + # "usage_gce". (see https://cloud.google.com/compute/docs/reference/rest/v1/projects/get) + print( + "Report name prefix not set, replacing with default value of " + "`usage_gce`." + ) + uel.report_name_prefix = "usage_gce" + return uel +# + diff --git a/samples/ingredients/usage_report/set_bucket.py b/samples/ingredients/usage_report/set_bucket.py new file mode 100644 index 000000000..7a948c8b7 --- /dev/null +++ b/samples/ingredients/usage_report/set_bucket.py @@ -0,0 +1,61 @@ +# 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 set_usage_export_bucket( + project_id: str, bucket_name: str, report_name_prefix: str = "" +) -> None: + """ + Set Compute Engine usage export bucket for the Cloud project. + This sample presents how to interpret the default value for the + report name prefix parameter. + + Args: + project_id: project ID or project number of the project to update. + bucket_name: Google Cloud Storage bucket used to store Compute Engine + usage reports. An existing Google Cloud Storage bucket is required. + report_name_prefix: Prefix of the usage report name which defaults to an empty string + to showcase default values behaviour. + """ + usage_export_location = compute_v1.UsageExportLocation() + usage_export_location.bucket_name = bucket_name + usage_export_location.report_name_prefix = report_name_prefix + + if not report_name_prefix: + # Sending an empty value for report_name_prefix results in the + # next usage report being generated with the default prefix value + # "usage_gce". (ref: https://cloud.google.com/compute/docs/reference/rest/v1/projects/setUsageExportBucket) + print( + "Setting report_name_prefix to empty value causes the report " + "to have the default prefix of `usage_gce`." + ) + + projects_client = compute_v1.ProjectsClient() + operation = projects_client.set_usage_export_bucket_unary( + 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) +# + diff --git a/samples/recipes/__init__.py b/samples/recipes/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/recipes/firewall/__init__.py b/samples/recipes/firewall/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/recipes/firewall/create.py b/samples/recipes/firewall/create.py new file mode 100644 index 000000000..8d76598fa --- /dev/null +++ b/samples/recipes/firewall/create.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/samples/recipes/firewall/delete.py b/samples/recipes/firewall/delete.py new file mode 100644 index 000000000..6c3752fa6 --- /dev/null +++ b/samples/recipes/firewall/delete.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/samples/recipes/firewall/list.py b/samples/recipes/firewall/list.py new file mode 100644 index 000000000..fbd0149f6 --- /dev/null +++ b/samples/recipes/firewall/list.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/samples/recipes/firewall/main.py b/samples/recipes/firewall/main.py new file mode 100644 index 000000000..c8a4d83b0 --- /dev/null +++ b/samples/recipes/firewall/main.py @@ -0,0 +1,58 @@ +# 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 + +# + + +# + +# + +# + +# + +# + +if __name__ == "__main__": + import google.auth + import google.auth.exceptions + + try: + default_project_id = google.auth.default()[1] + print(f"Using project {default_project_id}.") + except google.auth.exceptions.DefaultCredentialsError: + print( + "Please use `gcloud auth application-default login` " + "or set GOOGLE_APPLICATION_CREDENTIALS to use this script." + ) + else: + import uuid + + rule_name = "firewall-sample-" + uuid.uuid4().hex[:10] + print(f"Creating firewall rule {rule_name}...") + # The rule will be created with default priority of 1000. + create_firewall_rule(default_project_id, rule_name) + try: + print("Rule created:") + print(get_firewall_rule(default_project_id, rule_name)) + print("Updating rule priority to 10...") + patch_firewall_priority(default_project_id, rule_name, 10) + print("Rule updated: ") + print(get_firewall_rule(default_project_id, rule_name)) + print(f"Deleting rule {rule_name}...") + finally: + delete_firewall_rule(default_project_id, rule_name) + print("Done.") diff --git a/samples/recipes/firewall/patch.py b/samples/recipes/firewall/patch.py new file mode 100644 index 000000000..543157e1a --- /dev/null +++ b/samples/recipes/firewall/patch.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/samples/recipes/images/__init__.py b/samples/recipes/images/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/recipes/images/get.py b/samples/recipes/images/get.py new file mode 100644 index 000000000..4524e8f2f --- /dev/null +++ b/samples/recipes/images/get.py @@ -0,0 +1,28 @@ +# 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/samples/recipes/images/list.py b/samples/recipes/images/list.py new file mode 100644 index 000000000..80d3074cd --- /dev/null +++ b/samples/recipes/images/list.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/samples/recipes/images/pagination.py b/samples/recipes/images/pagination.py new file mode 100644 index 000000000..aa58b4f86 --- /dev/null +++ b/samples/recipes/images/pagination.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +# 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. + +# +# +import google.cloud.compute_v1 as compute_v1 + +# +# + + +# +def print_images_list(project: str) -> str: + """ + Prints a list of all non-deprecated image names available in given project. + + Args: + project: project ID or project number of the Cloud project you want to list images from. + + Returns: + The output as a string. + """ + images_client = compute_v1.ImagesClient() + # Listing only non-deprecated images to reduce the size of the reply. + images_list_request = compute_v1.ListImagesRequest( + project=project, max_results=100, filter="deprecated.state != DEPRECATED" + ) + output = [] + + # Although the `max_results` parameter is specified in the request, the iterable returned + # by the `list()` method hides the pagination mechanic. The library makes multiple + # requests to the API for you, so you can simply iterate over all the images. + for img in images_client.list(request=images_list_request): + print(f" - {img.name}") + output.append(f" - {img.name}") + return "\n".join(output) + + +# + + +# +def print_images_list_by_page(project: str, page_size: int = 10) -> str: + """ + Prints a list of all non-deprecated image names available in a given project, + divided into pages as returned by the Compute Engine API. + + Args: + project: project ID or project number of the Cloud project you want to list images from. + page_size: size of the pages you want the API to return on each call. + + Returns: + Output as a string. + """ + images_client = compute_v1.ImagesClient() + # Listing only non-deprecated images to reduce the size of the reply. + images_list_request = compute_v1.ListImagesRequest( + project=project, max_results=page_size, filter="deprecated.state != DEPRECATED" + ) + output = [] + + # Use the `pages` attribute of returned iterable to have more granular control of + # iteration over paginated results from the API. Each time you want to access the + # next page, the library retrieves that page from the API. + for page_num, page in enumerate( + images_client.list(request=images_list_request).pages, start=1 + ): + print(f"Page {page_num}: ") + output.append(f"Page {page_num}: ") + for img in page.items: + print(f" - {img.name}") + output.append(f" - {img.name}") + return "\n".join(output) + + +# + + +if __name__ == "__main__": + print("=================== Flat list of images ===================") + print_images_list("windows-sql-cloud") + print("================= Paginated list of images ================") + print_images_list_by_page("windows-sql-cloud", 5) diff --git a/samples/recipes/instance_templates/__init__.py b/samples/recipes/instance_templates/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/recipes/instance_templates/create.py b/samples/recipes/instance_templates/create.py new file mode 100644 index 000000000..6c313c2d2 --- /dev/null +++ b/samples/recipes/instance_templates/create.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/samples/recipes/instance_templates/create_from_instance.py b/samples/recipes/instance_templates/create_from_instance.py new file mode 100644 index 000000000..751416fe3 --- /dev/null +++ b/samples/recipes/instance_templates/create_from_instance.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/samples/recipes/instance_templates/create_with_subnet.py b/samples/recipes/instance_templates/create_with_subnet.py new file mode 100644 index 000000000..85639db00 --- /dev/null +++ b/samples/recipes/instance_templates/create_with_subnet.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/samples/recipes/instance_templates/delete.py b/samples/recipes/instance_templates/delete.py new file mode 100644 index 000000000..bf774c57d --- /dev/null +++ b/samples/recipes/instance_templates/delete.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/samples/recipes/instance_templates/get.py b/samples/recipes/instance_templates/get.py new file mode 100644 index 000000000..3036e7348 --- /dev/null +++ b/samples/recipes/instance_templates/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/samples/recipes/instance_templates/list.py b/samples/recipes/instance_templates/list.py new file mode 100644 index 000000000..6ce5c5b73 --- /dev/null +++ b/samples/recipes/instance_templates/list.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/samples/recipes/instances/__init__.py b/samples/recipes/instances/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/recipes/instances/create.py b/samples/recipes/instances/create.py new file mode 100644 index 000000000..b51a2e737 --- /dev/null +++ b/samples/recipes/instances/create.py @@ -0,0 +1,48 @@ +# 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 + +# +# + +# + +# + +# +# + +if __name__ == "__main__": + import uuid + import google.auth + import google.auth.exceptions + + try: + default_project_id = google.auth.default()[1] + except google.auth.exceptions.DefaultCredentialsError: + print( + "Please use `gcloud auth application-default login` " + "or set GOOGLE_APPLICATION_CREDENTIALS to use this script." + ) + else: + instance_name = "quickstart-" + uuid.uuid4().hex[:10] + instance_zone = "europe-central2-b" + + newest_debian = get_image_from_family( + project="debian-cloud", family="debian-10" + ) + disk_type = f"zones/{instance_zone}/diskTypes/pd-standard" + disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)] + + create_instance(default_project_id, instance_zone, instance_name, disks) diff --git a/samples/recipes/instances/create_start_instance/__init__.py b/samples/recipes/instances/create_start_instance/__init__.py new file mode 100644 index 000000000..e69de29bb 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 new file mode 100644 index 000000000..e50d60367 --- /dev/null +++ b/samples/recipes/instances/create_start_instance/create_from_custom_image.py @@ -0,0 +1,29 @@ +# 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/samples/recipes/instances/create_start_instance/create_from_public_image.py b/samples/recipes/instances/create_start_instance/create_from_public_image.py new file mode 100644 index 000000000..6f6f0ee04 --- /dev/null +++ b/samples/recipes/instances/create_start_instance/create_from_public_image.py @@ -0,0 +1,29 @@ +# 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/samples/recipes/instances/create_start_instance/create_from_snapshot.py b/samples/recipes/instances/create_start_instance/create_from_snapshot.py new file mode 100644 index 000000000..2047eeb57 --- /dev/null +++ b/samples/recipes/instances/create_start_instance/create_from_snapshot.py @@ -0,0 +1,26 @@ +# 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/samples/recipes/instances/create_start_instance/create_with_additional_disk.py b/samples/recipes/instances/create_start_instance/create_with_additional_disk.py new file mode 100644 index 000000000..ab9baa6e4 --- /dev/null +++ b/samples/recipes/instances/create_start_instance/create_with_additional_disk.py @@ -0,0 +1,33 @@ +# 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/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 new file mode 100644 index 000000000..858e61884 --- /dev/null +++ b/samples/recipes/instances/create_start_instance/create_with_snapshotted_data_disk.py @@ -0,0 +1,33 @@ +# 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/samples/recipes/instances/create_with_subnet.py b/samples/recipes/instances/create_with_subnet.py new file mode 100644 index 000000000..906edca50 --- /dev/null +++ b/samples/recipes/instances/create_with_subnet.py @@ -0,0 +1,29 @@ +# 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/samples/recipes/instances/custom_hostname/create.py b/samples/recipes/instances/custom_hostname/create.py new file mode 100644 index 000000000..55f3b47e6 --- /dev/null +++ b/samples/recipes/instances/custom_hostname/create.py @@ -0,0 +1,29 @@ +# 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/samples/recipes/instances/custom_hostname/get.py b/samples/recipes/instances/custom_hostname/get.py new file mode 100644 index 000000000..d69cce045 --- /dev/null +++ b/samples/recipes/instances/custom_hostname/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/samples/recipes/instances/custom_machine_types/__init__.py b/samples/recipes/instances/custom_machine_types/__init__.py new file mode 100644 index 000000000..e69de29bb 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 new file mode 100644 index 000000000..6adc80098 --- /dev/null +++ b/samples/recipes/instances/custom_machine_types/create_shared_with_helper.py @@ -0,0 +1,32 @@ +# 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/samples/recipes/instances/custom_machine_types/create_with_helper.py b/samples/recipes/instances/custom_machine_types/create_with_helper.py new file mode 100644 index 000000000..0ea883cf5 --- /dev/null +++ b/samples/recipes/instances/custom_machine_types/create_with_helper.py @@ -0,0 +1,34 @@ +# 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/samples/recipes/instances/custom_machine_types/create_without_helper.py b/samples/recipes/instances/custom_machine_types/create_without_helper.py new file mode 100644 index 000000000..e88388a82 --- /dev/null +++ b/samples/recipes/instances/custom_machine_types/create_without_helper.py @@ -0,0 +1,29 @@ +# 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/samples/recipes/instances/custom_machine_types/extra_mem_no_helper.py b/samples/recipes/instances/custom_machine_types/extra_mem_no_helper.py new file mode 100644 index 000000000..68fdc2759 --- /dev/null +++ b/samples/recipes/instances/custom_machine_types/extra_mem_no_helper.py @@ -0,0 +1,29 @@ +# 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/samples/recipes/instances/custom_machine_types/helper_class.py b/samples/recipes/instances/custom_machine_types/helper_class.py new file mode 100644 index 000000000..e5a48c0c9 --- /dev/null +++ b/samples/recipes/instances/custom_machine_types/helper_class.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/samples/recipes/instances/custom_machine_types/update_memory.py b/samples/recipes/instances/custom_machine_types/update_memory.py new file mode 100644 index 000000000..5817cd987 --- /dev/null +++ b/samples/recipes/instances/custom_machine_types/update_memory.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/samples/recipes/instances/delete.py b/samples/recipes/instances/delete.py new file mode 100644 index 000000000..68fc7f554 --- /dev/null +++ b/samples/recipes/instances/delete.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/samples/recipes/instances/delete_protection/__init__.py b/samples/recipes/instances/delete_protection/__init__.py new file mode 100644 index 000000000..a3ded82a3 --- /dev/null +++ b/samples/recipes/instances/delete_protection/__init__.py @@ -0,0 +1,14 @@ +# 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/samples/recipes/instances/delete_protection/create.py b/samples/recipes/instances/delete_protection/create.py new file mode 100644 index 000000000..f1bb3a9b3 --- /dev/null +++ b/samples/recipes/instances/delete_protection/create.py @@ -0,0 +1,29 @@ +# 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/samples/recipes/instances/delete_protection/get.py b/samples/recipes/instances/delete_protection/get.py new file mode 100644 index 000000000..1d7697dd1 --- /dev/null +++ b/samples/recipes/instances/delete_protection/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/samples/recipes/instances/delete_protection/set.py b/samples/recipes/instances/delete_protection/set.py new file mode 100644 index 000000000..785e8f781 --- /dev/null +++ b/samples/recipes/instances/delete_protection/set.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/samples/recipes/instances/from_instance_template/__init__.py b/samples/recipes/instances/from_instance_template/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/recipes/instances/from_instance_template/create_from_template.py b/samples/recipes/instances/from_instance_template/create_from_template.py new file mode 100644 index 000000000..c296366cc --- /dev/null +++ b/samples/recipes/instances/from_instance_template/create_from_template.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/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 new file mode 100644 index 000000000..27d1b2ae0 --- /dev/null +++ b/samples/recipes/instances/from_instance_template/create_from_template_with_overrides.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/samples/recipes/instances/list.py b/samples/recipes/instances/list.py new file mode 100644 index 000000000..92aff46b1 --- /dev/null +++ b/samples/recipes/instances/list.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/samples/recipes/instances/list_all.py b/samples/recipes/instances/list_all.py new file mode 100644 index 000000000..e1fafd7f2 --- /dev/null +++ b/samples/recipes/instances/list_all.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/samples/recipes/instances/preemptible/__init__.py b/samples/recipes/instances/preemptible/__init__.py new file mode 100644 index 000000000..a3ded82a3 --- /dev/null +++ b/samples/recipes/instances/preemptible/__init__.py @@ -0,0 +1,14 @@ +# 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/samples/recipes/instances/preemptible/create_preemptible.py b/samples/recipes/instances/preemptible/create_preemptible.py new file mode 100644 index 000000000..a61615412 --- /dev/null +++ b/samples/recipes/instances/preemptible/create_preemptible.py @@ -0,0 +1,29 @@ +# 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/samples/recipes/instances/preemptible/is_preemptible.py b/samples/recipes/instances/preemptible/is_preemptible.py new file mode 100644 index 000000000..d57031c83 --- /dev/null +++ b/samples/recipes/instances/preemptible/is_preemptible.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/samples/recipes/instances/preemptible/preemption_history.py b/samples/recipes/instances/preemptible/preemption_history.py new file mode 100644 index 000000000..0c9a9a8ce --- /dev/null +++ b/samples/recipes/instances/preemptible/preemption_history.py @@ -0,0 +1,24 @@ +# 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/samples/recipes/instances/reset.py b/samples/recipes/instances/reset.py new file mode 100644 index 000000000..0842ed544 --- /dev/null +++ b/samples/recipes/instances/reset.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/samples/recipes/instances/start.py b/samples/recipes/instances/start.py new file mode 100644 index 000000000..9ea6be08a --- /dev/null +++ b/samples/recipes/instances/start.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/samples/recipes/instances/start_encrypted.py b/samples/recipes/instances/start_encrypted.py new file mode 100644 index 000000000..6833c644e --- /dev/null +++ b/samples/recipes/instances/start_encrypted.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/samples/recipes/instances/stop.py b/samples/recipes/instances/stop.py new file mode 100644 index 000000000..7dda8bcfa --- /dev/null +++ b/samples/recipes/instances/stop.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/samples/recipes/operations/__init__.py b/samples/recipes/operations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/recipes/operations/operation_check.py b/samples/recipes/operations/operation_check.py new file mode 100644 index 000000000..8913e7324 --- /dev/null +++ b/samples/recipes/operations/operation_check.py @@ -0,0 +1,33 @@ +# 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 +# +# 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/samples/recipes/usage_report/__init__.py b/samples/recipes/usage_report/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/recipes/usage_report/usage_reports.py b/samples/recipes/usage_report/usage_reports.py new file mode 100644 index 000000000..4a293b800 --- /dev/null +++ b/samples/recipes/usage_report/usage_reports.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 +""" +A sample script showing how to handle default values when communicating +with the Compute Engine API and how to configure usage reports using the API. +""" +# +# +# +# +# + +# +# +# + + +# +# + +# + +# +# + +# +# + + +# +# + +# diff --git a/samples/requirements-test.txt b/samples/requirements-test.txt index 5737e3584..45720ccd4 100644 --- a/samples/requirements-test.txt +++ b/samples/requirements-test.txt @@ -1,4 +1,5 @@ pytest==7.0.1 +pytest-parallel==0.1.1 flaky==3.7.0 google-cloud-storage==2.1.0; python_version == '3.6' google-cloud-storage==2.1.0; python_version >= '3.7' \ No newline at end of file diff --git a/samples/sgs.py b/samples/sgs.py index f7d4f43c8..f8278f7b5 100644 --- a/samples/sgs.py +++ b/samples/sgs.py @@ -45,9 +45,9 @@ # directory and apply your changes there. """ -DEFAULT_OUTPUT_PATH = Path("sgs_test_fixtures/output") -INGREDIENTS_PATH = Path("sgs_test_fixtures/ingredients") -RECIPES_PATH = Path("sgs_test_fixtures/recipes") +DEFAULT_OUTPUT_PATH = Path("snippets") +INGREDIENTS_PATH = Path("ingredients") +RECIPES_PATH = Path("recipes") @dataclass @@ -133,7 +133,10 @@ def load_ingredient(path: Path) -> Ingredient: ingredient_name = INGREDIENTS_START.match(line).group(1) in_ingredient = True else: - warnings.warn(f"The ingredient in {path} has no closing tag.", SyntaxWarning) + if in_ingredient: + warnings.warn( + f"The ingredient in {path} has no closing tag.", SyntaxWarning + ) return Ingredient( name=ingredient_name, text="".join(ingredient_lines), @@ -164,7 +167,7 @@ def load_recipes(path: Path) -> dict: if ipath.is_dir(): recipes.update(load_recipes(ipath)) elif ipath.is_file(): - recipes[ipath] = load_recipe(ipath) + recipes[ipath.absolute()] = load_recipe(ipath) return recipes @@ -254,10 +257,9 @@ def save_rendered_recipe( output_dir: Path = DEFAULT_OUTPUT_PATH, recipes_path: Path = RECIPES_PATH, ) -> Path: - output_dir.mkdir(exist_ok=True) - + output_dir.mkdir(parents=True, exist_ok=True) output_path = output_dir / recipe_path.relative_to(recipes_path) - output_path.parent.mkdir(exist_ok=True) + output_path.parent.mkdir(parents=True, exist_ok=True) with output_path.open(mode="w") as out_file: out_file.write(rendered_recipe) @@ -282,7 +284,12 @@ def generate( for path, recipe in recipes.items(): rendered = render_recipe(recipe, ingredients) - out = save_rendered_recipe(path, rendered, output_dir=Path(args.output_dir)) + out = save_rendered_recipe( + path.absolute(), + rendered, + recipes_path=recipes_path.absolute(), + output_dir=Path(args.output_dir), + ) updated_paths.add(str(out)) print("Generated files:") diff --git a/samples/snippets/__init__.py b/samples/snippets/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/snippets/firewall/__init__.py b/samples/snippets/firewall/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/snippets/firewall/create.py b/samples/snippets/firewall/create.py new file mode 100644 index 000000000..5bcf1c5fc --- /dev/null +++ b/samples/snippets/firewall/create.py @@ -0,0 +1,74 @@ +# 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_firewall_create] +from google.cloud import compute_v1 + + +def create_firewall_rule( + project_id: str, firewall_rule_name: str, network: str = "global/networks/default" +) -> compute_v1.Firewall: + """ + Creates a simple firewall rule allowing for incoming HTTP and HTTPS access from the entire Internet. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + firewall_rule_name: name of the rule that is created. + network: name of the network the rule will be applied to. Available name formats: + * https://www.googleapis.com/compute/v1/projects/{project_id}/global/networks/{network} + * projects/{project_id}/global/networks/{network} + * global/networks/{network} + """ + firewall_rule = compute_v1.Firewall() + firewall_rule.name = firewall_rule_name + firewall_rule.direction = "INGRESS" + + allowed_ports = compute_v1.Allowed() + allowed_ports.I_p_protocol = "tcp" + allowed_ports.ports = ["80", "443"] + + firewall_rule.allowed = [allowed_ports] + firewall_rule.source_ranges = ["0.0.0.0/0"] + firewall_rule.network = network + firewall_rule.description = "Allowing TCP traffic on port 80 and 443 from Internet." + + firewall_rule.target_tags = ["web"] + + # Note that the default value of priority for the firewall API is 1000. + # If you check the value of `firewall_rule.priority` at this point it + # will be equal to 0, however it is not treated as "set" by the library and thus + # the default will be applied to the new rule. If you want to create a rule that + # has priority == 0, you need to explicitly set it so: + + # firewall_rule.priority = 0 + + firewall_client = compute_v1.FirewallsClient() + op = firewall_client.insert_unary( + project=project_id, firewall_resource=firewall_rule + ) + + op_client = compute_v1.GlobalOperationsClient() + op_client.wait(project=project_id, operation=op.name) + + return firewall_client.get(project=project_id, firewall=firewall_rule_name) + + +# [END compute_firewall_create] diff --git a/samples/snippets/firewall/delete.py b/samples/snippets/firewall/delete.py new file mode 100644 index 000000000..8dbea8709 --- /dev/null +++ b/samples/snippets/firewall/delete.py @@ -0,0 +1,44 @@ +# 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_firewall_delete] +from google.cloud import compute_v1 + + +def delete_firewall_rule(project_id: str, firewall_rule_name: str): + """ + Deleted a firewall rule from the project. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + 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_client = compute_v1.GlobalOperationsClient() + operation_client.wait(project=project_id, operation=operation.name) + return + + +# [END compute_firewall_delete] diff --git a/samples/snippets/firewall/list.py b/samples/snippets/firewall/list.py new file mode 100644 index 000000000..d4553ac12 --- /dev/null +++ b/samples/snippets/firewall/list.py @@ -0,0 +1,48 @@ +# 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_firewall_list] +from typing import Iterable + +from google.cloud import compute_v1 + + +def list_firewall_rules(project_id: str) -> Iterable[compute_v1.Firewall]: + """ + Return a list of all the firewall rules in specified project. Also prints the + list of firewall names and their descriptions. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + + Returns: + A flat list of all firewall rules defined for given project. + """ + firewall_client = compute_v1.FirewallsClient() + firewalls_list = firewall_client.list(project=project_id) + + for firewall in firewalls_list: + print(f" - {firewall.name}: {firewall.description}") + + return firewalls_list + + +# [END compute_firewall_list] diff --git a/samples/snippets/sample_firewall.py b/samples/snippets/firewall/main.py similarity index 82% rename from samples/snippets/sample_firewall.py rename to samples/snippets/firewall/main.py index c2bdd3fa7..d8b47a338 100644 --- a/samples/snippets/sample_firewall.py +++ b/samples/snippets/firewall/main.py @@ -1,65 +1,32 @@ -# Copyright 2021 Google LLC +# 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 +# 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 +# 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. +# 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 -from typing import Iterable - -# [START compute_firewall_list] -# [START compute_firewall_create] -# [START compute_firewall_patch] -# [START compute_firewall_delete] -import google.cloud.compute_v1 as compute_v1 - -# [END compute_firewall_delete] -# [END compute_firewall_patch] -# [END compute_firewall_create] -# [END compute_firewall_list] - - -# [START compute_firewall_list] -def list_firewall_rules(project_id: str) -> Iterable: - """ - Return a list of all the firewall rules in specified project. Also prints the - list of firewall names and their descriptions. - - Args: - project_id: project ID or project number of the Cloud project you want to use. - - Returns: - A flat list of all firewall rules defined for given project. - """ - firewall_client = compute_v1.FirewallsClient() - firewalls_list = firewall_client.list(project=project_id) - - for firewall in firewalls_list: - print(f" - {firewall.name}: {firewall.description}") - - return firewalls_list +# 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. -# [END compute_firewall_list] - +from typing import Iterable -def get_firewall_rule(project_id: str, firewall_rule_name: str) -> compute_v1.Firewall: - firewall_client = compute_v1.FirewallsClient() - return firewall_client.get(project=project_id, firewall=firewall_rule_name) +from google.cloud import compute_v1 -# [START compute_firewall_create] def create_firewall_rule( project_id: str, firewall_rule_name: str, network: str = "global/networks/default" -): +) -> compute_v1.Firewall: """ Creates a simple firewall rule allowing for incoming HTTP and HTTPS access from the entire Internet. @@ -102,30 +69,20 @@ def create_firewall_rule( op_client = compute_v1.GlobalOperationsClient() op_client.wait(project=project_id, operation=op.name) - return - - -# [END compute_firewall_create] + return firewall_client.get(project=project_id, firewall=firewall_rule_name) -# [START compute_firewall_patch] -def patch_firewall_priority(project_id: str, firewall_rule_name: str, priority: int): +def delete_firewall_rule(project_id: str, firewall_rule_name: str): """ - Modifies the priority of a given firewall rule. + Deleted a firewall rule from the project. Args: project_id: project ID or project number of the Cloud project you want to use. - firewall_rule_name: name of the rule you want to modify. - priority: the new priority to be set for the rule. + firewall_rule_name: name of the firewall rule you want to delete. """ - firewall_rule = compute_v1.Firewall() - firewall_rule.priority = 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( - project=project_id, firewall=firewall_rule_name, firewall_resource=firewall_rule + operation = firewall_client.delete_unary( + project=project_id, firewall=firewall_rule_name ) operation_client = compute_v1.GlobalOperationsClient() @@ -133,21 +90,48 @@ def patch_firewall_priority(project_id: str, firewall_rule_name: str, priority: return -# [END compute_firewall_patch] +def get_firewall_rule(project_id: str, firewall_rule_name: str) -> compute_v1.Firewall: + firewall_client = compute_v1.FirewallsClient() + return firewall_client.get(project=project_id, firewall=firewall_rule_name) -# [START compute_firewall_delete] -def delete_firewall_rule(project_id: str, firewall_rule_name: str): +def list_firewall_rules(project_id: str) -> Iterable[compute_v1.Firewall]: """ - Deleted a firewall rule from the project. + Return a list of all the firewall rules in specified project. Also prints the + list of firewall names and their descriptions. Args: project_id: project ID or project number of the Cloud project you want to use. - firewall_rule_name: name of the firewall rule you want to delete. + + Returns: + A flat list of all firewall rules defined for given project. """ firewall_client = compute_v1.FirewallsClient() - operation = firewall_client.delete_unary( - project=project_id, firewall=firewall_rule_name + firewalls_list = firewall_client.list(project=project_id) + + for firewall in firewalls_list: + print(f" - {firewall.name}: {firewall.description}") + + return firewalls_list + + +def patch_firewall_priority(project_id: str, firewall_rule_name: str, priority: int): + """ + Modifies the priority of a given firewall rule. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + firewall_rule_name: name of the rule you want to modify. + priority: the new priority to be set for the rule. + """ + firewall_rule = compute_v1.Firewall() + firewall_rule.priority = 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( + project=project_id, firewall=firewall_rule_name, firewall_resource=firewall_rule ) operation_client = compute_v1.GlobalOperationsClient() @@ -155,9 +139,6 @@ def delete_firewall_rule(project_id: str, firewall_rule_name: str): return -# [END compute_firewall_delete] - - if __name__ == "__main__": import google.auth import google.auth.exceptions diff --git a/samples/snippets/firewall/patch.py b/samples/snippets/firewall/patch.py new file mode 100644 index 000000000..e5f2a96d6 --- /dev/null +++ b/samples/snippets/firewall/patch.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. +# 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_firewall_patch] +from google.cloud import compute_v1 + + +def patch_firewall_priority(project_id: str, firewall_rule_name: str, priority: int): + """ + Modifies the priority of a given firewall rule. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + firewall_rule_name: name of the rule you want to modify. + priority: the new priority to be set for the rule. + """ + firewall_rule = compute_v1.Firewall() + firewall_rule.priority = 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( + 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) + return + + +# [END compute_firewall_patch] diff --git a/samples/snippets/images/__init__.py b/samples/snippets/images/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/snippets/images/get.py b/samples/snippets/images/get.py new file mode 100644 index 000000000..94c8f3af4 --- /dev/null +++ b/samples/snippets/images/get.py @@ -0,0 +1,55 @@ +# 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_images_get_from_family] +# [START compute_images_get] +from google.cloud import compute_v1 + +# [END compute_images_get] + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +# [END compute_images_get_from_family] + + +# [START compute_images_get] +def get_image(project_id: str, image_name: str) -> compute_v1.Image: + """ + Retrieve detailed information about a single image from a project. + + Args: + project_id: project ID or project number of the Cloud project you want to list images from. + image_name: name of the image you want to get details of. + + Returns: + An instance of compute_v1.Image object with information about specified image. + """ + image_client = compute_v1.ImagesClient() + return image_client.get(project=project_id, image=image_name) + + +# [END compute_images_get] diff --git a/samples/snippets/images/list.py b/samples/snippets/images/list.py new file mode 100644 index 000000000..361829533 --- /dev/null +++ b/samples/snippets/images/list.py @@ -0,0 +1,42 @@ +# 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_images_get_list] +from typing import Iterable + +from google.cloud import compute_v1 + + +def list_images(project_id: str) -> Iterable[compute_v1.Image]: + """ + Retrieve a list of images available in given project. + + Args: + project_id: project ID or project number of the Cloud project you want to list images from. + + Returns: + An iterable collection of compute_v1.Image objects. + """ + image_client = compute_v1.ImagesClient() + return image_client.list(project=project_id) + + +# [END compute_images_get_list] diff --git a/samples/snippets/sample_pagination.py b/samples/snippets/images/pagination.py similarity index 85% rename from samples/snippets/sample_pagination.py rename to samples/snippets/images/pagination.py index e2590b541..7ac6d0b6e 100644 --- a/samples/snippets/sample_pagination.py +++ b/samples/snippets/images/pagination.py @@ -14,6 +14,12 @@ # See the License for the specific language governing permissions and # limitations under the License. + +# 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_images_list_page] # [START compute_images_list] import google.cloud.compute_v1 as compute_v1 @@ -23,7 +29,7 @@ # [START compute_images_list] -def print_images_list(project: str) -> None: +def print_images_list(project: str) -> str: """ Prints a list of all non-deprecated image names available in given project. @@ -31,26 +37,29 @@ def print_images_list(project: str) -> None: project: project ID or project number of the Cloud project you want to list images from. Returns: - None. + The output as a string. """ images_client = compute_v1.ImagesClient() # Listing only non-deprecated images to reduce the size of the reply. images_list_request = compute_v1.ListImagesRequest( project=project, max_results=100, filter="deprecated.state != DEPRECATED" ) + output = [] # Although the `max_results` parameter is specified in the request, the iterable returned # by the `list()` method hides the pagination mechanic. The library makes multiple # requests to the API for you, so you can simply iterate over all the images. for img in images_client.list(request=images_list_request): print(f" - {img.name}") + output.append(f" - {img.name}") + return "\n".join(output) # [END compute_images_list] # [START compute_images_list_page] -def print_images_list_by_page(project: str, page_size: int = 10) -> None: +def print_images_list_by_page(project: str, page_size: int = 10) -> str: """ Prints a list of all non-deprecated image names available in a given project, divided into pages as returned by the Compute Engine API. @@ -60,13 +69,14 @@ def print_images_list_by_page(project: str, page_size: int = 10) -> None: page_size: size of the pages you want the API to return on each call. Returns: - None. + Output as a string. """ images_client = compute_v1.ImagesClient() # Listing only non-deprecated images to reduce the size of the reply. images_list_request = compute_v1.ListImagesRequest( project=project, max_results=page_size, filter="deprecated.state != DEPRECATED" ) + output = [] # Use the `pages` attribute of returned iterable to have more granular control of # iteration over paginated results from the API. Each time you want to access the @@ -75,8 +85,11 @@ def print_images_list_by_page(project: str, page_size: int = 10) -> None: images_client.list(request=images_list_request).pages, start=1 ): print(f"Page {page_num}: ") + output.append(f"Page {page_num}: ") for img in page.items: print(f" - {img.name}") + output.append(f" - {img.name}") + return "\n".join(output) # [END compute_images_list_page] diff --git a/samples/snippets/instance_templates/__init__.py b/samples/snippets/instance_templates/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/snippets/instance_templates/create.py b/samples/snippets/instance_templates/create.py new file mode 100644 index 000000000..f328bbfc1 --- /dev/null +++ b/samples/snippets/instance_templates/create.py @@ -0,0 +1,78 @@ +# 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_template_create] +from google.cloud import compute_v1 + + +def create_template(project_id: str, template_name: str) -> compute_v1.InstanceTemplate: + """ + Create a new instance template with the provided name and a specific + instance configuration. + + Args: + project_id: project ID or project number of the Cloud project you use. + template_name: name of the new template to create. + + Returns: + InstanceTemplate object that represents the new instance template. + """ + # The template describes the size and source image of the boot disk + # to attach to the instance. + disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = ( + "projects/debian-cloud/global/images/family/debian-11" + ) + initialize_params.disk_size_gb = 250 + disk.initialize_params = initialize_params + disk.auto_delete = True + disk.boot = True + + # The template connects the instance to the `default` network, + # without specifying a subnetwork. + network_interface = compute_v1.NetworkInterface() + network_interface.name = "global/networks/default" + + # The template lets the instance use an external IP address. + access_config = compute_v1.AccessConfig() + access_config.name = "External NAT" + access_config.type_ = "ONE_TO_ONE_NAT" + access_config.network_tier = "PREMIUM" + network_interface.access_configs = [access_config] + + template = compute_v1.InstanceTemplate() + template.name = template_name + template.properties.disks = [disk] + template.properties.machine_type = "e2-standard-4" + template.properties.network_interfaces = [network_interface] + + template_client = compute_v1.InstanceTemplatesClient() + operation_client = compute_v1.GlobalOperationsClient() + op = template_client.insert_unary( + project=project_id, instance_template_resource=template + ) + operation_client.wait(project=project_id, operation=op.name) + + return template_client.get(project=project_id, instance_template=template_name) + + +# [END compute_template_create] diff --git a/samples/snippets/instance_templates/create_from_instance.py b/samples/snippets/instance_templates/create_from_instance.py new file mode 100644 index 000000000..20afc7154 --- /dev/null +++ b/samples/snippets/instance_templates/create_from_instance.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. +# 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_template_create_from_instance] +from google.cloud import compute_v1 + + +def create_template_from_instance( + project_id: str, instance: str, template_name: str +) -> compute_v1.InstanceTemplate: + """ + Create a new instance template based on an existing instance. + This new template specifies a different boot disk. + + Args: + project_id: project ID or project number of the Cloud project you use. + instance: the instance to base the new template on. This value uses + the following format: "projects/{project}/zones/{zone}/instances/{instance_name}" + template_name: name of the new template to create. + + Returns: + InstanceTemplate object that represents the new instance template. + """ + disk = compute_v1.DiskInstantiationConfig() + # Device name must match the name of a disk attached to the instance you are + # basing your template on. + disk.device_name = "disk-1" + # Replace the original boot disk image used in your instance with a Rocky Linux image. + disk.instantiate_from = "CUSTOM_IMAGE" + disk.custom_image = "projects/rocky-linux-cloud/global/images/family/rocky-linux-8" + # Override the auto_delete setting. + disk.auto_delete = True + + template = compute_v1.InstanceTemplate() + template.name = template_name + template.source_instance = instance + template.source_instance_params = compute_v1.SourceInstanceParams() + template.source_instance_params.disk_configs = [disk] + + template_client = compute_v1.InstanceTemplatesClient() + operation_client = compute_v1.GlobalOperationsClient() + op = template_client.insert_unary( + project=project_id, instance_template_resource=template + ) + operation_client.wait(project=project_id, operation=op.name) + + return template_client.get(project=project_id, instance_template=template_name) + + +# [END compute_template_create_from_instance] diff --git a/samples/snippets/instance_templates/create_with_subnet.py b/samples/snippets/instance_templates/create_with_subnet.py new file mode 100644 index 000000000..ea6ddc191 --- /dev/null +++ b/samples/snippets/instance_templates/create_with_subnet.py @@ -0,0 +1,77 @@ +# 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_template_create_with_subnet] +from google.cloud import compute_v1 + + +def create_template_with_subnet( + project_id: str, network: str, subnetwork: str, template_name: str +) -> compute_v1.InstanceTemplate: + """ + Create an instance template that uses a provided subnet. + + Args: + project_id: project ID or project number of the Cloud project you use. + network: the network to be used in the new template. This value uses + the following format: "projects/{project}/global/networks/{network}" + subnetwork: the subnetwork to be used in the new template. This value + uses the following format: "projects/{project}/regions/{region}/subnetworks/{subnetwork}" + template_name: name of the new template to create. + + Returns: + InstanceTemplate object that represents the new instance template. + """ + # The template describes the size and source image of the book disk to + # attach to the instance. + disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = ( + "projects/debian-cloud/global/images/family/debian-11" + ) + initialize_params.disk_size_gb = 250 + disk.initialize_params = initialize_params + disk.auto_delete = True + disk.boot = True + + template = compute_v1.InstanceTemplate() + template.name = template_name + template.properties = compute_v1.InstanceProperties() + template.properties.disks = [disk] + template.properties.machine_type = "e2-standard-4" + + # The template connects the instance to the specified network and subnetwork. + network_interface = compute_v1.NetworkInterface() + network_interface.network = network + network_interface.subnetwork = subnetwork + template.properties.network_interfaces = [network_interface] + + template_client = compute_v1.InstanceTemplatesClient() + operation_client = compute_v1.GlobalOperationsClient() + op = template_client.insert_unary( + project=project_id, instance_template_resource=template + ) + operation_client.wait(project=project_id, operation=op.name) + + return template_client.get(project=project_id, instance_template=template_name) + + +# [END compute_template_create_with_subnet] diff --git a/samples/snippets/instance_templates/delete.py b/samples/snippets/instance_templates/delete.py new file mode 100644 index 000000000..b0700c9ab --- /dev/null +++ b/samples/snippets/instance_templates/delete.py @@ -0,0 +1,43 @@ +# 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_template_delete] +from google.cloud import compute_v1 + + +def delete_instance_template(project_id: str, template_name: str): + """ + Delete an instance template. + + Args: + project_id: project ID or project number of the Cloud project you use. + template_name: name of the template to delete. + """ + template_client = compute_v1.InstanceTemplatesClient() + operation_client = compute_v1.GlobalOperationsClient() + op = template_client.delete_unary( + project=project_id, instance_template=template_name + ) + operation_client.wait(project=project_id, operation=op.name) + return + + +# [END compute_template_delete] diff --git a/samples/snippets/instance_templates/get.py b/samples/snippets/instance_templates/get.py new file mode 100644 index 000000000..439b3bea9 --- /dev/null +++ b/samples/snippets/instance_templates/get.py @@ -0,0 +1,44 @@ +# 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_template_get] +from google.cloud import compute_v1 + + +def get_instance_template( + project_id: str, template_name: str +) -> compute_v1.InstanceTemplate: + """ + Retrieve an instance template, which you can use to create virtual machine + (VM) instances and managed instance groups (MIGs). + + Args: + project_id: project ID or project number of the Cloud project you use. + template_name: name of the template to retrieve. + + Returns: + InstanceTemplate object that represents the retrieved template. + """ + template_client = compute_v1.InstanceTemplatesClient() + return template_client.get(project=project_id, instance_template=template_name) + + +# [END compute_template_get] diff --git a/samples/snippets/instance_templates/list.py b/samples/snippets/instance_templates/list.py new file mode 100644 index 000000000..495686c62 --- /dev/null +++ b/samples/snippets/instance_templates/list.py @@ -0,0 +1,42 @@ +# 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_template_list] +from typing import Iterable + +from google.cloud import compute_v1 + + +def list_instance_templates(project_id: str) -> Iterable[compute_v1.InstanceTemplate]: + """ + Get a list of InstanceTemplate objects available in a project. + + Args: + project_id: project ID or project number of the Cloud project you use. + + Returns: + Iterable list of InstanceTemplate objects. + """ + template_client = compute_v1.InstanceTemplatesClient() + return template_client.list(project=project_id) + + +# [END compute_template_list] diff --git a/samples/snippets/instances/__init__.py b/samples/snippets/instances/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/snippets/instances/create.py b/samples/snippets/instances/create.py new file mode 100644 index 000000000..73d2d806c --- /dev/null +++ b/samples/snippets/instances/create.py @@ -0,0 +1,195 @@ +# 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] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +# [END compute_instances_create] + +if __name__ == "__main__": + import uuid + import google.auth + import google.auth.exceptions + + try: + default_project_id = google.auth.default()[1] + except google.auth.exceptions.DefaultCredentialsError: + print( + "Please use `gcloud auth application-default login` " + "or set GOOGLE_APPLICATION_CREDENTIALS to use this script." + ) + else: + instance_name = "quickstart-" + uuid.uuid4().hex[:10] + instance_zone = "europe-central2-b" + + newest_debian = get_image_from_family( + project="debian-cloud", family="debian-10" + ) + disk_type = f"zones/{instance_zone}/diskTypes/pd-standard" + disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)] + + create_instance(default_project_id, instance_zone, instance_name, disks) diff --git a/samples/snippets/instances/create_start_instance/__init__.py b/samples/snippets/instances/create_start_instance/__init__.py new file mode 100644 index 000000000..e69de29bb 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 new file mode 100644 index 000000000..0cea57407 --- /dev/null +++ b/samples/snippets/instances/create_start_instance/create_from_custom_image.py @@ -0,0 +1,193 @@ +# 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_from_custom_image] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_from_custom_image( + project_id: str, zone: str, instance_name: str, custom_image_link: str +) -> compute_v1.Instance: + """ + Create a new VM instance with custom image used as its 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. + custom_image_link: link to the custom image you want to use in the form of: + "projects/{project_name}/global/images/{image_name}" + + Returns: + Instance object. + """ + disk_type = f"zones/{zone}/diskTypes/pd-standard" + disks = [disk_from_image(disk_type, 10, True, custom_image_link)] + instance = create_instance(project_id, zone, instance_name, disks) + return instance + + +# [END compute_instances_create_from_custom_image] 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 new file mode 100644 index 000000000..0d309604a --- /dev/null +++ b/samples/snippets/instances/create_start_instance/create_from_public_image.py @@ -0,0 +1,192 @@ +# 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_from_image] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_from_public_image( + project_id: str, zone: str, instance_name: str +) -> compute_v1.Instance: + """ + Create a new VM instance with Debian 10 operating system. + + 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. + + Returns: + Instance object. + """ + 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)] + instance = create_instance(project_id, zone, instance_name, disks) + return instance + + +# [END compute_instances_create_from_image] diff --git a/samples/snippets/instances/create_start_instance/create_from_snapshot.py b/samples/snippets/instances/create_start_instance/create_from_snapshot.py new file mode 100644 index 000000000..bc7b01c26 --- /dev/null +++ b/samples/snippets/instances/create_start_instance/create_from_snapshot.py @@ -0,0 +1,185 @@ +# 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_from_snapshot] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def disk_from_snapshot( + disk_type: str, disk_size_gb: int, boot: bool, disk_snapshot: str +) -> compute_v1.AttachedDisk(): + """ + Create an AttachedDisk object to be used in VM instance creation. Uses a disk snapshot as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + disk_snapshot: disk snapshot to use when creating this disk. You must have read access to this disk. + This value uses the following format: "projects/{project_name}/global/snapshots/{snapshot_name}" + + Returns: + AttachedDisk object configured to be created using the specified snapshot. + """ + disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_snapshot = disk_snapshot + initialize_params.disk_type = disk_type + initialize_params.disk_size_gb = disk_size_gb + 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 = boot + return disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_from_snapshot( + project_id: str, zone: str, instance_name: str, snapshot_link: str +): + """ + Create a new VM instance with boot disk created from a snapshot. + + 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. + snapshot_link: link to the snapshot you want to use as the source of your + boot disk in the form of: "projects/{project_name}/global/snapshots/{snapshot_name}" + + Returns: + Instance object. + """ + disk_type = f"zones/{zone}/diskTypes/pd-standard" + disks = [disk_from_snapshot(disk_type, 11, True, snapshot_link)] + instance = create_instance(project_id, zone, instance_name, disks) + return instance + + +# [END compute_instances_create_from_snapshot] 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 new file mode 100644 index 000000000..7945638de --- /dev/null +++ b/samples/snippets/instances/create_start_instance/create_with_additional_disk.py @@ -0,0 +1,222 @@ +# 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_from_image_plus_empty_disk] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +def empty_disk(disk_type: str, disk_size_gb: int) -> 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. + + Args: + 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: + AttachedDisk object configured to be created as an empty disk. + """ + disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.disk_type = disk_type + initialize_params.disk_size_gb = disk_size_gb + 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 + return disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_with_additional_disk( + project_id: str, zone: str, instance_name: str +) -> compute_v1.Instance: + """ + Create a new VM instance with Debian 10 operating system and a 11 GB additional + empty 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. + + Returns: + Instance object. + """ + 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), + empty_disk(disk_type, 11), + ] + instance = create_instance(project_id, zone, instance_name, disks) + return instance + + +# [END compute_instances_create_from_image_plus_empty_disk] 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 new file mode 100644 index 000000000..134f41c01 --- /dev/null +++ b/samples/snippets/instances/create_start_instance/create_with_snapshotted_data_disk.py @@ -0,0 +1,229 @@ +# 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_from_image_plus_snapshot_disk] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +def disk_from_snapshot( + disk_type: str, disk_size_gb: int, boot: bool, disk_snapshot: str +) -> compute_v1.AttachedDisk(): + """ + Create an AttachedDisk object to be used in VM instance creation. Uses a disk snapshot as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + disk_snapshot: disk snapshot to use when creating this disk. You must have read access to this disk. + This value uses the following format: "projects/{project_name}/global/snapshots/{snapshot_name}" + + Returns: + AttachedDisk object configured to be created using the specified snapshot. + """ + disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_snapshot = disk_snapshot + initialize_params.disk_type = disk_type + initialize_params.disk_size_gb = disk_size_gb + 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 = boot + return disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_with_snapshotted_data_disk( + project_id: str, zone: str, instance_name: str, snapshot_link: str +): + """ + Create a new VM instance with Debian 10 operating system and data disk created from snapshot. + + 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. + snapshot_link: link to the snapshot you want to use as the source of your + data disk in the form of: "projects/{project_name}/global/snapshots/{snapshot_name}" + + Returns: + Instance object. + """ + 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), + disk_from_snapshot(disk_type, 11, False, snapshot_link), + ] + instance = create_instance(project_id, zone, instance_name, disks) + return instance + + +# [END compute_instances_create_from_image_plus_snapshot_disk] diff --git a/samples/snippets/instances/create_with_subnet.py b/samples/snippets/instances/create_with_subnet.py new file mode 100644 index 000000000..63e46d0cc --- /dev/null +++ b/samples/snippets/instances/create_with_subnet.py @@ -0,0 +1,205 @@ +# 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_subnet] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_with_subnet( + project_id: str, zone: str, instance_name: str, network_link: str, subnet_link: str +) -> compute_v1.Instance: + """ + Create a new VM instance with Debian 10 operating system in specified network and subnetwork. + + 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. + 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}" + + Returns: + Instance object. + """ + 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)] + instance = create_instance( + project_id, + zone, + instance_name, + disks, + network_link=network_link, + subnetwork_link=subnet_link, + ) + return instance + + +# [END compute_instances_create_with_subnet] diff --git a/samples/snippets/instances/custom_hostname/create.py b/samples/snippets/instances/custom_hostname/create.py new file mode 100644 index 000000000..c600f6c17 --- /dev/null +++ b/samples/snippets/instances/custom_hostname/create.py @@ -0,0 +1,195 @@ +# 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_custom_hostname] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_instance_custom_hostname( + project_id: str, zone: str, instance_name: str, hostname: str +) -> compute_v1.Instance: + """ + Create a new VM instance with Debian 10 operating system and a custom hostname. + + 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. + hostname: the hostname you want to use for the new instance. + + Returns: + Instance object. + """ + newest_debian = get_image_from_family(project="debian-cloud", family="debian-11") + disk_type = f"zones/{zone}/diskTypes/pd-standard" + disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)] + instance = create_instance( + project_id, zone, instance_name, disks, custom_hostname=hostname + ) + return instance + + +# [END compute_instances_create_custom_hostname] diff --git a/samples/snippets/instances/custom_hostname/get.py b/samples/snippets/instances/custom_hostname/get.py new file mode 100644 index 000000000..673d5c810 --- /dev/null +++ b/samples/snippets/instances/custom_hostname/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_hostname] +from google.cloud import compute_v1 + + +def get_hostname(project_id: str, zone: str, instance_name: str) -> str: + """ + Retrieve the hostname of given instance. + + 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 virtual machine to check. + + Returns: + The hostname of an instance. + """ + instance_client = compute_v1.InstancesClient() + instance = instance_client.get( + project=project_id, zone=zone, instance=instance_name + ) + return instance.hostname + + +# [END compute_instances_get_hostname] diff --git a/samples/snippets/instances/custom_machine_types/__init__.py b/samples/snippets/instances/custom_machine_types/__init__.py new file mode 100644 index 000000000..e69de29bb 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 new file mode 100644 index 000000000..16d107883 --- /dev/null +++ b/samples/snippets/instances/custom_machine_types/create_shared_with_helper.py @@ -0,0 +1,390 @@ +# 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_custom_machine_type_create_shared_with_helper] +from collections import namedtuple +from enum import Enum +from enum import unique +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def gb_to_mb(value: int) -> int: + return value << 10 + + +class CustomMachineType: + """ + Allows to create custom machine types to be used with the VM instances. + """ + + @unique + class CPUSeries(Enum): + N1 = "custom" + N2 = "n2-custom" + N2D = "n2d-custom" + E2 = "e2-custom" + E2_MICRO = "e2-custom-micro" + E2_SMALL = "e2-custom-small" + E2_MEDIUM = "e2-custom-medium" + + TypeLimits = namedtuple( + "TypeLimits", + [ + "allowed_cores", + "min_mem_per_core", + "max_mem_per_core", + "allow_extra_memory", + "extra_memory_limit", + ], + ) + + LIMITS = { + CPUSeries.E2: TypeLimits(frozenset(range(2, 33, 2)), 512, 8192, False, 0), + CPUSeries.E2_MICRO: TypeLimits(frozenset(), 1024, 2048, False, 0), + CPUSeries.E2_SMALL: TypeLimits(frozenset(), 2048, 4096, False, 0), + CPUSeries.E2_MEDIUM: TypeLimits(frozenset(), 4096, 8192, False, 0), + CPUSeries.N2: TypeLimits( + frozenset(range(2, 33, 2)).union(set(range(36, 129, 4))), + 512, + 8192, + True, + gb_to_mb(624), + ), + CPUSeries.N2D: TypeLimits( + frozenset({2, 4, 8, 16, 32, 48, 64, 80, 96}), 512, 8192, True, gb_to_mb(768) + ), + CPUSeries.N1: TypeLimits( + frozenset({1}.union(range(2, 97, 2))), 922, 6656, True, gb_to_mb(624) + ), + } + + def __init__( + self, zone: str, cpu_series: CPUSeries, memory_mb: int, core_count: int = 0 + ): + self.zone = zone + self.cpu_series = cpu_series + self.limits = self.LIMITS[self.cpu_series] + self.core_count = 2 if self.is_shared() else core_count + self.memory_mb = memory_mb + + self._check() + self.extra_memory_used = self._check_extra_memory() + + def is_shared(self): + return self.cpu_series in ( + CustomMachineType.CPUSeries.E2_SMALL, + CustomMachineType.CPUSeries.E2_MICRO, + CustomMachineType.CPUSeries.E2_MEDIUM, + ) + + def _check_extra_memory(self) -> bool: + # Assuming this runs after _check() and the total memory requested is correct + return self.memory_mb > self.core_count * self.limits.max_mem_per_core + + def _check(self): + """ + Check whether the requested parameters are allowed. Find more information about limitations of custom machine + types at: https://cloud.google.com/compute/docs/general-purpose-machines#custom_machine_types + """ + # Check the number of cores + if ( + self.limits.allowed_cores + and self.core_count not in self.limits.allowed_cores + ): + raise RuntimeError( + f"Invalid number of cores requested. Allowed number of cores for {self.cpu_series.name} is: {sorted(self.limits.allowed_cores)}" + ) + + # Memory must be a multiple of 256 MB + if self.memory_mb % 256 != 0: + raise RuntimeError("Requested memory must be a multiple of 256 MB.") + + # Check if the requested memory isn't too little + if self.memory_mb < self.core_count * self.limits.min_mem_per_core: + raise RuntimeError( + f"Requested memory is too low. Minimal memory for {self.cpu_series.name} is {self.limits.min_mem_per_core} MB per core." + ) + + # Check if the requested memory isn't too much + if self.memory_mb > self.core_count * self.limits.max_mem_per_core: + if self.limits.allow_extra_memory: + if self.memory_mb > self.limits.extra_memory_limit: + raise RuntimeError( + f"Requested memory is too large.. Maximum memory allowed for {self.cpu_series.name} is {self.limits.extra_memory_limit} MB." + ) + else: + raise RuntimeError( + f"Requested memory is too large.. Maximum memory allowed for {self.cpu_series.name} is {self.limits.max_mem_per_core} MB per core." + ) + + def __str__(self) -> str: + """ + Return the custom machine type in form of a string acceptable by Compute Engine API. + """ + if self.cpu_series in { + self.CPUSeries.E2_SMALL, + self.CPUSeries.E2_MICRO, + self.CPUSeries.E2_MEDIUM, + }: + return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.memory_mb}" + + if self.extra_memory_used: + return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.core_count}-{self.memory_mb}-ext" + + return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.core_count}-{self.memory_mb}" + + def short_type_str(self) -> str: + """ + Return machine type in a format without the zone. For example, n2-custom-0-10240. + This format is used to create instance templates. + """ + return str(self).rsplit("/", maxsplit=1)[1] + + @classmethod + def from_str(cls, machine_type: str): + """ + Construct a new object from a string. The string needs to be a valid custom machine type like: + - https://www.googleapis.com/compute/v1/projects/diregapic-mestiv/zones/us-central1-b/machineTypes/e2-custom-4-8192 + - zones/us-central1-b/machineTypes/e2-custom-4-8192 + - e2-custom-4-8192 (in this case, the zone parameter will not be set) + """ + zone = None + if machine_type.startswith("http"): + machine_type = machine_type[machine_type.find("zones/") :] + + if machine_type.startswith("zones/"): + _, zone, _, machine_type = machine_type.split("/") + + extra_mem = machine_type.endswith("-ext") + + if machine_type.startswith("custom"): + cpu = cls.CPUSeries.N1 + _, cores, memory = machine_type.rsplit("-", maxsplit=2) + else: + if extra_mem: + cpu_series, _, cores, memory, _ = machine_type.split("-") + else: + cpu_series, _, cores, memory = machine_type.split("-") + if cpu_series == "n2": + cpu = cls.CPUSeries.N2 + elif cpu_series == "n2d": + cpu = cls.CPUSeries.N2D + elif cpu_series == "e2": + cpu = cls.CPUSeries.E2 + if cores == "micro": + cpu = cls.CPUSeries.E2_MICRO + cores = 2 + elif cores == "small": + cpu = cls.CPUSeries.E2_SMALL + cores = 2 + elif cores == "medium": + cpu = cls.CPUSeries.E2_MEDIUM + cores = 2 + else: + raise RuntimeError("Unknown CPU series.") + + cores = int(cores) + memory = int(memory) + + return cls(zone, cpu, memory, cores) + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_custom_shared_core_instance( + project_id: str, + zone: str, + instance_name: str, + cpu_series: CustomMachineType.CPUSeries, + memory: int, +) -> compute_v1.Instance: + """ + Create a new VM instance with a custom type using shared CPUs. + + 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. + cpu_series: the type of CPU you want to use. Pick one value from the CustomMachineType.CPUSeries enum. + For example: CustomMachineType.CPUSeries.E2_MICRO + memory: the amount of memory for the VM instance, in megabytes. + + Return: + Instance object. + """ + assert cpu_series in ( + CustomMachineType.CPUSeries.E2_MICRO, + CustomMachineType.CPUSeries.E2_SMALL, + CustomMachineType.CPUSeries.E2_MEDIUM, + ) + custom_type = CustomMachineType(zone, cpu_series, memory) + + 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)] + + return create_instance(project_id, zone, instance_name, disks, str(custom_type)) + + +# [END compute_custom_machine_type_create_shared_with_helper] diff --git a/samples/snippets/sample_custom_types.py b/samples/snippets/instances/custom_machine_types/create_with_helper.py similarity index 54% rename from samples/snippets/sample_custom_types.py rename to samples/snippets/instances/custom_machine_types/create_with_helper.py index 38ad64b81..79e7d1a2a 100644 --- a/samples/snippets/sample_custom_types.py +++ b/samples/snippets/instances/custom_machine_types/create_with_helper.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google LLC +# 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. @@ -11,20 +11,25 @@ # 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. -# [START compute_custom_machine_type_create ] +# 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_custom_machine_type_create_with_helper] from collections import namedtuple -from enum import Enum, unique +from enum import Enum +from enum import unique +import re import sys -import time -from typing import Union +from typing import List from google.cloud import compute_v1 -# [END compute_custom_machine_type_create ] - - -# [START compute_custom_machine_type_helper_class ] def gb_to_mb(value: int) -> int: return value << 10 @@ -206,16 +211,58 @@ def from_str(cls, machine_type: str): return cls(zone, cpu, memory, cores) -# [END compute_custom_machine_type_helper_class ] +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk -# [START compute_custom_machine_type_create ] def create_instance( project_id: str, zone: str, instance_name: str, - machine_type: Union[str, "CustomMachineType"], -): + disks: List[compute_v1.AttachedDisk], + machine_type: str = "n1-standard-1", + network_link: str = "global/networks/default", + subnetwork_link: str = 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. @@ -226,39 +273,63 @@ def create_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" - OR - It can be a CustomMachineType object, describing a custom type - you want to use. - - Return: + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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() - # Describe the size and source image of the boot disk to attach to the instance. - disk = compute_v1.AttachedDisk() - initialize_params = compute_v1.AttachedDiskInitializeParams() - initialize_params.source_image = ( - "projects/debian-cloud/global/images/family/debian-10" - ) - initialize_params.disk_size_gb = 10 - disk.initialize_params = initialize_params - disk.auto_delete = True - disk.boot = True - disk.type_ = compute_v1.AttachedDisk.Type.PERSISTENT.name - - # Use the network interface provided in the network_name argument. + # Use the network interface provided in the network_link argument. network_interface = compute_v1.NetworkInterface() - network_interface.name = "global/networks/default" + network_interface.name = network_link + if subnetwork_link: + network_interface.subnetwork = subnetwork_link # Collect information into the Instance object. instance = compute_v1.Instance() instance.name = instance_name - instance.disks = [disk] - instance.machine_type = str(machine_type) + 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}" + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = True + # Prepare the request to insert an instance. request = compute_v1.InsertInstanceRequest() request.zone = zone @@ -266,9 +337,8 @@ def create_instance( request.instance_resource = instance # Wait for the create operation to complete. - print( - f"Creating the {instance_name} instance of type {instance.machine_type} in {zone}..." - ) + print(f"Creating the {instance_name} instance in {zone}...") + operation = instance_client.insert_unary(request=request) while operation.status != compute_v1.Operation.Status.DONE: operation = operation_client.wait( @@ -279,13 +349,9 @@ def create_instance( 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) + return instance -# [END compute_custom_machine_type_create ] - - -# [START compute_custom_machine_type_create_with_helper ] def create_custom_instance( project_id: str, zone: str, @@ -316,216 +382,12 @@ def create_custom_instance( CustomMachineType.CPUSeries.N2D, ) custom_type = CustomMachineType(zone, cpu_series, memory, core_count) - return create_instance(project_id, zone, instance_name, custom_type) - - -# [END compute_custom_machine_type_create_with_helper ] - - -# [START compute_custom_machine_type_create_shared_with_helper ] -def create_custom_shared_core_instance( - project_id: str, - zone: str, - instance_name: str, - cpu_series: CustomMachineType.CPUSeries, - memory: int, -): - """ - Create a new VM instance with a custom type using shared CPUs. - - 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. - cpu_series: the type of CPU you want to use. Pick one value from the CustomMachineType.CPUSeries enum. - For example: CustomMachineType.CPUSeries.E2_MICRO - memory: the amount of memory for the VM instance, in megabytes. - - Return: - Instance object. - """ - assert cpu_series in ( - CustomMachineType.CPUSeries.E2_MICRO, - CustomMachineType.CPUSeries.E2_SMALL, - CustomMachineType.CPUSeries.E2_MEDIUM, - ) - custom_type = CustomMachineType(zone, cpu_series, memory) - return create_instance(project_id, zone, instance_name, custom_type) - - -# [END compute_custom_machine_type_create_shared_with_helper ] - - -# [START compute_custom_machine_type_create_without_helper ] -def create_custom_instances_no_helper( - project_id: str, zone: str, instance_name: str, core_count: int, memory: int -): - """ - Create new VM instances without using a CustomMachineType helper function. - 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. - core_count: number of CPU cores you want to use. - memory: the amount of memory for the VM instance, in megabytes. - - Returns: - List of Instance objects. - """ - # The core_count and memory values are not validated anywhere and can be rejected by the API. - instances = [ - create_instance( - project_id, - zone, - f"{instance_name}_n1", - f"zones/{zone}/machineTypes/custom-{core_count}-{memory}", - ), - create_instance( - project_id, - zone, - f"{instance_name}_n2", - f"zones/{zone}/machineTypes/n2-custom-{core_count}-{memory}", - ), - create_instance( - project_id, - zone, - f"{instance_name}_n2d", - f"zones/{zone}/machineTypes/n2d-custom-{core_count}-{memory}", - ), - create_instance( - project_id, - zone, - f"{instance_name}_e2", - f"zones/{zone}/machineTypes/e2-custom-{core_count}-{memory}", - ), - create_instance( - project_id, - zone, - f"{instance_name}_e2_micro", - f"zones/{zone}/machineTypes/e2-custom-micro-{memory}", - ), - create_instance( - project_id, - zone, - f"{instance_name}_e2_small", - f"zones/{zone}/machineTypes/e2-custom-small-{memory}", - ), - create_instance( - project_id, - zone, - f"{instance_name}_e2_medium", - f"zones/{zone}/machineTypes/e2-custom-medium-{memory}", - ), - ] - return instances - - -# [END compute_custom_machine_type_create_without_helper ] - - -# [START compute_custom_machine_type_extra_mem_no_helper ] -def create_custom_instances_extra_mem_no_helper( - project_id: str, zone: str, instance_name: str, core_count: int, memory: int -): - """ - Create new VM instances with extra memory without using a CustomMachineType helper class. - - 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. - core_count: number of CPU cores you want to use. - memory: the amount of memory for the VM instance, in megabytes. - - Returns: - List of Instance objects. - """ - # The core_count and memory values are not validated anywhere and can be rejected by the API. - instances = [ - create_instance( - project_id, - zone, - f"{instance_name}_n1_extra_mem", - f"zones/{zone}/machineTypes/custom-{core_count}-{memory}-ext", - ), - create_instance( - project_id, - zone, - f"{instance_name}_n2_extra_mem", - f"zones/{zone}/machineTypes/n2-custom-{core_count}-{memory}-ext", - ), - create_instance( - project_id, - zone, - f"{instance_name}_n2d_extra_mem", - f"zones/{zone}/machineTypes/n2d-custom-{core_count}-{memory}-ext", - ), - ] - return instances - - -# [END compute_custom_machine_type_extra_mem_no_helper ] - - -# [START compute_custom_machine_type_update_memory ] -def add_extended_memory_to_instance( - project_id: str, zone: str, instance_name: str, new_memory: int -): - """ - Modify an existing VM to use extended memory. - - 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. - new_memory: the amount of memory for the VM instance, in megabytes. - - Returns: - Instance object. - """ - instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() - instance = instance_client.get( - project=project_id, zone=zone, instance=instance_name - ) - - # Make sure that the machine is turned off - if instance.status not in ( - instance.Status.TERMINATED.name, - instance.Status.STOPPED.name, - ): - op = instance_client.stop_unary( - project=project_id, zone=zone, instance=instance_name - ) - operation_client.wait(project=project_id, zone=zone, operation=op.name) - while instance.status not in ( - instance.Status.TERMINATED.name, - instance.Status.STOPPED.name, - ): - # Waiting for the instance to be turned off. - instance = instance_client.get( - project=project_id, zone=zone, instance=instance_name - ) - time.sleep(2) - - # Modify the machine definition, remember that extended memory is available only for N1, N2 and N2D CPUs - start, end = instance.machine_type.rsplit("-", maxsplit=1) - instance.machine_type = start + f"-{new_memory}-ext" - # Using CustomMachineType helper - # cmt = CustomMachineType.from_str(instance.machine_type) - # cmt.memory_mb = new_memory - # cmt.extra_memory_used = True - # instance.machine_type = str(cmt) - op = instance_client.update_unary( - project=project_id, - zone=zone, - instance=instance_name, - instance_resource=instance, - ) - operation_client.wait(project=project_id, zone=zone, operation=op.name) + 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)] - return instance_client.get(project=project_id, zone=zone, instance=instance_name) + return create_instance(project_id, zone, instance_name, disks, str(custom_type)) -# [END compute_custom_machine_type_update_memory ] +# [END compute_custom_machine_type_create_with_helper] diff --git a/samples/snippets/instances/custom_machine_types/create_without_helper.py b/samples/snippets/instances/custom_machine_types/create_without_helper.py new file mode 100644 index 000000000..5f04cc79f --- /dev/null +++ b/samples/snippets/instances/custom_machine_types/create_without_helper.py @@ -0,0 +1,245 @@ +# 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_custom_machine_type_create_without_helper] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_custom_instances_no_helper( + project_id: str, zone: str, instance_name: str, core_count: int, memory: int +) -> List[compute_v1.Instance]: + """ + Create new VM instances without using a CustomMachineType helper function. + + 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. + core_count: number of CPU cores you want to use. + memory: the amount of memory for the VM instance, in megabytes. + + Returns: + List of Instance objects. + """ + 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)] + # The core_count and memory values are not validated anywhere and can be rejected by the API. + instances = [ + create_instance( + project_id, + zone, + f"{instance_name}_n1", + disks, + f"zones/{zone}/machineTypes/custom-{core_count}-{memory}", + ), + create_instance( + project_id, + zone, + f"{instance_name}_n2", + disks, + f"zones/{zone}/machineTypes/n2-custom-{core_count}-{memory}", + ), + create_instance( + project_id, + zone, + f"{instance_name}_n2d", + disks, + f"zones/{zone}/machineTypes/n2d-custom-{core_count}-{memory}", + ), + create_instance( + project_id, + zone, + f"{instance_name}_e2", + disks, + f"zones/{zone}/machineTypes/e2-custom-{core_count}-{memory}", + ), + create_instance( + project_id, + zone, + f"{instance_name}_e2_micro", + disks, + f"zones/{zone}/machineTypes/e2-custom-micro-{memory}", + ), + create_instance( + project_id, + zone, + f"{instance_name}_e2_small", + disks, + f"zones/{zone}/machineTypes/e2-custom-small-{memory}", + ), + create_instance( + project_id, + zone, + f"{instance_name}_e2_medium", + disks, + f"zones/{zone}/machineTypes/e2-custom-medium-{memory}", + ), + ] + return instances + + +# [END compute_custom_machine_type_create_without_helper] 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 new file mode 100644 index 000000000..a2667437e --- /dev/null +++ b/samples/snippets/instances/custom_machine_types/extra_mem_no_helper.py @@ -0,0 +1,217 @@ +# 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_custom_machine_type_extra_mem_no_helper] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_custom_instances_extra_mem_no_helper( + project_id: str, zone: str, instance_name: str, core_count: int, memory: int +) -> List[compute_v1.Instance]: + """ + Create new VM instances with extra memory without using a CustomMachineType helper class. + + 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. + core_count: number of CPU cores you want to use. + memory: the amount of memory for the VM instance, in megabytes. + + Returns: + List of Instance objects. + """ + 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)] + # The core_count and memory values are not validated anywhere and can be rejected by the API. + instances = [ + create_instance( + project_id, + zone, + f"{instance_name}_n1_extra_mem", + disks, + f"zones/{zone}/machineTypes/custom-{core_count}-{memory}-ext", + ), + create_instance( + project_id, + zone, + f"{instance_name}_n2_extra_mem", + disks, + f"zones/{zone}/machineTypes/n2-custom-{core_count}-{memory}-ext", + ), + create_instance( + project_id, + zone, + f"{instance_name}_n2d_extra_mem", + disks, + f"zones/{zone}/machineTypes/n2d-custom-{core_count}-{memory}-ext", + ), + ] + return instances + + +# [END compute_custom_machine_type_extra_mem_no_helper] diff --git a/samples/snippets/instances/custom_machine_types/helper_class.py b/samples/snippets/instances/custom_machine_types/helper_class.py new file mode 100644 index 000000000..acd867c0f --- /dev/null +++ b/samples/snippets/instances/custom_machine_types/helper_class.py @@ -0,0 +1,209 @@ +# 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_custom_machine_type_helper_class] +from collections import namedtuple +from enum import Enum +from enum import unique + + +def gb_to_mb(value: int) -> int: + return value << 10 + + +class CustomMachineType: + """ + Allows to create custom machine types to be used with the VM instances. + """ + + @unique + class CPUSeries(Enum): + N1 = "custom" + N2 = "n2-custom" + N2D = "n2d-custom" + E2 = "e2-custom" + E2_MICRO = "e2-custom-micro" + E2_SMALL = "e2-custom-small" + E2_MEDIUM = "e2-custom-medium" + + TypeLimits = namedtuple( + "TypeLimits", + [ + "allowed_cores", + "min_mem_per_core", + "max_mem_per_core", + "allow_extra_memory", + "extra_memory_limit", + ], + ) + + LIMITS = { + CPUSeries.E2: TypeLimits(frozenset(range(2, 33, 2)), 512, 8192, False, 0), + CPUSeries.E2_MICRO: TypeLimits(frozenset(), 1024, 2048, False, 0), + CPUSeries.E2_SMALL: TypeLimits(frozenset(), 2048, 4096, False, 0), + CPUSeries.E2_MEDIUM: TypeLimits(frozenset(), 4096, 8192, False, 0), + CPUSeries.N2: TypeLimits( + frozenset(range(2, 33, 2)).union(set(range(36, 129, 4))), + 512, + 8192, + True, + gb_to_mb(624), + ), + CPUSeries.N2D: TypeLimits( + frozenset({2, 4, 8, 16, 32, 48, 64, 80, 96}), 512, 8192, True, gb_to_mb(768) + ), + CPUSeries.N1: TypeLimits( + frozenset({1}.union(range(2, 97, 2))), 922, 6656, True, gb_to_mb(624) + ), + } + + def __init__( + self, zone: str, cpu_series: CPUSeries, memory_mb: int, core_count: int = 0 + ): + self.zone = zone + self.cpu_series = cpu_series + self.limits = self.LIMITS[self.cpu_series] + self.core_count = 2 if self.is_shared() else core_count + self.memory_mb = memory_mb + + self._check() + self.extra_memory_used = self._check_extra_memory() + + def is_shared(self): + return self.cpu_series in ( + CustomMachineType.CPUSeries.E2_SMALL, + CustomMachineType.CPUSeries.E2_MICRO, + CustomMachineType.CPUSeries.E2_MEDIUM, + ) + + def _check_extra_memory(self) -> bool: + # Assuming this runs after _check() and the total memory requested is correct + return self.memory_mb > self.core_count * self.limits.max_mem_per_core + + def _check(self): + """ + Check whether the requested parameters are allowed. Find more information about limitations of custom machine + types at: https://cloud.google.com/compute/docs/general-purpose-machines#custom_machine_types + """ + # Check the number of cores + if ( + self.limits.allowed_cores + and self.core_count not in self.limits.allowed_cores + ): + raise RuntimeError( + f"Invalid number of cores requested. Allowed number of cores for {self.cpu_series.name} is: {sorted(self.limits.allowed_cores)}" + ) + + # Memory must be a multiple of 256 MB + if self.memory_mb % 256 != 0: + raise RuntimeError("Requested memory must be a multiple of 256 MB.") + + # Check if the requested memory isn't too little + if self.memory_mb < self.core_count * self.limits.min_mem_per_core: + raise RuntimeError( + f"Requested memory is too low. Minimal memory for {self.cpu_series.name} is {self.limits.min_mem_per_core} MB per core." + ) + + # Check if the requested memory isn't too much + if self.memory_mb > self.core_count * self.limits.max_mem_per_core: + if self.limits.allow_extra_memory: + if self.memory_mb > self.limits.extra_memory_limit: + raise RuntimeError( + f"Requested memory is too large.. Maximum memory allowed for {self.cpu_series.name} is {self.limits.extra_memory_limit} MB." + ) + else: + raise RuntimeError( + f"Requested memory is too large.. Maximum memory allowed for {self.cpu_series.name} is {self.limits.max_mem_per_core} MB per core." + ) + + def __str__(self) -> str: + """ + Return the custom machine type in form of a string acceptable by Compute Engine API. + """ + if self.cpu_series in { + self.CPUSeries.E2_SMALL, + self.CPUSeries.E2_MICRO, + self.CPUSeries.E2_MEDIUM, + }: + return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.memory_mb}" + + if self.extra_memory_used: + return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.core_count}-{self.memory_mb}-ext" + + return f"zones/{self.zone}/machineTypes/{self.cpu_series.value}-{self.core_count}-{self.memory_mb}" + + def short_type_str(self) -> str: + """ + Return machine type in a format without the zone. For example, n2-custom-0-10240. + This format is used to create instance templates. + """ + return str(self).rsplit("/", maxsplit=1)[1] + + @classmethod + def from_str(cls, machine_type: str): + """ + Construct a new object from a string. The string needs to be a valid custom machine type like: + - https://www.googleapis.com/compute/v1/projects/diregapic-mestiv/zones/us-central1-b/machineTypes/e2-custom-4-8192 + - zones/us-central1-b/machineTypes/e2-custom-4-8192 + - e2-custom-4-8192 (in this case, the zone parameter will not be set) + """ + zone = None + if machine_type.startswith("http"): + machine_type = machine_type[machine_type.find("zones/") :] + + if machine_type.startswith("zones/"): + _, zone, _, machine_type = machine_type.split("/") + + extra_mem = machine_type.endswith("-ext") + + if machine_type.startswith("custom"): + cpu = cls.CPUSeries.N1 + _, cores, memory = machine_type.rsplit("-", maxsplit=2) + else: + if extra_mem: + cpu_series, _, cores, memory, _ = machine_type.split("-") + else: + cpu_series, _, cores, memory = machine_type.split("-") + if cpu_series == "n2": + cpu = cls.CPUSeries.N2 + elif cpu_series == "n2d": + cpu = cls.CPUSeries.N2D + elif cpu_series == "e2": + cpu = cls.CPUSeries.E2 + if cores == "micro": + cpu = cls.CPUSeries.E2_MICRO + cores = 2 + elif cores == "small": + cpu = cls.CPUSeries.E2_SMALL + cores = 2 + elif cores == "medium": + cpu = cls.CPUSeries.E2_MEDIUM + cores = 2 + else: + raise RuntimeError("Unknown CPU series.") + + cores = int(cores) + memory = int(memory) + + return cls(zone, cpu, memory, cores) + + +# [END compute_custom_machine_type_helper_class] diff --git a/samples/snippets/instances/custom_machine_types/update_memory.py b/samples/snippets/instances/custom_machine_types/update_memory.py new file mode 100644 index 000000000..5a168e784 --- /dev/null +++ b/samples/snippets/instances/custom_machine_types/update_memory.py @@ -0,0 +1,87 @@ +# 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_custom_machine_type_update_memory] +import time + +from google.cloud import compute_v1 + + +def add_extended_memory_to_instance( + project_id: str, zone: str, instance_name: str, new_memory: int +): + """ + Modify an existing VM to use extended memory. + + 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. + new_memory: the amount of memory for the VM instance, in megabytes. + + Returns: + Instance object. + """ + instance_client = compute_v1.InstancesClient() + operation_client = compute_v1.ZoneOperationsClient() + instance = instance_client.get( + project=project_id, zone=zone, instance=instance_name + ) + + # Make sure that the machine is turned off + if instance.status not in ( + instance.Status.TERMINATED.name, + instance.Status.STOPPED.name, + ): + op = instance_client.stop_unary( + project=project_id, zone=zone, instance=instance_name + ) + operation_client.wait(project=project_id, zone=zone, operation=op.name) + while instance.status not in ( + instance.Status.TERMINATED.name, + instance.Status.STOPPED.name, + ): + # Waiting for the instance to be turned off. + instance = instance_client.get( + project=project_id, zone=zone, instance=instance_name + ) + time.sleep(2) + + # Modify the machine definition, remember that extended memory is available only for N1, N2 and N2D CPUs + start, end = instance.machine_type.rsplit("-", maxsplit=1) + instance.machine_type = start + f"-{new_memory}-ext" + # Using CustomMachineType helper + # cmt = CustomMachineType.from_str(instance.machine_type) + # cmt.memory_mb = new_memory + # cmt.extra_memory_used = True + # instance.machine_type = str(cmt) + op = instance_client.update_unary( + project=project_id, + zone=zone, + instance=instance_name, + instance_resource=instance, + ) + operation_client.wait(project=project_id, zone=zone, operation=op.name) + + return instance_client.get(project=project_id, zone=zone, instance=instance_name) + + +# [END compute_custom_machine_type_update_memory] diff --git a/samples/snippets/instances/delete.py b/samples/snippets/instances/delete.py new file mode 100644 index 000000000..be8c714fe --- /dev/null +++ b/samples/snippets/instances/delete.py @@ -0,0 +1,56 @@ +# 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_delete] +import sys + +from google.cloud import compute_v1 + + +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. + + 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” + 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( + project=project_id, zone=zone, instance=machine_name + ) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during deletion:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during deletion:", operation.warnings, file=sys.stderr) + print(f"Instance {machine_name} deleted.") + return + + +# [END compute_instances_delete] diff --git a/samples/snippets/instances/delete_protection/__init__.py b/samples/snippets/instances/delete_protection/__init__.py new file mode 100644 index 000000000..a3ded82a3 --- /dev/null +++ b/samples/snippets/instances/delete_protection/__init__.py @@ -0,0 +1,14 @@ +# 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/samples/snippets/instances/delete_protection/create.py b/samples/snippets/instances/delete_protection/create.py new file mode 100644 index 000000000..b4b21b7fc --- /dev/null +++ b/samples/snippets/instances/delete_protection/create.py @@ -0,0 +1,195 @@ +# 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_delete_protection_create] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_protected_instance( + project_id: str, zone: str, instance_name: str +) -> compute_v1.Instance: + """ + Create a new VM instance with Debian 10 operating system and delete protection + turned on. + + 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. + + Returns: + Instance object. + """ + newest_debian = get_image_from_family(project="debian-cloud", family="debian-11") + disk_type = f"zones/{zone}/diskTypes/pd-standard" + disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)] + instance = create_instance( + project_id, zone, instance_name, disks, delete_protection=True + ) + return instance + + +# [END compute_delete_protection_create] diff --git a/samples/snippets/instances/delete_protection/get.py b/samples/snippets/instances/delete_protection/get.py new file mode 100644 index 000000000..d6ecfa398 --- /dev/null +++ b/samples/snippets/instances/delete_protection/get.py @@ -0,0 +1,43 @@ +# 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_delete_protection_get] +from google.cloud import compute_v1 + + +def get_delete_protection(project_id: str, zone: str, instance_name: str) -> bool: + """ + Returns the state of delete protection flag of given instance. + 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 virtual machine to check. + Returns: + The state of the delete protection setting. + """ + instance_client = compute_v1.InstancesClient() + instance = instance_client.get( + project=project_id, zone=zone, instance=instance_name + ) + return instance.deletion_protection + + +# [END compute_delete_protection_get] diff --git a/samples/snippets/instances/delete_protection/set.py b/samples/snippets/instances/delete_protection/set.py new file mode 100644 index 000000000..e25269317 --- /dev/null +++ b/samples/snippets/instances/delete_protection/set.py @@ -0,0 +1,52 @@ +# 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_delete_protection_set] +from google.cloud import compute_v1 + + +def set_delete_protection( + project_id: str, zone: str, instance_name: str, delete_protection: bool +): + """ + Updates the delete protection setting of given instance. + 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 virtual machine to update. + delete_protection: boolean value indicating if the virtual machine should be + protected against deletion or not. + """ + instance_client = compute_v1.InstancesClient() + operation_client = compute_v1.ZoneOperationsClient() + + request = compute_v1.SetDeletionProtectionInstanceRequest() + request.project = project_id + request.zone = zone + 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) + return + + +# [END compute_delete_protection_set] diff --git a/samples/snippets/instances/from_instance_template/__init__.py b/samples/snippets/instances/from_instance_template/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/snippets/instances/from_instance_template/create_from_template.py b/samples/snippets/instances/from_instance_template/create_from_template.py new file mode 100644 index 000000000..6310cfd11 --- /dev/null +++ b/samples/snippets/instances/from_instance_template/create_from_template.py @@ -0,0 +1,61 @@ +# 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_from_template] +from google.cloud import compute_v1 + + +def create_instance_from_template( + project_id: str, zone: str, instance_name: str, instance_template_url: str +) -> compute_v1.Instance: + """ + Creates a Compute Engine VM instance from an instance template. + + Args: + project_id: ID or number of the project you want to use. + zone: Name of the zone you want to check, for example: us-west3-b + instance_name: Name of the new instance. + instance_template_url: URL of the instance template used for creating the new instance. + It can be a full or partial URL. + Examples: + - https://www.googleapis.com/compute/v1/projects/project/global/instanceTemplates/example-instance-template + - projects/project/global/instanceTemplates/example-instance-template + - global/instanceTemplates/example-instance-template + + Returns: + Instance object. + """ + operation_client = compute_v1.ZoneOperationsClient() + instance_client = compute_v1.InstancesClient() + + instance_insert_request = compute_v1.InsertInstanceRequest() + instance_insert_request.project = project_id + instance_insert_request.zone = zone + 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) + + return instance_client.get(project=project_id, zone=zone, instance=instance_name) + + +# [END compute_instances_create_from_template] diff --git a/samples/snippets/sample_instance_from_template.py b/samples/snippets/instances/from_instance_template/create_from_template_with_overrides.py similarity index 67% rename from samples/snippets/sample_instance_from_template.py rename to samples/snippets/instances/from_instance_template/create_from_template_with_overrides.py index 30ef65dba..6f76d3290 100644 --- a/samples/snippets/sample_instance_from_template.py +++ b/samples/snippets/instances/from_instance_template/create_from_template_with_overrides.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google LLC +# 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. @@ -11,53 +11,18 @@ # 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 -# [START compute_instances_create_from_template] -# [START compute_instances_create_from_template_with_overrides] -from google.cloud import compute_v1 - -# [END compute_instances_create_from_template_with_overrides] - - -def create_instance_from_template( - project_id: str, zone: str, instance_name: str, instance_template_url: str -) -> compute_v1.Instance: - """ - Creates a Compute Engine VM instance from an instance template. - - Args: - project_id: ID or number of the project you want to use. - zone: Name of the zone you want to check, for example: us-west3-b - instance_name: Name of the new instance. - instance_template_url: URL of the instance template used for creating the new instance. - It can be a full or partial URL. - Examples: - - https://www.googleapis.com/compute/v1/projects/project/global/instanceTemplates/example-instance-template - - projects/project/global/instanceTemplates/example-instance-template - - global/instanceTemplates/example-instance-template - - Returns: - Instance object. - """ - operation_client = compute_v1.ZoneOperationsClient() - instance_client = compute_v1.InstancesClient() - instance_insert_request = compute_v1.InsertInstanceRequest() - instance_insert_request.project = project_id - instance_insert_request.zone = zone - 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) - - return instance_client.get(project=project_id, zone=zone, instance=instance_name) +# 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. -# [END compute_instances_create_from_template] +# [START compute_instances_create_from_template_with_overrides] +from google.cloud import compute_v1 -# [START compute_instances_create_from_template_with_overrides] def create_instance_from_template_with_overrides( project_id: str, zone: str, @@ -80,7 +45,7 @@ def create_instance_from_template_with_overrides( - "zones/europe-west3-c/machineTypes/f1-micro" - You can find the list of available machine types using: https://cloud.google.com/sdk/gcloud/reference/compute/machine-types/list - newDiskSourceImage: Path the the disk image you want to use for your new + new_disk_source_image: Path the the disk image you want to use for your new disk. This can be one of the public images (like "projects/debian-cloud/global/images/family/debian-10") or a private image you have access to. diff --git a/samples/snippets/instances/list.py b/samples/snippets/instances/list.py new file mode 100644 index 000000000..45830c72e --- /dev/null +++ b/samples/snippets/instances/list.py @@ -0,0 +1,48 @@ +# 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_list] +from typing import Iterable + +from google.cloud import compute_v1 + + +def list_instances(project_id: str, zone: str) -> Iterable[compute_v1.Instance]: + """ + List all instances 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” + Returns: + An iterable collection of Instance objects. + """ + instance_client = compute_v1.InstancesClient() + instance_list = instance_client.list(project=project_id, zone=zone) + + print(f"Instances found in zone {zone}:") + for instance in instance_list: + print(f" - {instance.name} ({instance.machine_type})") + + return instance_list + + +# [END compute_instances_list] diff --git a/samples/snippets/instances/list_all.py b/samples/snippets/instances/list_all.py new file mode 100644 index 000000000..9549de0f4 --- /dev/null +++ b/samples/snippets/instances/list_all.py @@ -0,0 +1,62 @@ +# 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_list_all] +from typing import Dict, Iterable + +from google.cloud import compute_v1 + + +def list_all_instances( + project_id: str, +) -> Dict[str, Iterable[compute_v1.Instance]]: + """ + Return a dictionary of all instances present in a project, grouped by their zone. + + Args: + project_id: project ID or project number of the Cloud project you want to use. + Returns: + A dictionary with zone names as keys (in form of "zones/{zone_name}") and + iterable collections of Instance objects as values. + """ + instance_client = compute_v1.InstancesClient() + # Use the `max_results` parameter to limit the number of results that the API returns per response page. + request = compute_v1.AggregatedListInstancesRequest() + request.project = project_id + request.max_results = 50 + + agg_list = instance_client.aggregated_list(request=request) + + all_instances = {} + print("Instances found:") + # Despite using the `max_results` parameter, you don't need to handle the pagination + # yourself. The returned `AggregatedListPager` object handles pagination + # automatically, returning separated pages as you iterate over the results. + for zone, response in agg_list: + if response.instances: + all_instances[zone] = response.instances + print(f" {zone}:") + for instance in response.instances: + print(f" - {instance.name} ({instance.machine_type})") + return all_instances + + +# [END compute_instances_list_all] diff --git a/samples/snippets/instances/preemptible/__init__.py b/samples/snippets/instances/preemptible/__init__.py new file mode 100644 index 000000000..a3ded82a3 --- /dev/null +++ b/samples/snippets/instances/preemptible/__init__.py @@ -0,0 +1,14 @@ +# 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/samples/snippets/instances/preemptible/create_preemptible.py b/samples/snippets/instances/preemptible/create_preemptible.py new file mode 100644 index 000000000..2f4569bc8 --- /dev/null +++ b/samples/snippets/instances/preemptible/create_preemptible.py @@ -0,0 +1,192 @@ +# 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_preemptible_create] +import re +import sys +from typing import List + +from google.cloud import compute_v1 + + +def get_image_from_family(project: str, family: str) -> compute_v1.Image: + image_client = compute_v1.ImagesClient() + # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details + newest_image = image_client.get_from_family(project=project, family=family) + return newest_image + + +def disk_from_image( + disk_type: str, disk_size_gb: int, boot: bool, source_image: str +) -> compute_v1.AttachedDisk: + """ + Create an AttachedDisk object to be used in VM instance creation. Uses an image as the + source for the new disk. + + Args: + 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 + boot: boolean flag indicating whether this disk should be used as a boot disk of an instance + source_image: source image to use when creating this disk. You must have read access to this disk. This can be one + of the publicly available images or an image from one of your projects. + This value uses the following format: "projects/{project_name}/global/images/{image_name}" + + Returns: + AttachedDisk object configured to be created using the specified image. + """ + boot_disk = compute_v1.AttachedDisk() + initialize_params = compute_v1.AttachedDiskInitializeParams() + initialize_params.source_image = source_image + initialize_params.disk_size_gb = disk_size_gb + initialize_params.disk_type = disk_type + boot_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. + boot_disk.auto_delete = True + boot_disk.boot = boot + return boot_disk + + +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, + 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. + 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" + disks: a list of compute_v1.AttachedDisk objects describing the disks + you want to attach to your new instance. + 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}" + 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 + + # 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}" + + 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 + + # Shielded Instance settings + # Values presented here are the defaults. + # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() + # instance.shielded_instance_config.enable_secure_boot = False + # instance.shielded_instance_config.enable_vtpm = True + # instance.shielded_instance_config.enable_integrity_monitoring = 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) + while operation.status != compute_v1.Operation.Status.DONE: + operation = operation_client.wait( + operation=operation.name, zone=zone, project=project_id + ) + if operation.error: + print("Error during creation:", operation.error, file=sys.stderr) + if operation.warnings: + print("Warning during creation:", operation.warnings, file=sys.stderr) + print(f"Instance {instance_name} created.") + return instance + + +def create_preemptible_instance( + project_id: str, zone: str, instance_name: str +) -> compute_v1.Instance: + """ + Create a new preemptible VM instance with Debian 10 operating system. + + 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. + + Returns: + Instance object. + """ + newest_debian = get_image_from_family(project="debian-cloud", family="debian-11") + disk_type = f"zones/{zone}/diskTypes/pd-standard" + disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)] + instance = create_instance(project_id, zone, instance_name, disks, preemptible=True) + return instance + + +# [END compute_preemptible_create] diff --git a/samples/snippets/instances/preemptible/is_preemptible.py b/samples/snippets/instances/preemptible/is_preemptible.py new file mode 100644 index 000000000..8a0c966fd --- /dev/null +++ b/samples/snippets/instances/preemptible/is_preemptible.py @@ -0,0 +1,43 @@ +# 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_preemptible_check] +from google.cloud import compute_v1 + + +def is_preemptible(project_id: str, zone: str, instance_name: str) -> bool: + """ + Check if a given instance is preemptible or not. + 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 virtual machine to check. + Returns: + The preemptible status of the instance. + """ + instance_client = compute_v1.InstancesClient() + instance = instance_client.get( + project=project_id, zone=zone, instance=instance_name + ) + return instance.scheduling.preemptible + + +# [END compute_preemptible_check] diff --git a/samples/snippets/instances/preemptible/preemption_history.py b/samples/snippets/instances/preemptible/preemption_history.py new file mode 100644 index 000000000..23a1f7974 --- /dev/null +++ b/samples/snippets/instances/preemptible/preemption_history.py @@ -0,0 +1,87 @@ +# 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_preemptible_history] +import datetime +from typing import List, Tuple + +from google.cloud import compute_v1 +from google.cloud.compute_v1.services.zone_operations import pagers + + +def list_zone_operations( + project_id: str, zone: str, filter: str = "" +) -> pagers.ListPager: + """ + List all recent operations the happened in given zone in a project. Optionally filter those + operations by providing a filter. More about using the filter can be found here: + https://cloud.google.com/compute/docs/reference/rest/v1/zoneOperations/list + 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" + filter: filter string to be used for this listing operation. + Returns: + List of preemption operations in given zone. + """ + operation_client = compute_v1.ZoneOperationsClient() + request = compute_v1.ListZoneOperationsRequest() + request.project = project_id + request.zone = zone + request.filter = filter + + return operation_client.list(request) + + +def preemption_history( + project_id: str, zone: str, instance_name: str = None +) -> List[Tuple[str, datetime.datetime]]: + """ + Get a list of preemption operations from given zone in a project. Optionally limit + the results to instance name. + 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 virtual machine to look for. + Returns: + List of preemption operations in given zone. + """ + if instance_name: + filter = ( + f'operationType="compute.instances.preempted" ' + f"AND targetLink:instances/{instance_name}" + ) + else: + filter = 'operationType="compute.instances.preempted"' + + history = [] + + for operation in list_zone_operations(project_id, zone, filter): + this_instance_name = operation.target_link.rsplit("/", maxsplit=1)[1] + if instance_name and this_instance_name == instance_name: + # The filter used is not 100% accurate, it's `contains` not `equals` + # So we need to check the name to make sure it's the one we want. + moment = datetime.datetime.fromisoformat(operation.insert_time) + history.append((instance_name, moment)) + + return history + + +# [END compute_preemptible_history] diff --git a/samples/snippets/instances/reset.py b/samples/snippets/instances/reset.py new file mode 100644 index 000000000..74bb94c2f --- /dev/null +++ b/samples/snippets/instances/reset.py @@ -0,0 +1,46 @@ +# 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_reset_instance] +from google.cloud import compute_v1 + + +def reset_instance(project_id: str, zone: str, instance_name: str): + """ + Resets a stopped Google Compute Engine instance (with unencrypted disks). + Args: + project_id: project ID or project number of the Cloud project your instance belongs to. + zone: name of the zone your instance belongs to. + 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( + project=project_id, zone=zone, instance=instance_name + ) + + while op.status != compute_v1.Operation.Status.DONE: + op = op_client.wait(operation=op.name, zone=zone, project=project_id) + return + + +# [END compute_reset_instance] diff --git a/samples/snippets/instances/start.py b/samples/snippets/instances/start.py new file mode 100644 index 000000000..9de984bef --- /dev/null +++ b/samples/snippets/instances/start.py @@ -0,0 +1,46 @@ +# 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_start_instance] +from google.cloud import compute_v1 + + +def start_instance(project_id: str, zone: str, instance_name: str): + """ + Starts a stopped Google Compute Engine instance (with unencrypted disks). + Args: + project_id: project ID or project number of the Cloud project your instance belongs to. + zone: name of the zone your instance belongs to. + 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( + project=project_id, zone=zone, instance=instance_name + ) + + while op.status != compute_v1.Operation.Status.DONE: + op = op_client.wait(operation=op.name, zone=zone, project=project_id) + return + + +# [END compute_start_instance] diff --git a/samples/snippets/instances/start_encrypted.py b/samples/snippets/instances/start_encrypted.py new file mode 100644 index 000000000..c0d5c14e8 --- /dev/null +++ b/samples/snippets/instances/start_encrypted.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. +# 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_start_enc_instance] +from google.cloud import compute_v1 + + +def start_instance_with_encryption_key( + project_id: str, zone: str, instance_name: str, key: bytes +): + """ + Starts a stopped Google Compute Engine instance (with encrypted disks). + Args: + project_id: project ID or project number of the Cloud project your instance belongs to. + zone: name of the zone your instance belongs to. + instance_name: name of the instance your want to start. + key: bytes object representing a raw base64 encoded key to your machines boot disk. + For more information about disk encryption see: + 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 + ) + + # Prepare the information about disk encryption + disk_data = compute_v1.CustomerEncryptionKeyProtectedDisk() + disk_data.source = instance_data.disks[0].source + disk_data.disk_encryption_key = compute_v1.CustomerEncryptionKey() + # Use raw_key to send over the key to unlock the disk + # To use a key stored in KMS, you need to provide `kms_key_name` and `kms_key_service_account` + disk_data.disk_encryption_key.raw_key = key + enc_data = compute_v1.InstancesStartWithEncryptionKeyRequest() + enc_data.disks = [disk_data] + + op = instance_client.start_with_encryption_key_unary( + project=project_id, + zone=zone, + instance=instance_name, + instances_start_with_encryption_key_request_resource=enc_data, + ) + + while op.status != compute_v1.Operation.Status.DONE: + op = op_client.wait(operation=op.name, zone=zone, project=project_id) + return + + +# [END compute_start_enc_instance] diff --git a/samples/snippets/instances/stop.py b/samples/snippets/instances/stop.py new file mode 100644 index 000000000..cf155c74c --- /dev/null +++ b/samples/snippets/instances/stop.py @@ -0,0 +1,46 @@ +# 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_stop_instance] +from google.cloud import compute_v1 + + +def stop_instance(project_id: str, zone: str, instance_name: str): + """ + Stops a stopped Google Compute Engine instance. + Args: + project_id: project ID or project number of the Cloud project your instance belongs to. + zone: name of the zone your instance belongs to. + 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( + project=project_id, zone=zone, instance=instance_name + ) + + while op.status != compute_v1.Operation.Status.DONE: + op = op_client.wait(operation=op.name, zone=zone, project=project_id) + return + + +# [END compute_stop_instance] diff --git a/samples/snippets/operations/__init__.py b/samples/snippets/operations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/snippets/operations/operation_check.py b/samples/snippets/operations/operation_check.py new file mode 100644 index 000000000..d136372c3 --- /dev/null +++ b/samples/snippets/operations/operation_check.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. +# 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 +# +# 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_operation_check] +from google.cloud import compute_v1 + + +def wait_for_operation( + operation: compute_v1.Operation, project_id: str +) -> compute_v1.Operation: + """ + This method waits for an operation to be completed. Calling this function + will block until the operation is finished. + + Args: + operation: The Operation object representing the operation you want to + wait on. + project_id: project ID or project number of the Cloud project you want to use. + + Returns: + Finished Operation object. + """ + kwargs = {"project": project_id, "operation": operation.name} + if operation.zone: + client = compute_v1.ZoneOperationsClient() + # Operation.zone is a full URL address of a zone, so we need to extract just the name + kwargs["zone"] = operation.zone.rsplit("/", maxsplit=1)[1] + elif operation.region: + client = compute_v1.RegionOperationsClient() + # Operation.region is a full URL address of a region, so we need to extract just the name + kwargs["region"] = operation.region.rsplit("/", maxsplit=1)[1] + else: + client = compute_v1.GlobalOperationsClient() + return client.wait(**kwargs) + + +# [END compute_instances_operation_check] diff --git a/samples/snippets/quickstart.py b/samples/snippets/quickstart.py deleted file mode 100644 index 3303cc317..000000000 --- a/samples/snippets/quickstart.py +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2021 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. -""" -A sample script showing how to create, list and delete Google Compute Engine -instances using the google-cloud-compute library. It can be run from command -line to create, list and delete an instance in a given project in a given zone. -""" - -# [START compute_instances_create] -# [START compute_instances_delete] -import re -import sys - -# [START compute_instances_list] -# [START compute_instances_list_all] -# [START compute_instances_operation_check] -import typing - -import google.cloud.compute_v1 as compute_v1 - -# [END compute_instances_operation_check] -# [END compute_instances_list_all] -# [END compute_instances_list] -# [END compute_instances_delete] -# [END compute_instances_create] - - -# [START compute_instances_list] -def list_instances(project_id: str, zone: str) -> typing.Iterable[compute_v1.Instance]: - """ - List all instances 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” - Returns: - An iterable collection of Instance objects. - """ - instance_client = compute_v1.InstancesClient() - instance_list = instance_client.list(project=project_id, zone=zone) - - print(f"Instances found in zone {zone}:") - for instance in instance_list: - print(f" - {instance.name} ({instance.machine_type})") - - return instance_list - - -# [END compute_instances_list] - - -# [START compute_instances_list_all] -def list_all_instances( - project_id: str, -) -> typing.Dict[str, typing.Iterable[compute_v1.Instance]]: - """ - Return a dictionary of all instances present in a project, grouped by their zone. - - Args: - project_id: project ID or project number of the Cloud project you want to use. - Returns: - A dictionary with zone names as keys (in form of "zones/{zone_name}") and - iterable collections of Instance objects as values. - """ - instance_client = compute_v1.InstancesClient() - # Use the `max_results` parameter to limit the number of results that the API returns per response page. - request = compute_v1.AggregatedListInstancesRequest( - project=project_id, max_results=5 - ) - agg_list = instance_client.aggregated_list(request=request) - all_instances = {} - print("Instances found:") - # Despite using the `max_results` parameter, you don't need to handle the pagination - # yourself. The returned `AggregatedListPager` object handles pagination - # automatically, returning separated pages as you iterate over the results. - for zone, response in agg_list: - if response.instances: - all_instances[zone] = response.instances - print(f" {zone}:") - for instance in response.instances: - print(f" - {instance.name} ({instance.machine_type})") - return all_instances - - -# [END compute_instances_list_all] - - -# [START compute_instances_create] -def create_instance( - project_id: str, - zone: str, - instance_name: str, - machine_type: str = "n1-standard-1", - source_image: str = "projects/debian-cloud/global/images/family/debian-10", - network_name: str = "global/networks/default", -) -> 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 you want to use. For example: “us-west3-b” - instance_name: name of the new virtual machine. - 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" - source_image: path to the operating system image to mount on your boot - disk. This can be one of the public images - (like "projects/debian-cloud/global/images/family/debian-10") - or a private image you have access to. - network_name: name of the network you want the new instance to use. - For example: "global/networks/default" represents the `default` - network interface, which is created automatically for each project. - Returns: - Instance object. - """ - instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() - - # Describe the size and source image of the boot disk to attach to the instance. - disk = compute_v1.AttachedDisk() - initialize_params = compute_v1.AttachedDiskInitializeParams() - initialize_params.source_image = ( - source_image # "projects/debian-cloud/global/images/family/debian-10" - ) - initialize_params.disk_size_gb = 10 - disk.initialize_params = initialize_params - disk.auto_delete = True - disk.boot = True - disk.type_ = "PERSISTENT" - - # Use the network interface provided in the network_name argument. - network_interface = compute_v1.NetworkInterface() - network_interface.name = network_name - - # Collect information into the Instance object. - instance = compute_v1.Instance() - instance.name = instance_name - instance.disks = [disk] - 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}" - instance.network_interfaces = [network_interface] - - # 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) - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) - print(f"Instance {instance_name} created.") - return instance - - -# [END compute_instances_create] - - -# [START compute_instances_delete] -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. - - 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” - 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( - project=project_id, zone=zone, instance=machine_name - ) - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if operation.error: - print("Error during deletion:", operation.error, file=sys.stderr) - if operation.warnings: - print("Warning during deletion:", operation.warnings, file=sys.stderr) - print(f"Instance {machine_name} deleted.") - return - - -# [END compute_instances_delete] - - -# [START compute_instances_operation_check] -def wait_for_operation( - operation: compute_v1.Operation, project_id: str -) -> compute_v1.Operation: - """ - This method waits for an operation to be completed. Calling this function - will block until the operation is finished. - - Args: - operation: The Operation object representing the operation you want to - wait on. - project_id: project ID or project number of the Cloud project you want to use. - - Returns: - Finished Operation object. - """ - kwargs = {"project": project_id, "operation": operation.name} - if operation.zone: - client = compute_v1.ZoneOperationsClient() - # Operation.zone is a full URL address of a zone, so we need to extract just the name - kwargs["zone"] = operation.zone.rsplit("/", maxsplit=1)[1] - elif operation.region: - client = compute_v1.RegionOperationsClient() - # Operation.region is a full URL address of a region, so we need to extract just the name - kwargs["region"] = operation.region.rsplit("/", maxsplit=1)[1] - else: - client = compute_v1.GlobalOperationsClient() - return client.wait(**kwargs) - - -# [END compute_instances_operation_check] - - -def main(project_id: str, zone: str, instance_name: str) -> None: - - create_instance(project_id, zone, instance_name) - - zone_instances = list_instances(project_id, zone) - print(f"Instances found in {zone}:", ", ".join(i.name for i in zone_instances)) - - all_instances = list_all_instances(project_id) - print(f"Instances found in project {project_id}:") - for i_zone, instances in all_instances.items(): - print(f"{i_zone}:", ", ".join(i.name for i in instances)) - - delete_instance(project_id, zone, instance_name) - - -if __name__ == "__main__": - import uuid - import google.auth - import google.auth.exceptions - - try: - default_project_id = google.auth.default()[1] - except google.auth.exceptions.DefaultCredentialsError: - print( - "Please use `gcloud auth application-default login` " - "or set GOOGLE_APPLICATION_CREDENTIALS to use this script." - ) - else: - instance_name = "quickstart-" + uuid.uuid4().hex[:10] - instance_zone = "europe-central2-b" - main(default_project_id, instance_zone, instance_name) diff --git a/samples/snippets/sample_create_vm.py b/samples/snippets/sample_create_vm.py deleted file mode 100644 index 1ea6ba2d2..000000000 --- a/samples/snippets/sample_create_vm.py +++ /dev/null @@ -1,423 +0,0 @@ -# Copyright 2021 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. -import re -import sys -from typing import List - -# [START compute_instances_create_with_subnet] -# [START compute_instances_create_from_image_plus_snapshot_disk] -# [START compute_instances_create_from_snapshot] -# [START compute_instances_create_from_image_plus_empty_disk] -# [START compute_instances_create_from_custom_image] -# [START compute_instances_create_from_image] -from google.cloud import compute_v1 - - -# [END compute_instances_create_from_image] -# [END compute_instances_create_from_custom_image] -# [END compute_instances_create_from_image_plus_empty_disk] -# [END compute_instances_create_from_snapshot] -# [END compute_instances_create_from_image_plus_snapshot_disk] -# [END compute_instances_create_with_subnet] - - -# [START compute_instances_create_with_subnet] -# [START compute_instances_create_from_image_plus_snapshot_disk] -# [START compute_instances_create_from_image_plus_empty_disk] -# [START compute_instances_create_from_custom_image] -# [START compute_instances_create_from_image] -def disk_from_image( - disk_type: str, disk_size_gb: int, boot: bool, source_image: str -) -> compute_v1.AttachedDisk: - """ - Create an AttachedDisk object to be used in VM instance creation. Uses an image as the - source for the new disk. - - Args: - 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 - boot: boolean flag indicating whether this disk should be used as a boot disk of an instance - source_image: source image to use when creating this disk. You must have read access to this disk. This can be one - of the publicly available images or an image from one of your projects. - This value uses the following format: "projects/{project_name}/global/images/{image_name}" - - Returns: - AttachedDisk object configured to be created using the specified image. - """ - boot_disk = compute_v1.AttachedDisk() - initialize_params = compute_v1.AttachedDiskInitializeParams() - initialize_params.source_image = source_image - initialize_params.disk_size_gb = disk_size_gb - initialize_params.disk_type = disk_type - boot_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. - boot_disk.auto_delete = True - boot_disk.boot = boot - return boot_disk - - -# [END compute_instances_create_from_image] -# [END compute_instances_create_from_custom_image] -# [END compute_instances_create_from_image_plus_empty_disk] -# [END compute_instances_create_from_image_plus_snapshot_disk] -# [END compute_instances_create_with_subnet] - - -# [START compute_instances_create_from_image_plus_empty_disk] -def empty_disk(disk_type: str, disk_size_gb: int) -> 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. - - Args: - 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: - AttachedDisk object configured to be created as an empty disk. - """ - disk = compute_v1.AttachedDisk() - initialize_params = compute_v1.AttachedDiskInitializeParams() - initialize_params.disk_type = disk_type - initialize_params.disk_size_gb = disk_size_gb - 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 - return disk - - -# [END compute_instances_create_from_image_plus_empty_disk] - - -# [START compute_instances_create_from_image_plus_snapshot_disk] -# [START compute_instances_create_from_snapshot] -def disk_from_snapshot( - disk_type: str, disk_size_gb: int, boot: bool, disk_snapshot: str -) -> compute_v1.AttachedDisk(): - """ - Create an AttachedDisk object to be used in VM instance creation. Uses a disk snapshot as the - source for the new disk. - - Args: - 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 - boot: boolean flag indicating whether this disk should be used as a boot disk of an instance - disk_snapshot: disk snapshot to use when creating this disk. You must have read access to this disk. - This value uses the following format: "projects/{project_name}/global/snapshots/{snapshot_name}" - - Returns: - AttachedDisk object configured to be created using the specified snapshot. - """ - disk = compute_v1.AttachedDisk() - initialize_params = compute_v1.AttachedDiskInitializeParams() - initialize_params.source_snapshot = disk_snapshot - initialize_params.disk_type = disk_type - initialize_params.disk_size_gb = disk_size_gb - 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 = boot - return disk - - -# [END compute_instances_create_from_snapshot] -# [END compute_instances_create_from_image_plus_snapshot_disk] - - -# [START compute_instances_create_with_subnet] -# [START compute_instances_create_from_image_plus_snapshot_disk] -# [START compute_instances_create_from_snapshot] -# [START compute_instances_create_from_image_plus_empty_disk] -# [START compute_instances_create_from_custom_image] -# [START compute_instances_create_from_image] -def create_with_disks( - 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, -) -> 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. - 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" - disks: a list of compute_v1.AttachedDisk objects describing the disks - you want to attach to your new instance. - 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}" - 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 - - # 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}" - instance.network_interfaces = [network_interface] - - # Shielded Instance settings - # Values presented here are the defaults. - # instance.shielded_instance_config = compute_v1.ShieldedInstanceConfig() - # instance.shielded_instance_config.enable_secure_boot = False - # instance.shielded_instance_config.enable_vtpm = True - # instance.shielded_instance_config.enable_integrity_monitoring = 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) - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) - print(f"Instance {instance_name} created.") - return instance - - -# [END compute_instances_create_from_image] -# [END compute_instances_create_from_custom_image] -# [END compute_instances_create_from_image_plus_empty_disk] -# [END compute_instances_create_from_snapshot] -# [END compute_instances_create_from_image_plus_snapshot_disk] -# [END compute_instances_create_with_subnet] - - -# [START compute_instances_create_from_image] -def create_from_public_image(project_id: str, zone: str, instance_name: str): - """ - Create a new VM instance with Debian 10 operating system. - - 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. - - Returns: - Instance object. - """ - image_client = compute_v1.ImagesClient() - # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details - newest_debian = image_client.get_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)] - instance = create_with_disks(project_id, zone, instance_name, disks) - return instance - - -# [END compute_instances_create_from_image] - - -# [START compute_instances_create_from_custom_image] -def create_from_custom_image( - project_id: str, zone: str, instance_name: str, custom_image_link: str -): - """ - Create a new VM instance with custom image used as its 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. - custom_image_link: link to the custom image you want to use in the form of: - "projects/{project_name}/global/images/{image_name}" - - Returns: - Instance object. - """ - disk_type = f"zones/{zone}/diskTypes/pd-standard" - disks = [disk_from_image(disk_type, 10, True, custom_image_link)] - instance = create_with_disks(project_id, zone, instance_name, disks) - return instance - - -# [END compute_instances_create_from_custom_image] - - -# [START compute_instances_create_from_image_plus_empty_disk] -def create_with_additional_disk(project_id: str, zone: str, instance_name: str): - """ - Create a new VM instance with Debian 10 operating system and a 11 GB additional - empty 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. - - Returns: - Instance object. - """ - image_client = compute_v1.ImagesClient() - # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details - newest_debian = image_client.get_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), - empty_disk(disk_type, 11), - ] - instance = create_with_disks(project_id, zone, instance_name, disks) - return instance - - -# [END compute_instances_create_from_image_plus_empty_disk] - - -# [START compute_instances_create_from_snapshot] -def create_from_snapshot( - project_id: str, zone: str, instance_name: str, snapshot_link: str -): - """ - Create a new VM instance with boot disk created from a snapshot. - - 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. - snapshot_link: link to the snapshot you want to use as the source of your - boot disk in the form of: "projects/{project_name}/global/snapshots/{snapshot_name}" - - Returns: - Instance object. - """ - disk_type = f"zones/{zone}/diskTypes/pd-standard" - disks = [disk_from_snapshot(disk_type, 11, True, snapshot_link)] - instance = create_with_disks(project_id, zone, instance_name, disks) - return instance - - -# [END compute_instances_create_from_snapshot] - - -# [START compute_instances_create_from_image_plus_snapshot_disk] -def create_with_snapshotted_data_disk( - project_id: str, zone: str, instance_name: str, snapshot_link: str -): - """ - Create a new VM instance with Debian 10 operating system and data disk created from snapshot. - - 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. - snapshot_link: link to the snapshot you want to use as the source of your - data disk in the form of: "projects/{project_name}/global/snapshots/{snapshot_name}" - - Returns: - Instance object. - """ - image_client = compute_v1.ImagesClient() - # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details - newest_debian = image_client.get_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), - disk_from_snapshot(disk_type, 11, False, snapshot_link), - ] - instance = create_with_disks(project_id, zone, instance_name, disks) - return instance - - -# [END compute_instances_create_from_image_plus_snapshot_disk] - - -# [START compute_instances_create_with_subnet] -def create_with_subnet( - project_id: str, zone: str, instance_name: str, network_link: str, subnet_link: str -): - """ - Create a new VM instance with Debian 10 operating system in specified network and subnetwork. - - 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. - 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}" - - Returns: - Instance object. - """ - image_client = compute_v1.ImagesClient() - # List of public operating system (OS) images: https://cloud.google.com/compute/docs/images/os-details - newest_debian = image_client.get_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)] - instance = create_with_disks( - project_id, - zone, - instance_name, - disks, - network_link=network_link, - subnetwork_link=subnet_link, - ) - return instance - - -# [END compute_instances_create_with_subnet] diff --git a/samples/snippets/sample_custom_hostname.py b/samples/snippets/sample_custom_hostname.py deleted file mode 100644 index 8d732f594..000000000 --- a/samples/snippets/sample_custom_hostname.py +++ /dev/null @@ -1,118 +0,0 @@ -# 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. - -# [START compute_instances_create_custom_hostname] -import sys - - -# [START compute_instances_get_hostname] -from google.cloud import compute_v1 - -# [END compute_instances_get_hostname] -# [END compute_instances_create_custom_hostname] - - -# [START compute_instances_create_custom_hostname] -def create_instance( - project_id: str, zone: str, instance_name: str, hostname: str, -) -> 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 you want to use. For example: “us-west3-b” - instance_name: name of the new virtual machine. - hostname: Custom hostname of the new VM instance. - Custom hostnames must conform to RFC 1035 requirements for valid hostnames. - - Returns: - Instance object. - """ - instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() - - # Describe the size and source image of the boot disk to attach to the instance. - disk = compute_v1.AttachedDisk() - initialize_params = compute_v1.AttachedDiskInitializeParams() - initialize_params.source_image = ( - "projects/debian-cloud/global/images/family/debian-10" - ) - initialize_params.disk_size_gb = 10 - disk.initialize_params = initialize_params - disk.auto_delete = True - disk.boot = True - disk.type_ = "PERSISTENT" - - # Use the default VPC network. - network_interface = compute_v1.NetworkInterface() - network_interface.name = "default" - - # Collect information into the Instance object. - instance = compute_v1.Instance() - instance.name = instance_name - instance.disks = [disk] - instance.machine_type = f"zones/{zone}/machineTypes/e2-small" - instance.network_interfaces = [network_interface] - - # Custom hostnames are not resolved by the automatically created records - # provided by Compute Engine internal DNS. - # You must manually configure the DNS record for your custom hostname. - instance.hostname = hostname - - # 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) - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) - print(f"Instance {instance_name} created.") - return instance - - -# [END compute_instances_create_custom_hostname] - - -# [START compute_instances_get_hostname] -def get_instance_hostname(project_id: str, zone: str, instance_name: str) -> str: - """ - Get the hostname set for given instance. - - 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 virtual machine you want to check. - - Returns: - The hostname of given instance. - """ - instance_client = compute_v1.InstancesClient() - instance = instance_client.get( - project=project_id, zone=zone, instance=instance_name - ) - return instance.hostname - - -# [END compute_instances_get_hostname] diff --git a/samples/snippets/sample_delete_protection.py b/samples/snippets/sample_delete_protection.py deleted file mode 100644 index 1894d3903..000000000 --- a/samples/snippets/sample_delete_protection.py +++ /dev/null @@ -1,147 +0,0 @@ -# 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. -# [START compute_delete_protection_create] -import sys - -# [END compute_delete_protection_create] - -# [START compute_delete_protection_get] -# [START compute_delete_protection_set] -# [START compute_delete_protection_create] -from google.cloud import compute_v1 - -# [END compute_delete_protection_create] -# [END compute_delete_protection_set] -# [END compute_delete_protection_get] - - -# [START compute_delete_protection_create] -def create_instance( - project_id: str, zone: str, instance_name: str, delete_protection: bool, -) -> 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 you want to use. For example: “us-west3-b” - instance_name: name of the new virtual machine. - 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() - - # Describe the size and source image of the boot disk to attach to the instance. - disk = compute_v1.AttachedDisk() - initialize_params = compute_v1.AttachedDiskInitializeParams() - initialize_params.source_image = ( - "projects/debian-cloud/global/images/family/debian-10" - ) - initialize_params.disk_size_gb = 10 - disk.initialize_params = initialize_params - disk.auto_delete = True - disk.boot = True - disk.type_ = "PERSISTENT" - - # Use the default VPC network. - network_interface = compute_v1.NetworkInterface() - network_interface.name = "default" - - # Collect information into the Instance object. - instance = compute_v1.Instance() - instance.name = instance_name - instance.disks = [disk] - instance.machine_type = f"zones/{zone}/machineTypes/e2-small" - instance.network_interfaces = [network_interface] - - # Set the delete protection bit - instance.deletion_protection = delete_protection - - # 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) - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - if operation.warnings: - print("Warning during creation:", operation.warnings, file=sys.stderr) - print(f"Instance {instance_name} created.") - return instance - - -# [END compute_delete_protection_create] - - -# [START compute_delete_protection_set] -def set_delete_protection( - project_id: str, zone: str, instance_name: str, delete_protection: bool -): - """ - Updates the delete protection setting of given instance. - - 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 virtual machine to update. - delete_protection: boolean value indicating if the virtual machine should be - protected against deletion or not. - """ - instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() - - request = compute_v1.SetDeletionProtectionInstanceRequest() - request.project = project_id - request.zone = zone - 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) - - -# [END compute_delete_protection_set] - - -# [START compute_delete_protection_get] -def get_delete_protection(project_id: str, zone: str, instance_name: str) -> bool: - """ - Returns the state of delete protection flag of given instance. - - 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 virtual machine to check. - Returns: - The state of the delete protection setting. - """ - instance_client = compute_v1.InstancesClient() - instance = instance_client.get( - project=project_id, zone=zone, instance=instance_name - ) - return instance.deletion_protection - - -# [END compute_delete_protection_get] diff --git a/samples/snippets/sample_preemptible.py b/samples/snippets/sample_preemptible.py deleted file mode 100644 index 3e1b2fc97..000000000 --- a/samples/snippets/sample_preemptible.py +++ /dev/null @@ -1,193 +0,0 @@ -# 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. -# [START compute_preemptible_history] -import datetime - -# [END compute_preemptible_history] -# [START compute_preemptible_create] -import sys - -# [END compute_preemptible_create] - -# [START compute_preemptible_history] -from typing import List, Tuple - -# [END compute_preemptible_history] - -# [START compute_preemptible_create] -# [START compute_preemptible_check] -# [START compute_preemptible_history] -from google.cloud import compute_v1 - -# [END compute_preemptible_history] -# [END compute_preemptible_check] -# [END compute_preemptible_create] - -# [START compute_preemptible_history] -from google.cloud.compute_v1.services.zone_operations import pagers - -# [END compute_preemptible_history] - - -# [START compute_preemptible_create] -def create_preemptible_instance( - project_id: str, zone: str, instance_name: str, -) -> 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 you want to use. For example: "us-west3-b" - instance_name: name of the new virtual machine. - Returns: - Instance object. - """ - instance_client = compute_v1.InstancesClient() - operation_client = compute_v1.ZoneOperationsClient() - - # Describe the size and source image of the boot disk to attach to the instance. - disk = compute_v1.AttachedDisk() - initialize_params = compute_v1.AttachedDiskInitializeParams() - initialize_params.source_image = ( - "projects/debian-cloud/global/images/family/debian-10" - ) - initialize_params.disk_size_gb = 10 - disk.initialize_params = initialize_params - disk.auto_delete = True - disk.boot = True - disk.type_ = "PERSISTENT" - - # Use the default VPC network. - network_interface = compute_v1.NetworkInterface() - network_interface.name = "default" - - # Collect information into the Instance object. - instance = compute_v1.Instance() - instance.name = instance_name - instance.disks = [disk] - instance.machine_type = f"zones/{zone}/machineTypes/e2-small" - instance.network_interfaces = [network_interface] - - # Set the preemptible setting - instance.scheduling = compute_v1.Scheduling() - instance.scheduling.preemptible = 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) - while operation.status != compute_v1.Operation.Status.DONE: - operation = operation_client.wait( - operation=operation.name, zone=zone, project=project_id - ) - if operation.error: - print("Error during creation:", operation.error, file=sys.stderr) - 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) - - -# [END compute_preemptible_create] - - -# [START compute_preemptible_check] -def is_preemptible(project_id: str, zone: str, instance_name: str) -> bool: - """ - Check if a given instance is preemptible or not. - - 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 virtual machine to check. - Returns: - The preemptible status of the instance. - """ - instance_client = compute_v1.InstancesClient() - instance = instance_client.get( - project=project_id, zone=zone, instance=instance_name - ) - return instance.scheduling.preemptible - - -# [END compute_preemptible_check] - - -# [START compute_preemptible_history] -def list_zone_operations( - project_id: str, zone: str, filter: str = "" -) -> pagers.ListPager: - """ - List all recent operations the happened in given zone in a project. Optionally filter those - operations by providing a filter. More about using the filter can be found here: - https://cloud.google.com/compute/docs/reference/rest/v1/zoneOperations/list - - 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 virtual machine to look for. - Returns: - List of preemption operations in given zone. - """ - operation_client = compute_v1.ZoneOperationsClient() - request = compute_v1.ListZoneOperationsRequest() - request.project = project_id - request.zone = zone - request.filter = filter - - return operation_client.list(request) - - -def preemption_history( - project_id: str, zone: str, instance_name: str = None -) -> List[Tuple[str, datetime.datetime]]: - """ - Get a list of preemption operations from given zone in a project. Optionally limit - the results to instance name. - - 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 virtual machine to look for. - Returns: - List of preemption operations in given zone. - """ - if instance_name: - filter = ( - f'operationType="compute.instances.preempted" ' - f"AND targetLink:instances/{instance_name}" - ) - else: - filter = 'operationType="compute.instances.preempted"' - - history = [] - - for operation in list_zone_operations(project_id, zone, filter): - this_instance_name = operation.target_link.rsplit("/", maxsplit=1)[1] - if instance_name and this_instance_name == instance_name: - # The filter used is not 100% accurate, it's `contains` not `equals` - # So we need to check the name to make sure it's the one we want. - moment = datetime.datetime.fromisoformat(operation.insert_time) - history.append((instance_name, moment)) - - return history - - -# [END compute_preemptible_history] diff --git a/samples/snippets/sample_start_stop.py b/samples/snippets/sample_start_stop.py deleted file mode 100644 index 36fe54b99..000000000 --- a/samples/snippets/sample_start_stop.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2021 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. - -""" -A sample script showing how to start and stop Google Compute Engine instances. -""" - -# [START compute_start_instance] -# [START compute_start_enc_instance] -# [START compute_stop_instance] -# [START compute_reset_instance] -from google.cloud import compute_v1 - -# [END compute_reset_instance] -# [END compute_stop_instance] -# [END compute_start_enc_instance] -# [END compute_start_instance] - - -# [START compute_start_instance] -def start_instance(project_id: str, zone: str, instance_name: str): - """ - Starts a stopped Google Compute Engine instance (with unencrypted disks). - - Args: - project_id: project ID or project number of the Cloud project your instance belongs to. - zone: name of the zone your instance belongs to. - instance_name: name of the instance you want to start. - """ - instance_client = compute_v1.InstancesClient() - op_client = compute_v1.ZoneOperationsClient() - - op = instance_client.start_unary( - project=project_id, zone=zone, instance=instance_name - ) - - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - return - - -# [END compute_start_instance] - - -# [START compute_start_enc_instance] -def start_instance_with_encryption_key( - project_id: str, zone: str, instance_name: str, key: bytes -): - """ - Starts a stopped Google Compute Engine instance (with encrypted disks). - - Args: - project_id: project ID or project number of the Cloud project your instance belongs to. - zone: name of the zone your instance belongs to. - instance_name: name of the instance your want to start. - key: bytes object representing a raw base64 encoded key to your machines boot disk. - For more information about disk encryption see: - 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 - ) - - # Prepare the information about disk encryption - disk_data = compute_v1.CustomerEncryptionKeyProtectedDisk() - disk_data.source = instance_data.disks[0].source - disk_data.disk_encryption_key = compute_v1.CustomerEncryptionKey() - # Use raw_key to send over the key to unlock the disk - # To use a key stored in KMS, you need to provide `kms_key_name` and `kms_key_service_account` - disk_data.disk_encryption_key.raw_key = key - enc_data = compute_v1.InstancesStartWithEncryptionKeyRequest() - enc_data.disks = [disk_data] - - op = instance_client.start_with_encryption_key_unary( - project=project_id, - zone=zone, - instance=instance_name, - instances_start_with_encryption_key_request_resource=enc_data, - ) - - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - return - - -# [END compute_start_enc_instance] - - -# [START compute_stop_instance] -def stop_instance(project_id: str, zone: str, instance_name: str): - """ - Stops a running Google Compute Engine instance. - - Args: - project_id: project ID or project number of the Cloud project your instance belongs to. - zone: name of the zone your instance belongs to. - 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( - project=project_id, zone=zone, instance=instance_name - ) - - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - return - - -# [END compute_stop_instance] - - -# [START compute_reset_instance] -def reset_instance(project_id: str, zone: str, instance_name: str): - """ - Resets a running Google Compute Engine instance (with unencrypted disks). - - Args: - project_id: project ID or project number of the Cloud project your instance belongs to. - zone: name of the zone your instance belongs to. - 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( - project=project_id, zone=zone, instance=instance_name - ) - - while op.status != compute_v1.Operation.Status.DONE: - op = op_client.wait(operation=op.name, zone=zone, project=project_id) - return - - -# [END compute_reset_instance] diff --git a/samples/snippets/sample_templates.py b/samples/snippets/sample_templates.py deleted file mode 100644 index ddea06377..000000000 --- a/samples/snippets/sample_templates.py +++ /dev/null @@ -1,251 +0,0 @@ -# Copyright 2021 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. - -# [START compute_template_list ] -from typing import Iterable - -# [END compute_template_list ] - -# [START compute_template_create ] -# [START compute_template_list ] -# [START compute_template_get ] -# [START compute_template_create_from_instance ] -# [START compute_template_create_with_subnet ] -# [START compute_template_delete ] -from google.cloud import compute_v1 - -# [END compute_template_delete ] -# [END compute_template_create_with_subnet ] -# [END compute_template_create_from_instance ] -# [END compute_template_get ] -# [END compute_template_list ] -# [END compute_template_create ] - - -# [START compute_template_get ] -def get_instance_template( - project_id: str, template_name: str -) -> compute_v1.InstanceTemplate: - """ - Retrieve an instance template, which you can use to create virtual machine - (VM) instances and managed instance groups (MIGs). - - Args: - project_id: project ID or project number of the Cloud project you use. - template_name: name of the template to retrieve. - - Returns: - InstanceTemplate object that represents the retrieved template. - """ - template_client = compute_v1.InstanceTemplatesClient() - return template_client.get(project=project_id, instance_template=template_name) - - -# [END compute_template_get ] - - -# [START compute_template_list ] -def list_instance_templates(project_id: str) -> Iterable[compute_v1.InstanceTemplate]: - """ - Get a list of InstanceTemplate objects available in a project. - - Args: - project_id: project ID or project number of the Cloud project you use. - - Returns: - Iterable list of InstanceTemplate objects. - """ - template_client = compute_v1.InstanceTemplatesClient() - return template_client.list(project=project_id) - - -# [END compute_template_list ] - - -# [START compute_template_create ] -def create_template(project_id: str, template_name: str) -> compute_v1.InstanceTemplate: - """ - Create a new instance template with the provided name and a specific - instance configuration. - - Args: - project_id: project ID or project number of the Cloud project you use. - template_name: name of the new template to create. - - Returns: - InstanceTemplate object that represents the new instance template. - """ - # The template describes the size and source image of the boot disk - # to attach to the instance. - disk = compute_v1.AttachedDisk() - initialize_params = compute_v1.AttachedDiskInitializeParams() - initialize_params.source_image = ( - "projects/debian-cloud/global/images/family/debian-11" - ) - initialize_params.disk_size_gb = 250 - disk.initialize_params = initialize_params - disk.auto_delete = True - disk.boot = True - - # The template connects the instance to the `default` network, - # without specifying a subnetwork. - network_interface = compute_v1.NetworkInterface() - network_interface.name = "global/networks/default" - - # The template lets the instance use an external IP address. - access_config = compute_v1.AccessConfig() - access_config.name = "External NAT" - access_config.type_ = "ONE_TO_ONE_NAT" - access_config.network_tier = "PREMIUM" - network_interface.access_configs = [access_config] - - template = compute_v1.InstanceTemplate() - template.name = template_name - template.properties.disks = [disk] - template.properties.machine_type = "e2-standard-4" - template.properties.network_interfaces = [network_interface] - - template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.insert_unary( - project=project_id, instance_template_resource=template - ) - operation_client.wait(project=project_id, operation=op.name) - - return template_client.get(project=project_id, instance_template=template_name) - - -# [END compute_template_create ] - - -# [START compute_template_create_from_instance ] -def create_template_from_instance( - project_id: str, instance: str, template_name: str -) -> compute_v1.InstanceTemplate: - """ - Create a new instance template based on an existing instance. - This new template specifies a different boot disk. - - Args: - project_id: project ID or project number of the Cloud project you use. - instance: the instance to base the new template on. This value uses - the following format: "projects/{project}/zones/{zone}/instances/{instance_name}" - template_name: name of the new template to create. - - Returns: - InstanceTemplate object that represents the new instance template. - """ - disk = compute_v1.DiskInstantiationConfig() - # Device name must match the name of a disk attached to the instance you are - # basing your template on. - disk.device_name = "disk-1" - # Replace the original boot disk image used in your instance with a Rocky Linux image. - disk.instantiate_from = "CUSTOM_IMAGE" - disk.custom_image = "projects/rocky-linux-cloud/global/images/family/rocky-linux-8" - # Override the auto_delete setting. - disk.auto_delete = True - - template = compute_v1.InstanceTemplate() - template.name = template_name - template.source_instance = instance - template.source_instance_params = compute_v1.SourceInstanceParams() - template.source_instance_params.disk_configs = [disk] - - template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.insert_unary( - project=project_id, instance_template_resource=template - ) - operation_client.wait(project=project_id, operation=op.name) - - return template_client.get(project=project_id, instance_template=template_name) - - -# [END compute_template_create_from_instance ] - - -# [START compute_template_create_with_subnet ] -def create_template_with_subnet( - project_id: str, network: str, subnetwork: str, template_name: str -) -> compute_v1.InstanceTemplate: - """ - Create an instance template that uses a provided subnet. - - Args: - project_id: project ID or project number of the Cloud project you use. - network: the network to be used in the new template. This value uses - the following format: "projects/{project}/global/networks/{network}" - subnetwork: the subnetwork to be used in the new template. This value - uses the following format: "projects/{project}/regions/{region}/subnetworks/{subnetwork}" - template_name: name of the new template to create. - - Returns: - InstanceTemplate object that represents the new instance template. - """ - # The template describes the size and source image of the book disk to - # attach to the instance. - disk = compute_v1.AttachedDisk() - initialize_params = compute_v1.AttachedDiskInitializeParams() - initialize_params.source_image = ( - "projects/debian-cloud/global/images/family/debian-11" - ) - initialize_params.disk_size_gb = 250 - disk.initialize_params = initialize_params - disk.auto_delete = True - disk.boot = True - - template = compute_v1.InstanceTemplate() - template.name = template_name - template.properties = compute_v1.InstanceProperties() - template.properties.disks = [disk] - template.properties.machine_type = "e2-standard-4" - - # The template connects the instance to the specified network and subnetwork. - network_interface = compute_v1.NetworkInterface() - network_interface.network = network - network_interface.subnetwork = subnetwork - template.properties.network_interfaces = [network_interface] - - template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.insert_unary( - project=project_id, instance_template_resource=template - ) - operation_client.wait(project=project_id, operation=op.name) - - return template_client.get(project=project_id, instance_template=template_name) - - -# [END compute_template_create_with_subnet ] - - -# [START compute_template_delete ] -def delete_instance_template(project_id: str, template_name: str): - """ - Delete an instance template. - - Args: - project_id: project ID or project number of the Cloud project you use. - template_name: name of the template to delete. - """ - template_client = compute_v1.InstanceTemplatesClient() - operation_client = compute_v1.GlobalOperationsClient() - op = template_client.delete_unary( - project=project_id, instance_template=template_name - ) - operation_client.wait(project=project_id, operation=op.name) - return - - -# [END compute_template_delete ] diff --git a/samples/snippets/test_quickstart.py b/samples/snippets/test_quickstart.py deleted file mode 100644 index 705707656..000000000 --- a/samples/snippets/test_quickstart.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2021 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. - -import re -import typing -import uuid - -import google.auth - -from quickstart import main - -PROJECT = google.auth.default()[1] -INSTANCE_NAME = "i" + uuid.uuid4().hex[:10] -INSTANCE_ZONE = "europe-central2-b" - - -def test_main(capsys: typing.Any) -> None: - main(PROJECT, INSTANCE_ZONE, INSTANCE_NAME) - - out, _ = capsys.readouterr() - - assert f"Instance {INSTANCE_NAME} created." in out - assert re.search(f"Instances found in {INSTANCE_ZONE}:.+{INSTANCE_NAME}", out) - assert re.search(f"zones/{INSTANCE_ZONE}:.+{INSTANCE_NAME}", out) - assert f"Instance {INSTANCE_NAME} deleted." in out diff --git a/samples/snippets/tests/__init__.py b/samples/snippets/tests/__init__.py new file mode 100644 index 000000000..4bbe0ffdb --- /dev/null +++ b/samples/snippets/tests/__init__.py @@ -0,0 +1,13 @@ +# 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. diff --git a/samples/snippets/test_sample_custom_hostname.py b/samples/snippets/tests/test_custom_hostnames.py similarity index 77% rename from samples/snippets/test_sample_custom_hostname.py rename to samples/snippets/tests/test_custom_hostnames.py index 80666c459..b8583db39 100644 --- a/samples/snippets/test_sample_custom_hostname.py +++ b/samples/snippets/tests/test_custom_hostnames.py @@ -17,9 +17,9 @@ import google.auth import pytest -from quickstart import delete_instance -from sample_custom_hostname import create_instance -from sample_custom_hostname import get_instance_hostname +from ..instances.custom_hostname.create import create_instance_custom_hostname +from ..instances.custom_hostname.get import get_hostname +from ..instances.delete import delete_instance PROJECT = google.auth.default()[1] INSTANCE_ZONE = "europe-north1-c" @@ -39,13 +39,13 @@ def random_hostname(): yield "instance.{}.hostname".format(random.randint(0, 2 ** 10)) -def test_delete_protection(autodelete_instance_name, random_hostname): - instance = create_instance( +def test_custom_hostname(autodelete_instance_name, random_hostname): + instance = create_instance_custom_hostname( PROJECT, INSTANCE_ZONE, autodelete_instance_name, random_hostname ) assert instance.name == autodelete_instance_name assert instance.hostname == random_hostname assert ( - get_instance_hostname(PROJECT, INSTANCE_ZONE, autodelete_instance_name) + get_hostname(PROJECT, INSTANCE_ZONE, autodelete_instance_name) == random_hostname ) diff --git a/samples/snippets/test_sample_delete_protection.py b/samples/snippets/tests/test_delete_protection.py similarity index 80% rename from samples/snippets/test_sample_delete_protection.py rename to samples/snippets/tests/test_delete_protection.py index ee57a3e22..643c9294d 100644 --- a/samples/snippets/test_sample_delete_protection.py +++ b/samples/snippets/tests/test_delete_protection.py @@ -16,10 +16,10 @@ import google.auth import pytest -from quickstart import delete_instance -from sample_delete_protection import create_instance -from sample_delete_protection import get_delete_protection -from sample_delete_protection import set_delete_protection +from ..instances.delete import delete_instance +from ..instances.delete_protection.create import create_protected_instance +from ..instances.delete_protection.get import get_delete_protection +from ..instances.delete_protection.set import set_delete_protection PROJECT = google.auth.default()[1] INSTANCE_ZONE = "europe-central2-a" @@ -38,7 +38,9 @@ def autodelete_instance_name(): def test_delete_protection(autodelete_instance_name): - instance = create_instance(PROJECT, INSTANCE_ZONE, autodelete_instance_name, True) + instance = create_protected_instance( + PROJECT, INSTANCE_ZONE, autodelete_instance_name + ) assert instance.name == autodelete_instance_name assert ( diff --git a/samples/snippets/test_sample_preemptible.py b/samples/snippets/tests/test_preemptible.py similarity index 85% rename from samples/snippets/test_sample_preemptible.py rename to samples/snippets/tests/test_preemptible.py index 047a721e3..06c509279 100644 --- a/samples/snippets/test_sample_preemptible.py +++ b/samples/snippets/tests/test_preemptible.py @@ -16,10 +16,10 @@ import google.auth import pytest -from quickstart import delete_instance -from sample_preemptible import create_preemptible_instance -from sample_preemptible import is_preemptible -from sample_preemptible import list_zone_operations +from ..instances.delete import delete_instance +from ..instances.preemptible.create_preemptible import create_preemptible_instance +from ..instances.preemptible.is_preemptible import is_preemptible +from ..instances.preemptible.preemption_history import list_zone_operations PROJECT = google.auth.default()[1] INSTANCE_ZONE = "europe-central2-c" diff --git a/samples/snippets/test_sample_create_vm.py b/samples/snippets/tests/test_sample_create_vm.py similarity index 72% rename from samples/snippets/test_sample_create_vm.py rename to samples/snippets/tests/test_sample_create_vm.py index 3e3189d90..b08617f6e 100644 --- a/samples/snippets/test_sample_create_vm.py +++ b/samples/snippets/tests/test_sample_create_vm.py @@ -1,32 +1,38 @@ -# Copyright 2021 Google LLC +# 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 +# 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 +# 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. +# 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. import uuid import google.auth from google.cloud import compute_v1 import pytest -from quickstart import delete_instance, wait_for_operation - -from sample_create_vm import ( +from ..instances.create_start_instance.create_from_custom_image import ( create_from_custom_image, +) +from ..instances.create_start_instance.create_from_public_image import ( create_from_public_image, - create_from_snapshot, +) +from ..instances.create_start_instance.create_from_snapshot import create_from_snapshot +from ..instances.create_start_instance.create_with_additional_disk import ( create_with_additional_disk, +) +from ..instances.create_start_instance.create_with_snapshotted_data_disk import ( create_with_snapshotted_data_disk, - create_with_subnet, ) +from ..instances.create_with_subnet import create_with_subnet +from ..instances.delete import delete_instance +from ..operations.operation_check import wait_for_operation PROJECT = google.auth.default()[1] REGION = "us-central1" @@ -39,8 +45,8 @@ def get_active_debian(): return image_client.get_from_family(project="debian-cloud", family="debian-11") -@pytest.fixture(scope="class") -def src_disk(request): +@pytest.fixture() +def src_disk(): disk_client = compute_v1.DisksClient() disk = compute_v1.Disk() @@ -53,7 +59,6 @@ def src_disk(request): wait_for_operation(op, PROJECT) try: disk = disk_client.get(project=PROJECT, zone=INSTANCE_ZONE, disk=disk.name) - request.cls.disk = disk yield disk finally: op = disk_client.delete_unary( @@ -62,8 +67,8 @@ def src_disk(request): wait_for_operation(op, PROJECT) -@pytest.fixture(scope="class") -def snapshot(request, src_disk): +@pytest.fixture() +def snapshot(src_disk): snapshot_client = compute_v1.SnapshotsClient() snapshot = compute_v1.Snapshot() snapshot.name = "test-snap-" + uuid.uuid4().hex[:10] @@ -76,10 +81,9 @@ def snapshot(request, src_disk): ) wait_for_operation(op, PROJECT) try: - request.cls.snapshot = snapshot_client.get( + snapshot = snapshot_client.get( project=PROJECT, snapshot=snapshot.name ) - snapshot = request.cls.snapshot yield snapshot finally: @@ -87,8 +91,8 @@ def snapshot(request, src_disk): wait_for_operation(op, PROJECT) -@pytest.fixture(scope="class") -def image(request, src_disk): +@pytest.fixture() +def image(src_disk): image_client = compute_v1.ImagesClient() image = compute_v1.Image() image.source_disk = src_disk.self_link @@ -98,45 +102,47 @@ def image(request, src_disk): wait_for_operation(op, PROJECT) try: image = image_client.get(project=PROJECT, image=image.name) - request.cls.image = image yield image finally: op = image_client.delete_unary(project=PROJECT, image=image.name) wait_for_operation(op, PROJECT) -@pytest.mark.usefixtures("image", "snapshot") class TestCreation: - def test_create_from_custom_image(self): + 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, self.image.self_link + PROJECT, INSTANCE_ZONE, instance_name, image.self_link ) try: assert ( - instance.disks[0].initialize_params.source_image == self.image.self_link + 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,) + instance = create_from_public_image( + PROJECT, + INSTANCE_ZONE, + instance_name, + ) 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): + def test_create_from_snapshot(self, snapshot): instance_name = "i" + uuid.uuid4().hex[:10] instance = create_from_snapshot( - PROJECT, INSTANCE_ZONE, instance_name, self.snapshot.self_link + PROJECT, INSTANCE_ZONE, instance_name, snapshot.self_link ) try: assert ( instance.disks[0].initialize_params.source_snapshot - == self.snapshot.self_link + == snapshot.self_link ) finally: delete_instance(PROJECT, INSTANCE_ZONE, instance_name) @@ -155,10 +161,10 @@ def test_create_with_additional_disk(self): finally: delete_instance(PROJECT, INSTANCE_ZONE, instance_name) - def test_create_with_snapshotted_data_disk(self): + 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, self.snapshot.self_link + PROJECT, INSTANCE_ZONE, instance_name, snapshot.self_link ) try: assert any( diff --git a/samples/snippets/test_sample_custom_types.py b/samples/snippets/tests/test_sample_custom_types.py similarity index 84% rename from samples/snippets/test_sample_custom_types.py rename to samples/snippets/tests/test_sample_custom_types.py index 812b04b50..4b7c8108c 100644 --- a/samples/snippets/test_sample_custom_types.py +++ b/samples/snippets/tests/test_sample_custom_types.py @@ -16,13 +16,18 @@ import google.auth import pytest -from quickstart import create_instance, delete_instance -from sample_custom_types import ( - add_extended_memory_to_instance, - create_custom_instance, +from ..images.get import get_image_from_family +from ..instances.create import create_instance +from ..instances.create_start_instance.create_from_public_image import disk_from_image +from ..instances.custom_machine_types.create_shared_with_helper import ( create_custom_shared_core_instance, - CustomMachineType, ) +from ..instances.custom_machine_types.create_with_helper import create_custom_instance +from ..instances.custom_machine_types.helper_class import CustomMachineType +from ..instances.custom_machine_types.update_memory import ( + add_extended_memory_to_instance, +) +from ..instances.delete import delete_instance PROJECT = google.auth.default()[1] REGION = "us-central1" @@ -39,14 +44,22 @@ def auto_delete_instance_name(): @pytest.fixture def instance(): instance_name = "test-instance-" + uuid.uuid4().hex[:10] + + newest_debian = get_image_from_family(project="debian-cloud", family="debian-10") + disk_type = f"zones/{INSTANCE_ZONE}/diskTypes/pd-standard" + disks = [disk_from_image(disk_type, 10, True, newest_debian.self_link)] + instance = create_instance( - PROJECT, INSTANCE_ZONE, instance_name, "n2-custom-8-10240" + PROJECT, INSTANCE_ZONE, instance_name, disks, "n2-custom-8-10240" ) yield instance delete_instance(PROJECT, INSTANCE_ZONE, instance_name) def test_custom_instance_creation(auto_delete_instance_name): + # Need to import CustomMachineType from this module, or the assertion will fail + from ..instances.custom_machine_types.create_with_helper import CustomMachineType + instance = create_custom_instance( PROJECT, INSTANCE_ZONE, @@ -63,6 +76,11 @@ def test_custom_instance_creation(auto_delete_instance_name): def test_custom_shared_instance_creation(auto_delete_instance_name): + # Need to import CustomMachineType from this module, or the assertion will fail + from ..instances.custom_machine_types.create_shared_with_helper import ( + CustomMachineType, + ) + instance = create_custom_shared_core_instance( PROJECT, INSTANCE_ZONE, diff --git a/samples/snippets/test_sample_default_values.py b/samples/snippets/tests/test_sample_default_values.py similarity index 93% rename from samples/snippets/test_sample_default_values.py rename to samples/snippets/tests/test_sample_default_values.py index 23182e077..f609b3dd5 100644 --- a/samples/snippets/test_sample_default_values.py +++ b/samples/snippets/tests/test_sample_default_values.py @@ -20,11 +20,9 @@ import google.cloud.storage as storage import pytest -from sample_default_values import ( - disable_usage_export, - get_usage_export_bucket, - set_usage_export_bucket, -) +from ..usage_report.usage_reports import disable_usage_export +from ..usage_report.usage_reports import get_usage_export_bucket +from ..usage_report.usage_reports import set_usage_export_bucket PROJECT = google.auth.default()[1] BUCKET_NAME = "test" + uuid.uuid4().hex[:10] diff --git a/samples/snippets/test_sample_firewall.py b/samples/snippets/tests/test_sample_firewall.py similarity index 94% rename from samples/snippets/test_sample_firewall.py rename to samples/snippets/tests/test_sample_firewall.py index 517174395..86f978675 100644 --- a/samples/snippets/test_sample_firewall.py +++ b/samples/snippets/tests/test_sample_firewall.py @@ -19,13 +19,10 @@ from google.cloud import compute_v1 import pytest - -from sample_firewall import ( - create_firewall_rule, - delete_firewall_rule, - get_firewall_rule, - patch_firewall_priority, -) +from ..firewall.create import create_firewall_rule +from ..firewall.delete import delete_firewall_rule +from ..firewall.main import get_firewall_rule +from ..firewall.patch import patch_firewall_priority PROJECT = google.auth.default()[1] diff --git a/samples/snippets/test_sample_images.py b/samples/snippets/tests/test_sample_images.py similarity index 93% rename from samples/snippets/test_sample_images.py rename to samples/snippets/tests/test_sample_images.py index 23346c1f8..18852ac09 100644 --- a/samples/snippets/test_sample_images.py +++ b/samples/snippets/tests/test_sample_images.py @@ -12,7 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -from sample_images import get_image, list_images +from ..images.get import get_image +from ..images.list import list_images def test_list_images(): diff --git a/samples/snippets/test_sample_instance_from_template.py b/samples/snippets/tests/test_sample_instance_from_template.py similarity index 94% rename from samples/snippets/test_sample_instance_from_template.py rename to samples/snippets/tests/test_sample_instance_from_template.py index c6a2f0f62..e32208258 100644 --- a/samples/snippets/test_sample_instance_from_template.py +++ b/samples/snippets/tests/test_sample_instance_from_template.py @@ -17,13 +17,14 @@ from google.cloud import compute_v1 import pytest -from quickstart import delete_instance -from sample_instance_from_template import ( +from ..instances.delete import delete_instance +from ..instances.from_instance_template.create_from_template import ( create_instance_from_template, +) +from ..instances.from_instance_template.create_from_template_with_overrides import ( create_instance_from_template_with_overrides, ) - PROJECT = google.auth.default()[1] INSTANCE_ZONE = "europe-north1-c" diff --git a/samples/snippets/test_sample_pagination.py b/samples/snippets/tests/test_sample_pagination.py similarity index 66% rename from samples/snippets/test_sample_pagination.py rename to samples/snippets/tests/test_sample_pagination.py index 77672ba50..41e06703d 100644 --- a/samples/snippets/test_sample_pagination.py +++ b/samples/snippets/tests/test_sample_pagination.py @@ -11,20 +11,17 @@ # 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. -import typing - -from sample_pagination import print_images_list, print_images_list_by_page +from ..images.pagination import print_images_list +from ..images.pagination import print_images_list_by_page PROJECT = "windows-sql-cloud" -def test_pagination(capsys: typing.Any) -> None: - print_images_list(PROJECT) - out, _ = capsys.readouterr() +def test_pagination() -> None: + out = print_images_list(PROJECT) assert len(out.splitlines()) > 2 -def test_pagination_page(capsys: typing.Any) -> None: - print_images_list_by_page(PROJECT, 2) - out, _ = capsys.readouterr() +def test_pagination_page() -> None: + out = print_images_list_by_page(PROJECT, 2) assert "Page 2" in out diff --git a/samples/snippets/test_sample_start_stop.py b/samples/snippets/tests/test_sample_start_stop.py similarity index 97% rename from samples/snippets/test_sample_start_stop.py rename to samples/snippets/tests/test_sample_start_stop.py index bcf249f22..737400f8a 100644 --- a/samples/snippets/test_sample_start_stop.py +++ b/samples/snippets/tests/test_sample_start_stop.py @@ -19,14 +19,11 @@ import google.auth from google.cloud import compute_v1 - import pytest -from sample_start_stop import ( - start_instance, - start_instance_with_encryption_key, - stop_instance, -) +from ..instances.start import start_instance +from ..instances.start_encrypted import start_instance_with_encryption_key +from ..instances.stop import stop_instance PROJECT = google.auth.default()[1] diff --git a/samples/snippets/test_sample_templates.py b/samples/snippets/tests/test_sample_templates.py similarity index 88% rename from samples/snippets/test_sample_templates.py rename to samples/snippets/tests/test_sample_templates.py index 2c60aaafb..624a6f017 100644 --- a/samples/snippets/test_sample_templates.py +++ b/samples/snippets/tests/test_sample_templates.py @@ -17,17 +17,16 @@ import google.auth import pytest -from sample_templates import ( - create_template, - create_template_from_instance, - create_template_with_subnet, - delete_instance_template, - list_instance_templates, -) - # Turning off F401 check because flake8 doesn't recognize using # PyTest fixture as parameter as usage. -from test_sample_start_stop import compute_instance # noqa: F401 +from .test_sample_start_stop import compute_instance # noqa: F401 + +from ..instance_templates.create import create_template +from ..instance_templates.create_from_instance import \ + create_template_from_instance +from ..instance_templates.create_with_subnet import create_template_with_subnet +from ..instance_templates.delete import delete_instance_template +from ..instance_templates.list import list_instance_templates PROJECT = google.auth.default()[1] diff --git a/samples/snippets/usage_report/__init__.py b/samples/snippets/usage_report/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/samples/snippets/sample_default_values.py b/samples/snippets/usage_report/usage_reports.py similarity index 81% rename from samples/snippets/sample_default_values.py rename to samples/snippets/usage_report/usage_reports.py index 351487952..54af6034b 100644 --- a/samples/snippets/sample_default_values.py +++ b/samples/snippets/usage_report/usage_reports.py @@ -1,28 +1,34 @@ -#!/usr/bin/env python - -# Copyright 2021 Google LLC +# 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 +# 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 +# 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. +# 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 """ A sample script showing how to handle default values when communicating with the Compute Engine API. """ + +# 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_verify_default_value] # [START compute_usage_report_set] # [START compute_usage_report_get] # [START compute_usage_report_disable] from google.cloud import compute_v1 + # [END compute_usage_report_disable] # [END compute_usage_report_get] # [END compute_usage_report_set] @@ -44,9 +50,9 @@ def set_usage_export_bucket( report_name_prefix: Prefix of the usage report name which defaults to an empty string to showcase default values behaviour. """ - usage_export_location = compute_v1.UsageExportLocation( - bucket_name=bucket_name, report_name_prefix=report_name_prefix - ) + usage_export_location = compute_v1.UsageExportLocation() + usage_export_location.bucket_name = bucket_name + usage_export_location.report_name_prefix = report_name_prefix if not report_name_prefix: # Sending an empty value for report_name_prefix results in the @@ -70,7 +76,6 @@ def set_usage_export_bucket( # [END compute_usage_report_set] - # [START compute_usage_report_get] def get_usage_export_bucket(project_id: str) -> compute_v1.UsageExportLocation: """ diff --git a/samples/test_sgs.py b/samples/test_sgs.py index f1c1d71ae..dcc030a17 100644 --- a/samples/test_sgs.py +++ b/samples/test_sgs.py @@ -16,7 +16,7 @@ from pathlib import Path import tempfile -import sgs +from . import sgs FIXTURE_INGREDIENTS = Path("sgs_test_fixtures/ingredients") FIXTURE_RECIPES = Path("sgs_test_fixtures/recipes") @@ -26,7 +26,7 @@ def test_sgs_generate(): with tempfile.TemporaryDirectory() as tmp_dir: args = Namespace(output_dir=tmp_dir) - sgs.generate(args, FIXTURE_INGREDIENTS, FIXTURE_RECIPES) + sgs.generate(args, FIXTURE_INGREDIENTS.absolute(), FIXTURE_RECIPES.absolute()) for test_file in map(Path, glob.glob(f"{tmp_dir}/**")): match_file = FIXTURE_OUTPUT / test_file.relative_to(tmp_dir) assert test_file.read_bytes() == match_file.read_bytes()