blob: 13f59fd4b1bf04f1f583d5e365ca6c2b876815f5 [file]
# Copyright (c) 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""AutoRoll Bot (ARB) management pages."""
import json
import time
from google.appengine.api import memcache
from google.appengine.ext import db
from base_page import BasePage
import utils
# How much history to display on the arb status page.
HISTORY_LIMIT = 25
# Memcache keys used by the ARB pages.
ARB_STATUS_MEMCACHE_KEY = 'arb_status'
IS_STOPPED_MEMCACHE_KEY = 'arb_is_stopped'
class ARBStatus(db.Model):
"""The status of the ARB as reported by the bot."""
# The last status reported by the ARB.
last_reported_status = db.StringProperty(required=True)
# The codereview link of the DEPS roll.
deps_roll_link = db.LinkProperty()
# The revision that was used for the last DEPS roll.
last_roll_rev = db.StringProperty()
# The revision that is used for the current DEPS roll.
curr_roll_rev = db.StringProperty()
# The date when the status was modified.
date = db.DateTimeProperty(auto_now=True)
@staticmethod
def get_arb_status():
"""Returns the last reported ARB status."""
arb_status = memcache.get(ARB_STATUS_MEMCACHE_KEY)
if arb_status == None:
arb_status = ARBStatus.all().get()
memcache.add(ARB_STATUS_MEMCACHE_KEY, arb_status)
return arb_status
@staticmethod
def flush_cache():
"""Flushes the memcache key used by this datamodel."""
memcache.flush_all()
memcache.delete(ARB_STATUS_MEMCACHE_KEY)
# Wait for a second before accessing the memcache again (in case there is a
# propagation delay).
time.sleep(1)
class ARBStoppedAction(db.Model):
"""Contains information of whether the ARB was stopped/started."""
# The user set status of the ARB.
is_stopped = db.BooleanProperty(required=True)
# The username that stopped/started the ARB.
username = db.StringProperty(required=True)
# The reason ARB was stopped/started.
reason = db.StringProperty()
# The date when this data model was added.
date = db.DateTimeProperty(auto_now_add=True)
@staticmethod
def currently_stopped():
"""Returns the latest user specified setting."""
is_stopped = memcache.get(IS_STOPPED_MEMCACHE_KEY)
if is_stopped == None:
is_stopped = ARBStoppedAction.all().order('-date').get().is_stopped
memcache.add(IS_STOPPED_MEMCACHE_KEY, is_stopped)
return is_stopped
@staticmethod
def flush_cache():
"""Flushes the memcache key used by this datamodel."""
memcache.flush_all()
memcache.delete(IS_STOPPED_MEMCACHE_KEY)
# Wait for a second before accessing the memcache again (in case there is a
# propagation delay).
time.sleep(1)
@staticmethod
def get_actions_history(limit=HISTORY_LIMIT):
return ARBStoppedAction.all().order('-date').fetch(HISTORY_LIMIT)
class GetARBStatusPage(BasePage):
"""Returns the current status of the ARB in JSON."""
def get(self):
arb_status = ARBStatus.get_arb_status()
json_dict = {
'status': arb_status.last_reported_status,
'deps_roll_link': arb_status.deps_roll_link,
'last_roll_rev': arb_status.last_roll_rev,
'curr_roll_rev': arb_status.curr_roll_rev,
'date': str(arb_status.date),
}
json_output = json.dumps(json_dict)
self.response.headers['Content-Type'] = 'application/json'
self.response.headers['Access-Control-Allow-Origin'] = '*'
self.response.out.write(json_output)
class SetARBStatusPage(BasePage):
"""Allows the ARB to set its current status."""
@utils.admin_only
def post(self):
status = self.request.get('status')
deps_roll_link = self.request.get('deps_roll_link', None)
last_roll_rev = self.request.get('last_roll_rev', None)
curr_roll_rev = self.request.get('curr_roll_rev', None)
arb_status = ARBStatus.get_arb_status()
arb_status.last_reported_status = status
arb_status.deps_roll_link = deps_roll_link
arb_status.last_roll_rev = last_roll_rev
arb_status.curr_roll_rev = curr_roll_rev
arb_status.put()
# Flush the cache.
ARBStatus.flush_cache()
class ARBIsStoppedPage(BasePage):
"""Returns whether the ARB has been stopped/started."""
def get(self):
is_stopped = ARBStoppedAction.currently_stopped()
json_dict = {'is_stopped': is_stopped}
json_output = json.dumps(json_dict)
self.response.headers['Content-Type'] = 'application/json'
self.response.out.write(json_output)
class SetARBActionPage(BasePage):
"""Allows users to stop/start the ARB."""
@utils.require_user
def get(self):
return self._handle()
@utils.require_user
@utils.admin_only
def post(self):
new_action = ARBStoppedAction(
is_stopped=bool(self.request.get('is_stopped')),
username=self.user.email(),
reason=self.request.get('reason'))
new_action.put()
# Flush the cache.
ARBStoppedAction.flush_cache()
# Set template values and load the template.
self._handle()
def _handle(self):
"""Sets the information to be displayed on the builder status page."""
template_values = self.InitializeTemplate('AutoRoll Bot Status')
template_values['arb_status'] = ARBStatus.get_arb_status()
template_values['user_actions'] = ARBStoppedAction.get_actions_history()
template_values['history_limit'] = HISTORY_LIMIT
self.DisplayTemplate('arb_status.html', template_values)
def bootstrap():
# Guarantee that at least one instance exists.
if db.GqlQuery('SELECT __key__ FROM ARBStatus').get() is None:
ARBStatus(last_reported_status='In progress',
deps_roll_link='https://codereview.chromium.org/923103002/',
last_roll_rev='f16c00e41b72daa81ed7efacbead06b387767841',
curr_roll_rev='f89f60f6972569a41fa737c786d238559027fede').put()
if db.GqlQuery('SELECT __key__ FROM ARBStoppedAction').get() is None:
ARBStoppedAction(is_stopped=False, username='rmistry@google.com',
reason='Initial entry').put()