Please note that the contents of this offline web site may be out of date. To access the most recent documentation visit the online version .
Note that links that point to online resources are green in color and will open in a new window.
We would love it if you could give us feedback about this material by filling this form (You have to be online to fill it)



Using the Python Client Library

This document demonstrates how to use the Google Python Client Library for Google Compute Engine. It describes how to authorize requests and how to create, list, and stop instances. This exercise discusses how to use the google-api-python-client library to access Google Compute Engine from outside a VM instance. It does not discuss how to build and run applications within a VM instance.

For a full list of available client libraries, including other Google client libraries and third-party open source libraries, see the Client Libraries page .

Contents

Setup

Before you can try the examples in this exercise, you need to download and install the google-api-python-client library. This contains the core Python library for accessing Google APIs and also contains the OAuth 2.0 client library. For information on how to install this library, see the installation instructions . You also need to have Python 2.5, 2.6, or 2.7 to run the Google Python Client Library.

Getting Started

The purpose of this exercise is to describe how to use OAuth 2.0 authorization, and how to perform basic instance management tasks using the google-api-python-client library. At the end of this exercise, you should be able to:

  • Perform OAuth 2.0 authorization using the oauth2client library
  • Create an instance using the google-python-client library
  • List instances using the google-python-client library
  • Stop an instance using the google-python-client library

To skip the exercise and view the full code example, visit the google-cloud-platform-samples GitHub page.

Authorizing Requests

This sample uses OAuth 2.0 authorization. You will need to create a client ID and client secret, and use both with the oauth2client library. By default, the oauth2 library is included in the google-api-python-client library, which you should have downloaded in the Setup section.

To start, all applications are managed by the Google Developers Console . If you already have a registered application, you can use the client ID and secret from that application. If you don't have a registered application or would like to register a new application, follow the application registration process . Make sure to select Installed as the application type.

Once on the application page, expand the OAuth 2.0 Client ID section and click Download JSON . Save the file as client_secrets.json . The file should look similar to the following:

{
  "installed": {
    "client_id": "<your_client_id>",
    "client_secret":"<your_client_secret>",
    "redirect_uris": ["http://localhost", "urn:ietf:wg:oauth:2.0:oob"],
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://accounts.google.com/o/oauth2/token"
  }
}
Next, create a file called helloworld.py in the same directory as the client_secrets.json file and provide the following code:
#!/usr/bin/env python

import logging
import sys
import argparse
import httplib2
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client import tools
from oauth2client.tools import run_flow

CLIENT_SECRETS = 'client_secrets.json'
OAUTH2_STORAGE = 'oauth2.dat'
GCE_SCOPE = 'https://www.googleapis.com/auth/compute'

def main(argv):
  logging.basicConfig(level=logging.INFO)

  parser = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter,
    parents=[tools.argparser])

  # Parse the command-line flags.
  flags = parser.parse_args(argv[1:])

  # Perform OAuth 2.0 authorization.
  flow = flow_from_clientsecrets(CLIENT_SECRETS, scope=GCE_SCOPE)
  storage = Storage(OAUTH2_STORAGE)
  credentials = storage.get()

  if credentials is None or credentials.invalid:
    credentials = run_flow(flow, storage, flags)
  http = httplib2.Http()
  auth_http = credentials.authorize(http)

if __name__ == '__main__':
  main(sys.argv)

