From 5200c822183704e109f95e1893500429de6fa43b Mon Sep 17 00:00:00 2001 From: Joao Mario Lago Date: Wed, 20 Mar 2024 10:05:47 -0300 Subject: [PATCH] Add image details and platform ddetails in versions * Add for each version tag details about size and digest for each image * Add for each version tag details for active valid platforms specifications --- blueos_repository/consolidate.py | 52 ++++++++++++++++++++++++++++---- blueos_repository/registry.py | 8 ++--- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/blueos_repository/consolidate.py b/blueos_repository/consolidate.py index d6709c3..ea4fd89 100755 --- a/blueos_repository/consolidate.py +++ b/blueos_repository/consolidate.py @@ -44,6 +44,21 @@ def from_json(json_dict: Dict[str, str]) -> "Author": return Author(name=json_dict["name"], email=json_dict["email"]) +@dataclasses.dataclass +class Platform: + architecture: str + variant: Optional[str] = None + # pylint: disable=invalid-name + os: Optional[str] = None + + +@dataclasses.dataclass +class Image: + digest: Optional[str] + expanded_size: int + platform: Platform + + @dataclasses.dataclass class Company: name: str @@ -78,6 +93,7 @@ class Version: type: ExtensionType filter_tags: List[str] extra_links: Dict[str, str] + images: List[Image] @staticmethod def validate_filter_tags(tags: List[str]) -> List[str]: @@ -161,15 +177,38 @@ def valid_semver(string: str) -> Optional[semver.VersionInfo]: except ValueError: return None # not valid + def extract_images_from_tag(self, tag: Any) -> List[Image]: + active_images = [ + image + for image in tag["images"] + if (image["status"] == "active" and image["architecture"] != "unknown" and image["os"] != "unknown") + ] + + images = [ + Image( + digest=image.get("digest", None), + expanded_size=image["size"], + platform=Platform( + architecture=image["architecture"], + variant=image.get("variant", None), + os=image.get("os", None), + ), + ) + for image in active_images + ] + return images + # pylint: disable=too-many-locals async def run(self) -> None: async for repository in self.all_repositories(): for tag in await self.registry.fetch_remote_tags(repository.docker): + tag_name = tag["name"] + print(tag_name) try: - if not self.valid_semver(tag): - print(f"{tag} is not valid SemVer, ignoring it...") + if not self.valid_semver(tag_name): + print(f"{tag_name} is not valid SemVer, ignoring it...") continue - raw_labels = await self.registry.fetch_labels(f"{repository.docker}:{tag}") + raw_labels = await self.registry.fetch_labels(f"{repository.docker}:{tag_name}") permissions = raw_labels.get("permissions", None) links = json5.loads(raw_labels.get("links", "{}")) website = links.pop("website", raw_labels.get("website", None)) @@ -178,7 +217,7 @@ async def run(self) -> None: docs = links.pop("docs", links.pop("documentation", raw_labels.get("docs", None))) readme = raw_labels.get("readme", None) if readme is not None: - readme = readme.replace(r"{tag}", tag) + readme = readme.replace(r"{tag_name}", tag_name) try: readme = await self.fetch_readme(readme) except Exception as error: # pylint: disable=broad-except @@ -201,9 +240,10 @@ async def run(self) -> None: type=type_, filter_tags=Version.validate_filter_tags(filter_tags), requirements=raw_labels.get("requirements", None), - tag=tag, + tag=tag_name, + images=self.extract_images_from_tag(tag), ) - repository.versions[tag] = new_version + repository.versions[tag_name] = new_version except KeyError as error: raise Exception(f"unable to parse repository {repository}: {error}") from error # sort the versions, with the highest version first diff --git a/blueos_repository/registry.py b/blueos_repository/registry.py index a7ea716..6f82251 100644 --- a/blueos_repository/registry.py +++ b/blueos_repository/registry.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional +from typing import Any, Dict, Optional import aiohttp_retry @@ -41,7 +41,7 @@ async def _get_token(self, repo: str) -> str: raise Exception("Could not get auth token") return str((await resp.json(content_type=None))["token"]) - async def fetch_remote_tags(self, repository: str) -> List[str]: + async def fetch_remote_tags(self, repository: str) -> Any: """Fetches the tags available for an image in DockerHub""" print(f"fetching tags in {repository}") self.token = await self._get_token(repository) @@ -55,9 +55,7 @@ async def fetch_remote_tags(self, repository: str) -> List[str]: data = await resp.json(content_type=None) tags = data["results"] - valid_images = [tag["name"] for tag in tags] - print(valid_images) - return valid_images + return tags def is_compatible(self, entry: Any) -> bool: if entry["os"] != "linux":