Skip to content

Commit

Permalink
Merge 63fbd07 into f25fbd6
Browse files Browse the repository at this point in the history
  • Loading branch information
armenzg committed Aug 5, 2015
2 parents f25fbd6 + 63fbd07 commit 23ae413
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 24 deletions.
19 changes: 15 additions & 4 deletions mozci/mozci.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,22 @@

import logging

from mozci.platforms import determine_upstream_builder, is_downstream, filter_buildernames,\
build_talos_buildernames_for_repo
from mozci.platforms import determine_upstream_builder, is_downstream, \
filter_buildernames, build_talos_buildernames_for_repo
from mozci.sources import allthethings, buildapi, buildjson, pushlog
from mozci.query_jobs import PENDING, RUNNING, SUCCESS, UNKNOWN,\
COALESCED, WARNING, FAILURE, EXCEPTION, RETRY, BuildApi, TreeherderApi
from mozci.query_jobs import (
PENDING,
RUNNING,
SUCCESS,
WARNING,
UNKNOWN,
COALESCED,
FAILURE,
EXCEPTION,
RETRY,
BuildApi,
TreeherderApi
)
from mozci.utils.misc import _all_urls_reachable
from mozci.utils.transfer import path_to_file, clean_directory

Expand Down
28 changes: 28 additions & 0 deletions mozci/scheduling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
This module allow us to interact with the various scheduling systems
in a very generic manner.
Defined in here:
* BaseSchedulingClient
* TaskclusterSchedulingClient
"""
from __future__ import absolute_import
from abc import ABCMeta, abstractmethod

from mozci.sources import tc


class BaseSchedulingClient:
""" Base class for common scheduling methods. """

__metaclass__ = ABCMeta

@abstractmethod
def retrigger(self, uuid, **kwargs):
pass


class TaskclusterSchedulingClient(BaseSchedulingClient):

def retrigger(self, uuid, **kwargs):
return tc.retrigger_task(task_id=uuid, **kwargs)
5 changes: 2 additions & 3 deletions mozci/scripts/alltalos.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,9 @@ def main():
options = parse_args()

if options.debug:
LOG = setup_logging(logging.DEBUG)
LOG.info("Setting DEBUG level")
setup_logging(logging.DEBUG)
else:
LOG = setup_logging(logging.INFO)
setup_logging()

pgo = False
if options.repo_name in PGO_ONLY_BRANCHES or options.pgo:
Expand Down
20 changes: 9 additions & 11 deletions mozci/scripts/generate_triggercli.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,30 @@
3) Remove the --dry-run parameter and actually trigger intermittents via trigger.py script.
"""
import bugsy
import logging
import os

from argparse import ArgumentParser

import bugsy

from mozci.mozci import query_repo_name_from_buildername
from mozci.utils.misc import setup_logging

bugzilla = bugsy.Bugsy()
logging.basicConfig(format='%(asctime)s %(levelname)s:\t %(message)s',
datefmt='%m/%d/%Y %I:%M:%S')
LOG = logging.getLogger()
LOG.setLevel(logging.INFO)
LOG = setup_logging()


def main():
global LOG

options = parse_args()
bugs = []
assert options.bug_no or options.test_name, \
"Either call this with --bug-no or with --test-name"

if options.debug:
LOG.setLevel(logging.DEBUG)
logging.getLogger("requests").setLevel(logging.DEBUG)
LOG.info("Setting DEBUG level")
else:
LOG.setLevel(logging.INFO)
# requests is too noisy and adds no value
LOG = setup_logging(logging.DEBUG)

if options.bug_no:
bugs.append(options.bug_no)
Expand Down
45 changes: 45 additions & 0 deletions mozci/scripts/misc/taskcluster_retrigger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'''
taskcluster_retrigger.py allows you to retrigger a task from TaskCluster
past its deadline.
'''
import logging

from argparse import ArgumentParser

from mozci.scheduling import TaskclusterSchedulingClient
from mozci.utils.misc import setup_logging


def main():
parser = ArgumentParser()
parser.add_argument("--debug",
action="store_true",
dest="debug",
help="set debug for logging.")

parser.add_argument("--dry-run",
action="store_true",
dest="dry_run",
help="Dry run. No real actions are taken.")

parser.add_argument('task_ids',
metavar='task_id',
type=str,
nargs='+',
help='Task IDs to work with.')

options = parser.parse_args()

if options.debug:
LOG = setup_logging(logging.DEBUG)
else:
LOG = setup_logging()

sch = TaskclusterSchedulingClient()
for t_id in options.task_ids:
ret_code = sch.retrigger(uuid=t_id, dry_run=options.dry_run)
if ret_code < 0:
LOG.warning("We could not retrigger task %s" % t_id)

if __name__ == "__main__":
main()
1 change: 0 additions & 1 deletion mozci/scripts/trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ def main():

if options.debug:
LOG = setup_logging(logging.DEBUG)
LOG.info("Setting DEBUG level")
else:
LOG = setup_logging(logging.INFO)

Expand Down
1 change: 0 additions & 1 deletion mozci/scripts/triggerbyfilters.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ def main():

if options.debug:
LOG = setup_logging(logging.DEBUG)
LOG.info("Setting DEBUG level")
else:
LOG = setup_logging(logging.INFO)

