|
1 | 1 | #!/usr/bin/env python3 |
2 | 2 |
|
3 | | -import gzip |
4 | 3 | import json |
5 | 4 | import os |
6 | 5 | from typing import Any |
7 | | -from urllib.request import urlopen |
| 6 | +from urllib.error import HTTPError |
| 7 | +from urllib.request import Request, urlopen |
8 | 8 | from warnings import warn |
9 | 9 |
|
10 | 10 | import boto3 |
11 | 11 | from octokit import Octokit |
12 | 12 |
|
13 | 13 |
|
14 | | -S3 = boto3.resource("s3") |
15 | | -BUCKET_NAME = "ossci-raw-job-status" |
16 | | -BUCKET = S3.Bucket(BUCKET_NAME) |
17 | | - |
18 | 14 | DYNAMO = boto3.resource("dynamodb") |
19 | 15 |
|
20 | | - |
21 | | -def json_dumps(body: Any) -> str: |
22 | | - # This logic is copied from github-status-test lambda function |
23 | | - return json.dumps(body, sort_keys=True, indent=4, separators=(",", ": ")) |
| 16 | +# torchci's authenticated backfill route, which hands the job to the |
| 17 | +# gha-log-uploader lambda. That lambda owns log downloading now; re-implementing |
| 18 | +# it here is how this script and github-status-test used to drift apart. |
| 19 | +HUD_URL = os.environ.get("HUD_URL", "https://hud.pytorch.org") |
| 20 | +LOG_UPLOADER_BOT_KEY = os.environ.get("LOG_UPLOADER_BOT_KEY", "") |
24 | 21 |
|
25 | 22 |
|
26 | | -def upload_log( |
27 | | - client: Octokit, owner: str, repo: str, job_id: int, conclusion: str |
28 | | -) -> None: |
29 | | - # This logic is copied from github-status-test lambda function |
30 | | - log = client.actions.download_job_logs_for_workflow_run( |
31 | | - owner=owner, repo=repo, job_id=job_id |
32 | | - ).json |
| 23 | +def upload_log(owner: str, repo: str, job_id: int, conclusion: str) -> None: |
| 24 | + if not LOG_UPLOADER_BOT_KEY: |
| 25 | + warn("LOG_UPLOADER_BOT_KEY is not set, skipping the log upload...") |
| 26 | + return |
33 | 27 |
|
34 | | - log_path = f"log/{job_id}" |
35 | | - if repo != "pytorch": |
36 | | - log_path = f"log/{owner}/{repo}/{job_id}" |
| 28 | + print(f"..Requesting a log upload for {owner}/{repo} job {job_id}") |
| 29 | + request = Request( |
| 30 | + f"{HUD_URL}/api/log-uploader/backfill", |
| 31 | + method="POST", |
| 32 | + data=json.dumps( |
| 33 | + { |
| 34 | + "repo": f"{owner}/{repo}", |
| 35 | + "job_id": job_id, |
| 36 | + "conclusion": conclusion, |
| 37 | + } |
| 38 | + ).encode(), |
| 39 | + headers={ |
| 40 | + "Content-Type": "application/json", |
| 41 | + "Authorization": LOG_UPLOADER_BOT_KEY, |
| 42 | + }, |
| 43 | + ) |
37 | 44 |
|
38 | | - print(f"..Uploading log to {log_path}") |
39 | 45 | try: |
40 | | - # This needs to be in try catch because GitHub doesn't keep log older than 60 days I think |
41 | | - S3.Object(BUCKET_NAME, log_path).put( |
42 | | - Body=gzip.compress(log.encode(encoding="UTF-8")), |
43 | | - ContentType="text/plain", |
44 | | - ContentEncoding="gzip", |
45 | | - Metadata={"conclusion": conclusion}, |
46 | | - ) |
47 | | - |
48 | | - # Invoke log classifier |
49 | | - urlopen( |
50 | | - f"https://vwg52br27lx5oymv4ouejwf4re0akoeg.lambda-url.us-east-1.on.aws/?job_id={job_id}&repo={owner}/{repo}" |
51 | | - ) |
52 | | - except Exception as error: |
| 46 | + # GitHub drops logs after around 60 days, so an old job simply has |
| 47 | + # nothing to fetch. That is a warning, not a reason to stop the backfill. |
| 48 | + with urlopen(request, timeout=30) as response: |
| 49 | + if response.status != 200: |
| 50 | + warn(f"Log upload for job {job_id} returned {response.status}") |
| 51 | + except (HTTPError, OSError) as error: |
53 | 52 | warn( |
54 | | - f"Failed to upload {log} for job {job_id} from repo {owner}/{repo}: " |
55 | | - + f"{error}, skipping..." |
| 53 | + f"Failed to request a log upload for job {job_id} from repo " |
| 54 | + f"{owner}/{repo}: {error}, skipping..." |
56 | 55 | ) |
57 | 56 |
|
58 | 57 |
|
59 | 58 | def process_event(owner: str, repo: str, event: str, body: Any) -> None: |
60 | | - # This logic is copied from github-status-test lambda function |
61 | | - if repo == "pytorch": |
62 | | - repo_prefix = "" |
63 | | - else: |
64 | | - repo_prefix = f"{owner}/{repo}/" |
65 | | - |
| 59 | + # Only DynamoDB, which is what clickhouse-replicator-dynamo reads. The raw |
| 60 | + # event archive github-status-test used to write to S3 was never read by |
| 61 | + # anything and is not reproduced here. |
66 | 62 | if "id" not in body: |
67 | 63 | warn(f"Missing ID in {body}, skipping...") |
68 | 64 | return |
69 | 65 |
|
70 | 66 | id = body["id"] |
71 | | - print(f"{event}/{repo_prefix}{id}") |
72 | | - S3.Object(BUCKET_NAME, f"{event}/{repo_prefix}{id}").put( |
73 | | - Body=json_dumps(body), ContentType="application/json" |
74 | | - ) |
| 67 | + print(f"{event} {owner}/{repo}/{id}") |
75 | 68 |
|
76 | 69 | dynamodb_table = "" |
77 | 70 | if event == "workflow_run": |
@@ -131,7 +124,7 @@ def process_workflow_run( |
131 | 124 | conclusion = workflow_job["conclusion"] |
132 | 125 |
|
133 | 126 | process_event(owner, repo, "workflow_job", workflow_job) |
134 | | - upload_log(client, owner, repo, job_id, conclusion) |
| 127 | + upload_log(owner, repo, job_id, conclusion) |
135 | 128 |
|
136 | 129 | if not count or count >= total_count: |
137 | 130 | # Finish processing all events |
|
0 commit comments