chore: Moving GCE API samples from python-docs-samples (b/191786905) (#1429)
Co-authored-by: Anthonios Partheniou <partheniou@google.com>
diff --git a/samples/README.md b/samples/README.md
index d94e0cc..ca40e90 100644
--- a/samples/README.md
+++ b/samples/README.md
@@ -195,6 +195,18 @@
</tr>
</table>
+##  Cloud Compute Engine API
+
+Lets you manage the Google Compute Engine instances in your projects.
+
+<table>
+ <tr>
+ <td><a href="compute">samples/compute</a></td>
+ <td>Creates a Google Compute Engine instance to modify a samples image and upload the result
+ to a Cloud Storage bucket, then deletes the instance.</td>
+ </tr>
+</table>
+
##  Cloud Storage API
Lets you store and retrieve potentially-large, immutable data objects.
@@ -397,4 +409,3 @@
Getting Started with Google Tasks API</a></td>
</tr>
</table>
-
diff --git a/samples/compute/README.md b/samples/compute/README.md
new file mode 100644
index 0000000..769d5f2
--- /dev/null
+++ b/samples/compute/README.md
@@ -0,0 +1,199 @@
+# Using the Cloud Client Libraries for Python
+
+This document demonstrates how to use the Cloud Client Libraries for Python for Compute Engine.
+It describes how to authorize requests and how to create, list, and delete instances.
+This exercise discusses how to use the `google-api-python-client` library to access Compute Engine
+resources. You can run this sample from your local machine or on a VM instance, provided that
+you have authorized the sample correctly.
+
+For a full list of available client libraries, including other Google client libraries and
+third-party open source libraries, see the [client libraries page](https://cloud.google.com/compute/docs/api/libraries).
+
+To view the full code example with all of the necessary imports, see the [create_instance.py file](create_instance.py).
+
+## Objectives
+
+ * Perform OAuth 2.0 authorization using the `oauth2client` library
+ * Create, list and delete instances using the `google-api-python-client` library
+
+## Costs
+
+This tutorial uses billable components of Google Cloud including Compute Engine.
+
+## Before you begin
+
+1. In the Google Cloud Console, on the project selector page, select or create a Google Cloud project.
+ [Go to project selector](https://console.cloud.google.com/projectselector2/home/dashboard).
+1. Make sure that billing is enabled for your cloud project.
+ [Learn how to confirm that billing is enabled for your project.](https://cloud.google.com/billing/docs/how-to/modify-project)
+1. [Install Google Cloud SDK and `gcloud`](https://cloud.google.com/sdk)
+1. After the SDK is installed, run `gcloud auth application-default login`.
+1. Install the [google-api-python-client](http://github.com/googleapis/google-api-python-client) library. Typically, you can run:
+
+ ```bash
+ pip install --upgrade google-api-python-client
+ ```
+
+1. Enable the Cloud Storage API.
+ ```bash
+ gcloud services enable storage.googleapis.com
+ ```
+1. [Create a Cloud Storage bucket](https://cloud.google.com/storage/docs/creating-buckets) and note the bucket name for later.
+
+## Authorizing requests
+
+This sample uses OAuth 2.0 authorization. There are many ways to authorize requests using OAuth 2.0,
+but for the example use [application default credentials](https://developers.google.com/accounts/docs/application-default-credentials). This lets you reuse the credentials from
+the `gcloud` tool if you are running the sample on a local workstation or reuse credentials from a
+service account if you are running the sample from within Compute Engine or App Engine. You should
+have installed and authorized the `gcloud` tool in the "Before you begin" section.
+
+Application default credentials are provided in Google API Client Libraries automatically.
+You just have to build and initialize the API:
+
+```python
+import googleapiclient
+compute = googleapiclient.discovery.build('compute', 'v1')
+```
+
+See the `main()` method in the [create_instance.py](create_instance.py) script, to see how an API
+client is built and used.
+
+## Listing instances
+
+Using `google-api-python-client`, you can list instances by using the `compute.instances().list()` method.
+You need to provide the project ID and the zone for which you want to list instances. For example:
+
+```python
+def list_instances(compute, project, zone):
+ result = compute.instances().list(project=project, zone=zone).execute()
+ return result['items'] if 'items' in result else None
+```
+
+## Adding an instance
+
+To add an instance, use the `compute.instances().insert()` method and specify the properties of the new
+instance. These properties are specified in the request body; for details about each property see
+the [API reference for `instances.insert`](https://cloud.google.com/compute/docs/reference/latest/instances/insert).
+
+At a minimum, your request must provide values for the following properties when you create a new
+instance:
+
+* Instance name
+* Root persistent disk
+* Machine type
+* Zone
+* Network Interfaces
+
+This sample starts an instance with the following properties in a zone of your choice:
+
+* Machine type: e2-standard-2
+* Root persistent disk: a new persistent disk based on the latest Debian 8 image
+* The Compute Engine default service account with the following scopes:
+ * https://www.googleapis.com/auth/devstorage.read_write, so the instance can read and write files in Cloud Storage
+ * https://www.googleapis.com/auth/logging.write, so the instances logs can upload to Cloud Logging
+* Metadata to specify commands that the instance should execute upon startup
+
+You can see an example of instance creation in the `create_instance` method in [create_instance.py](create_instance.py) file.
+
+### Root persistent disks
+
+All instances must boot from a [root persistent disk](https://cloud.google.com/compute/docs/disks/create-root-persistent-disks).
+The root persistent disk contains all of the necessary files required for starting an instance.
+When you create a root persistent disk you must select a public image or a custom image to apply to
+the disk. In the example above, a new root persistent disk is created based on Debian 8 at the same
+time as the instance. However, it is also possible to create a disk beforehand and attach it to the
+instance.
+
+To create an instance using your own custom OS image, you need to provide a different URL than
+the one included in the example. For more information about starting an instance with your own
+images, see [Creating an instance from a custom image](https://cloud.google.com/compute/docs/instances/create-start-instance#creating_an_instance_from_a_custom_image).
+
+
+
+### Instance metadata
+
+When you create your instance, you might want to include instance metadata such as a [startup script](https://cloud.google.com/compute/docs/startupscript),
+configuration variables, and SSH keys. In the example above, you used the `metadata` field in your
+request body to specify a startup script for the instance and some configuration variables as
+key/values pairs. The [startup-script.sh](startup-script.sh) shows how to read these variables and use them
+to apply text to an image and upload it to [Cloud Storage](https://cloud.google.com/storage).
+
+## Deleting an Instance
+
+To delete an instance, you need to call the `compute.instances().delete()` method and provide the name,
+zone, and project ID of the instance to delete. When the `autoDelete` parameter is set to `true` for the
+boot disk it is also deleted with the instance. This setting is off by default but is
+useful when your use case calls for disks and instances to be deleted together.
+
+```python
+def delete_instance(compute, project, zone, name):
+ return compute.instances().delete(
+ project=project,
+ zone=zone,
+ instance=name).execute()
+```
+
+## Running the sample
+
+You can run the full sample by downloading the code and running it on the command line. Make sure
+to download the `create_instance.py` file and the `startup-script.sh` file. To run the sample:
+
+```bash
+python create_instance.py --name [INSTANCE_NAME] --zone [ZONE] [PROJECT_ID] [CLOUD_STORAGE_BUCKET]
+```
+
+where:
+
+* `[INSTANCE_NAME]` is the name of the instance to create.
+* `[ZONE]` is the desired zone for this request.
+* `[PROJECT_ID]` is our project ID.
+* `[CLOUD_STORAGE_BUCKET]` is the name of the bucket you initially set up but without the `gs://` prefix.
+
+For example:
+
+```bash
+python python-example.py --name example-instance --zone us-central1-a example-project my-gcs-bucket
+```
+
+## Waiting for operations to complete
+
+Requests to the Compute Engine API that modify resources such as instances immediately return a
+response acknowledging your request. The acknowledgement lets you check the status of the requested
+operation. Operations can take a few minutes to complete, so it's often easier to wait for the
+operation to complete before continuing. This helper method waits until the operation completes
+before returning:
+
+```python
+def wait_for_operation(compute, project, zone, operation):
+ print('Waiting for operation to finish...')
+ while True:
+ result = compute.zoneOperations().get(
+ project=project,
+ zone=zone,
+ operation=operation).execute()
+
+ if result['status'] == 'DONE':
+ print("done.")
+ if 'error' in result:
+ raise Exception(result['error'])
+ return result
+
+ time.sleep(1)
+```
+
+When you query per-zone operations, use the `compute.zoneOperations.get()` method. When you query global
+operations, use the `compute.globalOperations.get()` method. For more information, see zone resources.
+
+## Cleaning up
+
+To avoid incurring charges to your Google Cloud account for the resources used in this tutorial,
+either delete the project that contains the resources, or keep the project and delete the
+individual resources.
+
+### Delete your Cloud Storage bucket
+
+To delete a Cloud Storage bucket:
+1. In the Cloud Console, go to the Cloud Storage [Browser page](https://console.cloud.google.com/storage/browser).
+1. Click the checkbox for the bucket that you want to delete.
+1. To delete the bucket, click `Delete`, and then follow the instructions.
diff --git a/samples/compute/create_instance.py b/samples/compute/create_instance.py
new file mode 100644
index 0000000..3ccffc5
--- /dev/null
+++ b/samples/compute/create_instance.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+
+# Copyright 2015 Google Inc. All Rights Reserved.
+#
+# 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.
+
+"""Example of using the Compute Engine API to create and delete instances.
+
+Creates a new compute engine instance and uses it to apply a caption to
+an image.
+
+For more information, see the README.md under samples/compute.
+"""
+
+import argparse
+import os
+import time
+
+import googleapiclient.discovery
+from six.moves import input
+
+
+# [START compute_apiary_list_instances]
+def list_instances(compute, project, zone):
+ result = compute.instances().list(project=project, zone=zone).execute()
+ return result['items'] if 'items' in result else None
+# [END compute_apiary_list_instances]
+
+
+# [START compute_apiary_create_instance]
+def create_instance(compute, project, zone, name, bucket):
+ # Get the latest Debian Jessie image.
+ image_response = compute.images().getFromFamily(
+ project='debian-cloud', family='debian-9').execute()
+ source_disk_image = image_response['selfLink']
+
+ # Configure the machine
+ machine_type = "zones/%s/machineTypes/n1-standard-1" % zone
+ startup_script = open(
+ os.path.join(
+ os.path.dirname(__file__), 'startup-script.sh'), 'r').read()
+ image_url = "http://storage.googleapis.com/gce-demo-input/photo.jpg"
+ image_caption = "Ready for dessert?"
+
+ config = {
+ 'name': name,
+ 'machineType': machine_type,
+
+ # Specify the boot disk and the image to use as a source.
+ 'disks': [
+ {
+ 'boot': True,
+ 'autoDelete': True,
+ 'initializeParams': {
+ 'sourceImage': source_disk_image,
+ }
+ }
+ ],
+
+ # Specify a network interface with NAT to access the public
+ # internet.
+ 'networkInterfaces': [{
+ 'network': 'global/networks/default',
+ 'accessConfigs': [
+ {'type': 'ONE_TO_ONE_NAT', 'name': 'External NAT'}
+ ]
+ }],
+
+ # Allow the instance to access cloud storage and logging.
+ 'serviceAccounts': [{
+ 'email': 'default',
+ 'scopes': [
+ 'https://www.googleapis.com/auth/devstorage.read_write',
+ 'https://www.googleapis.com/auth/logging.write'
+ ]
+ }],
+
+ # Metadata is readable from the instance and allows you to
+ # pass configuration from deployment scripts to instances.
+ 'metadata': {
+ 'items': [{
+ # Startup script is automatically executed by the
+ # instance upon startup.
+ 'key': 'startup-script',
+ 'value': startup_script
+ }, {
+ 'key': 'url',
+ 'value': image_url
+ }, {
+ 'key': 'text',
+ 'value': image_caption
+ }, {
+ 'key': 'bucket',
+ 'value': bucket
+ }]
+ }
+ }
+
+ return compute.instances().insert(
+ project=project,
+ zone=zone,
+ body=config).execute()
+# [END compute_apiary_create_instance]
+
+
+# [START compute_apiary_delete_instance]
+def delete_instance(compute, project, zone, name):
+ return compute.instances().delete(
+ project=project,
+ zone=zone,
+ instance=name).execute()
+# [END compute_apiary_delete_instance]
+
+
+# [START compute_apiary_wait_for_operation]
+def wait_for_operation(compute, project, zone, operation):
+ print('Waiting for operation to finish...')
+ while True:
+ result = compute.zoneOperations().get(
+ project=project,
+ zone=zone,
+ operation=operation).execute()
+
+ if result['status'] == 'DONE':
+ print("done.")
+ if 'error' in result:
+ raise Exception(result['error'])
+ return result
+
+ time.sleep(1)
+# [END compute_apiary_wait_for_operation]
+
+
+# [START compute_apiary_run]
+def main(project, bucket, zone, instance_name, wait=True):
+ compute = googleapiclient.discovery.build('compute', 'v1')
+
+ print('Creating instance.')
+
+ operation = create_instance(compute, project, zone, instance_name, bucket)
+ wait_for_operation(compute, project, zone, operation['name'])
+
+ instances = list_instances(compute, project, zone)
+
+ print('Instances in project %s and zone %s:' % (project, zone))
+ for instance in instances:
+ print(' - ' + instance['name'])
+
+ print("""
+Instance created.
+It will take a minute or two for the instance to complete work.
+Check this URL: http://storage.googleapis.com/{}/output.png
+Once the image is uploaded press enter to delete the instance.
+""".format(bucket))
+
+ if wait:
+ input()
+
+ print('Deleting instance.')
+
+ operation = delete_instance(compute, project, zone, instance_name)
+ wait_for_operation(compute, project, zone, operation['name'])
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+ parser.add_argument('project_id', help='Your Google Cloud project ID.')
+ parser.add_argument(
+ 'bucket_name', help='Your Google Cloud Storage bucket name.')
+ parser.add_argument(
+ '--zone',
+ default='us-central1-f',
+ help='Compute Engine zone to deploy to.')
+ parser.add_argument(
+ '--name', default='demo-instance', help='New instance name.')
+
+ args = parser.parse_args()
+
+ main(args.project_id, args.bucket_name, args.zone, args.name)
+# [END compute_apiary_run]
diff --git a/samples/compute/create_instance_test.py b/samples/compute/create_instance_test.py
new file mode 100644
index 0000000..5888978
--- /dev/null
+++ b/samples/compute/create_instance_test.py
@@ -0,0 +1,40 @@
+# Copyright 2015, Google, Inc.
+# 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 os
+import uuid
+
+import pytest
+
+from create_instance import main
+
+PROJECT = os.environ['GOOGLE_CLOUD_PROJECT']
+BUCKET = os.environ['CLOUD_STORAGE_BUCKET']
+
+
+@pytest.mark.flaky(max_runs=3, min_passes=1)
+def test_main(capsys):
+ instance_name = 'test-instance-{}'.format(uuid.uuid4())
+ main(
+ PROJECT,
+ BUCKET,
+ 'us-central1-f',
+ instance_name,
+ wait=False)
+
+ out, _ = capsys.readouterr()
+
+ assert "Instances in project" in out
+ assert "zone us-central1-f" in out
+ assert instance_name in out
+ assert "Deleting instance" in out
diff --git a/samples/compute/requirements-test.txt b/samples/compute/requirements-test.txt
new file mode 100644
index 0000000..323e05a
--- /dev/null
+++ b/samples/compute/requirements-test.txt
@@ -0,0 +1,2 @@
+pytest==6.2.4
+flaky==3.7.0
diff --git a/samples/compute/requirements.txt b/samples/compute/requirements.txt
new file mode 100644
index 0000000..bd60e03
--- /dev/null
+++ b/samples/compute/requirements.txt
@@ -0,0 +1,3 @@
+google-api-python-client==2.11.0
+google-auth==1.31.0
+google-auth-httplib2==0.1.0
diff --git a/samples/compute/startup-script.sh b/samples/compute/startup-script.sh
new file mode 100644
index 0000000..5e59b2d
--- /dev/null
+++ b/samples/compute/startup-script.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# Copyright 2015 Google Inc. All Rights Reserved.
+#
+# 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_apiary_startup_script]
+apt-get update
+apt-get -y install imagemagick
+
+# Use the metadata server to get the configuration specified during
+# instance creation. Read more about metadata here:
+# https://cloud.google.com/compute/docs/metadata#querying
+IMAGE_URL=$(curl http://metadata/computeMetadata/v1/instance/attributes/url -H "Metadata-Flavor: Google")
+TEXT=$(curl http://metadata/computeMetadata/v1/instance/attributes/text -H "Metadata-Flavor: Google")
+CS_BUCKET=$(curl http://metadata/computeMetadata/v1/instance/attributes/bucket -H "Metadata-Flavor: Google")
+
+mkdir image-output
+cd image-output
+wget $IMAGE_URL
+convert * -pointsize 30 -fill white -stroke black -gravity center -annotate +10+40 "$TEXT" output.png
+
+# Create a Google Cloud Storage bucket.
+gsutil mb gs://$CS_BUCKET
+
+# Store the image in the Google Cloud Storage bucket and allow all users
+# to read it.
+gsutil cp -a public-read output.png gs://$CS_BUCKET/output.png
+
+# [END compute_apiary_startup_script]