import logging
import apiauth
import webapp2
from google.appengine.api import app_identity
from google.appengine.api import taskqueue
ACTION_STATUS = 'status'
ACTION_START = 'start'
ACTION_RESTART = 'restart'
COMPUTE_STATUS = 'status'
COMPUTE_STATUS_TERMINATED = 'TERMINATED'
COMPUTE_STATUS_RUNNING = 'RUNNING'
START_TASK_MIN_WAIT_S = 3
COMPUTE_API_URL = 'https://www.googleapis.com/auth/compute'
def enqueue_start_task(instance, zone):
taskqueue.add(url='/compute/%s/%s/%s' % (ACTION_START, instance, zone),
countdown=START_TASK_MIN_WAIT_S)
def enqueue_restart_task(instance, zone):
taskqueue.add(url='/compute/%s/%s/%s' % (ACTION_RESTART, instance, zone),
countdown=START_TASK_MIN_WAIT_S)
class ComputePage(webapp2.RequestHandler):
def __init__(self, request, response):
self.initialize(request, response)
self.compute_service = self._build_compute_service()
if self.compute_service is None:
logging.warning('Unable to create Compute service object.')
def _build_compute_service(self):
return apiauth.build(scope=COMPUTE_API_URL,
service_name='compute',
version='v1')
def _maybe_restart_instance(self, instance, zone):
if self.compute_service is None:
logging.warning('Compute service unavailable.')
return
status = self._compute_status(instance, zone)
logging.info('GCE VM \'%s (%s)\' status: \'%s\'.',
instance, zone, status)
if status == COMPUTE_STATUS_RUNNING:
logging.info('Stopping GCE VM: %s (%s)', instance, zone)
self.compute_service.instances().stop(
project=app_identity.get_application_id(),
instance=instance,
zone=zone).execute()
enqueue_start_task(instance, zone)
def _maybe_start_instance(self, instance, zone):
if self.compute_service is None:
logging.warning('Unable to start Compute instance, service unavailable.')
return
status = self._compute_status(instance, zone)
logging.info('GCE VM \'%s (%s)\' status: \'%s\'.',
instance, zone, status)
if status == COMPUTE_STATUS_TERMINATED:
logging.info('Starting GCE VM: %s (%s)', instance, zone)
self.compute_service.instances().start(
project=app_identity.get_application_id(),
instance=instance,
zone=zone).execute()
if status != COMPUTE_STATUS_RUNNING:
enqueue_start_task(instance, zone)
def _compute_status(self, instance, zone):
if self.compute_service is None:
logging.warning('Service unavailable: unable to start GCE VM: %s (%s)',
instance, zone)
return
info = self.compute_service.instances().get(
project=app_identity.get_application_id(),
instance=instance,
zone=zone).execute()
return info[COMPUTE_STATUS]
def get(self, action, instance, zone):
if action == ACTION_STATUS:
self.response.write(self._compute_status(instance, zone))
def post(self, action, instance, zone):
if action == ACTION_START:
self._maybe_start_instance(instance, zone)
elif action == ACTION_RESTART:
self._maybe_restart_instance(instance, zone)