Expand Down
3 changes: 2 additions & 1 deletion mozci/sources/buildapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

import requests

from mozci.utils.authentication import get_credentials, remove_credentials, AuthenticationError
from mozci.utils.authentication import get_credentials, remove_credentials, \
AuthenticationError
from mozci.utils.transfer import path_to_file

LOG = logging.getLogger('mozci')
Expand Down
89 changes: 89 additions & 0 deletions mozci/sources/tc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""
This module allow us to interact with taskcluster through the taskcluster
client.
"""
import datetime
import json
import logging
import traceback

import taskcluster as taskcluster_client

LOG = logging.getLogger('mozci')
TASKCLUSTER_TOOLS_HOST = 'https://tools.taskcluster.net'


def retrigger_task(task_id, dry_run=False):
""" Given a task id (our uuid) we query it and build
a new task based on the old one which we schedule on TaskCluster.
We don't call the rerun API since we can't rerun a task past
its deadline, instead we create a new task with a new taskGroupId,
expiration, creation and deadline values.
task_id (int) - ID that identifies a task on Taskcluster
dry_run (bool) - Default to False. If True, it won't trigger
a task.
returns - 0 for dry_run case, -1 for any failure or the task id (int)
of a succesful retriggered task.
http://docs.taskcluster.net/queue/api-docs/#createTask
"""
one_year = 365
new_task_id = 0

try:
queue = taskcluster_client.Queue()
task = queue.task(task_id)

LOG.debug("Original task: (Limit 1024 char)")
LOG.debug(str(json.dumps(task))[:1024])
new_task_id = taskcluster_client.slugId()

artifacts = task['payload'].get('artifacts', {})
for artifact, definition in artifacts.iteritems():
definition['expires'] = taskcluster_client.fromNow('%s days' % one_year)

# The task group will be identified by the ID of the only
# task in the group
task['taskGroupId'] = new_task_id
# https://bugzilla.mozilla.org/show_bug.cgi?id=1190660
# TC workers create public logs which are 365 days; if the task expiration
# date is the same or less than that we won't have logs for the task
task['expires'] = taskcluster_client.fromNow('%s days' % (one_year + 1))
now = datetime.datetime.utcnow()
tomorrow = now + datetime.timedelta(hours=24)
task['created'] = taskcluster_client.stringDate(now)
task['deadline'] = taskcluster_client.stringDate(tomorrow)

LOG.debug("Contents of new task: (Limit 1024 char)")
LOG.debug(str(task)[:1024])

if not dry_run:
LOG.info("Attempting to schedule new task with task_id: {}".format(new_task_id))
result = queue.createTask(new_task_id, task)
LOG.debug(json.dumps(result))
LOG.info("{}/task-inspector/#{}".format(TASKCLUSTER_TOOLS_HOST, new_task_id))
else:
LOG.info("Dry-run mode: Nothing was retriggered.")

except taskcluster_client.exceptions.TaskclusterRestFailure as e:
traceback.print_exc()
new_task_id = -1

except taskcluster_client.exceptions.TaskclusterAuthFailure as e:
# Hack until we fix it in the issue
if str(e) == "Authorization Failed":
LOG.error("The taskclaster client that you specified is lacking "
"the right set of scopes.")
LOG.error("Run this same command with --debug and you will see "
"the missing scopes (the output comes from the "
"taskcluster python client)")
elif str(e) == "Authentication Error":
LOG.error("Make sure that you create permanent credentials and you "
"set these environment variables: TASKCLUSTER_CLIENT_ID & "
"TASKCLUSTER_ACCESS_TOKEN")
new_task_id = -1

return new_task_id
13 changes: 10 additions & 3 deletions mozci/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def _all_urls_reachable(urls):
return True


def setup_logging(level):
def setup_logging(level=logging.INFO):
"""
Save every message (including debug ones) to ~/.mozilla/mozci/mozci-debug.log.
Expand All @@ -53,23 +53,30 @@ def setup_logging(level):
As seen in:
https://docs.python.org/2/howto/logging-cookbook.html#logging-to-multiple-destinations
"""
LOG = logging.getLogger('mozci')
LOG = logging.getLogger()

# Handler 1 - Store all debug messages in a specific file
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(levelname)s:\t %(message)s',
datefmt='%m/%d/%Y %I:%M:%S',
filename=path_to_file('mozci-debug.log'),
filemode='w')

# Handler 2 - Console output
console = logging.StreamHandler()
console.setLevel(level)
# console does not use the same formatter specified in basicConfig
# we have to set it again
formatter = logging.Formatter('%(asctime)s %(levelname)s:\t %(message)s',
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s:\t %(message)s',
datefmt='%m/%d/%Y %I:%M:%S')
console.setFormatter(formatter)
LOG.addHandler(console)

if level != logging.DEBUG:
# requests is too noisy and adds no value
logging.getLogger("requests").setLevel(logging.WARNING)

if level == logging.DEBUG:
LOG.info("Setting DEBUG level")

return LOG
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
'progressbar>=2.3',
'requests>=2.5.1',
'keyring>=5.3',
'taskcluster>=0.0.22',
'treeherder-client>=1.4'
],

Expand Down

0 comments on commit 23ae413

Please sign in to comment.