The above code uses the OAuth 2.0 scope specified ( https://www.googleapis.com/auth/compute ) and the client_secrets.json information to request a refresh and access token, which is then stored in the oauth2.dat file. Because the refresh token never expires, your application can reuse the refresh token to request new access tokens when necessary. This also eliminates further authorization events, unless the refresh token has been explicitly revoked.

If you run helloworld.py now on the command line, it should automatically open a browser window for you to authorize access.

Initializing the API

Before you can make requests, you first need to initialize an instance of the Google Compute Engine service. Add the following bold lines to your helloworld.py :

#!/usr/bin/env python

import logging
import sys
import argparse
import httplib2
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client import tools
from oauth2client.tools import run_flow

from apiclient.discovery import build

API_VERSION = 'v1'
GCE_URL = 'https://www.googleapis.com/compute/%s/projects/' % (API_VERSION)
PROJECT_ID = '<your_project_id>'
CLIENT_SECRETS = 'client_secrets.json'
OAUTH2_STORAGE = 'oauth2.dat'
GCE_SCOPE = 'https://www.googleapis.com/auth/compute'

def main(argv):
  logging.basicConfig(level=logging.INFO)

  parser = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter,
    parents=[tools.argparser])

  # Parse the command-line flags.
  flags = parser.parse_args(argv[1:])

  # Perform OAuth 2.0 authorization.
  flow = flow_from_clientsecrets(CLIENT_SECRETS, scope=GCE_SCOPE)
  storage = Storage(OAUTH2_STORAGE)
  credentials = storage.get()

  if credentials is None or credentials.invalid:
    credentials = run_flow(flow, storage, flags)
  http = httplib2.Http()
  auth_http = credentials.authorize(http)

  # Build the service
  gce_service = build('compute', API_VERSION)
  project_url = '%s%s' % (GCE_URL, PROJECT_ID)

if __name__ == '__main__':
  main(sys.argv)

Listing Instances

Next, to list your instances, call the instances().list method, providing the project ID, the zone for which you want to list instances, and any optional filters :

#!/usr/bin/env python

import logging
import sys
import argparse
import httplib2
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client import tools
from oauth2client.tools import run_flow

from apiclient.discovery import build

DEFAULT_ZONE = 'us-central1-a'
API_VERSION = 'v1'
GCE_URL = 'https://www.googleapis.com/compute/%s/projects/' % (API_VERSION)
PROJECT_ID = '<your_project_id>'
CLIENT_SECRETS = 'client_secrets.json'
OAUTH2_STORAGE = 'oauth2.dat'
GCE_SCOPE = 'https://www.googleapis.com/auth/compute'

def main(argv):
  logging.basicConfig(level=logging.INFO)

  parser = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter,
    parents=[tools.argparser])

  # Parse the command-line flags.
  flags = parser.parse_args(argv[1:])

  # Perform OAuth 2.0 authorization.
  flow = flow_from_clientsecrets(CLIENT_SECRETS, scope=GCE_SCOPE)
  storage = Storage(OAUTH2_STORAGE)
  credentials = storage.get()

  if credentials is None or credentials.invalid:
    credentials = run_flow(flow, storage, flags)
  http = httplib2.Http()
  auth_http = credentials.authorize(http)

  # Build the service
  gce_service = build('compute', API_VERSION)
  project_url = '%s%s' % (GCE_URL, PROJECT_ID)

  # List instances
  request = gce_service.instances().list(project=PROJECT_ID, filter=None, zone=DEFAULT_ZONE)
  response = request.execute(http=auth_http)
  if response and 'items' in response:
    instances = response['items']
    for instance in instances:
      print instance['name']
  else:
    print 'No instances to list.'

if __name__ == '__main__':
  main(sys.argv)

Run helloworld.py on the command line and you should see a list of instances for your specified project:

user@mymachine:~/gce_demo$ python helloworld.py
instance1
instance2
hello-world

Adding an Instance

To add an instance, use the instances().insert() method and provide appropriate request body with the JSON properties described at the API reference documentation. 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

For this example, you are going to start an instance with the following properties:

  • Zone: us-central1-a
  • Machine type: n1-standard-1
  • Root persistent disk: my-root-pd
  • The default service account with the following scopes:
    • https://www.googleapis.com/auth/devstorage.full_control
    • https://www.googleapis.com/auth/compute

Root persistent disks

All instances must boot from a root persistent disk . If you have an existing root persistent disk, you can use it for this part of the exercise. For the purposes of this guide, we're also going to demonstrate how to create a root persistent disk.

