Source code
Revision control
Copy as Markdown
Other Tools
# 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
import logging
from .registry import register_callback_action
from .util import create_tasks, fetch_graph_and_labels
logger = logging.getLogger(__name__)
TASK_LABEL = "bhr-aggregate-cron"
@register_callback_action(
title="BHR aggregation (custom date)",
name="bhr-aggregate",
symbol="bhr-custom",
description=(
"Run the Background Hang Reporter aggregation for a specific build date "
"and/or sample size, rather than the daily cron's four-days-ago at 0.5. "
"Used to backfill a historical day or re-run a day that failed."
),
order=1000,
context=[],
# Its own permission rather than "generic": the task this creates carries
# secrets:get on the production BigQuery credential, and the action task has
# to hold that scope to grant it. Keeping it off action:generic means the
# grant covers this action alone. Needs a matching role and hook in
permission="bhr-aggregate",
schema={
"type": "object",
"properties": {
"date": {
"type": "string",
"pattern": "^[0-9]{8}$",
"title": "Build date",
"description": (
"Build date to aggregate, as YYYYMMDD. Leave empty to keep "
"the cron's behaviour of resolving the date at run time from "
"BHR_AGGREGATE_DATE_OFFSET_DAYS."
),
},
"sample_size": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 1,
"title": "Sample size",
"description": (
"Fraction of pings to read, in (0, 1]. Leave empty to keep the "
"cron's production sampling. A small value is much cheaper and "
"is usually enough to check that a change behaves."
),
},
},
"additionalProperties": False,
},
# The job reads production BigQuery with a stored credential granted only to
# the level-3 mozilla-central cron, so it must not be reachable elsewhere.
available=lambda parameters: parameters["project"] == "mozilla-central",
)
def bhr_aggregate_action(parameters, graph_config, input, task_group_id, task_id):
decision_task_id, full_task_graph, label_to_taskid, _ = fetch_graph_and_labels(
parameters, graph_config
)
if TASK_LABEL not in full_task_graph.tasks:
raise Exception(f"{TASK_LABEL} was not found in the task-graph")
date = input.get("date")
sample_size = input.get("sample_size")
def modifier(task):
if task.label != TASK_LABEL:
return task
env = task.task["payload"]["env"]
if date:
# Pins the run to one build date. The script prefers this over
# resolving an offset against the current time, so the task stays
# reproducible however long after the fact it is triggered.
env["BHR_AGGREGATE_DATE"] = date
if sample_size is not None:
env["BHR_AGGREGATE_SAMPLE_SIZE"] = str(sample_size)
# Distinguish the one-off from the daily run on Treeherder.
task.task["extra"]["treeherder"]["symbol"] += "-custom"
return task
logger.info(
"Triggering %s with date=%s sample_size=%s",
TASK_LABEL,
date or "(cron default)",
sample_size if sample_size is not None else "(cron default)",
)
create_tasks(
graph_config,
[TASK_LABEL],
full_task_graph,
label_to_taskid,
parameters,
decision_task_id,
modifier=modifier,
)