Bug 1381597 - create a taskcluster task that tests the decision graph for invalid buildbot-bridge builder names. r=dustin draft
authorJustin Wood <Callek@gmail.com>
Tue, 19 Sep 2017 16:21:19 -0400
changeset 668458 39e853f98dcfafe252504f724cdf84b95b0eece8
parent 667935 319a34bea9e4f3459886b5b9e835bd338320f1fd
child 732715 6689e685d1ce5fffb81ed23ec854ea1f7a916826
push id81059
push userCallek@gmail.com
push dateThu, 21 Sep 2017 18:24:57 +0000
reviewersdustin
bugs1381597
milestone57.0a1
Bug 1381597 - create a taskcluster task that tests the decision graph for invalid buildbot-bridge builder names. r=dustin This adds a download of allthethings.json to the Decision Task (in optimize phase). If there is a network error, in order to avoid a broken decision task, we treat all buildbot-bridge jobs as valid. MozReview-Commit-ID: GpKVV5pUwGL
taskcluster/taskgraph/util/bbb_validation.py
taskcluster/taskgraph/util/verify.py
new file mode 100644
--- /dev/null
+++ b/taskcluster/taskgraph/util/bbb_validation.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+import json
+import logging
+import requests
+
+from mozbuild.util import memoize
+from redo import retry
+from requests import exceptions
+
+ALLTHETHINGS_URL = "https://secure.pub.build.mozilla.org/builddata/reports/allthethings.json.gz"
+
+logger = logging.getLogger(__name__)
+
+
+def fetch_all_the_things():
+    response = retry(requests.get, attempts=2, sleeptime=10,
+                     args=(ALLTHETHINGS_URL,),
+                     kwargs={'timeout': 60})
+    return response.content
+
+
+@memoize
+def valid_bbb_builders():
+    try:
+        allthethings = fetch_all_the_things()
+        builders = set(json.loads(allthethings).get('builders', {}).keys())
+        return builders
+
+    # In the event of request times out, requests will raise a TimeoutError.
+    except exceptions.Timeout:
+        logger.warning("Timeout fetching list of buildbot builders.")
+
+    # In the event of a network problem (e.g. DNS failure, refused connection, etc),
+    # requests will raise a ConnectionError.
+    except exceptions.ConnectionError:
+        logger.warning("Connection Error while fetching list of buildbot builders")
+
+    # We just print the error out as a debug message if we failed to catch the exception above
+    except exceptions.RequestException as error:
+        logger.warning(error)
+
+    # When we get invalid JSON (i.e. 500 error), it results in a ValueError
+    except ValueError as error:
+        logger.warning("Invalid JSON, possible server error: {}".format(error))
+
+    # None returned to treat as "All Builders Valid"
+    return None
--- a/taskcluster/taskgraph/util/verify.py
+++ b/taskcluster/taskgraph/util/verify.py
@@ -5,16 +5,17 @@
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import re
 import os
 import sys
 
 from .. import GECKO
+from taskgraph.util.bbb_validation import valid_bbb_builders
 
 base_path = os.path.join(GECKO, 'taskcluster', 'docs')
 
 
 class VerificationSequence(object):
     """
     Container for a sequence of verifications over a TaskGraph. Each
     verification is represented as a callable taking (task, taskgraph,
@@ -142,8 +143,31 @@ def verify_dependency_tiers(task, taskgr
         for task in taskgraph.tasks.itervalues():
             tier = tiers[task.label]
             for d in task.dependencies.itervalues():
                 if tier < tiers[d]:
                     raise Exception(
                         '{} (tier {}) cannot depend on {} (tier {})'
                         .format(task.label, printable_tier(tier),
                                 d, printable_tier(tiers[d])))
+
+
+@verifications.add('optimized_task_graph')
+def verify_bbb_builders_valid(task, taskgraph, scratch_pad):
+    """
+        This function ensures that any task which is run
+        in buildbot (via buildbot-bridge) is using a recognized buildername.
+
+        If you see an unexpected failure with a task due to this check, please
+        see the IRC Channel, #releng.
+    """
+    if task is None:
+        return
+    valid_builders = valid_bbb_builders()
+    if valid_builders is None:
+        return
+    if task.task.get('workerType') == 'buildbot-bridge':
+        buildername = task.task['payload']['buildername']
+        if buildername not in valid_builders:
+            raise Exception(
+                '{} uses an invalid buildbot buildername ("{}") '
+                ' - contact #releng for help'
+                .format(task.label, buildername))