OLD | NEW |
1 # Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """A common base class for pages that are used to edit configs.""" | 5 """A common base class for pages that are used to edit configs.""" |
6 | 6 |
| 7 import json |
| 8 |
| 9 from google.appengine.api import app_identity |
| 10 from google.appengine.api import mail |
7 from google.appengine.api import taskqueue | 11 from google.appengine.api import taskqueue |
| 12 from google.appengine.api import users |
8 | 13 |
9 from dashboard import list_tests | 14 from dashboard import list_tests |
10 from dashboard.common import request_handler | 15 from dashboard.common import request_handler |
11 from dashboard.common import utils | 16 from dashboard.common import utils |
12 from dashboard.common import xsrf | 17 from dashboard.common import xsrf |
13 | 18 |
14 # Max number of entities to put in one request to /put_entities_task. | 19 # Max number of entities to put in one request to /put_entities_task. |
15 _MAX_TESTS_TO_PUT_AT_ONCE = 25 | 20 _MAX_TESTS_TO_PUT_AT_ONCE = 25 |
16 | 21 |
17 # The queue to use to re-put tests. Should be present in queue.yaml. | 22 # The queue to use to re-put tests. Should be present in queue.yaml. |
18 _TASK_QUEUE_NAME = 'edit-sheriffs-queue' | 23 _TASK_QUEUE_NAME = 'edit-sheriffs-queue' |
19 | 24 |
20 # Minimum time before starting tasks, in seconds. It appears that the tasks | 25 # Minimum time before starting tasks, in seconds. It appears that the tasks |
21 # may be executed before the sheriff is saved, so this is a workaround for that. | 26 # may be executed before the sheriff is saved, so this is a workaround for that. |
22 # See http://crbug.com/621499 | 27 # See http://crbug.com/621499 |
23 _TASK_QUEUE_COUNTDOWN = 60 | 28 _TASK_QUEUE_COUNTDOWN = 60 |
24 | 29 |
| 30 _NOTIFICATION_EMAIL_BODY = """ |
| 31 The configuration of %(hostname)s was changed by %(user)s. |
| 32 |
| 33 Key: %(key)s |
| 34 |
| 35 Added test paths: |
| 36 %(added_test_paths)s |
| 37 |
| 38 Removed test paths: |
| 39 %(removed_test_paths)s |
| 40 """ |
| 41 |
| 42 # TODO(qyearsley): Make this customizable by storing the value in datastore. |
| 43 # Make sure to send a notification to both old and new address if this value |
| 44 # gets changed. |
| 45 _NOTIFICATION_ADDRESS = 'chrome-performance-monitoring-alerts@google.com' |
| 46 _SENDER_ADDRESS = 'gasper-alerts@google.com' |
| 47 |
25 | 48 |
26 class EditConfigHandler(request_handler.RequestHandler): | 49 class EditConfigHandler(request_handler.RequestHandler): |
27 """Base class for handlers that are used to add or edit entities. | 50 """Base class for handlers that are used to add or edit entities. |
28 | 51 |
29 Specifically, this is a common base class for EditSheriffsHandler | 52 Specifically, this is a common base class for EditSheriffsHandler |
30 and EditAnomalyConfigsHandler. Both of these kinds of entities | 53 and EditAnomalyConfigsHandler. Both of these kinds of entities |
31 represent a configuration that can apply to a set of tests, where | 54 represent a configuration that can apply to a set of tests, where |
32 the set of tests is specified with a list of test path patterns. | 55 the set of tests is specified with a list of test path patterns. |
33 """ | 56 """ |
34 | 57 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 def _UpdateAndReportResults(self, entity): | 120 def _UpdateAndReportResults(self, entity): |
98 """Updates the entity and reports the results of this updating.""" | 121 """Updates the entity and reports the results of this updating.""" |
99 new_patterns = _SplitPatternLines(self.request.get('patterns')) | 122 new_patterns = _SplitPatternLines(self.request.get('patterns')) |
100 old_patterns = entity.patterns | 123 old_patterns = entity.patterns |
101 entity.patterns = new_patterns | 124 entity.patterns = new_patterns |
102 self._UpdateFromRequestParameters(entity) | 125 self._UpdateFromRequestParameters(entity) |
103 entity.put() | 126 entity.put() |
104 added_test_paths, removed_test_paths = _ChangeTestPatterns( | 127 added_test_paths, removed_test_paths = _ChangeTestPatterns( |
105 old_patterns, new_patterns) | 128 old_patterns, new_patterns) |
106 self._RenderResults(entity, added_test_paths, removed_test_paths) | 129 self._RenderResults(entity, added_test_paths, removed_test_paths) |
| 130 self._SendNotificationEmail(entity, added_test_paths, removed_test_paths) |
| 131 |
| 132 def _SendNotificationEmail( |
| 133 self, entity, added_test_paths, removed_test_paths): |
| 134 user_email = users.get_current_user().email() |
| 135 subject = 'Added or updated %s: %s by %s' % ( |
| 136 self._model_class.__name__, entity.key.string_id(), user_email) |
| 137 email_body = _NOTIFICATION_EMAIL_BODY % { |
| 138 'key': entity.key.string_id(), |
| 139 'added_test_paths': json.dumps( |
| 140 list(added_test_paths), indent=2, sort_keys=True, |
| 141 separators=(',', ': ')), |
| 142 'removed_test_paths': json.dumps( |
| 143 list(removed_test_paths), indent=2, sort_keys=True, |
| 144 separators=(',', ': ')), |
| 145 'hostname': app_identity.get_default_version_hostname(), |
| 146 'user': user_email, |
| 147 } |
| 148 mail.send_mail( |
| 149 sender=_SENDER_ADDRESS, |
| 150 to=_NOTIFICATION_ADDRESS, |
| 151 subject=subject, |
| 152 body=email_body) |
107 | 153 |
108 def _UpdateFromRequestParameters(self, entity): | 154 def _UpdateFromRequestParameters(self, entity): |
109 """Updates the given entity based on query parameters. | 155 """Updates the given entity based on query parameters. |
110 | 156 |
111 This method does not need to put() the entity. | 157 This method does not need to put() the entity. |
112 | 158 |
113 Args: | 159 Args: |
114 entity: The entity to update. | 160 entity: The entity to update. |
115 """ | 161 """ |
116 raise NotImplementedError() | 162 raise NotImplementedError() |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 test_paths: List of test paths of tests to be re-put. | 273 test_paths: List of test paths of tests to be re-put. |
228 """ | 274 """ |
229 for start_index in range(0, len(test_paths), _MAX_TESTS_TO_PUT_AT_ONCE): | 275 for start_index in range(0, len(test_paths), _MAX_TESTS_TO_PUT_AT_ONCE): |
230 group = test_paths[start_index:start_index + _MAX_TESTS_TO_PUT_AT_ONCE] | 276 group = test_paths[start_index:start_index + _MAX_TESTS_TO_PUT_AT_ONCE] |
231 urlsafe_keys = [utils.TestKey(t).urlsafe() for t in group] | 277 urlsafe_keys = [utils.TestKey(t).urlsafe() for t in group] |
232 taskqueue.add( | 278 taskqueue.add( |
233 url='/put_entities_task', | 279 url='/put_entities_task', |
234 params={'keys': ','.join(urlsafe_keys)}, | 280 params={'keys': ','.join(urlsafe_keys)}, |
235 queue_name=_TASK_QUEUE_NAME, | 281 queue_name=_TASK_QUEUE_NAME, |
236 countdown=_TASK_QUEUE_COUNTDOWN) | 282 countdown=_TASK_QUEUE_COUNTDOWN) |
OLD | NEW |