• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2015 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Provides a web interface for loading graph data from the production server.
6
7This is meant to be used on a dev server only.
8"""
9
10import base64
11import json
12import os
13import urllib
14
15from google.appengine.api import app_identity
16from google.appengine.api import urlfetch
17from google.appengine.ext import ndb
18from google.appengine.ext.ndb import model
19
20from dashboard import datastore_hooks
21from dashboard import request_handler
22from dashboard import update_test_suites
23
24_DEV_APP_ID = 'dev~' + app_identity.get_application_id()
25
26_PROD_DUMP_GRAPH_JSON_URL = 'https://chromeperf.appspot.com/dump_graph_json'
27
28
29class LoadFromProdHandler(request_handler.RequestHandler):
30  """Debugging handler to load data from the production instance."""
31
32  def get(self):
33    if 'Development' not in os.environ['SERVER_SOFTWARE']:
34      self.RenderHtml('result.html', {
35          'errors': [
36              'This should not be run in production, only on dev server.']})
37      return
38    self.RenderHtml('load_from_prod.html', {})
39
40  def post(self):
41    """Loads the requested data from the production server."""
42    if 'Development' not in os.environ['SERVER_SOFTWARE']:
43      self.RenderHtml('result.html', {
44          'errors': [
45              'This should not be run in production, only on dev server.']})
46      return
47
48    sheriff = self.request.get('sheriff')
49    test_path = self.request.get('test_path')
50    if test_path:
51      num_points = self.request.get('num_points')
52      end_rev = self.request.get('end_rev')
53      url = ('%s?test_path=%s&num_points=%s' %
54             (_PROD_DUMP_GRAPH_JSON_URL, urllib.quote(test_path), num_points))
55      if end_rev:
56        url += '&end_rev=%s' % end_rev
57    elif sheriff:
58      sheriff_name = self.request.get('sheriff')
59      num_alerts = self.request.get('num_alerts')
60      num_points = self.request.get('num_points')
61      url = ('%s?sheriff=%s&num_alerts=%s&num_points=%s' %
62             (_PROD_DUMP_GRAPH_JSON_URL, urllib.quote(sheriff_name), num_alerts,
63              num_points))
64    else:
65      self.RenderHtml('result.html', {
66          'errors': ['Need to specify a test_path or sheriff.']})
67      return
68
69    # This takes a while.
70    response = urlfetch.fetch(url, deadline=60)
71    if response.status_code != 200:
72      self.RenderHtml('result.html', {'errors': ['Could not fetch %s' % url]})
73      return
74    protos = json.loads(response.content)
75
76    kinds = ['Master', 'Bot', 'TestMetadata', 'Row', 'Sheriff', 'Anomaly']
77    entities = {k: [] for k in kinds}
78    for proto in protos:
79      pb = model.entity_pb.EntityProto(base64.b64decode(proto))
80      # App ID is set in the key and all the ReferenceProperty keys to
81      # 's~chromeperf'. It won't be found in queries unless we use the
82      # devserver app ID.
83      key = pb.mutable_key()
84      key.set_app(_DEV_APP_ID)
85      for prop in pb.property_list():
86        val = prop.mutable_value()
87        if val.has_referencevalue():
88          ref = val.mutable_referencevalue()
89          ref.set_app(_DEV_APP_ID)
90      entity = ndb.ModelAdapter().pb_to_entity(pb)
91      entities[entity.key.kind()].append(entity)
92
93    for kind in kinds:
94      ndb.put_multi(entities[kind])
95
96    update_test_suites.UpdateTestSuites(datastore_hooks.INTERNAL)
97    update_test_suites.UpdateTestSuites(datastore_hooks.EXTERNAL)
98
99    num_entities = sum(len(entities[kind]) for kind in kinds)
100    self.RenderHtml('result.html', {
101        'results': [
102            {
103                'name': 'Added data',
104                'value': '%d entities' % num_entities
105            }
106        ]
107    })
108