A root persistent disk contains all of the necessary files required for starting your instance. When you create a root persistent disk, you specify the name and the OS image that should be applied to the disk. You can also create a root persistent disk at the same time as your virtual machine instance, or you can create the root persistent disk separately and attach it to a new instance. For this example, you will create a Debian 7 root persistent disk as part of the instance creation request.

Add the following lines to helloworld.py :

#!/usr/bin/env python

import logging
import sys
import argparse
import httplib2
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client import tools
from oauth2client.tools import run_flow

from apiclient.discovery import build

# New instance properties
DEFAULT_MACHINE_TYPE = 'n1-standard-1'
DEFAULT_NETWORK = 'default'
DEFAULT_SERVICE_EMAIL = 'default'
DEFAULT_SCOPES = ['https://www.googleapis.com/auth/devstorage.full_control',
                  'https://www.googleapis.com/auth/compute']
NEW_INSTANCE_NAME = 'my-new-instance'

# New root persistent disk properties
DEFAULT_IMAGE = 'debian'
DEFAULT_IMAGES = {
    'debian': 'debian-7-wheezy-v20131120',
    'centos': 'centos-6-v20131120'
}
DEFAULT_ROOT_PD_NAME = 'my-root-pd'

DEFAULT_ZONE = 'us-central1-a'
API_VERSION = 'v1'
GCE_URL = 'https://www.googleapis.com/compute/%s/projects/' % (API_VERSION)
PROJECT_ID = '<your_project_id>'
CLIENT_SECRETS = 'client_secrets.json'
OAUTH2_STORAGE = 'oauth2.dat'
GCE_SCOPE = 'https://www.googleapis.com/auth/compute'

def main(argv):
  logging.basicConfig(level=logging.INFO)

  parser = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawDescriptionHelpFormatter,
    parents=[tools.argparser])

  # Parse the command-line flags.
  flags = parser.parse_args(argv[1:])

  # Perform OAuth 2.0 authorization.
  flow = flow_from_clientsecrets(CLIENT_SECRETS, scope=GCE_SCOPE)
  storage = Storage(OAUTH2_STORAGE)
  credentials = storage.get()

  if credentials is None or credentials.invalid:
    credentials = run_flow(flow, storage, flags)
  http = httplib2.Http()
  auth_http = credentials.authorize(http)

  # Build the service
  gce_service = build('compute', API_VERSION)
  project_url = '%s%s' % (GCE_URL, PROJECT_ID)

  # List instances
  request = gce_service.instances().list(project=PROJECT_ID, filter=None, zone=DEFAULT_ZONE)
  response = request.execute(http=auth_http)
  if response and 'items' in response:
    instances = response['items']
    for instance in instances:
      print instance['name']
  else:
    print 'No instances exist.'

  # Construct URLs
  image_url = '%s%s/global/images/%s' % (
         GCE_URL, 'debian-cloud', DEFAULT_IMAGES['debian'])
  machine_type_url = '%s/zones/%s/machineTypes/%s' % (
        project_url, DEFAULT_ZONE, DEFAULT_MACHINE_TYPE)
  network_url = '%s/global/networks/%s' % (project_url, DEFAULT_NETWORK)

  # Construct the request body
  instance = {
    'name': NEW_INSTANCE_NAME,
    'machineType': machine_type_url,
    'disks': [{
        'autoDelete': 'true',
        'boot': 'true',
        'type': 'PERSISTENT',
        'initializeParams' : {
          'diskName': DEFAULT_ROOT_PD_NAME,
          'sourceImage': image_url
        }
      }],
    'networkInterfaces': [{
      'accessConfigs': [{
        'type': 'ONE_TO_ONE_NAT',
        'name': 'External NAT'
       }],
      'network': network_url
    }],
    'serviceAccounts': [{
         'email': DEFAULT_SERVICE_EMAIL,
         'scopes': DEFAULT_SCOPES
    }]
  }

  # Create the instance
  request = gce_service.instances().insert(
       project=PROJECT_ID, body=instance, zone=DEFAULT_ZONE)
  response = request.execute(http=auth_http)
  response = _blocking_call(gce_service, auth_http, response)

  print response

