blob: dbcde82cff7a13b014991002d45b1ad9ae515632 [file]
#!/usr/bin/env python3
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import argparse
import datetime
import json
import logging
import urllib.error
from pathlib import Path
from typing import Dict, Any
from http_utils import get
from cmd_utils import init_log, REPO_ROOT
DOCKER_API_BASE = "https://hub.docker.com/v2/"
PAGE_SIZE = 25
TEST_DATA = None
def docker_api(url: str, use_pagination: bool = False) -> Dict[str, Any]:
"""
Run a paginated fetch from the public Docker Hub API
"""
if TEST_DATA is not None:
if url not in TEST_DATA:
raise urllib.error.HTTPError(url, 404, "Not found", {}, None)
return TEST_DATA[url]
pagination = ""
if use_pagination:
pagination = f"?page_size={PAGE_SIZE}&page=1"
url = DOCKER_API_BASE + url + pagination
r, headers = get(url)
reset = headers.get("x-ratelimit-reset")
if reset is not None:
reset = datetime.datetime.fromtimestamp(int(reset))
reset = reset.isoformat()
logging.info(
f"Docker API Rate Limit: {headers.get('x-ratelimit-remaining')} / {headers.get('x-ratelimit-limit')} (reset at {reset})"
)
return r
def image_exists(spec: str) -> bool:
name, tag = spec.split(":")
try:
r = docker_api(f"repositories/{name}/tags/{tag}")
logging.info(f"Image exists, got response: {json.dumps(r, indent=2)}")
return True
except urllib.error.HTTPError as e:
# Image was not found
logging.exception(e)
return False
if __name__ == "__main__":
init_log()
parser = argparse.ArgumentParser(
description="Writes out Docker images names to be used to .docker-image-names/"
)
parser.add_argument(
"--testing-docker-data",
help="(testing only) JSON data to mock response from Docker Hub API",
)
parser.add_argument(
"--base-dir",
default=".docker-image-names",
help="(testing only) Folder to write image names to",
)
args, other = parser.parse_known_args()
name_dir = Path(args.base_dir)
images = {}
for item in other:
name, tag = item.split("=")
images[name] = tag
if args.testing_docker_data is not None:
TEST_DATA = json.loads(args.testing_docker_data)
logging.info(f"Checking if these images exist in tlcpack: {images}")
name_dir.mkdir(exist_ok=True)
images_to_use = {}
for filename, spec in images.items():
if image_exists(spec):
logging.info(f"{spec} found in tlcpack")
images_to_use[filename] = spec
else:
logging.info(f"{spec} not found in tlcpack, using tlcpackstaging")
part, tag = spec.split(":")
user, repo = part.split("/")
tlcpackstaging_tag = f"tlcpackstaging/{repo.replace('-', '_')}:{tag}"
images_to_use[filename] = tlcpackstaging_tag
for filename, image in images_to_use.items():
logging.info(f"Writing image {image} to {name_dir / filename}")
with open(name_dir / filename, "w") as f:
f.write(image)