summaryrefslogtreecommitdiff
path: root/buildscripts/resmokelib/undodb/fetch.py
blob: 153977f30b448e8d295d385288e08d208d47c744 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
"""Subcommand for fetching UndoDB recordings from Evergreen."""
import os
from typing import List, Optional
import subprocess
import tempfile
from urllib.request import urlopen
from shutil import copyfileobj
import tarfile

import evergreen
from evergreen import RetryingEvergreenApi
from buildscripts.resmokelib.plugin import Subcommand


def _is_jira_ticket(asset: str) -> bool:
    maybe_ticket = asset.upper()
    return maybe_ticket.startswith("BF-") or maybe_ticket.startswith("BFG-")


class Fetch(Subcommand):
    """Fetch UndoDB recordings from a given Evergreen task ID or BF ticket."""

    def __init__(self, asset: str):
        """Constructor."""
        if _is_jira_ticket(asset):
            self._ticket = asset
            self._task_id = None
        else:
            self._ticket = None
            self._task_id = asset

    def execute(self) -> None:
        """
        Work your magic.

        :return: None
        """
        if self._ticket:
            raise NotImplementedError("Fetching recordings from JIRA tickets not yet implemented")

        assert self._task_id

        evg = RetryingEvergreenApi.get_api(use_config_file=True)
        artifacts = evg.task_by_id(self._task_id).artifacts
        url = _find_undodb_artifact_url(artifacts)
        if not url:
            print(
                f"Evergreen task '{self._task_id}' does not have an UndoDB recordings archive attached to it"
            )
            return

        local_file = _download_archive(url)
        if not local_file:
            print(f"Failed to download archive from '{url}'")
            return

        _extract_archive(local_file)
        _cleanup(local_file)


def _find_undodb_artifact_url(artifacts: List[evergreen.task.Artifact]) -> Optional[str]:
    for artifact in artifacts:
        if artifact.name.startswith("UndoDB Recordings - Execution "):
            return artifact.url

    return None


def _download_archive(url: str) -> Optional[str]:
    """Download the archive from the given url.

    :return path to the downloaded archive, or None if nothing was downloaded
    """
    fname = os.path.basename(url)
    out_file = os.path.join(tempfile.gettempdir(), fname)
    if os.path.exists(out_file):
        print(f"Output file '{out_file}' exists, assuming that it's valid")
        return out_file
    try:
        print(f"Downloading to '{out_file}'")
        with urlopen(url) as fsrc, open(out_file, "wb") as fdst:
            copyfileobj(fsrc, fdst)  # type: ignore

    except Exception as ex:
        if ex is KeyboardInterrupt:
            print("Cancelled download")
        _cleanup(out_file)
        raise ex

    return out_file


def _extract_archive(fname: str):
    print(f"Extracting to '{os.getcwd()}'")
    with tarfile.open(fname) as tfile:
        tfile.extractall()


def _cleanup(out_file: str):
    if os.path.isfile(out_file):
        print("Cleaning up temporary files")
        os.remove(out_file)