def _blocking_call(gce_service, auth_http, response):
  """Blocks until the operation status is done for the given operation."""

  status = response['status']
  while status != 'DONE' and response:
    operation_id = response['name']

    # Identify if this is a per-zone resource
    if 'zone' in response:
      zone_name = response['zone'].split('/')[-1]
      request = gce_service.zoneOperations().get(
          project=PROJECT_ID,
          operation=operation_id,
          zone=zone_name)
    else:
      request = gce_service.globalOperations().get(
           project=PROJECT_ID, operation=operation_id)

    response = request.execute(http=auth_http)
    if response:
      status = response['status']
  return response

if __name__ == '__main__':
  main(sys.argv)

Notice that you construct the JSON for your instance here:

instance = {
    'name': NEW_INSTANCE_NAME,
    'machineType': machine_type_url,
    'disks': [{
        'autoDelete': 'true',
        'boot': 'true',
        'type': 'PERSISTENT',
        'initializeParams' : {
          'diskName': DEFAULT_ROOT_PD_NAME,
          'sourceImage': image_url
        }
      }],
    'networkInterfaces': [{
      'accessConfigs': [{
        'type': 'ONE_TO_ONE_NAT',
        'name': 'External NAT'
       }],
      'network': network_url
    }],
    'serviceAccounts': [{
         'email': DEFAULT_SERVICE_EMAIL,
         'scopes': DEFAULT_SCOPES
    }]

If you would rather not hand construct the JSON for your request, many Google Compute Engine tools can automatic generate the JSON for you. For example, the Google Developers Console , which allows you to configure and create resources for your Google Compute Engine project, also provides a handy REST Request feature that constructs the JSON for the request for you. For more information, see Using the Console to Generate REST Requests .

Blocking until the operation is complete

By default, when you send a request to Google Compute Engine API, you'll immediately receive a response describing the status of your operation as RUNNING . To check when the operation is finished, you need to periodically query the server for the operation status. To eliminate this extra step, we've included a helper method in the sample above that "blocks" and waits for the operation status to become DONE before it returns a response.

Notice when you query per-zone operations, you use the zoneOperations.get() method, while querying global operations requires using the globalOperations.get() method. For more information, see zone resources .


Run your helloworld.py file to create your new disk.

Adding Instance Metadata

When you create your instance, you may want to include instance metadata, such as a startup script URL, or sshKeys. To do so, include the metadata field with your request body:

instance = {
    'name': NEW_INSTANCE_NAME,
    'machineType': machine_type_url,
    'disks': [{
        'source': root_disk_url,
        'boot': 'true',
        'type': 'PERSISTENT',
      }],
    'networkInterfaces': [{
      'accessConfigs': [{
        'type': 'ONE_TO_ONE_NAT',
        'name': 'External NAT'
       }],
      'network': network_url
    }],
    'serviceAccounts': [{
         'email': DEFAULT_SERVICE_EMAIL,
         'scopes': DEFAULT_SCOPES
    }],
    'metadata': [{
         'items': [{
            'key': <key>,
            'value': <value>,
         .....
         }]
    }]
  }

For example, you can use the metadata field to specify a startup script with your instance. Create a new file named startup.sh and populate it with the following contents:

#!/bin/bash
apt-get -y install imagemagick
IMAGE_URL=$(curl http://metadata/computeMetadata/v1/instance/attributes/url -H "X-Google-Metadata-Request: True")
TEXT=$(curl http://metadata/computeMetadata/v1/instance/attributes/text -H "X-Google-Metadata-Request: True")
CS_BUCKET=$(curl http://metadata/computeMetadata/v1/instance/attributes/cs-bucket -H "X-Google-Metadata-Request: True")
mkdir image-output
cd image-output
wget $IMAGE_URL
convert * -pointsize 30 -fill black -annotate +10+40 $TEXT output.png
gsutil cp -a public-read output.png gs://$CS_BUCKET/output.png

This startup script installs the ImageMagick application, downloads an image from the Internet, adds some text on top, and copies it to Google Cloud Storage . To try it out, make the following changes to your helloworld.py file. If you do not have a Google Cloud Storage account, you can sign up for the service during the limited free trial, which ends December 31, 2012. After you have signed up for the service, create your bucket using the Google Cloud Storage manager .

  # Construct URLs
  machine_type_url = '%s/zones/%s/machine-types/%s' % (
        project_url, DEFAULT_ZONE, DEFAULT_MACHINE_TYPE)
  network_url = '%s/global/networks/%s' % (project_url, DEFAULT_NETWORK)
  image_url = '%s%s/global/images/%s' % (
         GCE_URL, 'debian-cloud', DEFAULT_IMAGES['debian'])

  my_image = '<url_of_image>' # Choose an image from the Internet and put its URL here
  cs_bucket = '<your_google_cloud_storage_bucket>' # Must already exist, e.g. 'samplebucket'
  startup_script = 'startup.sh'

  # Construct the request body
  instance = {
    'name': 'startup-script-demo',
    'machineType': machine_type_url,
    'disks': [{
        'autoDelete': 'true',
        'boot': 'true',
        'type': 'PERSISTENT',
        'initializeParams' : {
          'diskName': DEFAULT_ROOT_PD_NAME,
          'sourceImage': image_url
        }
      }],
    'networkInterfaces': [{
      'accessConfigs': [{
        'type': 'ONE_TO_ONE_NAT',
        'name': 'External NAT'
       }],
      'network': network_url
    }],
     'serviceAccounts': [{
         'email': DEFAULT_SERVICE_EMAIL,
         'scopes': DEFAULT_SCOPES
    }],
     'metadata': [{
         'items': [{
             'key': 'startup-script',
             'value': open(startup_script, 'r').read()
           }, {
             'key': 'url',
             'value': my_image
           }, {
             'key': 'text',
             'value': 'AWESOME'
           }, {
             'key': 'cs-bucket',
             'value': cs_bucket
          }]
    }]
  }

  request = gce_service.instances().insert(
       project=PROJECT_ID, body=instance, zone=DEFAULT_ZONE)
  response = request.execute(http=auth_http)
  response = _blocking_call(gce_service, auth_http, response)

  print response
  print '\n'
  print 'Visit http://storage.googleapis.com/%s/output.png' % (
      cs_bucket)
  print 'It might take a minute for the output.png file to show up.'

Try running helloworld.py , which creates a new instance named startup-script-demo, and viewing your image in the provided URL.

Deleting an Instance

To delete an instance, you need to call the instances().delete() method and provide the name, zone, and project ID of the instance to delete. Add the following lines to your helloworld.py to delete the instance. For the purposes of this example, the following code also deletes the associated root persistent disk:

  # Delete an instance and the associated root persistent disk
  request = gce_service.instances().delete(
       project=PROJECT_ID, instance=INSTANCE_TO_DELETE, zone=DEFAULT_ZONE)
  response = request.execute(http=auth_http)
  response = _blocking_call(gce_service, auth_http, response)

  print response

When you set the root persistent disk in initial request to autoDelete , it indicated to Google Compute Engine that the root persistent disk for this instance should also be deleted when the instance is deleted. This setting is off by default, but can be useful so you can delete instances and their root persistent disks in one step.

Next Steps

Now that you've completed this exercise, you can:

  • Download and view the full code sample . The full sample includes a simple wrapper for the instance management methods, and is generally more cleaner than our example here. Feel free to download it, change it, and run it to suit your needs.
  • Review the API reference to learn how to perform other tasks with the API.
  • Start creating your own applications!

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.