diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index c731c87d..2cd2a9d5 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -31,7 +31,8 @@ jobs: run: | # renovate: datasource=github-releases depName=terraform-docs/terraform-docs extractVersion=^v(?.+)$ VERSION=0.20.0 - curl -sSLo ./terraform-docs.tar.gz "https://terraform-docs.io/dl/v${VERSION}/terraform-docs-v${VERSION}-$(uname)-amd64.tar.gz" + ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') + curl -sSLo ./terraform-docs.tar.gz "https://terraform-docs.io/dl/v${VERSION}/terraform-docs-v${VERSION}-$(uname)-${ARCH}.tar.gz" tar -xzf terraform-docs.tar.gz terraform-docs chmod +x terraform-docs mv terraform-docs /usr/local/bin/terraform-docs diff --git a/ansible/bootstrap-ansible.sh b/ansible/bootstrap-ansible.sh index 75f54670..5c1a1312 100755 --- a/ansible/bootstrap-ansible.sh +++ b/ansible/bootstrap-ansible.sh @@ -16,9 +16,22 @@ install_ansible_on_ubuntu() { # Installing Ansible on Ubuntu # https://docs.ansible.com/ansible/latest/installation_guide/installation_distros.html#installing-ansible-on-ubuntu apt-get update - apt-get install --yes software-properties-common - add-apt-repository --yes --update ppa:ansible/ansible - apt-get install --yes --no-install-recommends ansible python3-pip + + UBUNTU_CODENAME=$(. /etc/os-release && echo "$VERSION_CODENAME") + + case "$UBUNTU_CODENAME" in + jammy|focal|bionic) + apt-get install --yes software-properties-common + add-apt-repository --yes --update ppa:ansible/ansible + apt-get install --yes --no-install-recommends ansible python3-pip + ;; + *) + # Ubuntu 24.04+ (noble and newer) includes Ansible in the universe repository; + # the PPA is unnecessary and its "noble" distribution causes apt-get update to + # hang in Docker builds. + apt-get install --yes --no-install-recommends ansible python3-pip + ;; + esac # "--ignore-installed" is added to fix error "Cannot uninstall PyYAML 6.0.1 ... The package was installed by debian." pip install passlib ansible-lint --ignore-installed --break-system-packages diff --git a/ansible/inventory/group_vars/debian/vars.yaml b/ansible/inventory/group_vars/debian/vars.yaml index 02eb7396..d8d4994d 100644 --- a/ansible/inventory/group_vars/debian/vars.yaml +++ b/ansible/inventory/group_vars/debian/vars.yaml @@ -13,7 +13,7 @@ debian_base_install_crowdsec_bouncer: false # https://github.com/go-task/task/releases # renovate: datasource=github-releases depName=go-task/task -debian_base_go_task_version: "v3.44.1" +debian_base_go_task_version: "v3.50.0" linuxbrew_use_installer: true linuxbrew_init_shell: true diff --git a/ansible/roles/debian_base/tasks/60-go-task.yaml b/ansible/roles/debian_base/tasks/60-go-task.yaml index 33062aaf..58efc591 100644 --- a/ansible/roles/debian_base/tasks/60-go-task.yaml +++ b/ansible/roles/debian_base/tasks/60-go-task.yaml @@ -12,31 +12,29 @@ mode: "0755" when: debian_base_task_version_check.rc != 0 -- name: Set go-task architecture for arm - ansible.builtin.set_fact: - debian_base_task_arch: "arm" - when: ansible_architecture == "armv7l" +- name: Fail on unsupported architecture + ansible.builtin.fail: + msg: "Unsupported architecture: {{ ansible_facts['architecture'] }}" + when: ansible_facts['architecture'] not in ["x86_64", "aarch64", "armv7l", "armv6l"] -- name: Set go-task architecture for amd64 +- name: Set go-task architecture ansible.builtin.set_fact: - debian_base_task_arch: "amd64" - when: ansible_architecture == "x86_64" + debian_base_task_arch: "{{ {'x86_64': 'amd64', 'aarch64': 'arm64', 'armv7l': 'arm', 'armv6l': 'arm'}[ansible_facts['architecture']] }}" -- name: Set go-task architecture for arm64 +- name: Set go-task version ansible.builtin.set_fact: - debian_base_task_arch: "arm64" - when: ansible_architecture == "aarch64" + debian_base_go_task_version: "{{ debian_base_go_task_version | default('v3.50.0') }}" - name: Download go-task .deb package ansible.builtin.get_url: - url: "https://github.com/go-task/task/releases/download/{{ debian_base_go_task_version | default('v3.44.1') }}/task_linux_{{ debian_base_task_arch }}.deb" - dest: "/tmp/go-task/task_linux_{{ debian_base_task_arch }}.deb" + url: "https://github.com/go-task/task/releases/download/{{ debian_base_go_task_version }}/task_{{ debian_base_go_task_version | regex_replace('^v', '') }}_linux_{{ debian_base_task_arch }}.deb" + dest: "/tmp/go-task/task_{{ debian_base_go_task_version }}_linux_{{ debian_base_task_arch }}.deb" mode: "0644" when: debian_base_task_version_check.rc != 0 - name: Install go-task from downloaded .deb package ansible.builtin.apt: - deb: "/tmp/go-task/task_linux_{{ debian_base_task_arch }}.deb" + deb: "/tmp/go-task/task_{{ debian_base_go_task_version }}_linux_{{ debian_base_task_arch }}.deb" state: present when: debian_base_task_version_check.rc != 0 diff --git a/scripts/infra-mcp/tools/get_container_tags.py b/scripts/infra-mcp/tools/get_container_tags.py index daed7fa2..0777bdff 100755 --- a/scripts/infra-mcp/tools/get_container_tags.py +++ b/scripts/infra-mcp/tools/get_container_tags.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import argparse +import platform import sys from datetime import datetime from email.utils import parsedate_to_datetime @@ -16,6 +17,13 @@ REGISTRY_REQUEST_TIMEOUT = 30 MAX_TAGS_FETCH_LIMIT = 1000 +_arch_map = {"x86_64": "amd64", "aarch64": "arm64", "armv7l": "arm"} + + +def _default_architecture() -> str: + arch = _arch_map.get(platform.machine(), platform.machine()) + return f"linux/{arch}" + class ContainerTagFinder: """ @@ -39,8 +47,8 @@ def _parse_arch(self, arch: str) -> tuple[str, str]: tuple: A tuple containing (os_part, arch_part) """ parts = arch.split("/") - os_part = parts[0] if parts else "linux" - arch_part = parts[1] if len(parts) > 1 else "amd64" + os_part = parts[0] if parts and parts[0] else "linux" + arch_part = parts[1] if len(parts) > 1 and parts[1] else _arch_map.get(platform.machine(), platform.machine()) return os_part, arch_part def _parse_version(self, tag_name: str) -> tuple[int, ...] | None: @@ -196,7 +204,7 @@ def _sort_tags(self, tag_data: list[dict[str, Any]], sort_by: str) -> None: # else: sort_by == "default", keep original order def get_docker_hub_tags( - self, image_name: str, limit: int = 10, architecture: str = "linux/amd64", sort_by: str = "version" + self, image_name: str, limit: int = 10, architecture: str | None = None, sort_by: str = "version" ) -> list[dict[str, Any]]: """Query Docker Hub for image tags with timestamp information. @@ -209,6 +217,9 @@ def get_docker_hub_tags( Returns: list: List of tag dictionaries sorted according to sort_by parameter """ + if architecture is None: + architecture = _default_architecture() + # Parse repository name if "/" in image_name: namespace, repo = image_name.split("/", 1) @@ -299,7 +310,7 @@ def get_registry_tags( registry_url: str, image_name: str, limit: int = 10, - architecture: str = "linux/amd64", + architecture: str | None = None, sort_by: str = "version", ) -> list[dict[str, Any]]: """Query a registry API v2 for image tags and attempt to get creation time. @@ -314,6 +325,9 @@ def get_registry_tags( Returns: list: List of tag dictionaries sorted according to sort_by parameter """ + if architecture is None: + architecture = _default_architecture() + url: str = f"{registry_url}/v2/{image_name}/tags/list" try: response = requests.get(url, timeout=REGISTRY_REQUEST_TIMEOUT) @@ -626,7 +640,7 @@ def get_most_specific_tag(self, args: argparse.Namespace) -> dict[str, Any] | No def main() -> None: parser = argparse.ArgumentParser(description="Operations on container image tags") parser.add_argument("--registry", help="Registry URL (defaults to Docker Hub if not specified)") - parser.add_argument("--architecture", default="linux/amd64", help="Architecture to query for (default: linux/amd64)") + parser.add_argument("--architecture", default=_default_architecture(), help="Architecture to query for (default: auto-detected)") parser.add_argument("--quiet", action="store_true", help="Only output final results, no status or progress messages") subparsers = parser.add_subparsers(dest="command", help="Command to execute", required=True) diff --git a/scripts/infra-mcp/utils/constants.py b/scripts/infra-mcp/utils/constants.py index 471a51ef..274b83d1 100644 --- a/scripts/infra-mcp/utils/constants.py +++ b/scripts/infra-mcp/utils/constants.py @@ -3,6 +3,8 @@ This module centralizes magic numbers and configuration values used throughout the codebase. """ +import platform as _platform + # HTTP Request Timeouts (in seconds) DEFAULT_REQUEST_TIMEOUT = 10 REGISTRY_REQUEST_TIMEOUT = 30 @@ -13,7 +15,9 @@ DEFAULT_SAME_HASH_LIMIT = 100 # Container Architecture -DEFAULT_CONTAINER_ARCHITECTURE = "linux/amd64" + +_arch_map = {"x86_64": "amd64", "aarch64": "arm64", "armv7l": "arm"} +DEFAULT_CONTAINER_ARCHITECTURE = f"linux/{_arch_map.get(_platform.machine(), _platform.machine())}" # Task Execution TASK_COMMAND_TIMEOUT = 600 # 10 minutes in seconds diff --git a/scripts/infra-mcp/utils/models.py b/scripts/infra-mcp/utils/models.py index 4225afdc..3bd634c3 100644 --- a/scripts/infra-mcp/utils/models.py +++ b/scripts/infra-mcp/utils/models.py @@ -3,7 +3,15 @@ This module contains dataclass definitions for shared data structures used throughout the codebase. """ -from dataclasses import dataclass +import platform +from dataclasses import dataclass, field + +_arch_map = {"x86_64": "amd64", "aarch64": "arm64", "armv7l": "arm"} + + +def _default_architecture() -> str: + arch = _arch_map.get(platform.machine(), platform.machine()) + return f"linux/{arch}" @dataclass @@ -20,7 +28,7 @@ class ContainerTagFinderArgs: """ image: str - architecture: str = "linux/amd64" + architecture: str = field(default_factory=_default_architecture) limit: int = 10 quiet: bool = True registry: str | None = None