pythongoogle-cloud-platformgoogle-cloud-functionsicloud-api

google cloud function Compute engine python api not shutting down instance on call to stop as expected


I am using a google cloud function with python 3.9 My intention is to trigger this cloud function from an http trigger to stop a compute engine instance. The code for my cloud function is as below (entry point stop_server )

# python 3.9 code for cloud function body 
from googleapiclient import discovery
def stop_server (request):
"""
Responds to HTTP Get request stops server specified inget param instancename=<name>
Returns status
"""
service = discovery.build('compute', 'v1')
# Project ID for this request.
project = 'my-gcp-project'
# The name of the zone for this request.
zone = 'us-east1-b'
# determine instance to stop from http params
if request.args and 'instancename' in request.args:
   instance = request.args.get('instancename')
   status = service.instances().stop(project=project, zone=zone, instance=instance)
   return f'instance: {instance} - stopped  --> status = {status}'
else: # no instance specified 
   return f'specify instance in get param ?instancename="name"'

The "requirements.txt" is as follows

# Function dependencies
# package>=version
google-api-core 
google-api-python-client

This code deploys fine in gcp and I can generate a "trigger url" as follows

https://us-east1-myproject.cloudfunctions.net/stop-specified-vm?instancename=name_of_instance

When I run the code through trigger URL - the code executes fine and returns the status message in http response as follows

instance: my-gcp-instance - stopped --> status =

However the specified instance does not stop as expected

So in order to debug I need to find the documentation for the stop instances.stop api - I examined type of "service object" in runtime by printing its type as follows

enter code here
 service = discovery.build('compute', 'v1')
 stype=(type(service))
 print(f'type of service = {stype}')

that shows in logs that service object is of type "googleapiclient.discovery.Resource' I suppose this is a base class object that holds an object of appropriate specific type based on what service argument you passed to build. So in my case case since the service is compute engine - what is this bound to when I call service = discovery.build('compute', 'v1')

Where can I find documentation for that api

Any other debugging tips ?

See response from John Hanley below - As he rightly pointed out I had missed calling execute() on the (request) object returned by call to service.instances().stop

So basically - I needed to understand the paradigm used here. The service.instances().stop returns an object that is a client for requested restful service (stop in this case) . And then I have to call "execute" to actually invoke that service :-)

posting full working code below again

# python 3.9 code for cloud function body 
from googleapiclient import discovery
def stop_server (request):
"""
Responds to HTTP Get request stops server specified inget param instancename=<name>
Returns status
"""
service = discovery.build('compute', 'v1')
# Project ID for this request.
project = 'my-gcp-project'
# The name of the zone for this request.
zone = 'us-east1-b'
# determine instance to stop from http params
if request.args and 'instancename' in request.args:
   instance = request.args.get('instancename')
   request= service.instances().stop(project=project, zone=zone, instance=instance)
   response = request.execute() # returning full dictionary object for caller to examine
   rstr=str(response)
   return f'instance: {instance} - stop requested  --> response = {rstr}'
else: # no instance specified 
   return f'specify instance in get param ?instancename="name"'

Solution

  • The API stop() returns an Operation resource and not a string. You must poll the operation resource to get the status of the stop operation. This includes success and failure.

    Note: Your code is not calling execute() after setting up the request.

    request = service.instances().stop(project=project, zone=zone, instance=instance)
    response = request.execute()
    

    Since you are writing new code, I recommend that you do not use your current Python library.

    Client libraries explained

    Instead switch to the current library that is still being developed.

    Python Client for Compute Engine

    Example for starting and stopping an instance