From 5b26d91f83fe003659eb4a8888199b9ca7585094 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Sat, 6 Jun 2026 13:37:35 +0530 Subject: [PATCH 01/15] fix: replace ipcalc with ansible.utils.ipaddr filter --- .../tasks/validate_network_spec.yml | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/prepare_oim/roles/prepare_oim_validation/tasks/validate_network_spec.yml b/prepare_oim/roles/prepare_oim_validation/tasks/validate_network_spec.yml index 622f633d61..3779f7767f 100644 --- a/prepare_oim/roles/prepare_oim_validation/tasks/validate_network_spec.yml +++ b/prepare_oim/roles/prepare_oim_validation/tasks/validate_network_spec.yml @@ -79,14 +79,22 @@ success_msg: "{{ admin_nic_ip_success_msg }}" when: fetch_oim_hostname.stdout in oim_hostname -- name: Compute network address using ipcalc - ansible.builtin.command: "/usr/bin/ipcalc -n {{ admin_nic_ip }}/{{ admin_netmask_bits }}" - register: network_address_output - changed_when: false +# - name: Compute network address using ipcalc +# ansible.builtin.command: "/usr/bin/ipcalc -n {{ admin_nic_ip }}/{{ admin_netmask_bits }}" +# register: network_address_output +# changed_when: false + +# - name: Extract network address +# ansible.builtin.set_fact: +# admin_net_addr: "{{ network_address_output.stdout.split('=')[1] }}" + +- name: Compute network address + ansible.builtin.set_fact: + network_address: "{{ (admin_nic_ip + '/' + (admin_netmask_bits | string)) | ansible.utils.ipaddr('network') }}" -- name: Extract network address +- name: Set admin_net_addr from computed network address ansible.builtin.set_fact: - admin_net_addr: "{{ network_address_output.stdout.split('=')[1] }}" + admin_net_addr: "{{ network_address }}" - name: Initialize network_interface_type ansible.builtin.set_fact: From b7352c2b11d5d70f91058a278717e4d51aff6e7c Mon Sep 17 00:00:00 2001 From: Sayuri Date: Sun, 7 Jun 2026 11:59:25 +0530 Subject: [PATCH 02/15] fix: make update-ca-trust and CA trust paths OS-aware for Wolfi compatibility --- .../library/module_utils/local_repo/config.py | 13 ++++++++++- .../pulp/tasks/create_pulp_config_https.yml | 23 ++++++++++++++++++- .../deploy_containers/pulp/vars/main.yml | 1 - .../tasks/create_k8s_config_nfs.yml | 23 ++++++++++++++++++- provision/roles/k8s_config/vars/main.yml | 1 - 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/common/library/module_utils/local_repo/config.py b/common/library/module_utils/local_repo/config.py index 5a8d4a63f5..9d6a407fcc 100644 --- a/common/library/module_utils/local_repo/config.py +++ b/common/library/module_utils/local_repo/config.py @@ -134,7 +134,18 @@ ISO_TIMEOUT_MIN = 45 # minutes TASK_POLL_INTERVAL = 10 # seconds FILE_URI = "/pulp/api/v3/content/file/files/" -PULP_SSL_CA_CERT = "/etc/pki/ca-trust/source/anchors/pulp_webserver.crt" + +import os + +def _get_ca_cert_path(): + """Return CA cert path based on OS. Fedora/RHEL vs Wolfi/Debian.""" + rhel_path = "/etc/pki/ca-trust/source/anchors/pulp_webserver.crt" + wolfi_path = "/usr/local/share/ca-certificates/pulp_webserver.crt" + if os.path.exists("/etc/pki/ca-trust/source/anchors"): + return rhel_path + return wolfi_path + +PULP_SSL_CA_CERT = _get_ca_cert_path() # ---------------------------- # Used by download_image.py # ---------------------------- diff --git a/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml b/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml index f015f6ce74..0127f8e905 100644 --- a/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml +++ b/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml @@ -108,15 +108,36 @@ state: file loop: "{{ cert_items.values() }}" + - name: Detect CA trust anchors directory + ansible.builtin.set_fact: + ca_trust_anchors_dir: >- + {{ '/etc/pki/ca-trust/source/anchors' + if ansible_facts['os_family'] | default('') in ['RedHat', 'Fedora'] + else '/usr/local/share/ca-certificates' }} + when: ca_trust_anchors_dir is not defined + + - name: Set anchors path + ansible.builtin.set_fact: + ca_trust_path: "{{ ca_trust_anchors_dir }}/pulp_webserver.crt" + when: ca_trust_path is not defined + - name: Copy Pulp crt to container trust ansible.builtin.copy: src: "{{ pulp_cert_src }}" dest: "{{ ca_trust_path }}" mode: "{{ logs_dir_permission }}" + - name: Detect CA trust update command + ansible.builtin.set_fact: + ca_trust_cmd: >- + {{ 'update-ca-trust extract' + if ansible_facts['os_family'] | default('') in ['RedHat', 'Fedora'] + else 'update-ca-certificates' }} + when: ca_trust_cmd is not defined + - name: Add Pulp Certificate to TrustStore ansible.builtin.command: - cmd: update-ca-trust extract + cmd: "{{ ca_trust_cmd }}" changed_when: false - name: Create a track file diff --git a/prepare_oim/roles/deploy_containers/pulp/vars/main.yml b/prepare_oim/roles/deploy_containers/pulp/vars/main.yml index da17b168d3..d352bfc2e0 100644 --- a/prepare_oim/roles/deploy_containers/pulp/vars/main.yml +++ b/prepare_oim/roles/deploy_containers/pulp/vars/main.yml @@ -138,7 +138,6 @@ generate_cert_cmd: > -addext {{ cert_san }} pulp_cert_src: "/opt/omnia/pulp/settings/certs/pulp_webserver.crt" -ca_trust_path: "/etc/pki/ca-trust/source/anchors/" # Usage: reload_pulp_nginx.yml nginx_reload_cmd: "nginx -s reload" diff --git a/provision/roles/k8s_config/tasks/create_k8s_config_nfs.yml b/provision/roles/k8s_config/tasks/create_k8s_config_nfs.yml index 47a48f976d..624417ff36 100644 --- a/provision/roles/k8s_config/tasks/create_k8s_config_nfs.yml +++ b/provision/roles/k8s_config/tasks/create_k8s_config_nfs.yml @@ -200,6 +200,19 @@ nfs_subdir_external_provisioner_pkg: "{{ k8s_packages_json['service_kube_control_plane_first']['cluster'] | selectattr('type', 'equalto', 'tarball') | selectattr('package', 'search', 'nfs-subdir-external-provisioner') | map(attribute='package') | join }}" # noqa: yaml[line-length] whereabouts_pkg: "{{ k8s_packages_json['service_kube_control_plane_first']['cluster'] | selectattr('type', 'equalto', 'git') | selectattr('package', 'search', 'whereabouts') | map(attribute='package') | join }}" # noqa: yaml[line-length] +- name: Detect CA trust anchors directory + ansible.builtin.set_fact: + ca_trust_anchors_dir: >- + {{ '/etc/pki/ca-trust/source/anchors' + if ansible_facts['os_family'] | default('') in ['RedHat', 'Fedora'] + else '/usr/local/share/ca-certificates' }} + when: ca_trust_anchors_dir is not defined + +- name: Set anchors path + ansible.builtin.set_fact: + anchors_path: "{{ ca_trust_anchors_dir }}/pulp_webserver.crt" + when: anchors_path is not defined + - name: Copy pulp webserver certificate to target host ansible.builtin.copy: src: "{{ pulp_webserver_cert_path }}" @@ -207,8 +220,16 @@ mode: "{{ file_mode }}" become: true +- name: Detect CA trust update command + ansible.builtin.set_fact: + ca_trust_cmd: >- + {{ 'update-ca-trust' + if ansible_facts['os_family'] | default('') in ['RedHat', 'Fedora'] + else 'update-ca-certificates' }} + when: ca_trust_cmd is not defined + - name: Update CA trust on target host - ansible.builtin.command: update-ca-trust + ansible.builtin.command: "{{ ca_trust_cmd }}" register: update_ca changed_when: false diff --git a/provision/roles/k8s_config/vars/main.yml b/provision/roles/k8s_config/vars/main.yml index c949564d70..baa9583d29 100644 --- a/provision/roles/k8s_config/vars/main.yml +++ b/provision/roles/k8s_config/vars/main.yml @@ -27,7 +27,6 @@ whereabouts_git_url: "{{ offline_git_path }}/{{ whereabouts_pkg }}/{{ whereabout file_mode: "0644" ha_config_file: "{{ input_project_dir }}/high_availability_config.yml" pulp_webserver_cert_path: "/opt/omnia/pulp/settings/certs/pulp_webserver.crt" -anchors_path: "/etc/pki/ca-trust/source/anchors/pulp_webserver.crt" # Usage: create_node_dir.yml nodes_yaml: "{{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami/workdir/nodes/nodes.yaml" From 6529f1ae7b7c5d7b544a2f8d0d668dc24455cba5 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Sun, 7 Jun 2026 13:05:29 +0530 Subject: [PATCH 03/15] fix: ca directory issue --- .../pulp/tasks/create_pulp_config_https.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml b/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml index 0127f8e905..d057d6e346 100644 --- a/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml +++ b/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml @@ -121,6 +121,12 @@ ca_trust_path: "{{ ca_trust_anchors_dir }}/pulp_webserver.crt" when: ca_trust_path is not defined + - name: Ensure CA trust directory exists + ansible.builtin.file: + path: "{{ ca_trust_anchors_dir }}" + state: directory + mode: '0755' + - name: Copy Pulp crt to container trust ansible.builtin.copy: src: "{{ pulp_cert_src }}" From 6e7e4a2b6f3d4a05e0e2899806d74e008b3145e8 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Tue, 9 Jun 2026 11:47:00 +0530 Subject: [PATCH 04/15] Configured pulp as fallback to download RHEL packages --- .../library/module_utils/local_repo/config.py | 1 + .../module_utils/local_repo/download_rpm.py | 277 ++++++++++++------ .../tasks/create_metadata.yml | 14 + .../tasks/process_rpm_repo.yml | 7 + .../roles/validation/tasks/prerequisites.yml | 7 + .../pulp/tasks/create_pulp_config_https.yml | 63 +++- 6 files changed, 277 insertions(+), 92 deletions(-) diff --git a/common/library/module_utils/local_repo/config.py b/common/library/module_utils/local_repo/config.py index 9d6a407fcc..3ac531779e 100644 --- a/common/library/module_utils/local_repo/config.py +++ b/common/library/module_utils/local_repo/config.py @@ -86,6 +86,7 @@ "x86_64": ["dnf", "info", "--quiet"], "aarch64": ["dnf", "info", "--quiet", "--forcearch=aarch64"] } +PULP_RPM_PACKAGES_API = "/pulp/api/v3/content/rpm/packages/" # ---------------------------- # Cleanup File Types diff --git a/common/library/module_utils/local_repo/download_rpm.py b/common/library/module_utils/local_repo/download_rpm.py index e6fe9603a2..1af2c4ea9d 100644 --- a/common/library/module_utils/local_repo/download_rpm.py +++ b/common/library/module_utils/local_repo/download_rpm.py @@ -18,17 +18,91 @@ import subprocess import os import glob +import json import shutil from pathlib import Path from ansible.module_utils.local_repo.config import ( DNF_COMMANDS, - DNF_INFO_COMMANDS + DNF_INFO_COMMANDS, + PULP_RPM_PACKAGES_API ) from multiprocessing import Lock from ansible.module_utils.local_repo.parse_and_download import write_status_to_file, _prefix_repo_name_with_arch file_lock = Lock() + +def _is_dnf_available(): + """Check if dnf binary is available on the system.""" + return shutil.which('dnf') is not None + + +def _pulp_cmd(cmd_string, logger=None): + """Run a pulp CLI command and return parsed JSON output, or None on failure.""" + result = subprocess.run(cmd_string, shell=True, check=False, capture_output=True, text=True) + if result.returncode != 0: + if logger: + logger.debug(f"Pulp command failed: {cmd_string}, stderr: {result.stderr}") + return None + try: + return json.loads(result.stdout) + except (json.JSONDecodeError, ValueError): + return None + + +def _pulp_get_repo_version(repo_name, logger): + """Get latest_version_href for a Pulp RPM repository.""" + data = _pulp_cmd(f"pulp rpm repository show --name {repo_name}", logger) + if isinstance(data, dict): + return data.get("latest_version_href", "") + return "" + + +def _pulp_find_package(pkg_name, repo_name, logger): + """Find RPM package in a Pulp repository. Returns package info dict or None.""" + version_href = _pulp_get_repo_version(repo_name, logger) + if not version_href: + return None + api_url = f"{PULP_RPM_PACKAGES_API}?name={pkg_name}&repository_version={version_href}&limit=1" + data = _pulp_cmd(f"pulp show --href '{api_url}'", logger) + if isinstance(data, dict) and data.get("count", 0) > 0: + return data.get("results", [None])[0] + if isinstance(data, list) and len(data) > 0: + return data[0] + return None + + +def _pulp_validate_package(pkg_name, repo_name, logger): + """Check if package exists in Pulp repo (replaces dnf info).""" + return _pulp_find_package(pkg_name, repo_name, logger) is not None + + +def _pulp_download_rpm(pkg_name, repo_name, rpm_directory, logger): + """Download a single RPM from Pulp distribution (replaces dnf download).""" + pkg_info = _pulp_find_package(pkg_name, repo_name, logger) + if not pkg_info: + logger.error(f"Package '{pkg_name}' not found in Pulp repo '{repo_name}'") + return False + location_href = pkg_info.get("location_href", "") + if not location_href: + logger.error(f"No location_href for package '{pkg_name}'") + return False + dist_data = _pulp_cmd(f"pulp rpm distribution show --name {repo_name}", logger) + if not isinstance(dist_data, dict) or not dist_data.get("base_url"): + logger.error(f"Could not get distribution URL for '{repo_name}'") + return False + base_url = dist_data["base_url"].rstrip("/") + download_url = f"{base_url}/{location_href}" + logger.info(f"Downloading '{pkg_name}' from {download_url}") + dl_result = subprocess.run( + ["wget", "-c", "-q", "--no-check-certificate", "-P", rpm_directory, download_url], + check=False, capture_output=True, text=True + ) + if dl_result.returncode == 0 or _check_rpm_downloaded(rpm_directory, pkg_name): + return True + logger.error(f"wget failed for '{pkg_name}': {dl_result.stderr}") + return False + def _check_rpm_downloaded(rpm_directory, pkg_name): """ Check if an RPM file for the given package exists in the directory. @@ -100,86 +174,107 @@ def process_rpm(package, repo_store_path, status_file_path, cluster_os_type, arch_key = "x86_64" if arc.lower() in ("x86_64") else "aarch64" - # First try to download all at once - dnf_download_command = ( - DNF_COMMANDS[arch_key] - + [f"--destdir={rpm_directory}"] - + rpm_list - ) - - result = subprocess.run( - dnf_download_command, - check=False, - capture_output=True, - text=True - ) - logger.info(f"Return code {result.returncode}") - logger.debug(f"STDOUT:\n{result.stdout}") - logger.debug(f"STDERR:\n{result.stderr}") - - stdout_lines = result.stdout.splitlines() - stderr_lines = result.stderr.splitlines() - downloaded = [] failed = [] - # Detect successes/failures from combined run - # Use filesystem check instead of parsing output (works with both DNF4 and DNF5) - for pkg in rpm_list: - # Get repo_name for this specific RPM from mapping - pkg_repo_name = repo_mapping.get(pkg, "") + if _is_dnf_available(): + # First try to download all at once + dnf_download_command = ( + DNF_COMMANDS[arch_key] + + [f"--destdir={rpm_directory}"] + + rpm_list + ) - # Check if package was downloaded by looking for the RPM file - pkg_downloaded = _check_rpm_downloaded(rpm_directory, pkg) - - # Also check for "No match for argument" or "No package" errors in stderr - pkg_not_found = False - for line in stderr_lines: - if pkg in line and ("No match for argument" in line or - "No package" in line or - "not found" in line.lower()): - pkg_not_found = True - break - - if pkg_downloaded and not pkg_not_found: - downloaded.append(pkg) - write_status_to_file(status_file_path, pkg, "rpm", "Success", logger, file_lock, pkg_repo_name) - logger.info(f"Package '{pkg}' downloaded successfully.") - else: - failed.append(pkg) - if pkg_not_found: - logger.warning(f"Package '{pkg}' not found in configured repositories") - - # Retry failed ones individually - if failed: - logger.warning(f"Retrying failed packages individually: {failed}") - for pkg in failed[:]: - cmd = DNF_COMMANDS[arch_key] + [f'--destdir={rpm_directory}', pkg] - retry_res = subprocess.run(cmd, check=False, capture_output=True, text=True) + result = subprocess.run( + dnf_download_command, + check=False, + capture_output=True, + text=True + ) + logger.info(f"Return code {result.returncode}") + logger.debug(f"STDOUT:\n{result.stdout}") + logger.debug(f"STDERR:\n{result.stderr}") + + stdout_lines = result.stdout.splitlines() + stderr_lines = result.stderr.splitlines() + + # Detect successes/failures from combined run + # Use filesystem check instead of parsing output (works with both DNF4 and DNF5) + for pkg in rpm_list: # Get repo_name for this specific RPM from mapping pkg_repo_name = repo_mapping.get(pkg, "") - # Check for package not found errors - retry_stderr = retry_res.stderr.lower() - pkg_invalid = any(err in retry_stderr for err in [ - "no match for argument", - "no package", - "not found", - "unable to find a match" - ]) - - # Check if RPM file exists after retry (works with both DNF4 and DNF5) - if retry_res.returncode == 0 and _check_rpm_downloaded(rpm_directory, pkg): + # Check if package was downloaded by looking for the RPM file + pkg_downloaded = _check_rpm_downloaded(rpm_directory, pkg) + + # Also check for "No match for argument" or "No package" errors in stderr + pkg_not_found = False + for line in stderr_lines: + if pkg in line and ("No match for argument" in line or + "No package" in line or + "not found" in line.lower()): + pkg_not_found = True + break + + if pkg_downloaded and not pkg_not_found: downloaded.append(pkg) - failed.remove(pkg) write_status_to_file(status_file_path, pkg, "rpm", "Success", logger, file_lock, pkg_repo_name) - logger.info(f"Package '{pkg}' downloaded successfully on retry.") + logger.info(f"Package '{pkg}' downloaded successfully.") else: - write_status_to_file(status_file_path, pkg, "rpm", "Failed", logger, file_lock, pkg_repo_name) - if pkg_invalid: - logger.error(f"Package '{pkg}' does not exist in configured repositories.") + failed.append(pkg) + if pkg_not_found: + logger.warning(f"Package '{pkg}' not found in configured repositories") + + # Retry failed ones individually + if failed: + logger.warning(f"Retrying failed packages individually: {failed}") + for pkg in failed[:]: + cmd = DNF_COMMANDS[arch_key] + [f'--destdir={rpm_directory}', pkg] + retry_res = subprocess.run(cmd, check=False, capture_output=True, text=True) + # Get repo_name for this specific RPM from mapping + pkg_repo_name = repo_mapping.get(pkg, "") + + # Check for package not found errors + retry_stderr = retry_res.stderr.lower() + pkg_invalid = any(err in retry_stderr for err in [ + "no match for argument", + "no package", + "not found", + "unable to find a match" + ]) + + # Check if RPM file exists after retry (works with both DNF4 and DNF5) + if retry_res.returncode == 0 and _check_rpm_downloaded(rpm_directory, pkg): + downloaded.append(pkg) + failed.remove(pkg) + write_status_to_file(status_file_path, pkg, "rpm", "Success", logger, file_lock, pkg_repo_name) + logger.info(f"Package '{pkg}' downloaded successfully on retry.") + else: + write_status_to_file(status_file_path, pkg, "rpm", "Failed", logger, file_lock, pkg_repo_name) + if pkg_invalid: + logger.error(f"Package '{pkg}' does not exist in configured repositories.") + else: + logger.error(f"Package '{pkg}' still failed after retry.") + + else: + # Pulp-based download (dnf not available, e.g. Wolfi container) + logger.info("dnf not available, using Pulp CLI for RPM download") + for pkg in rpm_list: + pkg_repo_name = repo_mapping.get(pkg, "") + if pkg_repo_name: + prefixed_repo_name = _prefix_repo_name_with_arch(pkg_repo_name, status_file_path, logger) + if _pulp_download_rpm(pkg, prefixed_repo_name, rpm_directory, logger): + downloaded.append(pkg) + write_status_to_file(status_file_path, pkg, "rpm", "Success", logger, file_lock, pkg_repo_name) + logger.info(f"Package '{pkg}' downloaded successfully via Pulp.") else: - logger.error(f"Package '{pkg}' still failed after retry.") + failed.append(pkg) + write_status_to_file(status_file_path, pkg, "rpm", "Failed", logger, file_lock, pkg_repo_name) + logger.error(f"Package '{pkg}' download failed via Pulp.") + else: + failed.append(pkg) + logger.warning(f"No repo_name mapping for package '{pkg}', cannot download via Pulp") + write_status_to_file(status_file_path, pkg, "rpm", "Failed", logger, file_lock, "") # Determine final status if not failed: @@ -191,35 +286,47 @@ def process_rpm(package, repo_store_path, status_file_path, cluster_os_type, else: logger.info("RPM won't be downloaded when repo_config is partial or never") - logger.info("Validating package availability using dnf info...") arch_key = "x86_64" if arc.lower() in ("x86_64") else "aarch64" valid_packages = [] invalid_packages = [] + use_dnf = _is_dnf_available() + + if use_dnf: + logger.info("Validating package availability using dnf info...") + else: + logger.info("dnf not available, validating package availability using Pulp CLI...") for pkg in package["rpm_list"]: # Get repo_name for this specific RPM from mapping pkg_repo_name = repo_mapping.get(pkg, "") - # Validate package using dnf info with specific repo only - if pkg_repo_name: - # Apply architecture prefixing if needed - prefixed_repo_name = _prefix_repo_name_with_arch(pkg_repo_name, status_file_path, logger) + if not pkg_repo_name: + # Skip validation if no specific repo is defined + logger.warning(f"No repo_name defined for package '{pkg}', skipping validation") + continue + + # Apply architecture prefixing if needed + prefixed_repo_name = _prefix_repo_name_with_arch(pkg_repo_name, status_file_path, logger) + + if use_dnf: + # Validate package using dnf info with specific repo dnf_info_command = DNF_INFO_COMMANDS[arch_key] + [ f"--repo={prefixed_repo_name}", # Search specific repo from JSON pkg ] + result = subprocess.run( + dnf_info_command, + check=False, + capture_output=True, + text=True + ) + pkg_exists = result.returncode == 0 else: - # Skip validation if no specific repo is defined - logger.warning(f"No repo_name defined for package '{pkg}', skipping validation") - continue - result = subprocess.run( - dnf_info_command, - check=False, - capture_output=True, - text=True - ) - if result.returncode == 0: + # Validate package using Pulp CLI + pkg_exists = _pulp_validate_package(pkg, prefixed_repo_name, logger) + + if pkg_exists: # Package exists and is available valid_packages.append(pkg) write_status_to_file( diff --git a/local_repo/roles/parse_and_download/tasks/create_metadata.yml b/local_repo/roles/parse_and_download/tasks/create_metadata.yml index c994f225dc..54eaea6cc9 100644 --- a/local_repo/roles/parse_and_download/tasks/create_metadata.yml +++ b/local_repo/roles/parse_and_download/tasks/create_metadata.yml @@ -15,6 +15,13 @@ - name: Clean DNF cache ansible.builtin.command: dnf clean all changed_when: false + when: ansible_facts['pkg_mgr'] | default('') in ['dnf', 'dnf4', 'dnf5', 'yum'] + +- name: Clean apk cache + ansible.builtin.command: apk cache clean + changed_when: false + failed_when: false + when: ansible_facts['pkg_mgr'] | default('') == 'apk' - name: Remove pulp.repo if exists ansible.builtin.file: @@ -25,6 +32,13 @@ ansible.builtin.dnf: update_cache: true changed_when: false + when: ansible_facts['pkg_mgr'] | default('') in ['dnf', 'dnf4', 'dnf5', 'yum'] + +- name: Regenerate apk package index + community.general.apk: + update_cache: true + changed_when: false + when: ansible_facts['pkg_mgr'] | default('') == 'apk' - name: Check for data folder existence ansible.builtin.stat: diff --git a/local_repo/roles/parse_and_download/tasks/process_rpm_repo.yml b/local_repo/roles/parse_and_download/tasks/process_rpm_repo.yml index 166e6f8784..78de31f50e 100644 --- a/local_repo/roles/parse_and_download/tasks/process_rpm_repo.yml +++ b/local_repo/roles/parse_and_download/tasks/process_rpm_repo.yml @@ -43,3 +43,10 @@ ansible.builtin.dnf: update_cache: true changed_when: false + when: ansible_facts['pkg_mgr'] | default('') in ['dnf', 'dnf4', 'dnf5', 'yum'] + +- name: Regenerate apk package index + community.general.apk: + update_cache: true + changed_when: false + when: ansible_facts['pkg_mgr'] | default('') == 'apk' diff --git a/local_repo/roles/validation/tasks/prerequisites.yml b/local_repo/roles/validation/tasks/prerequisites.yml index a969bce84e..de6c5ffac8 100644 --- a/local_repo/roles/validation/tasks/prerequisites.yml +++ b/local_repo/roles/validation/tasks/prerequisites.yml @@ -25,3 +25,10 @@ loop: - "{{ ['max_parallel_downloads', dnf_max_parallel] }}" - "{{ ['strict', 'False'] }}" + when: ansible_facts['pkg_mgr'] | default('') in ['dnf', 'dnf4', 'dnf5', 'yum'] + +- name: Refresh apk package index + community.general.apk: + update_cache: true + changed_when: false + when: ansible_facts['pkg_mgr'] | default('') == 'apk' diff --git a/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml b/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml index d057d6e346..8b228e8860 100644 --- a/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml +++ b/prepare_oim/roles/deploy_containers/pulp/tasks/create_pulp_config_https.yml @@ -133,18 +133,67 @@ dest: "{{ ca_trust_path }}" mode: "{{ logs_dir_permission }}" - - name: Detect CA trust update command + - name: Change group ownership of SSL certificate and key + ansible.builtin.file: + path: "{{ item }}" + group: pulp + state: file + loop: "{{ cert_items.values() }}" + + # ── CA Trust: OS-aware cert installation ──────────────────────────────── + # Fedora/RHEL: use update-ca-trust (native command exists) + # Wolfi/Other: directly append cert to system CA bundle (no command exists) + + - name: Detect CA trust anchors directory ansible.builtin.set_fact: - ca_trust_cmd: >- - {{ 'update-ca-trust extract' + ca_trust_anchors_dir: >- + {{ '/etc/pki/ca-trust/source/anchors' if ansible_facts['os_family'] | default('') in ['RedHat', 'Fedora'] - else 'update-ca-certificates' }} - when: ca_trust_cmd is not defined + else '/usr/local/share/ca-certificates' }} + when: ca_trust_anchors_dir is not defined + + - name: Set anchors path + ansible.builtin.set_fact: + ca_trust_path: "{{ ca_trust_anchors_dir }}/pulp_webserver.crt" + when: ca_trust_path is not defined - - name: Add Pulp Certificate to TrustStore + - name: Ensure CA trust directory exists + ansible.builtin.file: + path: "{{ ca_trust_anchors_dir }}" + state: directory + mode: '0755' + + - name: Copy Pulp crt to container trust + ansible.builtin.copy: + src: "{{ pulp_cert_src }}" + dest: "{{ ca_trust_path }}" + mode: "{{ logs_dir_permission }}" + + - name: Add Pulp Certificate to TrustStore (RHEL/Fedora) ansible.builtin.command: - cmd: "{{ ca_trust_cmd }}" + cmd: update-ca-trust extract + changed_when: false + when: ansible_facts['os_family'] | default('') in ['RedHat', 'Fedora'] + + - name: Add Pulp Certificate to TrustStore (Wolfi/Other) + ansible.builtin.shell: | + cat "{{ ca_trust_path }}" >> /etc/ssl/certs/ca-certificates.crt changed_when: false + when: ansible_facts['os_family'] | default('') not in ['RedHat', 'Fedora'] + + # ── End CA Trust ──────────────────────────────────────────────────────── + + - name: Create a track file + ansible.builtin.file: + path: "{{ track_file_path }}" + state: touch + mode: "{{ logs_dir_permission }}" + + - name: Record current timestamp in track file + ansible.builtin.copy: + dest: "{{ track_file_path }}" + content: "Timestamp: {{ ansible_date_time.iso8601 }}" + mode: "{{ logs_dir_permission }}" - name: Create a track file ansible.builtin.file: From 7c2fb62f42a7f7c1fbf8cdf9798fb1bb554066f2 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Sat, 27 Jun 2026 17:57:28 +0530 Subject: [PATCH 05/15] Misc: Ubuntu Support --- .../tasks/build_compute_image.yml | 2 +- .../roles/image_creation/vars/main.yml | 6 +- .../roles/prepare_arm_node/vars/main.yml | 2 +- .../tasks/build_compute_image.yml | 2 +- .../roles/image_creation/vars/main.yml | 8 +- .../input_validation/common_utils/config.py | 5 +- .../common_utils/en_us_validation_msg.py | 4 +- .../schema/local_repo_config.json | 108 ++++++++++++++++ .../schema/software_config.json | 2 +- .../validation_flows/common_validation.py | 13 +- .../library/module_utils/local_repo/config.py | 47 +++++++ .../module_utils/local_repo/download_rpm.py | 58 +++++---- .../module_utils/local_repo/software_utils.py | 76 +++++++---- common/library/modules/parallel_tasks.py | 4 +- common/library/modules/process_rpm_config.py | 98 +++++++++++---- ...late_sles_16.0_x86-64_software_config.json | 35 ++++++ ...e_ubuntu_26.04_x86-64_software_config.json | 35 ++++++ .../aarch64/rhel/10.0/slurm_custom.json | 1 - .../sles/16.0/additional_packages.json | 27 ++++ .../sles/16.0/admin_debug_packages.json | 56 +++++++++ .../aarch64/sles/16.0/default_packages.json | 39 ++++++ input/config/aarch64/sles/16.0/ldms.json | 10 ++ input/config/aarch64/sles/16.0/openldap.json | 10 ++ input/config/aarch64/sles/16.0/openmpi.json | 14 +++ .../aarch64/sles/16.0/slurm_custom.json | 49 ++++++++ input/config/aarch64/sles/16.0/ucx.json | 12 ++ .../ubuntu/26.04/additional_packages.json | 27 ++++ .../ubuntu/26.04/admin_debug_packages.json | 52 ++++++++ .../ubuntu/26.04/default_packages.json | 41 ++++++ input/config/aarch64/ubuntu/26.04/ldms.json | 10 ++ .../config/aarch64/ubuntu/26.04/openldap.json | 10 ++ .../config/aarch64/ubuntu/26.04/openmpi.json | 14 +++ .../aarch64/ubuntu/26.04/slurm_custom.json | 48 +++++++ input/config/aarch64/ubuntu/26.04/ucx.json | 12 ++ .../x86_64/rhel/10.0/service_k8s_v1.35.1.json | 1 - .../config/x86_64/rhel/10.0/slurm_custom.json | 1 - .../x86_64/sles/16.0/additional_packages.json | 47 +++++++ .../sles/16.0/admin_debug_packages.json | 56 +++++++++ .../sles/16.0/csi_driver_powerscale.json | 89 +++++++++++++ .../x86_64/sles/16.0/default_packages.json | 39 ++++++ input/config/x86_64/sles/16.0/ldms.json | 10 ++ input/config/x86_64/sles/16.0/openldap.json | 10 ++ input/config/x86_64/sles/16.0/openmpi.json | 14 +++ .../x86_64/sles/16.0/service_k8s_v1.35.1.json | 117 +++++++++++++++++ .../config/x86_64/sles/16.0/slurm_custom.json | 50 ++++++++ input/config/x86_64/sles/16.0/ucx.json | 12 ++ .../ubuntu/26.04/additional_packages.json | 47 +++++++ .../ubuntu/26.04/admin_debug_packages.json | 52 ++++++++ .../ubuntu/26.04/csi_driver_powerscale.json | 89 +++++++++++++ .../x86_64/ubuntu/26.04/default_packages.json | 41 ++++++ input/config/x86_64/ubuntu/26.04/ldms.json | 10 ++ .../config/x86_64/ubuntu/26.04/openldap.json | 10 ++ input/config/x86_64/ubuntu/26.04/openmpi.json | 14 +++ .../ubuntu/26.04/service_k8s_v1.35.1.json | 118 ++++++++++++++++++ .../x86_64/ubuntu/26.04/slurm_custom.json | 49 ++++++++ input/config/x86_64/ubuntu/26.04/ucx.json | 12 ++ input/local_repo_config.yml | 102 ++++++++++++++- input_validation/validate_config.yml | 8 +- .../tasks/process_rpm_repo.yml | 2 +- local_repo/roles/validation/vars/main.yml | 10 +- provision/{changed: | 0 61 files changed, 1849 insertions(+), 98 deletions(-) create mode 100644 examples/software_config_template/template_sles_16.0_x86-64_software_config.json create mode 100644 examples/software_config_template/template_ubuntu_26.04_x86-64_software_config.json create mode 100644 input/config/aarch64/sles/16.0/additional_packages.json create mode 100644 input/config/aarch64/sles/16.0/admin_debug_packages.json create mode 100644 input/config/aarch64/sles/16.0/default_packages.json create mode 100644 input/config/aarch64/sles/16.0/ldms.json create mode 100644 input/config/aarch64/sles/16.0/openldap.json create mode 100644 input/config/aarch64/sles/16.0/openmpi.json create mode 100644 input/config/aarch64/sles/16.0/slurm_custom.json create mode 100644 input/config/aarch64/sles/16.0/ucx.json create mode 100644 input/config/aarch64/ubuntu/26.04/additional_packages.json create mode 100644 input/config/aarch64/ubuntu/26.04/admin_debug_packages.json create mode 100644 input/config/aarch64/ubuntu/26.04/default_packages.json create mode 100644 input/config/aarch64/ubuntu/26.04/ldms.json create mode 100644 input/config/aarch64/ubuntu/26.04/openldap.json create mode 100644 input/config/aarch64/ubuntu/26.04/openmpi.json create mode 100644 input/config/aarch64/ubuntu/26.04/slurm_custom.json create mode 100644 input/config/aarch64/ubuntu/26.04/ucx.json create mode 100644 input/config/x86_64/sles/16.0/additional_packages.json create mode 100644 input/config/x86_64/sles/16.0/admin_debug_packages.json create mode 100644 input/config/x86_64/sles/16.0/csi_driver_powerscale.json create mode 100644 input/config/x86_64/sles/16.0/default_packages.json create mode 100644 input/config/x86_64/sles/16.0/ldms.json create mode 100644 input/config/x86_64/sles/16.0/openldap.json create mode 100644 input/config/x86_64/sles/16.0/openmpi.json create mode 100644 input/config/x86_64/sles/16.0/service_k8s_v1.35.1.json create mode 100644 input/config/x86_64/sles/16.0/slurm_custom.json create mode 100644 input/config/x86_64/sles/16.0/ucx.json create mode 100644 input/config/x86_64/ubuntu/26.04/additional_packages.json create mode 100644 input/config/x86_64/ubuntu/26.04/admin_debug_packages.json create mode 100644 input/config/x86_64/ubuntu/26.04/csi_driver_powerscale.json create mode 100644 input/config/x86_64/ubuntu/26.04/default_packages.json create mode 100644 input/config/x86_64/ubuntu/26.04/ldms.json create mode 100644 input/config/x86_64/ubuntu/26.04/openldap.json create mode 100644 input/config/x86_64/ubuntu/26.04/openmpi.json create mode 100644 input/config/x86_64/ubuntu/26.04/service_k8s_v1.35.1.json create mode 100644 input/config/x86_64/ubuntu/26.04/slurm_custom.json create mode 100644 input/config/x86_64/ubuntu/26.04/ucx.json create mode 100644 provision/{changed: diff --git a/build_image_aarch64/roles/image_creation/tasks/build_compute_image.yml b/build_image_aarch64/roles/image_creation/tasks/build_compute_image.yml index 0ca77db3df..f2ac1e176d 100644 --- a/build_image_aarch64/roles/image_creation/tasks/build_compute_image.yml +++ b/build_image_aarch64/roles/image_creation/tasks/build_compute_image.yml @@ -62,7 +62,7 @@ podman run --rm --device /dev/fuse --network host \ -e S3_ACCESS={{ s3_access }} -e S3_SECRET={{ s3_secret }} \ {{ aws_checksum_env }} --user 0 --privileged \ - -v {{ pulp_cert_host_path }}:/etc/pki/ca-trust/source/anchors/pulp_webserver.crt:z \ + -v {{ pulp_cert_host_path }}:/usr/local/share/ca-certificates/pulp_webserver.crt:z \ -v {{ openchami_work_dir }}/images/rhel-{{ item.key }}{{ compute_image_suffix }}-{{ rhel_tag }}.yaml:/home/builder/config.yaml:z \ {{ ochami_aarch64_image | join(' ') }} \ {{ ochami_base_command | join(' ') }} \ diff --git a/build_image_aarch64/roles/image_creation/vars/main.yml b/build_image_aarch64/roles/image_creation/vars/main.yml index 97773fd26c..d8cf7bcbaa 100644 --- a/build_image_aarch64/roles/image_creation/vars/main.yml +++ b/build_image_aarch64/roles/image_creation/vars/main.yml @@ -25,17 +25,17 @@ job_async: "7200" openchami_work_dir: "{{ oim_shared_path }}/omnia/openchami/workdir" ochami_mounts: - --user 0 --privileged - - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/etc/pki/ca-trust/source/anchors/pulp_webserver.crt:z + - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/usr/local/share/ca-certificates/pulp_webserver.crt:z - -v {{ openchami_work_dir }}/images/{{ rhel_aarch64_base_image_name }}-{{ rhel_tag }}.yaml:/home/builder/config.yaml:z ochami_compute_mounts: - --user 0 --privileged - - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/etc/pki/ca-trust/source/anchors/pulp_webserver.crt:z + - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/usr/local/share/ca-certificates/pulp_webserver.crt:z - -v {{ openchami_work_dir }}/images/{{ rhel_base_compute_image_name }}-{{ rhel_tag }}.yaml:/home/builder/config.yaml:z ochami_aarch64_image: - --entrypoint /bin/bash - "localhost/{{ aarch64_local_tag }}" ochami_base_command: - - -c 'update-ca-trust extract && image-build --config /home/builder/config.yaml --log-level DEBUG' + - -c 'update-ca-certificates && image-build --config /home/builder/config.yaml --log-level DEBUG' # Usage: build_base_image.yml diff --git a/build_image_aarch64/roles/prepare_arm_node/vars/main.yml b/build_image_aarch64/roles/prepare_arm_node/vars/main.yml index 26426b6026..c58188b927 100644 --- a/build_image_aarch64/roles/prepare_arm_node/vars/main.yml +++ b/build_image_aarch64/roles/prepare_arm_node/vars/main.yml @@ -15,7 +15,7 @@ # input files input_project_dir: "{{ hostvars['localhost']['input_project_dir'] }}" -pulp_aarch64_image_name: "dellhpcomniaaisolution/image-build-aarch64:1.1" +pulp_aarch64_image_name: "dellhpcomniaaisolution/image-build-wolfi-aarch64:1.1" aarch64_local_tag: "aarch64-image-builder/ochami" pull_image_retries: "5" pull_image_delay: "10" diff --git a/build_image_x86_64/roles/image_creation/tasks/build_compute_image.yml b/build_image_x86_64/roles/image_creation/tasks/build_compute_image.yml index 84f6a2b063..6d2c54b695 100644 --- a/build_image_x86_64/roles/image_creation/tasks/build_compute_image.yml +++ b/build_image_x86_64/roles/image_creation/tasks/build_compute_image.yml @@ -58,7 +58,7 @@ podman run --rm --device /dev/fuse --network host \ -e S3_ACCESS={{ s3_access }} -e S3_SECRET={{ s3_secret }} \ {{ aws_checksum_env }} --user 0 --privileged \ - -v {{ pulp_cert_host_path }}:/etc/pki/ca-trust/source/anchors/pulp_webserver.crt:z \ + -v {{ pulp_cert_host_path }}:/usr/local/share/ca-certificates/pulp_webserver.crt:z \ -v {{ openchami_work_dir }}/images/rhel-{{ item.key }}{{ compute_image_suffix }}-{{ rhel_tag }}.yaml:/home/builder/config.yaml:z \ {{ ochami_x86_64_image | join(' ') }} \ {{ ochami_base_command | join(' ') }} \ diff --git a/build_image_x86_64/roles/image_creation/vars/main.yml b/build_image_x86_64/roles/image_creation/vars/main.yml index 84785d385b..c7117d45e6 100644 --- a/build_image_x86_64/roles/image_creation/vars/main.yml +++ b/build_image_x86_64/roles/image_creation/vars/main.yml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. --- -pulp_x86_64_image_name: "dellhpcomniaaisolution/image-build-el10:1.1" +pulp_x86_64_image_name: "dellhpcomniaaisolution/image-build-wolfi:1.1" x86_64_local_tag: "x86_64-image-builder/ochami" pull_image_retries: "5" pull_image_delay: "10" @@ -29,18 +29,18 @@ anchors_path: "/etc/pki/ca-trust/source/anchors/pulp_webserver.crt" openchami_work_dir: "{{ oim_shared_path }}/omnia/openchami/workdir" ochami_mounts: - --user 0 --privileged - - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/etc/pki/ca-trust/source/anchors/pulp_webserver.crt:z + - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/usr/local/share/ca-certificates/pulp_webserver.crt:z - -v {{ openchami_work_dir }}/images/{{ rhel_x86_64_base_image_name }}-{{ rhel_tag }}.yaml:/home/builder/config.yaml:z ochami_compute_mounts: - --user 0 --privileged - - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/etc/pki/ca-trust/source/anchors/pulp_webserver.crt:z + - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/usr/local/share/ca-certificates/pulp_webserver.crt:z - -v {{ openchami_work_dir }}/images/{{ rhel_base_compute_image_name }}-{{ rhel_tag }}.yaml:/home/builder/config.yaml:z ochami_x86_64_image: - --entrypoint /bin/bash - "localhost/{{ x86_64_local_tag }}" ochami_base_command: - - -c 'update-ca-trust extract && image-build --config /home/builder/config.yaml --log-level DEBUG' + - -c 'update-ca-certificates && image-build --config /home/builder/config.yaml --log-level DEBUG' # build_base_image.yml openchami_log_dir: "{{ oim_shared_path }}/omnia/log/openchami" diff --git a/common/library/module_utils/input_validation/common_utils/config.py b/common/library/module_utils/input_validation/common_utils/config.py index 9240080e1b..1984a1bae9 100644 --- a/common/library/module_utils/input_validation/common_utils/config.py +++ b/common/library/module_utils/input_validation/common_utils/config.py @@ -164,8 +164,9 @@ os_version_ranges = { "rhel": ["10.0", "10.1"], + "ubuntu": ["26.04"], + "sles": ["16.0"], #"rocky": ["9.4"], - #"ubuntu": ["20.04", "22.04", "24.04"] } @@ -175,6 +176,8 @@ "rpm_list": ["package_list", "repo_name"], "rpm_file": ["package", "url"], "rpm_repo": ["package", "repo_name"], + "deb": ["package", "repo_name"], + "deb_repo": ["package", "repo_name"], "ansible_galaxy_collection": ["package", "version"], "git": ["package", "version", "url"], "image": ["package", ["tag", "digest"]], # Special: one of tag or digest diff --git a/common/library/module_utils/input_validation/common_utils/en_us_validation_msg.py b/common/library/module_utils/input_validation/common_utils/en_us_validation_msg.py index 305e743809..94d92562cb 100644 --- a/common/library/module_utils/input_validation/common_utils/en_us_validation_msg.py +++ b/common/library/module_utils/input_validation/common_utils/en_us_validation_msg.py @@ -208,7 +208,7 @@ "Please redeploy omnia core container with NFS share path option " "or remove aarch64 nodes from pxe_mapping_file.csv." ) -CLUSTER_OS_FAIL_MSG = "Cluster OS must be 'rhel' for RHEL Omnia Infrastructure Manager" +CLUSTER_OS_FAIL_MSG = "Cluster OS must be 'rhel', 'ubuntu', or 'sles'" # local_repo.yml REPO_STORE_PATH_MSG = "Please provide a valid repo_store_path value." @@ -498,7 +498,7 @@ def boolean_fail_msg(value): def os_version_fail_msg(cluster_os_type, min_version, max_version): """Returns a formatted message indicating os_version_fail_msg.""" - if cluster_os_type == "ubuntu": + if max_version: return (f"For OS type '{cluster_os_type}', the version must be either {min_version} or " f"{max_version}.") return f"For OS type '{cluster_os_type}', the supported version is {min_version}." diff --git a/common/library/module_utils/input_validation/schema/local_repo_config.json b/common/library/module_utils/input_validation/schema/local_repo_config.json index 587851d0b3..49ef818c4d 100644 --- a/common/library/module_utils/input_validation/schema/local_repo_config.json +++ b/common/library/module_utils/input_validation/schema/local_repo_config.json @@ -1414,6 +1414,114 @@ ] }, "description": "Optional configuration for overriding policy and caching settings for RHEL subscription-based repositories on aarch64 architecture." + }, + "ubuntu_os_url_x86_64": { + "type": ["array", "null"], + "items": { + "type": "object", + "properties": { + "url": { "type": "string", "minLength": 1 }, + "gpgkey": { "type": "string" }, + "name": { "type": "string", "minLength": 1 } + }, + "required": ["url", "name"] + }, + "description": "Ubuntu OS repository URLs for x86_64 architecture." + }, + "ubuntu_os_url_aarch64": { + "type": ["array", "null"], + "items": { + "type": "object", + "properties": { + "url": { "type": "string", "minLength": 1 }, + "gpgkey": { "type": "string" }, + "name": { "type": "string", "minLength": 1 } + }, + "required": ["url", "name"] + }, + "description": "Ubuntu OS repository URLs for aarch64 architecture." + }, + "sles_os_url_x86_64": { + "type": ["array", "null"], + "items": { + "type": "object", + "properties": { + "url": { "type": "string", "minLength": 1 }, + "gpgkey": { "type": "string" }, + "name": { "type": "string", "minLength": 1 } + }, + "required": ["url", "name"] + }, + "description": "SLES OS repository URLs for x86_64 architecture." + }, + "sles_os_url_aarch64": { + "type": ["array", "null"], + "items": { + "type": "object", + "properties": { + "url": { "type": "string", "minLength": 1 }, + "gpgkey": { "type": "string" }, + "name": { "type": "string", "minLength": 1 } + }, + "required": ["url", "name"] + }, + "description": "SLES OS repository URLs for aarch64 architecture." + }, + "omnia_repo_url_ubuntu_x86_64": { + "type": ["array", "null"], + "items": { + "type": "object", + "properties": { + "url": { "type": "string", "minLength": 1 }, + "gpgkey": { "type": "string" }, + "name": { "type": "string", "minLength": 1 }, + "policy": { "enum": ["always", "partial", "never"] } + }, + "required": ["url", "gpgkey", "name"] + }, + "description": "URLs for repositories from which packages will be downloaded for Omnia features on Ubuntu x86_64." + }, + "omnia_repo_url_ubuntu_aarch64": { + "type": ["array", "null"], + "items": { + "type": "object", + "properties": { + "url": { "type": "string", "minLength": 1 }, + "gpgkey": { "type": "string" }, + "name": { "type": "string", "minLength": 1 }, + "policy": { "enum": ["always", "partial", "never"] } + }, + "required": ["url", "gpgkey", "name"] + }, + "description": "URLs for repositories from which packages will be downloaded for Omnia features on Ubuntu aarch64." + }, + "omnia_repo_url_sles_x86_64": { + "type": ["array", "null"], + "items": { + "type": "object", + "properties": { + "url": { "type": "string", "minLength": 1 }, + "gpgkey": { "type": "string" }, + "name": { "type": "string", "minLength": 1 }, + "policy": { "enum": ["always", "partial", "never"] } + }, + "required": ["url", "gpgkey", "name"] + }, + "description": "URLs for repositories from which packages will be downloaded for Omnia features on SLES x86_64." + }, + "omnia_repo_url_sles_aarch64": { + "type": ["array", "null"], + "items": { + "type": "object", + "properties": { + "url": { "type": "string", "minLength": 1 }, + "gpgkey": { "type": "string" }, + "name": { "type": "string", "minLength": 1 }, + "policy": { "enum": ["always", "partial", "never"] } + }, + "required": ["url", "gpgkey", "name"] + }, + "description": "URLs for repositories from which packages will be downloaded for Omnia features on SLES aarch64." } }, "required": [ diff --git a/common/library/module_utils/input_validation/schema/software_config.json b/common/library/module_utils/input_validation/schema/software_config.json index cc398eb0c3..f8e01e12c1 100644 --- a/common/library/module_utils/input_validation/schema/software_config.json +++ b/common/library/module_utils/input_validation/schema/software_config.json @@ -4,7 +4,7 @@ "properties": { "cluster_os_type": { "type": "string", - "enum": [ "rhel" ], + "enum": [ "rhel", "ubuntu", "sles" ], "description": "Specifies the type of operating system for the cluster." }, "cluster_os_version": { diff --git a/common/library/module_utils/input_validation/validation_flows/common_validation.py b/common/library/module_utils/input_validation/validation_flows/common_validation.py index c3bed411d2..c46333b5bd 100644 --- a/common/library/module_utils/input_validation/validation_flows/common_validation.py +++ b/common/library/module_utils/input_validation/validation_flows/common_validation.py @@ -111,7 +111,18 @@ def validate_software_config( "cluster_os_version", cluster_os_version, en_us_validation_msg.os_version_fail_msg( - cluster_os_type, version_range[0], version_range[1] + cluster_os_type, ", ".join(version_range), None + ), + ) + ) + elif cluster_os_type.lower() == "sles": + if cluster_os_version not in version_range: + errors.append( + create_error_msg( + "cluster_os_version", + cluster_os_version, + en_us_validation_msg.os_version_fail_msg( + cluster_os_type, ", ".join(version_range), None ), ) ) diff --git a/common/library/module_utils/local_repo/config.py b/common/library/module_utils/local_repo/config.py index 3ac531779e..de8e67b8c3 100644 --- a/common/library/module_utils/local_repo/config.py +++ b/common/library/module_utils/local_repo/config.py @@ -87,6 +87,7 @@ "aarch64": ["dnf", "info", "--quiet", "--forcearch=aarch64"] } PULP_RPM_PACKAGES_API = "/pulp/api/v3/content/rpm/packages/" +PULP_DEB_PACKAGES_API = "/pulp/api/v3/content/deb/packages/" # ---------------------------- # Cleanup File Types @@ -228,6 +229,52 @@ def _get_ca_cert_path(): "update_distribution_repo_config": "pulp rpm distribution update --name %s --generate-repo-config" } +# Map Ubuntu version to release codename for APT repos +UBUNTU_CODENAME_MAP = { + "26.04": "plucky", + "25.10": "questing", + "24.04": "noble", + "22.04": "jammy", + "20.04": "focal", +} + +pulp_deb_commands = { + "create_repository": "pulp deb repository create --name %s", + "pulp_cleanup": "pulp orphan cleanup", + "show_repository": "pulp deb repository show --name %s", + "create_remote": "pulp deb remote create --name %s --url %s --policy %s", + "show_remote": "pulp deb remote show --name %s", + "update_remote": "pulp deb remote update --name %s --url %s --policy %s", + "sync_repository": "pulp deb repository sync --name %s --remote %s", + "publish_repository": "pulp deb publication -t verbatim create --repository %s", + "distribute_repository": "pulp deb distribution create --name %s --base-path %s --repository %s", + "update_distribution": "pulp deb distribution update --name %s --base-path %s --repository %s", + "create_remote_cert": "pulp deb remote create --name %s --url %s --policy %s --ca-cert %s --client-cert %s --client-key %s", + "update_remote_cert": "pulp deb remote update --name %s --url %s --policy %s --ca-cert %s --client-cert %s --client-key %s", + "check_distribution": "pulp deb distribution show --name %s", + "delete_repository": "pulp deb repository destroy --name %s", + "delete_remote": "pulp deb remote destroy --name %s", + "delete_distribution": "pulp deb distribution destroy --name %s", + "list_publications": "pulp deb publication list --repository %s --limit 1000", + "update_distribution_publication": "pulp deb distribution update --name %s --publication %s", + "check_publication": "pulp deb publication list --repository %s --limit 1000", + "delete_publication": "pulp deb publication destroy --href %s", + "get_repo_version": "pulp deb repository show --name %s", + "list_repositories": "pulp deb repository list --limit 1000", + "list_remotes": "pulp deb remote list --limit 1000", + "list_distributions": "pulp deb distribution list --limit 1000", + "orphan_cleanup": "pulp orphan cleanup --protection-time 0", + "list_all_publications": "pulp deb publication list --limit 1000", + "upload_content": "pulp deb content upload --repository %s --file %s", + "update_distribution_repo_config": "pulp deb distribution update --name %s" +} + +def get_pulp_commands(cluster_os_type): + """Return the appropriate Pulp command set based on the cluster OS type.""" + if cluster_os_type in ("ubuntu",): + return pulp_deb_commands + return pulp_rpm_commands + # ---------------------------- # Pulp Cleanup Configuration # Used by pulp_cleanup.py and Ansible modules diff --git a/common/library/module_utils/local_repo/download_rpm.py b/common/library/module_utils/local_repo/download_rpm.py index 1af2c4ea9d..960442983f 100644 --- a/common/library/module_utils/local_repo/download_rpm.py +++ b/common/library/module_utils/local_repo/download_rpm.py @@ -24,7 +24,9 @@ from ansible.module_utils.local_repo.config import ( DNF_COMMANDS, DNF_INFO_COMMANDS, - PULP_RPM_PACKAGES_API + PULP_RPM_PACKAGES_API, + PULP_DEB_PACKAGES_API, + get_pulp_commands ) from multiprocessing import Lock from ansible.module_utils.local_repo.parse_and_download import write_status_to_file, _prefix_repo_name_with_arch @@ -50,21 +52,28 @@ def _pulp_cmd(cmd_string, logger=None): return None -def _pulp_get_repo_version(repo_name, logger): - """Get latest_version_href for a Pulp RPM repository.""" - data = _pulp_cmd(f"pulp rpm repository show --name {repo_name}", logger) +def _pulp_get_repo_version(repo_name, logger, cluster_os_type="rhel"): + """Get latest_version_href for a Pulp repository.""" + cmds = get_pulp_commands(cluster_os_type) + data = _pulp_cmd(cmds["show_repository"] % repo_name, logger) if isinstance(data, dict): return data.get("latest_version_href", "") return "" -def _pulp_find_package(pkg_name, repo_name, logger): - """Find RPM package in a Pulp repository. Returns package info dict or None.""" - version_href = _pulp_get_repo_version(repo_name, logger) +def _pulp_find_package(pkg_name, repo_name, logger, cluster_os_type="rhel"): + """Find package in a Pulp repository. Returns package info dict or None.""" + version_href = _pulp_get_repo_version(repo_name, logger, cluster_os_type) if not version_href: return None - api_url = f"{PULP_RPM_PACKAGES_API}?name={pkg_name}&repository_version={version_href}&limit=1" + packages_api = PULP_DEB_PACKAGES_API if cluster_os_type == "ubuntu" else PULP_RPM_PACKAGES_API + name_field = "package" if cluster_os_type == "ubuntu" else "name" + api_url = f"{packages_api}?{name_field}={pkg_name}&repository_version={version_href}&limit=1" + if logger: + logger.info(f"Pulp package query: pulp show --href '{api_url}'") data = _pulp_cmd(f"pulp show --href '{api_url}'", logger) + if logger: + logger.info(f"Pulp query result for '{pkg_name}': type={type(data).__name__}, data={str(data)[:200]}") if isinstance(data, dict) and data.get("count", 0) > 0: return data.get("results", [None])[0] if isinstance(data, list) and len(data) > 0: @@ -72,22 +81,24 @@ def _pulp_find_package(pkg_name, repo_name, logger): return None -def _pulp_validate_package(pkg_name, repo_name, logger): +def _pulp_validate_package(pkg_name, repo_name, logger, cluster_os_type="rhel"): """Check if package exists in Pulp repo (replaces dnf info).""" - return _pulp_find_package(pkg_name, repo_name, logger) is not None + return _pulp_find_package(pkg_name, repo_name, logger, cluster_os_type) is not None -def _pulp_download_rpm(pkg_name, repo_name, rpm_directory, logger): - """Download a single RPM from Pulp distribution (replaces dnf download).""" - pkg_info = _pulp_find_package(pkg_name, repo_name, logger) +def _pulp_download_rpm(pkg_name, repo_name, rpm_directory, logger, cluster_os_type="rhel"): + """Download a single package from Pulp distribution.""" + pkg_info = _pulp_find_package(pkg_name, repo_name, logger, cluster_os_type) if not pkg_info: logger.error(f"Package '{pkg_name}' not found in Pulp repo '{repo_name}'") return False - location_href = pkg_info.get("location_href", "") + location_field = "relative_path" if cluster_os_type == "ubuntu" else "location_href" + location_href = pkg_info.get(location_field, "") if not location_href: - logger.error(f"No location_href for package '{pkg_name}'") + logger.error(f"No {location_field} for package '{pkg_name}'") return False - dist_data = _pulp_cmd(f"pulp rpm distribution show --name {repo_name}", logger) + cmds = get_pulp_commands(cluster_os_type) + dist_data = _pulp_cmd(cmds["check_distribution"] % repo_name, logger) if not isinstance(dist_data, dict) or not dist_data.get("base_url"): logger.error(f"Could not get distribution URL for '{repo_name}'") return False @@ -165,9 +176,10 @@ def process_rpm(package, repo_store_path, status_file_path, cluster_os_type, sw_json_name = Path(status_file_path).parent.name logger.info(f"Software rpms : {sw_json_name}") + pkg_dir_type = 'deb' if cluster_os_type == 'ubuntu' else 'rpm' rpm_directory = os.path.join( repo_store_path, 'offline_repo', - 'cluster', arc.lower(), cluster_os_type, cluster_os_version, 'rpm', sw_json_name + 'cluster', arc.lower(), cluster_os_type, cluster_os_version, pkg_dir_type, sw_json_name ) logger.info(f"rpm_dir {rpm_directory}") os.makedirs(rpm_directory, exist_ok=True) @@ -177,7 +189,8 @@ def process_rpm(package, repo_store_path, status_file_path, cluster_os_type, downloaded = [] failed = [] - if _is_dnf_available(): + is_deb_os = cluster_os_type in ('ubuntu',) + if _is_dnf_available() and not is_deb_os: # First try to download all at once dnf_download_command = ( DNF_COMMANDS[arch_key] @@ -263,7 +276,7 @@ def process_rpm(package, repo_store_path, status_file_path, cluster_os_type, pkg_repo_name = repo_mapping.get(pkg, "") if pkg_repo_name: prefixed_repo_name = _prefix_repo_name_with_arch(pkg_repo_name, status_file_path, logger) - if _pulp_download_rpm(pkg, prefixed_repo_name, rpm_directory, logger): + if _pulp_download_rpm(pkg, prefixed_repo_name, rpm_directory, logger, cluster_os_type): downloaded.append(pkg) write_status_to_file(status_file_path, pkg, "rpm", "Success", logger, file_lock, pkg_repo_name) logger.info(f"Package '{pkg}' downloaded successfully via Pulp.") @@ -290,12 +303,13 @@ def process_rpm(package, repo_store_path, status_file_path, cluster_os_type, arch_key = "x86_64" if arc.lower() in ("x86_64") else "aarch64" valid_packages = [] invalid_packages = [] - use_dnf = _is_dnf_available() + is_deb_os = cluster_os_type in ('ubuntu',) + use_dnf = _is_dnf_available() and not is_deb_os if use_dnf: logger.info("Validating package availability using dnf info...") else: - logger.info("dnf not available, validating package availability using Pulp CLI...") + logger.info(f"Using Pulp CLI for package validation (os_type={cluster_os_type})...") for pkg in package["rpm_list"]: # Get repo_name for this specific RPM from mapping @@ -324,7 +338,7 @@ def process_rpm(package, repo_store_path, status_file_path, cluster_os_type, pkg_exists = result.returncode == 0 else: # Validate package using Pulp CLI - pkg_exists = _pulp_validate_package(pkg, prefixed_repo_name, logger) + pkg_exists = _pulp_validate_package(pkg, prefixed_repo_name, logger, cluster_os_type) if pkg_exists: # Package exists and is available diff --git a/common/library/module_utils/local_repo/software_utils.py b/common/library/module_utils/local_repo/software_utils.py index 2c8a3b3da0..8149909426 100644 --- a/common/library/module_utils/local_repo/software_utils.py +++ b/common/library/module_utils/local_repo/software_utils.py @@ -28,6 +28,7 @@ from jinja2 import Template import requests from requests.adapters import HTTPAdapter +from ansible.module_utils.local_repo.config import UBUNTU_CODENAME_MAP from urllib3.poolmanager import PoolManager from ansible.module_utils.local_repo.standard_logger import setup_standard_logger from ansible.module_utils.local_repo.common_functions import is_encrypted, process_file, get_arch_from_sw_config @@ -278,12 +279,12 @@ def transform_package_dict(data, arch_val,logger): repo_mapping = {} for item in items: - if item.get("type") in ("rpm", "rpm_repo"): + if item.get("type") in ("rpm", "rpm_repo", "deb", "deb_repo"): rpm_packages.append(item["package"]) # Preserve repo_name if available if "repo_name" in item: repo_mapping[item["package"]] = item["repo_name"] - elif item.get("type") == "rpm_list": + elif item.get("type") in ("rpm_list", "deb_list"): rpm_packages.extend(item["package_list"]) # Preserve repo_mapping if available if "repo_mapping" in item: @@ -371,16 +372,20 @@ def parse_repo_urls(repo_config, local_repo_config_path, for arch in archs_to_process: # Always ensure these are lists - rhel_repo_entry[arch] = list(local_yaml.get(f"rhel_os_url_{arch}") or []) - repo_entries[arch] = list(local_yaml.get(f"omnia_repo_url_rhel_{arch}") or []) + # Use OS-specific repo URL keys based on cluster_os_type + os_url_key = f"{cluster_os_type}_os_url_{arch}" + omnia_url_key = f"omnia_repo_url_{cluster_os_type}_{arch}" + rhel_repo_entry[arch] = list(local_yaml.get(os_url_key) or []) + repo_entries[arch] = list(local_yaml.get(omnia_url_key) or []) user_repo_entry[arch] = list(local_yaml.get(f"user_repo_url_{arch}") or []) + logger.info(f"Using OS repo key '{os_url_key}' and omnia repo key '{omnia_url_key}' for arch '{arch}'") # In case of Subscription, Subscription URLs take precedence if present and non-empty if sub_urls and arch in sub_urls and sub_urls[arch]: - logger.info(f"Subscription URLs detected for arch {arch}. Overriding RHEL URLs.") + logger.info(f"Subscription URLs detected for arch {arch}. Overriding OS URLs.") if not isinstance(rhel_repo_entry.get(arch), list): rhel_repo_entry[arch] = [] rhel_repo_entry[arch] = list(sub_urls[arch]) - logger.info(f" Updated RHEL URLs: {rhel_repo_entry[arch]}") + logger.info(f" Updated OS URLs: {rhel_repo_entry[arch]}") parsed_repos = [] vault_key_path = os.path.join( @@ -420,7 +425,7 @@ def parse_repo_urls(repo_config, local_repo_config_path, return url, False sw_name = build_repo_name(arch, cluster_os_type, cluster_os_version, name) - parsed_repos.append({ + user_entry = { "package": sw_name, "url": url, "gpgkey": gpgkey if gpgkey else "null", @@ -430,7 +435,17 @@ def parse_repo_urls(repo_config, local_repo_config_path, "client_cert": client_cert, "policy": policy, "sw_arch": arch - }) + } + # Add APT metadata for Ubuntu user repos + if cluster_os_type == "ubuntu": + deb_arch = "arm64" if arch == "aarch64" else "amd64" + user_entry["apt_distributions"] = url_.get("apt_distributions", "/") + apt_comp = url_.get("apt_components") + if apt_comp: + user_entry["apt_components"] = apt_comp + user_entry["apt_architectures"] = deb_arch + logger.info(f"APT metadata for user repo '{sw_name}': dist={user_entry['apt_distributions']}, arch={deb_arch}") + parsed_repos.append(user_entry) logger.info(f"Added user repo entry: {sw_name}") @@ -449,9 +464,9 @@ def parse_repo_urls(repo_config, local_repo_config_path, policy_given, caching_given, logger ) - logger.info(f"Processing RHEL repo '{name}' for arch '{arch}' - URL: {url}") - logger.info(f"RHEL SSL paths: ca_cert={ca_cert}, client_key={client_key}, client_cert={client_cert}") - logger.info(f"RHEL SSL files exist: ca_cert={os.path.exists(ca_cert) if ca_cert else 'N/A'}, " + logger.info(f"Processing OS repo '{name}' for arch '{arch}' - URL: {url}") + logger.info(f"OS SSL paths: ca_cert={ca_cert}, client_key={client_key}, client_cert={client_cert}") + logger.info(f"OS SSL files exist: ca_cert={os.path.exists(ca_cert) if ca_cert else 'N/A'}, " f"client_key={os.path.exists(client_key) if client_key else 'N/A'}, " f"client_cert={os.path.exists(client_cert) if client_cert else 'N/A'}") @@ -460,19 +475,19 @@ def parse_repo_urls(repo_config, local_repo_config_path, if path and is_encrypted(path): result, message = process_file(path, vault_key_path, mode) if result is False: - logger.error(f"Decryption failed for RHEL repo path: {path} | Error: {message}") - return f"Error during decrypt for rhel repository path:{path}", False + logger.error(f"Decryption failed for OS repo path: {path} | Error: {message}") + return f"Error during decrypt for OS repository path:{path}", False if not is_remote_url_reachable(url, client_cert=client_cert, client_key=client_key, ca_cert=ca_cert): - logger.error(f"RHEL repo URL unreachable: {url}") + logger.error(f"OS repo URL unreachable: {url}") return url, False # if not is_remote_url_reachable(url): # return url, False sw_name = build_repo_name(arch, cluster_os_type, cluster_os_version, name) - parsed_repos.append({ + repo_entry = { "package": sw_name, "url": url, "gpgkey": gpgkey if gpgkey else "null", @@ -482,8 +497,17 @@ def parse_repo_urls(repo_config, local_repo_config_path, "client_cert": client_cert, "policy": policy, "sw_arch": arch - }) - logger.info(f"Added RHEL repo entry: {sw_name}") + } + # Add APT metadata for Ubuntu OS repos + if cluster_os_type == "ubuntu": + codename = UBUNTU_CODENAME_MAP.get(cluster_os_version, "plucky") + deb_arch = "arm64" if arch == "aarch64" else "amd64" + repo_entry["apt_distributions"] = codename + repo_entry["apt_components"] = name + repo_entry["apt_architectures"] = deb_arch + logger.info(f"APT metadata for OS repo '{sw_name}': dist={codename}, comp={name}, arch={deb_arch}") + parsed_repos.append(repo_entry) + logger.info(f"Added OS repo entry: {sw_name}") # Handle OMNIA repositories seen_urls = set() @@ -547,14 +571,24 @@ def parse_repo_urls(repo_config, local_repo_config_path, version = version_variables[var] break - parsed_repos.append({ + repo_entry = { "package": sw_name, "url": rendered_url, "gpgkey": rendered_gpgkey, "version": version if version else "null", "policy": policy, "sw_arch": arch - }) + } + # Add APT metadata for Ubuntu OMNIA repos + if cluster_os_type == "ubuntu": + deb_arch = "arm64" if arch == "aarch64" else "amd64" + repo_entry["apt_distributions"] = repo.get("apt_distributions", "/") + apt_comp = repo.get("apt_components") + if apt_comp: + repo_entry["apt_components"] = apt_comp + repo_entry["apt_architectures"] = deb_arch + logger.info(f"APT metadata for OMNIA repo '{sw_name}': dist={repo_entry['apt_distributions']}, arch={deb_arch}") + parsed_repos.append(repo_entry) logger.info(f"Added OMNIA repo entry: {sw_name}") logger.info(f"Successfully parsed {len(parsed_repos)} repository entries.") @@ -1004,7 +1038,7 @@ def remove_duplicates_from_trans(trans): if group == "default_packages": # Handle nested rpm_list case for pkg in items: - if pkg.get("type") in ("rpm", "rpm_repo") and "rpm_list" in pkg: + if pkg.get("type") in ("rpm", "rpm_repo", "deb", "deb_repo") and "rpm_list" in pkg: pkg["rpm_list"] = list(dict.fromkeys(pkg["rpm_list"])) continue @@ -1028,7 +1062,7 @@ def remove_duplicates_from_trans(trans): elif type_ == "git": key = (item.get("url"), item.get("version")) - elif type_ in ("rpm", "rpm_repo") and "rpm_list" in item: + elif type_ in ("rpm", "rpm_repo", "deb", "deb_repo") and "rpm_list" in item: item["rpm_list"] = list(dict.fromkeys(item["rpm_list"])) key = item.get("package") diff --git a/common/library/modules/parallel_tasks.py b/common/library/modules/parallel_tasks.py index 48b5d6b5dc..df0cc35ae8 100644 --- a/common/library/modules/parallel_tasks.py +++ b/common/library/modules/parallel_tasks.py @@ -170,7 +170,7 @@ def determine_function( # Build the Pulp repo name once for all non-image/non-rpm task types repo_name = None content_base_dir = None - if task_type not in ("image", "rpm", "rpm_repo"): + if task_type not in ("image", "rpm", "rpm_repo", "deb", "deb_repo"): repo_name = build_task_repo_name( task, arc, cluster_os_type, cluster_os_version, version_variables ) @@ -217,7 +217,7 @@ def determine_function( return process_rpm_file, [ task, status_file, content_base_dir, repo_name ] - if task_type in ("rpm", "rpm_repo"): + if task_type in ("rpm", "rpm_repo", "deb", "deb_repo"): return process_rpm, [ task, repo_store_path, status_file, cluster_os_type, cluster_os_version, repo_config_value, arc diff --git a/common/library/modules/process_rpm_config.py b/common/library/modules/process_rpm_config.py index 34d650d4a3..ccc18c53f2 100644 --- a/common/library/modules/process_rpm_config.py +++ b/common/library/modules/process_rpm_config.py @@ -31,10 +31,28 @@ pulp_rpm_commands, AGGREGATED_REPO_SUFFIX, AGGREGATED_BASE_PATH_TEMPLATE, - PULP_CONCURRENCY + PULP_CONCURRENCY, + get_pulp_commands ) from ansible.module_utils.local_repo.software_utils import build_repo_name + +def _append_apt_params(command, repo, log): + """Append APT-specific params (--distribution, --component, --architecture) to a pulp deb remote command.""" + apt_dist = repo.get("apt_distributions") + if not apt_dist: + return command + command += f" --distribution {apt_dist}" + apt_comp = repo.get("apt_components") + if apt_comp: + command += f" --component {apt_comp}" + apt_arch = repo.get("apt_architectures") + if apt_arch: + command += f" --architecture {apt_arch}" + log.info(f"APT params appended: dist={apt_dist}, comp={apt_comp}, arch={apt_arch}") + return command + + def validate_command_input(value): """ Validates input values to prevent command injection. @@ -145,8 +163,10 @@ def check_repository_synced(repo_name, log): bool: True if repository has synced packages, False otherwise. """ try: + cmd_string = pulp_rpm_commands["show_repository"] % repo_name + cmd_list = shlex.split(cmd_string) result = subprocess.run( - ["pulp", "rpm", "repository", "show", "--name", repo_name], + cmd_list, capture_output=True, text=True, check=True ) repo_info = json.loads(result.stdout) @@ -245,34 +265,40 @@ def create_rpm_remote(repo,log): remote_name = repo_name - # Check if remote already exists - skip if it does - if show_rpm_remote(remote_name, log): - log.info("Remote '%s' already exists. Skipping.", remote_name) - return True, repo_name - - # Remote doesn't exist - create it + remote_exists = show_rpm_remote(remote_name, log) repo_keys = repo.keys() + if "ca_cert" in repo_keys and repo["ca_cert"]: ca_cert = f"@{repo['ca_cert']}" client_cert = f"@{repo['client_cert']}" client_key = f"@{repo['client_key']}" - if not show_rpm_remote(remote_name,log): + if remote_exists: + command = pulp_rpm_commands["update_remote_cert"] % (remote_name, remote_url, policy_type, ca_cert, client_cert, client_key) + command = _append_apt_params(command, repo, log) + log.info("Remote '%s' already exists. Updating with certs.", remote_name) + else: command = pulp_rpm_commands["create_remote_cert"] % (remote_name, remote_url, policy_type, ca_cert, client_cert, client_key) + command = _append_apt_params(command, repo, log) log.info("Remote '%s' does not exist. Executing creation command with certs.", remote_name) - result = execute_command(command,log) - log.info("Remote %s created.", remote_name) + result = execute_command(command, log) + log.info("Remote %s created/updated.", remote_name) else: log.info("Repository does not use SSL certificates for remote") - if not show_rpm_remote(remote_name,log): + if remote_exists: + command = pulp_rpm_commands["update_remote"] % (remote_name, remote_url, policy_type) + command = _append_apt_params(command, repo, log) + log.info("Remote '%s' already exists. Updating.", remote_name) + else: command = pulp_rpm_commands["create_remote"] % (remote_name, remote_url, policy_type) + command = _append_apt_params(command, repo, log) log.info("Remote '%s' does not exist. Executing creation command.", remote_name) - result = execute_command(command,log) - log.info("Remote %s created.", remote_name) - return result, repo_name + result = execute_command(command, log) + log.info("Remote %s created/updated.", remote_name) + return result, repo_name, remote_exists except Exception as e: log.error("Unexpected error while creating remote '%s': %s", repo.get("package", "unknown"), str(e)) - return False, repo.get("package", "unknown") + return False, repo.get("package", "unknown"), False finally: log.info("Completed RPM remote creation process for '%s'", repo.get("package", "unknown")) @@ -343,9 +369,10 @@ def sync_rpm_repository(repo,log, resync_repos=None): if repo_name in resync_list: force_sync = True log.info(f"Force resync enabled for {repo_name}") - else: - #log.info(f"{repo_name} not in resync list. Skipping.") + elif check_repository_synced(repo_name, log): + # Already has content and not in resync list — skip return True, repo_name, False, False # Not actually synced, no version change + # else: not in list but never synced (version 0) — fall through and sync # Check if already synced (skip check if force_sync is True) if not force_sync and check_repository_synced(repo_name, log): @@ -685,11 +712,13 @@ def create_distribution(repo, log, resync_repos=None, cluster_os_version="10.0") version = repo.get("version") sw_arch = repo.get("sw_arch") + cluster_os_type = repo.get("cluster_os_type", "rhel") + pkg_type = "debs" if cluster_os_type == "ubuntu" else "rpms" if version != "null": - base_path = f" opt/omnia/offline_repo/cluster/{sw_arch}/rhel/{cluster_os_version}/rpms/{package_name}/{version}" + base_path = f" opt/omnia/offline_repo/cluster/{sw_arch}/{cluster_os_type}/{cluster_os_version}/{pkg_type}/{package_name}/{version}" repo_name = f"{repo_name}_{version}" else: - base_path = f"opt/omnia/offline_repo/cluster/{sw_arch}/rhel/{cluster_os_version}/rpms/{package_name}" + base_path = f"opt/omnia/offline_repo/cluster/{sw_arch}/{cluster_os_type}/{cluster_os_version}/{pkg_type}/{package_name}" show_command = pulp_rpm_commands["check_distribution"] % repo_name create_command = pulp_rpm_commands["distribute_repository"] % (repo_name, base_path, repo_name) @@ -1215,8 +1244,9 @@ def create_aggregated_distribution(repo_name, base_path, pub_href, log): # Use subprocess with argument list - validated_href is passed as a separate argument # This prevents argument injection as the value is validated against expected format log.info(f"Updating distribution '{dist_name}' with publication href") + update_pub_cmd = pulp_rpm_commands["update_distribution_publication"] % (dist_name, validated_href) update_result = subprocess.run( - ["pulp", "rpm", "distribution", "update", "--name", dist_name, "--publication", validated_href], + shlex.split(update_pub_cmd), shell=False, capture_output=True, text=True ) result = update_result.returncode == 0 @@ -1319,7 +1349,7 @@ def manage_aggregated_repos(additional_repos_config, log, cluster_os_type="rhel" log.info("Completed management of all aggregated repositories") return True, "success" -def manage_rpm_repositories_multiprocess(rpm_config, log, sw_archs=None, resync_repos=None, cluster_os_version="10.0"): +def manage_rpm_repositories_multiprocess(rpm_config, log, sw_archs=None, resync_repos=None, cluster_os_version="10.0", cluster_os_type="rhel"): """ Manage RPM repositories using multiprocessing. @@ -1397,11 +1427,23 @@ def manage_rpm_repositories_multiprocess(rpm_config, log, sw_archs=None, resync_ log.info("Step 2: Starting concurrent RPM remote creation") with multiprocessing.Pool(processes=process) as pool: sync_result = pool.map(partial(create_rpm_remote, log=log), rpm_config) - failed = [name for success, name in sync_result if not success] + failed = [name for success, name, _ in sync_result if not success] if failed: log.error("Failed during creation of RPM remote for: %s", ", ".join(failed)) return False, f"During creation of RPM remote for: {', '.join(failed)}" + # Force resync repos whose remotes were just updated (they may have stale content) + updated_remotes = [name for success, name, was_updated in sync_result if success and was_updated] + if updated_remotes: + log.info("Remotes updated for: %s — forcing resync.", ", ".join(updated_remotes)) + if resync_repos == "all": + pass # Already resyncing everything + elif resync_repos: + existing = resync_repos if isinstance(resync_repos, list) else [r.strip() for r in resync_repos.split(",")] + resync_repos = list(set(existing + updated_remotes)) + else: + resync_repos = updated_remotes + # Step 3: Concurrent synchronization log.info("Step 3: Starting concurrent RPM repository synchronization") with multiprocessing.Pool(processes=pulp_process) as pool: @@ -1430,6 +1472,9 @@ def manage_rpm_repositories_multiprocess(rpm_config, log, sw_archs=None, resync_ # Step 5: Concurrent distribution creation/update log.info("Step 5: Starting concurrent RPM distribution creation/update") log.info(f"Processing distribution for {len(repos_for_pub_dist)} repos") + # Inject cluster_os_type into each repo dict for create_distribution + for repo in repos_for_pub_dist: + repo["cluster_os_type"] = cluster_os_type with multiprocessing.Pool(processes=min(pulp_process, len(repos_for_pub_dist))) as pool: result = pool.map(partial(create_distribution, log=log, resync_repos=resync_repos, cluster_os_version=cluster_os_version), repos_for_pub_dist) failed = [name for success, name in result if not success] @@ -1534,7 +1579,12 @@ def main(): log.info(f"Architectures to process: {sw_archs}") log.info(f"Resync repos setting: {resync_repos}") # Call the function to manage RPM repositories - result, output = manage_rpm_repositories_multiprocess(rpm_config, log, sw_archs, resync_repos, cluster_os_version) + # Select the appropriate Pulp command set based on cluster OS type + global pulp_rpm_commands + pulp_rpm_commands = get_pulp_commands(cluster_os_type) + log.info(f"Using Pulp commands for OS type: {cluster_os_type}") + + result, output = manage_rpm_repositories_multiprocess(rpm_config, log, sw_archs, resync_repos, cluster_os_version, cluster_os_type) if result is False: module.fail_json(msg=f"Error {output}, check {standard_log_path}") diff --git a/examples/software_config_template/template_sles_16.0_x86-64_software_config.json b/examples/software_config_template/template_sles_16.0_x86-64_software_config.json new file mode 100644 index 0000000000..6a10ec6695 --- /dev/null +++ b/examples/software_config_template/template_sles_16.0_x86-64_software_config.json @@ -0,0 +1,35 @@ +{ + "cluster_os_type": "sles", + "cluster_os_version": "16.0", + "repo_config": "partial", + "softwares": [ + {"name": "default_packages", "arch": ["x86_64"]}, + {"name": "admin_debug_packages", "arch": ["x86_64"]}, + {"name": "openldap", "arch": ["x86_64"]}, + {"name": "slurm_custom", "arch": ["x86_64"]}, + {"name": "service_k8s", "version": "1.35.1", "arch": ["x86_64"]}, + {"name": "ldms", "arch": ["x86_64"]}, + {"name": "additional_packages", "arch": ["x86_64"]} + ], + "slurm_custom": [ + {"name": "slurm_control_node"}, + {"name": "slurm_node"}, + {"name": "login_node"}, + {"name": "login_compiler_node"} + ], + "service_k8s": [ + {"name": "service_kube_control_plane_first"}, + {"name": "service_kube_control_plane"}, + {"name": "service_kube_node"} + ], + "additional_packages":[ + {"name": "service_kube_control_plane_first"}, + {"name": "service_kube_control_plane"}, + {"name": "service_kube_node"}, + {"name": "slurm_control_node"}, + {"name": "slurm_node"}, + {"name": "login_node"}, + {"name": "login_compiler_node"}, + {"name": "os"} + ] +} diff --git a/examples/software_config_template/template_ubuntu_26.04_x86-64_software_config.json b/examples/software_config_template/template_ubuntu_26.04_x86-64_software_config.json new file mode 100644 index 0000000000..24af7038f6 --- /dev/null +++ b/examples/software_config_template/template_ubuntu_26.04_x86-64_software_config.json @@ -0,0 +1,35 @@ +{ + "cluster_os_type": "ubuntu", + "cluster_os_version": "26.04", + "repo_config": "partial", + "softwares": [ + {"name": "default_packages", "arch": ["x86_64"]}, + {"name": "admin_debug_packages", "arch": ["x86_64"]}, + {"name": "openldap", "arch": ["x86_64"]}, + {"name": "slurm_custom", "arch": ["x86_64"]}, + {"name": "service_k8s", "version": "1.35.1", "arch": ["x86_64"]}, + {"name": "ldms", "arch": ["x86_64"]}, + {"name": "additional_packages", "arch": ["x86_64"]} + ], + "slurm_custom": [ + {"name": "slurm_control_node"}, + {"name": "slurm_node"}, + {"name": "login_node"}, + {"name": "login_compiler_node"} + ], + "service_k8s": [ + {"name": "service_kube_control_plane_first"}, + {"name": "service_kube_control_plane"}, + {"name": "service_kube_node"} + ], + "additional_packages":[ + {"name": "service_kube_control_plane_first"}, + {"name": "service_kube_control_plane"}, + {"name": "service_kube_node"}, + {"name": "slurm_control_node"}, + {"name": "slurm_node"}, + {"name": "login_node"}, + {"name": "login_compiler_node"}, + {"name": "os"} + ] +} diff --git a/input/config/aarch64/rhel/10.0/slurm_custom.json b/input/config/aarch64/rhel/10.0/slurm_custom.json index ade7d526ce..7e1eb1082a 100644 --- a/input/config/aarch64/rhel/10.0/slurm_custom.json +++ b/input/config/aarch64/rhel/10.0/slurm_custom.json @@ -7,7 +7,6 @@ {"package": "pmix", "type": "rpm", "repo_name": "appstream"}, {"package": "nvcr.io/nvidia/hpc-benchmarks", "tag": "25.09", "type": "image"}, {"package": "apptainer", "type": "rpm", "repo_name": "epel" }, - {"package": "doca-ofed", "type": "rpm_repo", "repo_name": "doca" }, {"package": "iscsi-initiator-utils", "type": "rpm", "repo_name": "baseos"}, {"package": "device-mapper-multipath", "type": "rpm", "repo_name": "baseos"}, {"package": "sg3_utils", "type": "rpm", "repo_name": "baseos"}, diff --git a/input/config/aarch64/sles/16.0/additional_packages.json b/input/config/aarch64/sles/16.0/additional_packages.json new file mode 100644 index 0000000000..2809c294e9 --- /dev/null +++ b/input/config/aarch64/sles/16.0/additional_packages.json @@ -0,0 +1,27 @@ +{ + "additional_packages": { + "cluster": [ + + ] + }, + "slurm_node": { + "cluster": [ + + ] + }, + "login_node": { + "cluster": [ + + ] + }, + "login_compiler_node": { + "cluster": [ + + ] + }, + "os": { + "cluster": [ + + ] + } +} diff --git a/input/config/aarch64/sles/16.0/admin_debug_packages.json b/input/config/aarch64/sles/16.0/admin_debug_packages.json new file mode 100644 index 0000000000..5d9b095c39 --- /dev/null +++ b/input/config/aarch64/sles/16.0/admin_debug_packages.json @@ -0,0 +1,56 @@ +{ + "admin_debug_packages": { + "cluster": [ + {"package": "which", "type": "rpm", "repo_name": "basesystem"}, + {"package": "tcpdump", "type": "rpm", "repo_name": "basesystem"}, + {"package": "traceroute", "type": "rpm", "repo_name": "basesystem"}, + {"package": "iperf3", "type": "rpm", "repo_name": "packagehub"}, + {"package": "fping", "type": "rpm", "repo_name": "packagehub"}, + {"package": "dmidecode", "type": "rpm", "repo_name": "basesystem"}, + {"package": "hwloc", "type": "rpm", "repo_name": "basesystem"}, + {"package": "hwloc-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "lshw", "type": "rpm", "repo_name": "basesystem"}, + {"package": "pciutils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "vim", "type": "rpm", "repo_name": "basesystem"}, + {"package": "emacs", "type": "rpm", "repo_name": "desktop-applications"}, + {"package": "zsh", "type": "rpm", "repo_name": "basesystem"}, + {"package": "openssh", "type": "rpm", "repo_name": "basesystem"}, + {"package": "openssh-server", "type": "rpm", "repo_name": "basesystem"}, + {"package": "openssh-clients", "type": "rpm", "repo_name": "basesystem"}, + {"package": "rsync", "type": "rpm", "repo_name": "basesystem"}, + {"package": "file", "type": "rpm", "repo_name": "basesystem"}, + {"package": "libcurl4", "type": "rpm", "repo_name": "basesystem"}, + {"package": "tar", "type": "rpm", "repo_name": "basesystem"}, + {"package": "bzip2", "type": "rpm", "repo_name": "basesystem"}, + {"package": "man", "type": "rpm", "repo_name": "basesystem"}, + {"package": "man-pages", "type": "rpm", "repo_name": "basesystem"}, + {"package": "strace", "type": "rpm", "repo_name": "basesystem"}, + {"package": "kexec-tools", "type": "rpm", "repo_name": "basesystem"}, + {"package": "libopenssl-devel", "type": "rpm", "repo_name": "basesystem"}, + {"package": "ipmitool", "type": "rpm", "repo_name": "server-applications"}, + {"package": "gdb", "type": "rpm", "repo_name": "development-tools"}, + {"package": "gdbserver", "type": "rpm", "repo_name": "development-tools"}, + {"package": "lldb", "type": "rpm", "repo_name": "development-tools"}, + {"package": "lldb-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "valgrind", "type": "rpm", "repo_name": "development-tools"}, + {"package": "valgrind-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "ltrace", "type": "rpm", "repo_name": "development-tools"}, + {"package": "kernel-default-extra", "type": "rpm", "repo_name": "basesystem"}, + {"package": "perf", "type": "rpm", "repo_name": "basesystem"}, + {"package": "papi", "type": "rpm", "repo_name": "development-tools"}, + {"package": "papi-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "cmake", "type": "rpm", "repo_name": "development-tools"}, + {"package": "make", "type": "rpm", "repo_name": "basesystem"}, + {"package": "autoconf", "type": "rpm", "repo_name": "development-tools"}, + {"package": "automake", "type": "rpm", "repo_name": "development-tools"}, + {"package": "libtool", "type": "rpm", "repo_name": "development-tools"}, + {"package": "gcc", "type": "rpm", "repo_name": "development-tools"}, + {"package": "gcc-c++", "type": "rpm", "repo_name": "development-tools"}, + {"package": "gcc-fortran", "type": "rpm", "repo_name": "development-tools"}, + {"package": "binutils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "binutils-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "clustershell", "type": "rpm", "repo_name": "packagehub"}, + {"package": "bash-completion", "type": "rpm", "repo_name": "basesystem"} + ] + } +} diff --git a/input/config/aarch64/sles/16.0/default_packages.json b/input/config/aarch64/sles/16.0/default_packages.json new file mode 100644 index 0000000000..f4e1cf6f58 --- /dev/null +++ b/input/config/aarch64/sles/16.0/default_packages.json @@ -0,0 +1,39 @@ +{ + "default_packages": { + "cluster": [ + {"package": "systemd", "type": "rpm", "repo_name": "basesystem"}, + {"package": "systemd-udev", "type": "rpm", "repo_name": "basesystem"}, + {"package": "kernel-default", "type": "rpm", "repo_name": "basesystem"}, + {"package": "dracut", "type": "rpm", "repo_name": "basesystem"}, + {"package": "dracut-tools", "type": "rpm", "repo_name": "basesystem"}, + {"package": "squashfs-tools", "type": "rpm", "repo_name": "basesystem"}, + {"package": "nfs-client", "type": "rpm", "repo_name": "basesystem"}, + {"package": "nfs4-acl-tools", "type": "rpm", "repo_name": "basesystem"}, + {"package": "NetworkManager", "type": "rpm", "repo_name": "basesystem"}, + {"package": "iproute2", "type": "rpm", "repo_name": "basesystem"}, + {"package": "iputils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "curl", "type": "rpm", "repo_name": "basesystem"}, + {"package": "bash", "type": "rpm", "repo_name": "basesystem"}, + {"package": "coreutils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "grep", "type": "rpm", "repo_name": "basesystem"}, + {"package": "sed", "type": "rpm", "repo_name": "basesystem"}, + {"package": "gawk", "type": "rpm", "repo_name": "basesystem"}, + {"package": "findutils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "util-linux", "type": "rpm", "repo_name": "basesystem"}, + {"package": "kbd", "type": "rpm", "repo_name": "basesystem"}, + {"package": "lsof", "type": "rpm", "repo_name": "basesystem"}, + {"package": "cryptsetup", "type": "rpm", "repo_name": "basesystem"}, + {"package": "lvm2", "type": "rpm", "repo_name": "basesystem"}, + {"package": "device-mapper", "type": "rpm", "repo_name": "basesystem"}, + {"package": "rsyslog", "type": "rpm", "repo_name": "basesystem"}, + {"package": "chrony", "type": "rpm", "repo_name": "basesystem"}, + {"package": "sudo", "type": "rpm", "repo_name": "basesystem"}, + {"package": "gzip", "type": "rpm", "repo_name": "basesystem"}, + {"package": "wget", "type": "rpm", "repo_name": "basesystem"}, + {"package": "cloud-init", "type": "rpm", "repo_name": "server-applications"}, + {"package": "glibc-locale", "type": "rpm", "repo_name": "basesystem"}, + {"package": "gedit", "type": "rpm", "repo_name": "desktop-applications"}, + {"package": "docker.io/dellhpcomniaaisolution/image-build-aarch64", "tag": "1.1", "type": "image" } + ] + } +} diff --git a/input/config/aarch64/sles/16.0/ldms.json b/input/config/aarch64/sles/16.0/ldms.json new file mode 100644 index 0000000000..90757cf4c5 --- /dev/null +++ b/input/config/aarch64/sles/16.0/ldms.json @@ -0,0 +1,10 @@ +{ + "ldms": { + "cluster": [ + {"package": "python3-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "python3-Cython", "type": "rpm", "repo_name": "development-tools"}, + {"package": "libopenssl3", "type": "rpm", "repo_name": "basesystem"}, + {"package": "ovis-ldms", "type": "rpm", "repo_name": "ldms"} + ] + } +} diff --git a/input/config/aarch64/sles/16.0/openldap.json b/input/config/aarch64/sles/16.0/openldap.json new file mode 100644 index 0000000000..d945837d19 --- /dev/null +++ b/input/config/aarch64/sles/16.0/openldap.json @@ -0,0 +1,10 @@ +{ + "openldap": { + "cluster": [ + {"package": "openldap2-client", "type": "rpm", "repo_name": "basesystem"}, + {"package": "nss-pam-ldapd", "type": "rpm", "repo_name": "basesystem"}, + {"package": "sssd", "type": "rpm", "repo_name": "basesystem"}, + {"package": "pam_mkhomedir", "type": "rpm", "repo_name": "basesystem"} + ] + } +} diff --git a/input/config/aarch64/sles/16.0/openmpi.json b/input/config/aarch64/sles/16.0/openmpi.json new file mode 100644 index 0000000000..7cf1583a8d --- /dev/null +++ b/input/config/aarch64/sles/16.0/openmpi.json @@ -0,0 +1,14 @@ +{ + "openmpi": { + "cluster": [ + { "package": "openmpi", + "type": "tarball", + "url": "https://download.open-mpi.org/release/open-mpi/v{{ openmpi_version.split('.')[:2] | join('.') }}/openmpi-{{ openmpi_version }}.tar.gz" + }, + {"package": "pmix-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "munge-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "gcc-c++", "type": "rpm", "repo_name": "development-tools"}, + {"package": "make", "type": "rpm", "repo_name": "basesystem"} + ] + } +} diff --git a/input/config/aarch64/sles/16.0/slurm_custom.json b/input/config/aarch64/sles/16.0/slurm_custom.json new file mode 100644 index 0000000000..4ea3751af7 --- /dev/null +++ b/input/config/aarch64/sles/16.0/slurm_custom.json @@ -0,0 +1,49 @@ +{ + "slurm_custom": { + "cluster": [ + {"package": "munge", "type": "rpm", "repo_name": "server-applications"}, + {"package": "firewalld", "type": "rpm", "repo_name": "basesystem"}, + {"package": "python3-firewall", "type": "rpm", "repo_name": "basesystem"}, + {"package": "pmix", "type": "rpm", "repo_name": "server-applications"}, + {"package": "nvcr.io/nvidia/hpc-benchmarks", "tag": "25.09", "type": "image"}, + {"package": "apptainer", "type": "rpm", "repo_name": "packagehub" }, + {"package": "open-iscsi", "type": "rpm", "repo_name": "basesystem"}, + {"package": "multipath-tools", "type": "rpm", "repo_name": "basesystem"}, + {"package": "sg3_utils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "lsscsi", "type": "rpm", "repo_name": "basesystem"}, + {"package": "imb", "type": "tarball", "url": "https://github.com/intel/mpi-benchmarks/archive/refs/tags/IMB-v2021.8.tar.gz"}, + {"package": "osu-micro-benchmarks", "type": "tarball", "url": "https://mvapich.cse.ohio-state.edu/download/mvapich/osu-micro-benchmarks-7.5.tar.gz"}, + {"package": "likwid", "type": "tarball", "url": "https://github.com/RRZE-HPC/likwid/archive/refs/tags/v5.4.1.tar.gz"}, + {"package": "geopm", "type": "tarball", "url": "https://github.com/geopm/geopm/archive/refs/tags/v3.1.0.tar.gz"}, + {"package": "papi", "type": "tarball", "url": "https://github.com/icl-utk-edu/papi/releases/download/papi-7-2-0-t/papi-7.2.0.tar.gz"}, + {"package": "sionlib", "type": "tarball", "url": "https://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.7"} + ] + }, + "slurm_control_node": { + "cluster": [ + {"package": "slurm-slurmctld", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "slurm-slurmdbd", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "python3-PyMySQL", "type": "rpm", "repo_name": "server-applications"}, + {"package": "mariadb-server", "type": "rpm", "repo_name": "server-applications"} + ] + }, + "slurm_node": { + "cluster": [ + {"package": "slurm-slurmd", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "slurm-pam_slurm", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "kernel-default-devel", "type": "rpm", "repo_name": "development-tools"} + ] + }, + "login_node":{ + "cluster": [ + {"package": "slurm-slurmd", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "slurm", "type": "rpm", "repo_name": "slurm_custom"} + ] + }, + "login_compiler_node":{ + "cluster": [ + {"package": "slurm", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "slurm-slurmd", "type": "rpm", "repo_name": "slurm_custom"} + ] + } +} diff --git a/input/config/aarch64/sles/16.0/ucx.json b/input/config/aarch64/sles/16.0/ucx.json new file mode 100644 index 0000000000..ac7b203da3 --- /dev/null +++ b/input/config/aarch64/sles/16.0/ucx.json @@ -0,0 +1,12 @@ +{ + "ucx": { + "cluster": [ + { "package": "ucx", + "type": "tarball", + "url": "https://github.com/openucx/ucx/releases/download/v{{ ucx_version }}/ucx-{{ ucx_version }}.tar.gz" + }, + {"package": "gcc-c++", "type": "rpm", "repo_name": "development-tools"}, + {"package": "make", "type": "rpm", "repo_name": "basesystem"} + ] + } +} diff --git a/input/config/aarch64/ubuntu/26.04/additional_packages.json b/input/config/aarch64/ubuntu/26.04/additional_packages.json new file mode 100644 index 0000000000..2809c294e9 --- /dev/null +++ b/input/config/aarch64/ubuntu/26.04/additional_packages.json @@ -0,0 +1,27 @@ +{ + "additional_packages": { + "cluster": [ + + ] + }, + "slurm_node": { + "cluster": [ + + ] + }, + "login_node": { + "cluster": [ + + ] + }, + "login_compiler_node": { + "cluster": [ + + ] + }, + "os": { + "cluster": [ + + ] + } +} diff --git a/input/config/aarch64/ubuntu/26.04/admin_debug_packages.json b/input/config/aarch64/ubuntu/26.04/admin_debug_packages.json new file mode 100644 index 0000000000..dfe6401c99 --- /dev/null +++ b/input/config/aarch64/ubuntu/26.04/admin_debug_packages.json @@ -0,0 +1,52 @@ +{ + "admin_debug_packages": { + "cluster": [ + {"package": "debianutils", "type": "deb", "repo_name": "main"}, + {"package": "tcpdump", "type": "deb", "repo_name": "main"}, + {"package": "traceroute", "type": "deb", "repo_name": "universe"}, + {"package": "iperf3", "type": "deb", "repo_name": "universe"}, + {"package": "fping", "type": "deb", "repo_name": "universe"}, + {"package": "dmidecode", "type": "deb", "repo_name": "main"}, + {"package": "hwloc", "type": "deb", "repo_name": "universe"}, + {"package": "libhwloc15", "type": "deb", "repo_name": "universe"}, + {"package": "lshw", "type": "deb", "repo_name": "main"}, + {"package": "pciutils", "type": "deb", "repo_name": "main"}, + {"package": "vim", "type": "deb", "repo_name": "main"}, + {"package": "emacs", "type": "deb", "repo_name": "universe"}, + {"package": "zsh", "type": "deb", "repo_name": "main"}, + {"package": "openssh-client", "type": "deb", "repo_name": "main"}, + {"package": "openssh-server", "type": "deb", "repo_name": "main"}, + {"package": "rsync", "type": "deb", "repo_name": "main"}, + {"package": "file", "type": "deb", "repo_name": "main"}, + {"package": "libcurl4", "type": "deb", "repo_name": "main"}, + {"package": "tar", "type": "deb", "repo_name": "main"}, + {"package": "bzip2", "type": "deb", "repo_name": "main"}, + {"package": "man-db", "type": "deb", "repo_name": "main"}, + {"package": "manpages", "type": "deb", "repo_name": "main"}, + {"package": "strace", "type": "deb", "repo_name": "main"}, + {"package": "kexec-tools", "type": "deb", "repo_name": "main"}, + {"package": "libssl-dev", "type": "deb", "repo_name": "main"}, + {"package": "ipmitool", "type": "deb", "repo_name": "universe"}, + {"package": "gdb", "type": "deb", "repo_name": "main"}, + {"package": "gdbserver", "type": "deb", "repo_name": "main"}, + {"package": "lldb", "type": "deb", "repo_name": "universe"}, + {"package": "liblldb-dev", "type": "deb", "repo_name": "universe"}, + {"package": "valgrind", "type": "deb", "repo_name": "universe"}, + {"package": "ltrace", "type": "deb", "repo_name": "universe"}, + {"package": "linux-tools-generic", "type": "deb", "repo_name": "main"}, + {"package": "libpapi-dev", "type": "deb", "repo_name": "universe"}, + {"package": "cmake", "type": "deb", "repo_name": "main"}, + {"package": "make", "type": "deb", "repo_name": "main"}, + {"package": "autoconf", "type": "deb", "repo_name": "main"}, + {"package": "automake", "type": "deb", "repo_name": "main"}, + {"package": "libtool", "type": "deb", "repo_name": "main"}, + {"package": "gcc", "type": "deb", "repo_name": "main"}, + {"package": "g++", "type": "deb", "repo_name": "main"}, + {"package": "gfortran", "type": "deb", "repo_name": "main"}, + {"package": "binutils", "type": "deb", "repo_name": "main"}, + {"package": "binutils-dev", "type": "deb", "repo_name": "main"}, + {"package": "clustershell", "type": "deb", "repo_name": "universe"}, + {"package": "bash-completion", "type": "deb", "repo_name": "main"} + ] + } +} diff --git a/input/config/aarch64/ubuntu/26.04/default_packages.json b/input/config/aarch64/ubuntu/26.04/default_packages.json new file mode 100644 index 0000000000..70692e07fa --- /dev/null +++ b/input/config/aarch64/ubuntu/26.04/default_packages.json @@ -0,0 +1,41 @@ +{ + "default_packages": { + "cluster": [ + {"package": "systemd", "type": "deb", "repo_name": "main"}, + {"package": "udev", "type": "deb", "repo_name": "main"}, + {"package": "linux-image-generic", "type": "deb", "repo_name": "main"}, + {"package": "initramfs-tools", "type": "deb", "repo_name": "main"}, + {"package": "live-boot", "type": "deb", "repo_name": "universe"}, + {"package": "initramfs-tools-core", "type": "deb", "repo_name": "main"}, + {"package": "squashfs-tools", "type": "deb", "repo_name": "main"}, + {"package": "nfs-common", "type": "deb", "repo_name": "main"}, + {"package": "nfs4-acl-tools", "type": "deb", "repo_name": "universe"}, + {"package": "network-manager", "type": "deb", "repo_name": "main"}, + {"package": "network-manager-gnome", "type": "deb", "repo_name": "main"}, + {"package": "iproute2", "type": "deb", "repo_name": "main"}, + {"package": "iputils-ping", "type": "deb", "repo_name": "main"}, + {"package": "curl", "type": "deb", "repo_name": "main"}, + {"package": "bash", "type": "deb", "repo_name": "main"}, + {"package": "coreutils", "type": "deb", "repo_name": "main"}, + {"package": "grep", "type": "deb", "repo_name": "main"}, + {"package": "sed", "type": "deb", "repo_name": "main"}, + {"package": "gawk", "type": "deb", "repo_name": "main"}, + {"package": "findutils", "type": "deb", "repo_name": "main"}, + {"package": "util-linux", "type": "deb", "repo_name": "main"}, + {"package": "kbd", "type": "deb", "repo_name": "main"}, + {"package": "lsof", "type": "deb", "repo_name": "main"}, + {"package": "cryptsetup", "type": "deb", "repo_name": "main"}, + {"package": "lvm2", "type": "deb", "repo_name": "main"}, + {"package": "dmsetup", "type": "deb", "repo_name": "main"}, + {"package": "rsyslog", "type": "deb", "repo_name": "main"}, + {"package": "chrony", "type": "deb", "repo_name": "main"}, + {"package": "sudo", "type": "deb", "repo_name": "main"}, + {"package": "gzip", "type": "deb", "repo_name": "main"}, + {"package": "wget", "type": "deb", "repo_name": "main"}, + {"package": "cloud-init", "type": "deb", "repo_name": "main"}, + {"package": "locales", "type": "deb", "repo_name": "main"}, + {"package": "gedit", "type": "deb", "repo_name": "universe"}, + {"package": "docker.io/dellhpcomniaaisolution/image-build-aarch64", "tag": "1.1", "type": "image" } + ] + } +} diff --git a/input/config/aarch64/ubuntu/26.04/ldms.json b/input/config/aarch64/ubuntu/26.04/ldms.json new file mode 100644 index 0000000000..ea2966695b --- /dev/null +++ b/input/config/aarch64/ubuntu/26.04/ldms.json @@ -0,0 +1,10 @@ +{ + "ldms": { + "cluster": [ + {"package": "python3-dev", "type": "deb", "repo_name": "main"}, + {"package": "cython3", "type": "deb", "repo_name": "universe"}, + {"package": "libssl3", "type": "deb", "repo_name": "main"}, + {"package": "ovis-ldms", "type": "deb", "repo_name": "ldms"} + ] + } +} diff --git a/input/config/aarch64/ubuntu/26.04/openldap.json b/input/config/aarch64/ubuntu/26.04/openldap.json new file mode 100644 index 0000000000..a3ef5a64d7 --- /dev/null +++ b/input/config/aarch64/ubuntu/26.04/openldap.json @@ -0,0 +1,10 @@ +{ + "openldap": { + "cluster": [ + {"package": "ldap-utils", "type": "deb", "repo_name": "main"}, + {"package": "libnss-ldapd", "type": "deb", "repo_name": "universe"}, + {"package": "sssd", "type": "deb", "repo_name": "main"}, + {"package": "libpam-mkhomedir", "type": "deb", "repo_name": "main"} + ] + } +} diff --git a/input/config/aarch64/ubuntu/26.04/openmpi.json b/input/config/aarch64/ubuntu/26.04/openmpi.json new file mode 100644 index 0000000000..7e9f66e465 --- /dev/null +++ b/input/config/aarch64/ubuntu/26.04/openmpi.json @@ -0,0 +1,14 @@ +{ + "openmpi": { + "cluster": [ + { "package": "openmpi", + "type": "tarball", + "url": "https://download.open-mpi.org/release/open-mpi/v{{ openmpi_version.split('.')[:2] | join('.') }}/openmpi-{{ openmpi_version }}.tar.gz" + }, + {"package": "libpmix-dev", "type": "deb", "repo_name": "universe"}, + {"package": "libmunge-dev", "type": "deb", "repo_name": "universe"}, + {"package": "g++", "type": "deb", "repo_name": "main"}, + {"package": "make", "type": "deb", "repo_name": "main"} + ] + } +} diff --git a/input/config/aarch64/ubuntu/26.04/slurm_custom.json b/input/config/aarch64/ubuntu/26.04/slurm_custom.json new file mode 100644 index 0000000000..00979e1a1c --- /dev/null +++ b/input/config/aarch64/ubuntu/26.04/slurm_custom.json @@ -0,0 +1,48 @@ +{ + "slurm_custom": { + "cluster": [ + {"package": "munge", "type": "deb", "repo_name": "main"}, + {"package": "ufw", "type": "deb", "repo_name": "main"}, + {"package": "libpmix2", "type": "deb", "repo_name": "universe"}, + {"package": "nvcr.io/nvidia/hpc-benchmarks", "tag": "25.09", "type": "image"}, + {"package": "apptainer", "type": "deb", "repo_name": "universe" }, + {"package": "open-iscsi", "type": "deb", "repo_name": "main"}, + {"package": "multipath-tools", "type": "deb", "repo_name": "main"}, + {"package": "sg3-utils", "type": "deb", "repo_name": "main"}, + {"package": "lsscsi", "type": "deb", "repo_name": "main"}, + {"package": "imb", "type": "tarball", "url": "https://github.com/intel/mpi-benchmarks/archive/refs/tags/IMB-v2021.8.tar.gz"}, + {"package": "osu-micro-benchmarks", "type": "tarball", "url": "https://mvapich.cse.ohio-state.edu/download/mvapich/osu-micro-benchmarks-7.5.tar.gz"}, + {"package": "likwid", "type": "tarball", "url": "https://github.com/RRZE-HPC/likwid/archive/refs/tags/v5.4.1.tar.gz"}, + {"package": "geopm", "type": "tarball", "url": "https://github.com/geopm/geopm/archive/refs/tags/v3.1.0.tar.gz"}, + {"package": "papi", "type": "tarball", "url": "https://github.com/icl-utk-edu/papi/releases/download/papi-7-2-0-t/papi-7.2.0.tar.gz"}, + {"package": "sionlib", "type": "tarball", "url": "https://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.7"} + ] + }, + "slurm_control_node": { + "cluster": [ + {"package": "slurmctld", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "slurmdbd", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "python3-pymysql", "type": "deb", "repo_name": "main"}, + {"package": "mariadb-server", "type": "deb", "repo_name": "universe"} + ] + }, + "slurm_node": { + "cluster": [ + {"package": "slurmd", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "libpam-slurm-adopt", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "linux-headers-generic", "type": "deb", "repo_name": "main"} + ] + }, + "login_node":{ + "cluster": [ + {"package": "slurmd", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "slurm-client", "type": "deb", "repo_name": "slurm_custom"} + ] + }, + "login_compiler_node":{ + "cluster": [ + {"package": "slurm-client", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "slurmd", "type": "deb", "repo_name": "slurm_custom"} + ] + } +} diff --git a/input/config/aarch64/ubuntu/26.04/ucx.json b/input/config/aarch64/ubuntu/26.04/ucx.json new file mode 100644 index 0000000000..3ad9ec8df6 --- /dev/null +++ b/input/config/aarch64/ubuntu/26.04/ucx.json @@ -0,0 +1,12 @@ +{ + "ucx": { + "cluster": [ + { "package": "ucx", + "type": "tarball", + "url": "https://github.com/openucx/ucx/releases/download/v{{ ucx_version }}/ucx-{{ ucx_version }}.tar.gz" + }, + {"package": "g++", "type": "deb", "repo_name": "main"}, + {"package": "make", "type": "deb", "repo_name": "main"} + ] + } +} diff --git a/input/config/x86_64/rhel/10.0/service_k8s_v1.35.1.json b/input/config/x86_64/rhel/10.0/service_k8s_v1.35.1.json index 966a94d7b9..e95258e63a 100644 --- a/input/config/x86_64/rhel/10.0/service_k8s_v1.35.1.json +++ b/input/config/x86_64/rhel/10.0/service_k8s_v1.35.1.json @@ -52,7 +52,6 @@ { "package": "victoria-metrics-operator-0.59.3", "type": "tarball", "url": "https://github.com/VictoriaMetrics/helm-charts/releases/download/victoria-metrics-operator-0.59.3/victoria-metrics-operator-0.59.3.tgz" }, { "package": "docker.io/timberio/vector", "tag": "0.54.0-debian", "type": "image" }, { "package": "apptainer", "type": "rpm", "repo_name": "epel" }, - { "package": "doca-ofed", "type": "rpm_repo", "repo_name": "doca" }, { "package": "iscsi-initiator-utils", "type": "rpm", "repo_name": "baseos" }, { "package": "device-mapper-multipath", "type": "rpm", "repo_name": "baseos" }, { "package": "sg3_utils", "type": "rpm", "repo_name": "baseos" }, diff --git a/input/config/x86_64/rhel/10.0/slurm_custom.json b/input/config/x86_64/rhel/10.0/slurm_custom.json index e2f13ecf68..227aa1d8f2 100644 --- a/input/config/x86_64/rhel/10.0/slurm_custom.json +++ b/input/config/x86_64/rhel/10.0/slurm_custom.json @@ -7,7 +7,6 @@ {"package": "pmix", "type": "rpm", "repo_name": "appstream"}, {"package": "nvcr.io/nvidia/hpc-benchmarks", "tag": "25.09", "type": "image"}, {"package": "apptainer", "type": "rpm", "repo_name": "epel" }, - {"package": "doca-ofed", "type": "rpm_repo", "repo_name": "doca" }, {"package": "iscsi-initiator-utils", "type": "rpm", "repo_name": "baseos"}, {"package": "device-mapper-multipath", "type": "rpm", "repo_name": "baseos"}, {"package": "sg3_utils", "type": "rpm", "repo_name": "baseos"}, diff --git a/input/config/x86_64/sles/16.0/additional_packages.json b/input/config/x86_64/sles/16.0/additional_packages.json new file mode 100644 index 0000000000..7cc4f60a9f --- /dev/null +++ b/input/config/x86_64/sles/16.0/additional_packages.json @@ -0,0 +1,47 @@ +{ + "additional_packages": { + "cluster": [ + + ] + }, + "service_kube_control_plane_first": { + "cluster": [ + + ] + }, + "service_kube_control_plane": { + "cluster": [ + + ] + }, + "service_kube_node": { + "cluster": [ + + ] + }, + "slurm_control_node": { + "cluster": [ + + ] + }, + "slurm_node": { + "cluster": [ + + ] + }, + "login_node": { + "cluster": [ + + ] + }, + "login_compiler_node": { + "cluster": [ + + ] + }, + "os": { + "cluster": [ + + ] + } +} diff --git a/input/config/x86_64/sles/16.0/admin_debug_packages.json b/input/config/x86_64/sles/16.0/admin_debug_packages.json new file mode 100644 index 0000000000..5d9b095c39 --- /dev/null +++ b/input/config/x86_64/sles/16.0/admin_debug_packages.json @@ -0,0 +1,56 @@ +{ + "admin_debug_packages": { + "cluster": [ + {"package": "which", "type": "rpm", "repo_name": "basesystem"}, + {"package": "tcpdump", "type": "rpm", "repo_name": "basesystem"}, + {"package": "traceroute", "type": "rpm", "repo_name": "basesystem"}, + {"package": "iperf3", "type": "rpm", "repo_name": "packagehub"}, + {"package": "fping", "type": "rpm", "repo_name": "packagehub"}, + {"package": "dmidecode", "type": "rpm", "repo_name": "basesystem"}, + {"package": "hwloc", "type": "rpm", "repo_name": "basesystem"}, + {"package": "hwloc-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "lshw", "type": "rpm", "repo_name": "basesystem"}, + {"package": "pciutils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "vim", "type": "rpm", "repo_name": "basesystem"}, + {"package": "emacs", "type": "rpm", "repo_name": "desktop-applications"}, + {"package": "zsh", "type": "rpm", "repo_name": "basesystem"}, + {"package": "openssh", "type": "rpm", "repo_name": "basesystem"}, + {"package": "openssh-server", "type": "rpm", "repo_name": "basesystem"}, + {"package": "openssh-clients", "type": "rpm", "repo_name": "basesystem"}, + {"package": "rsync", "type": "rpm", "repo_name": "basesystem"}, + {"package": "file", "type": "rpm", "repo_name": "basesystem"}, + {"package": "libcurl4", "type": "rpm", "repo_name": "basesystem"}, + {"package": "tar", "type": "rpm", "repo_name": "basesystem"}, + {"package": "bzip2", "type": "rpm", "repo_name": "basesystem"}, + {"package": "man", "type": "rpm", "repo_name": "basesystem"}, + {"package": "man-pages", "type": "rpm", "repo_name": "basesystem"}, + {"package": "strace", "type": "rpm", "repo_name": "basesystem"}, + {"package": "kexec-tools", "type": "rpm", "repo_name": "basesystem"}, + {"package": "libopenssl-devel", "type": "rpm", "repo_name": "basesystem"}, + {"package": "ipmitool", "type": "rpm", "repo_name": "server-applications"}, + {"package": "gdb", "type": "rpm", "repo_name": "development-tools"}, + {"package": "gdbserver", "type": "rpm", "repo_name": "development-tools"}, + {"package": "lldb", "type": "rpm", "repo_name": "development-tools"}, + {"package": "lldb-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "valgrind", "type": "rpm", "repo_name": "development-tools"}, + {"package": "valgrind-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "ltrace", "type": "rpm", "repo_name": "development-tools"}, + {"package": "kernel-default-extra", "type": "rpm", "repo_name": "basesystem"}, + {"package": "perf", "type": "rpm", "repo_name": "basesystem"}, + {"package": "papi", "type": "rpm", "repo_name": "development-tools"}, + {"package": "papi-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "cmake", "type": "rpm", "repo_name": "development-tools"}, + {"package": "make", "type": "rpm", "repo_name": "basesystem"}, + {"package": "autoconf", "type": "rpm", "repo_name": "development-tools"}, + {"package": "automake", "type": "rpm", "repo_name": "development-tools"}, + {"package": "libtool", "type": "rpm", "repo_name": "development-tools"}, + {"package": "gcc", "type": "rpm", "repo_name": "development-tools"}, + {"package": "gcc-c++", "type": "rpm", "repo_name": "development-tools"}, + {"package": "gcc-fortran", "type": "rpm", "repo_name": "development-tools"}, + {"package": "binutils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "binutils-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "clustershell", "type": "rpm", "repo_name": "packagehub"}, + {"package": "bash-completion", "type": "rpm", "repo_name": "basesystem"} + ] + } +} diff --git a/input/config/x86_64/sles/16.0/csi_driver_powerscale.json b/input/config/x86_64/sles/16.0/csi_driver_powerscale.json new file mode 100644 index 0000000000..7ff53df763 --- /dev/null +++ b/input/config/x86_64/sles/16.0/csi_driver_powerscale.json @@ -0,0 +1,89 @@ +{ + "csi_driver_powerscale": { + "cluster": [ + { + "package": "csi-powerscale-v2.16.0", + "url": "https://github.com/dell/csi-powerscale.git", + "type": "git", + "version": "v2.16.0" + }, + { + "package": "external-snapshotter-v8.4.0", + "url": "https://github.com/kubernetes-csi/external-snapshotter.git", + "type": "git", + "version": "v8.4.0" + }, + { + "package": "helm-charts-2.16.0", + "url": "https://github.com/dell/helm-charts.git", + "type": "git", + "version": "csi-isilon-2.16.0" + }, + { + "package": "quay.io/dell/container-storage-modules/csi-isilon", + "tag": "v2.16.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-attacher", + "tag": "v4.10.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-provisioner", + "tag": "v6.1.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-snapshotter", + "tag": "v8.4.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-resizer", + "tag": "v2.0.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-node-driver-registrar", + "tag": "v2.15.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-external-health-monitor-controller", + "tag": "v0.16.0", + "type": "image" + }, + { + "package": "quay.io/dell/container-storage-modules/dell-csi-replicator", + "tag": "v1.14.0", + "type": "image" + }, + { + "package": "quay.io/dell/container-storage-modules/podmon", + "tag": "v1.15.0", + "type": "image" + }, + { + "package": "quay.io/dell/container-storage-modules/csm-authorization-sidecar", + "tag": "v2.4.0", + "type": "image" + }, + { + "package": "quay.io/dell/container-storage-modules/csi-metadata-retriever", + "tag": "v1.13.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/snapshot-controller", + "tag": "v8.4.0", + "type": "image" + }, + { + "package": "docker.io/dellemc/csm-encryption", + "tag": "v0.6.0", + "type": "image" + } + ] + } +} diff --git a/input/config/x86_64/sles/16.0/default_packages.json b/input/config/x86_64/sles/16.0/default_packages.json new file mode 100644 index 0000000000..b8dfc19594 --- /dev/null +++ b/input/config/x86_64/sles/16.0/default_packages.json @@ -0,0 +1,39 @@ +{ + "default_packages": { + "cluster": [ + {"package": "systemd", "type": "rpm", "repo_name": "basesystem"}, + {"package": "systemd-udev", "type": "rpm", "repo_name": "basesystem"}, + {"package": "kernel-default", "type": "rpm", "repo_name": "basesystem"}, + {"package": "dracut", "type": "rpm", "repo_name": "basesystem"}, + {"package": "dracut-tools", "type": "rpm", "repo_name": "basesystem"}, + {"package": "squashfs-tools", "type": "rpm", "repo_name": "basesystem"}, + {"package": "nfs-client", "type": "rpm", "repo_name": "basesystem"}, + {"package": "nfs4-acl-tools", "type": "rpm", "repo_name": "basesystem"}, + {"package": "NetworkManager", "type": "rpm", "repo_name": "basesystem"}, + {"package": "iproute2", "type": "rpm", "repo_name": "basesystem"}, + {"package": "iputils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "curl", "type": "rpm", "repo_name": "basesystem"}, + {"package": "bash", "type": "rpm", "repo_name": "basesystem"}, + {"package": "coreutils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "grep", "type": "rpm", "repo_name": "basesystem"}, + {"package": "sed", "type": "rpm", "repo_name": "basesystem"}, + {"package": "gawk", "type": "rpm", "repo_name": "basesystem"}, + {"package": "findutils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "util-linux", "type": "rpm", "repo_name": "basesystem"}, + {"package": "kbd", "type": "rpm", "repo_name": "basesystem"}, + {"package": "lsof", "type": "rpm", "repo_name": "basesystem"}, + {"package": "cryptsetup", "type": "rpm", "repo_name": "basesystem"}, + {"package": "lvm2", "type": "rpm", "repo_name": "basesystem"}, + {"package": "device-mapper", "type": "rpm", "repo_name": "basesystem"}, + {"package": "rsyslog", "type": "rpm", "repo_name": "basesystem"}, + {"package": "chrony", "type": "rpm", "repo_name": "basesystem"}, + {"package": "sudo", "type": "rpm", "repo_name": "basesystem"}, + {"package": "gzip", "type": "rpm", "repo_name": "basesystem"}, + {"package": "wget", "type": "rpm", "repo_name": "basesystem"}, + {"package": "cloud-init", "type": "rpm", "repo_name": "server-applications"}, + {"package": "glibc-locale", "type": "rpm", "repo_name": "basesystem"}, + {"package": "gedit", "type": "rpm", "repo_name": "desktop-applications"}, + {"package": "docker.io/dellhpcomniaaisolution/image-build-el10", "tag": "1.1", "type": "image" } + ] + } +} diff --git a/input/config/x86_64/sles/16.0/ldms.json b/input/config/x86_64/sles/16.0/ldms.json new file mode 100644 index 0000000000..90757cf4c5 --- /dev/null +++ b/input/config/x86_64/sles/16.0/ldms.json @@ -0,0 +1,10 @@ +{ + "ldms": { + "cluster": [ + {"package": "python3-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "python3-Cython", "type": "rpm", "repo_name": "development-tools"}, + {"package": "libopenssl3", "type": "rpm", "repo_name": "basesystem"}, + {"package": "ovis-ldms", "type": "rpm", "repo_name": "ldms"} + ] + } +} diff --git a/input/config/x86_64/sles/16.0/openldap.json b/input/config/x86_64/sles/16.0/openldap.json new file mode 100644 index 0000000000..d945837d19 --- /dev/null +++ b/input/config/x86_64/sles/16.0/openldap.json @@ -0,0 +1,10 @@ +{ + "openldap": { + "cluster": [ + {"package": "openldap2-client", "type": "rpm", "repo_name": "basesystem"}, + {"package": "nss-pam-ldapd", "type": "rpm", "repo_name": "basesystem"}, + {"package": "sssd", "type": "rpm", "repo_name": "basesystem"}, + {"package": "pam_mkhomedir", "type": "rpm", "repo_name": "basesystem"} + ] + } +} diff --git a/input/config/x86_64/sles/16.0/openmpi.json b/input/config/x86_64/sles/16.0/openmpi.json new file mode 100644 index 0000000000..7cf1583a8d --- /dev/null +++ b/input/config/x86_64/sles/16.0/openmpi.json @@ -0,0 +1,14 @@ +{ + "openmpi": { + "cluster": [ + { "package": "openmpi", + "type": "tarball", + "url": "https://download.open-mpi.org/release/open-mpi/v{{ openmpi_version.split('.')[:2] | join('.') }}/openmpi-{{ openmpi_version }}.tar.gz" + }, + {"package": "pmix-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "munge-devel", "type": "rpm", "repo_name": "development-tools"}, + {"package": "gcc-c++", "type": "rpm", "repo_name": "development-tools"}, + {"package": "make", "type": "rpm", "repo_name": "basesystem"} + ] + } +} diff --git a/input/config/x86_64/sles/16.0/service_k8s_v1.35.1.json b/input/config/x86_64/sles/16.0/service_k8s_v1.35.1.json new file mode 100644 index 0000000000..2dc0c8bb6c --- /dev/null +++ b/input/config/x86_64/sles/16.0/service_k8s_v1.35.1.json @@ -0,0 +1,117 @@ +{ + "service_k8s": { + "cluster": [ + { "package": "docker.io/library/busybox", "type": "image", "tag": "1.36" }, + { "package": "firewalld", "type": "rpm", "repo_name": "basesystem" }, + { "package": "python3-firewall", "type": "rpm", "repo_name": "basesystem" }, + { "package": "git", "type": "rpm", "repo_name": "development-tools"}, + { "package": "vim", "type": "rpm", "repo_name": "basesystem"}, + { "package": "fuse-overlayfs", "type": "rpm", "repo_name": "server-applications"}, + { "package": "podman", "type": "rpm", "repo_name": "server-applications"}, + { "package": "kubeadm-1.35.1", "type": "rpm", "repo_name": "kubernetes-v1-35"}, + { "package": "kubelet-1.35.1", "type": "rpm", "repo_name": "kubernetes-v1-35"}, + { "package": "cri-o-1.35.1", "type": "rpm", "repo_name": "cri-o-v1-35"}, + { "package": "docker.io/victoriametrics/victoria-metrics", "type": "image", "tag": "v1.128.0" }, + { "package": "docker.io/victoriametrics/vmagent", "type": "image", "tag": "v1.128.0" }, + { "package": "docker.io/victoriametrics/vmstorage", "type": "image", "tag": "v1.128.0-cluster" }, + { "package": "docker.io/victoriametrics/vminsert", "type": "image", "tag": "v1.128.0-cluster" }, + { "package": "docker.io/victoriametrics/vmselect", "type": "image", "tag": "v1.128.0-cluster" }, + { "package": "docker.io/victoriametrics/victoria-logs", "type": "image", "tag": "v1.50.0" }, + { "package": "docker.io/victoriametrics/vlagent", "type": "image", "tag": "v1.50.0" }, + { "package": "docker.io/alpine/kubectl", "tag": "1.35.1", "type": "image" }, + { "package": "docker.io/curlimages/curl", "type": "image", "tag": "8.17.0" }, + { "package": "docker.io/rmohr/activemq", "type": "image", "tag": "5.15.9" }, + { "package": "docker.io/library/mysql", "type": "image", "tag": "9.3.0" }, + { "package": "docker.io/library/python", "type": "image", "tag": "3.12-slim" }, + { "package": "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver", "type": "image", "tag": "1.3" }, + { "package": "docker.io/dellhpcomniaaisolution/kafkapump", "type": "image", "tag": "1.3" }, + { "package": "docker.io/dellhpcomniaaisolution/victoriapump", "type": "image", "tag": "1.3" }, + { "package": "cryptography==45.0.7", "type": "pip_module" }, + { "package": "omsdk==1.2.518", "type": "pip_module" }, + { "package": "cffi==1.17.1", "type": "pip_module" }, + { "package": "prometheus_client==0.20.0", "type": "pip_module" }, + { "package": "kubernetes==33.1.0", "type": "pip_module" }, + { "package": "quay.io/strimzi/operator", "tag": "0.48.0", "type": "image" }, + { "package": "quay.io/strimzi/kafka", "tag": "0.48.0-kafka-4.1.0", "type": "image" }, + { "package": "docker.io/dellhpcomniaaisolution/ubuntu-ldms", "tag": "1.1", "type": "image" }, + { "package": "quay.io/dell/container-storage-modules/csm-metrics-powerscale", "tag": "v1.11.0", "type": "image" }, + { "package": "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector", "tag": "0.143.1", "type": "image" }, + { "package": "docker.io/nginxinc/nginx-unprivileged", "tag": "1.29", "type": "image" }, + { "package": "karavi-observability", "type": "git", "url": "https://github.com/dell/karavi-observability.git", "version": "v1.12.0" }, + { "package": "helm-charts", "type": "git", "url": "https://github.com/dell/helm-charts.git", "version": "container-storage-modules-1.9.2" }, + { "package": "quay.io/jetstack/cert-manager-controller", "tag": "v1.10.0", "type": "image" }, + { "package": "quay.io/jetstack/cert-manager-cainjector", "tag": "v1.10.0", "type": "image" }, + { "package": "quay.io/jetstack/cert-manager-webhook", "tag": "v1.10.0", "type": "image" }, + { "package": "quay.io/jetstack/cert-manager-acmesolver", "tag": "v1.10.0", "type": "image" }, + { "package": "cert-manager-v1.10.0", "type": "tarball", "url": "https://charts.jetstack.io/charts/cert-manager-v1.10.0.tgz" }, + { "package": "strimzi-kafka-operator-helm-3-chart-0.48.0", "type": "tarball", "url": "https://github.com/strimzi/strimzi-kafka-operator/releases/download/0.48.0/strimzi-kafka-operator-helm-3-chart-0.48.0.tgz" }, + { "package": "quay.io/strimzi/kafka-bridge", "tag": "0.33.1", "type": "image" }, + { "package": "docker.io/victoriametrics/operator", "tag": "v0.68.3", "type": "image" }, + { "package": "docker.io/victoriametrics/operator", "tag": "config-reloader-v0.68.3", "type": "image" }, + { "package": "victoria-metrics-operator-0.59.3", "type": "tarball", "url": "https://github.com/VictoriaMetrics/helm-charts/releases/download/victoria-metrics-operator-0.59.3/victoria-metrics-operator-0.59.3.tgz" }, + { "package": "docker.io/timberio/vector", "tag": "0.54.0-debian", "type": "image" }, + { "package": "apptainer", "type": "rpm", "repo_name": "packagehub" }, + { "package": "open-iscsi", "type": "rpm", "repo_name": "basesystem" }, + { "package": "multipath-tools", "type": "rpm", "repo_name": "basesystem" }, + { "package": "sg3_utils", "type": "rpm", "repo_name": "basesystem" }, + { "package": "lsscsi", "type": "rpm", "repo_name": "basesystem" } + ] + }, + "service_kube_control_plane": { + "cluster": [ + { "package": "ghcr.io/kube-vip/kube-vip", "tag": "v0.8.9", "type": "image" }, + { "package": "docker.io/alpine/kubectl", "tag": "1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-apiserver", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-controller-manager", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-scheduler", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-proxy", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/coredns/coredns", "tag": "v1.13.1", "type": "image" }, + { "package": "registry.k8s.io/pause", "tag": "3.10.1", "type": "image" }, + { "package": "registry.k8s.io/etcd", "tag": "3.6.6-0", "type": "image" }, + { "package": "docker.io/calico/cni", "tag": "v3.31.4", "type": "image" }, + { "package": "docker.io/calico/kube-controllers", "tag": "v3.31.4", "type": "image" }, + { "package": "docker.io/calico/node", "tag": "v3.31.4", "type": "image" }, + { "package": "quay.io/metallb/speaker", "tag": "v0.15.3", "type": "image" }, + { "package": "kubectl-1.35.1", "type": "rpm", "repo_name": "kubernetes-v1-35"}, + { "package": "prettytable==3.14.0", "type": "pip_module" }, + { "package": "python3", "type": "rpm", "repo_name": "basesystem" }, + { "package": "git", "type": "rpm", "repo_name": "development-tools"}, + { "package": "kubernetes==33.1.0", "type": "pip_module" }, + { "package": "PyMySQL==1.1.2", "type": "pip_module" } + ] + }, + "service_kube_control_plane_first": { + "cluster": [ + { "package": "ghcr.io/kube-vip/kube-vip", "tag": "v0.8.9", "type": "image" }, + { "package": "registry.k8s.io/kube-apiserver", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-controller-manager", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-scheduler", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-proxy", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/coredns/coredns", "tag": "v1.13.1", "type": "image" }, + { "package": "docker.io/alpine/kubectl", "tag": "1.35.1", "type": "image" }, + { "package": "registry.k8s.io/pause", "tag": "3.10.1", "type": "image" }, + { "package": "registry.k8s.io/etcd", "tag": "3.6.6-0", "type": "image" }, + { "package": "docker.io/calico/cni", "tag": "v3.31.4", "type": "image" }, + { "package": "docker.io/calico/kube-controllers", "tag": "v3.31.4", "type": "image" }, + { "package": "docker.io/calico/node", "tag": "v3.31.4", "type": "image" }, + { "package": "quay.io/metallb/speaker", "tag": "v0.15.3", "type": "image" }, + { "package": "calico-v3.31.4","type": "manifest", "url": "https://raw.githubusercontent.com/projectcalico/calico/v3.31.4/manifests/calico.yaml" }, + { "package": "metallb-native-v0.15.3", "type": "manifest", "url": "https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml" }, + { "package": "helm-v3.20.1-amd64", "type": "tarball", "url": "https://get.helm.sh/helm-v3.20.1-linux-amd64.tar.gz" }, + { "package": "nfs-subdir-external-provisioner-4.0.18", "type": "tarball", "url": "https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/releases/download/nfs-subdir-external-provisioner-4.0.18/nfs-subdir-external-provisioner-4.0.18.tgz" }, + { "package": "kubectl-1.35.1", "type": "rpm", "repo_name": "kubernetes-v1-35"}, + { "package": "prettytable==3.14.0", "type": "pip_module" }, + { "package": "python3", "type": "rpm", "repo_name": "basesystem" }, + { "package": "git", "type": "rpm", "repo_name": "development-tools"}, + { "package": "kubernetes==33.1.0", "type": "pip_module" }, + { "package": "PyMySQL==1.1.2", "type": "pip_module" } + ] + }, + "service_kube_node": { + "cluster": [ + { "package": "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner", "tag": "v4.0.2", "type": "image" }, + { "package": "quay.io/metallb/speaker", "tag": "v0.15.3", "type": "image" }, + { "package": "quay.io/metallb/controller", "tag": "v0.15.3", "type": "image" } + ] + } +} diff --git a/input/config/x86_64/sles/16.0/slurm_custom.json b/input/config/x86_64/sles/16.0/slurm_custom.json new file mode 100644 index 0000000000..2deb365ad9 --- /dev/null +++ b/input/config/x86_64/sles/16.0/slurm_custom.json @@ -0,0 +1,50 @@ +{ + "slurm_custom": { + "cluster": [ + {"package": "munge", "type": "rpm", "repo_name": "server-applications"}, + {"package": "firewalld", "type": "rpm", "repo_name": "basesystem"}, + {"package": "python3-firewall", "type": "rpm", "repo_name": "basesystem"}, + {"package": "pmix", "type": "rpm", "repo_name": "server-applications"}, + {"package": "nvcr.io/nvidia/hpc-benchmarks", "tag": "25.09", "type": "image"}, + {"package": "apptainer", "type": "rpm", "repo_name": "packagehub" }, + {"package": "open-iscsi", "type": "rpm", "repo_name": "basesystem"}, + {"package": "multipath-tools", "type": "rpm", "repo_name": "basesystem"}, + {"package": "sg3_utils", "type": "rpm", "repo_name": "basesystem"}, + {"package": "lsscsi", "type": "rpm", "repo_name": "basesystem"}, + {"package": "imb", "type": "tarball", "url": "https://github.com/intel/mpi-benchmarks/archive/refs/tags/IMB-v2021.8.tar.gz"}, + {"package": "osu-micro-benchmarks", "type": "tarball", "url": "https://mvapich.cse.ohio-state.edu/download/mvapich/osu-micro-benchmarks-7.5.tar.gz"}, + {"package": "likwid", "type": "tarball", "url": "https://github.com/RRZE-HPC/likwid/archive/refs/tags/v5.4.1.tar.gz"}, + {"package": "geopm", "type": "tarball", "url": "https://github.com/geopm/geopm/archive/refs/tags/v3.1.0.tar.gz"}, + {"package": "papi", "type": "tarball", "url": "https://github.com/icl-utk-edu/papi/releases/download/papi-7-2-0-t/papi-7.2.0.tar.gz"}, + {"package": "msr-safe", "type": "tarball", "url": "https://github.com/llnl/msr-safe/archive/refs/tags/v1.7.0.tar.gz"}, + {"package": "sionlib", "type": "tarball", "url": "https://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.7"} + ] + }, + "slurm_control_node": { + "cluster": [ + {"package": "slurm-slurmctld", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "slurm-slurmdbd", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "python3-PyMySQL", "type": "rpm", "repo_name": "server-applications"}, + {"package": "mariadb-server", "type": "rpm", "repo_name": "server-applications"} + ] + }, + "slurm_node": { + "cluster": [ + {"package": "slurm-slurmd", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "slurm-pam_slurm", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "kernel-default-devel", "type": "rpm", "repo_name": "development-tools"} + ] + }, + "login_node":{ + "cluster": [ + {"package": "slurm-slurmd", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "slurm", "type": "rpm", "repo_name": "slurm_custom"} + ] + }, + "login_compiler_node":{ + "cluster": [ + {"package": "slurm", "type": "rpm", "repo_name": "slurm_custom"}, + {"package": "slurm-slurmd", "type": "rpm", "repo_name": "slurm_custom"} + ] + } +} diff --git a/input/config/x86_64/sles/16.0/ucx.json b/input/config/x86_64/sles/16.0/ucx.json new file mode 100644 index 0000000000..ac7b203da3 --- /dev/null +++ b/input/config/x86_64/sles/16.0/ucx.json @@ -0,0 +1,12 @@ +{ + "ucx": { + "cluster": [ + { "package": "ucx", + "type": "tarball", + "url": "https://github.com/openucx/ucx/releases/download/v{{ ucx_version }}/ucx-{{ ucx_version }}.tar.gz" + }, + {"package": "gcc-c++", "type": "rpm", "repo_name": "development-tools"}, + {"package": "make", "type": "rpm", "repo_name": "basesystem"} + ] + } +} diff --git a/input/config/x86_64/ubuntu/26.04/additional_packages.json b/input/config/x86_64/ubuntu/26.04/additional_packages.json new file mode 100644 index 0000000000..7cc4f60a9f --- /dev/null +++ b/input/config/x86_64/ubuntu/26.04/additional_packages.json @@ -0,0 +1,47 @@ +{ + "additional_packages": { + "cluster": [ + + ] + }, + "service_kube_control_plane_first": { + "cluster": [ + + ] + }, + "service_kube_control_plane": { + "cluster": [ + + ] + }, + "service_kube_node": { + "cluster": [ + + ] + }, + "slurm_control_node": { + "cluster": [ + + ] + }, + "slurm_node": { + "cluster": [ + + ] + }, + "login_node": { + "cluster": [ + + ] + }, + "login_compiler_node": { + "cluster": [ + + ] + }, + "os": { + "cluster": [ + + ] + } +} diff --git a/input/config/x86_64/ubuntu/26.04/admin_debug_packages.json b/input/config/x86_64/ubuntu/26.04/admin_debug_packages.json new file mode 100644 index 0000000000..dfe6401c99 --- /dev/null +++ b/input/config/x86_64/ubuntu/26.04/admin_debug_packages.json @@ -0,0 +1,52 @@ +{ + "admin_debug_packages": { + "cluster": [ + {"package": "debianutils", "type": "deb", "repo_name": "main"}, + {"package": "tcpdump", "type": "deb", "repo_name": "main"}, + {"package": "traceroute", "type": "deb", "repo_name": "universe"}, + {"package": "iperf3", "type": "deb", "repo_name": "universe"}, + {"package": "fping", "type": "deb", "repo_name": "universe"}, + {"package": "dmidecode", "type": "deb", "repo_name": "main"}, + {"package": "hwloc", "type": "deb", "repo_name": "universe"}, + {"package": "libhwloc15", "type": "deb", "repo_name": "universe"}, + {"package": "lshw", "type": "deb", "repo_name": "main"}, + {"package": "pciutils", "type": "deb", "repo_name": "main"}, + {"package": "vim", "type": "deb", "repo_name": "main"}, + {"package": "emacs", "type": "deb", "repo_name": "universe"}, + {"package": "zsh", "type": "deb", "repo_name": "main"}, + {"package": "openssh-client", "type": "deb", "repo_name": "main"}, + {"package": "openssh-server", "type": "deb", "repo_name": "main"}, + {"package": "rsync", "type": "deb", "repo_name": "main"}, + {"package": "file", "type": "deb", "repo_name": "main"}, + {"package": "libcurl4", "type": "deb", "repo_name": "main"}, + {"package": "tar", "type": "deb", "repo_name": "main"}, + {"package": "bzip2", "type": "deb", "repo_name": "main"}, + {"package": "man-db", "type": "deb", "repo_name": "main"}, + {"package": "manpages", "type": "deb", "repo_name": "main"}, + {"package": "strace", "type": "deb", "repo_name": "main"}, + {"package": "kexec-tools", "type": "deb", "repo_name": "main"}, + {"package": "libssl-dev", "type": "deb", "repo_name": "main"}, + {"package": "ipmitool", "type": "deb", "repo_name": "universe"}, + {"package": "gdb", "type": "deb", "repo_name": "main"}, + {"package": "gdbserver", "type": "deb", "repo_name": "main"}, + {"package": "lldb", "type": "deb", "repo_name": "universe"}, + {"package": "liblldb-dev", "type": "deb", "repo_name": "universe"}, + {"package": "valgrind", "type": "deb", "repo_name": "universe"}, + {"package": "ltrace", "type": "deb", "repo_name": "universe"}, + {"package": "linux-tools-generic", "type": "deb", "repo_name": "main"}, + {"package": "libpapi-dev", "type": "deb", "repo_name": "universe"}, + {"package": "cmake", "type": "deb", "repo_name": "main"}, + {"package": "make", "type": "deb", "repo_name": "main"}, + {"package": "autoconf", "type": "deb", "repo_name": "main"}, + {"package": "automake", "type": "deb", "repo_name": "main"}, + {"package": "libtool", "type": "deb", "repo_name": "main"}, + {"package": "gcc", "type": "deb", "repo_name": "main"}, + {"package": "g++", "type": "deb", "repo_name": "main"}, + {"package": "gfortran", "type": "deb", "repo_name": "main"}, + {"package": "binutils", "type": "deb", "repo_name": "main"}, + {"package": "binutils-dev", "type": "deb", "repo_name": "main"}, + {"package": "clustershell", "type": "deb", "repo_name": "universe"}, + {"package": "bash-completion", "type": "deb", "repo_name": "main"} + ] + } +} diff --git a/input/config/x86_64/ubuntu/26.04/csi_driver_powerscale.json b/input/config/x86_64/ubuntu/26.04/csi_driver_powerscale.json new file mode 100644 index 0000000000..7ff53df763 --- /dev/null +++ b/input/config/x86_64/ubuntu/26.04/csi_driver_powerscale.json @@ -0,0 +1,89 @@ +{ + "csi_driver_powerscale": { + "cluster": [ + { + "package": "csi-powerscale-v2.16.0", + "url": "https://github.com/dell/csi-powerscale.git", + "type": "git", + "version": "v2.16.0" + }, + { + "package": "external-snapshotter-v8.4.0", + "url": "https://github.com/kubernetes-csi/external-snapshotter.git", + "type": "git", + "version": "v8.4.0" + }, + { + "package": "helm-charts-2.16.0", + "url": "https://github.com/dell/helm-charts.git", + "type": "git", + "version": "csi-isilon-2.16.0" + }, + { + "package": "quay.io/dell/container-storage-modules/csi-isilon", + "tag": "v2.16.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-attacher", + "tag": "v4.10.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-provisioner", + "tag": "v6.1.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-snapshotter", + "tag": "v8.4.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-resizer", + "tag": "v2.0.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-node-driver-registrar", + "tag": "v2.15.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/csi-external-health-monitor-controller", + "tag": "v0.16.0", + "type": "image" + }, + { + "package": "quay.io/dell/container-storage-modules/dell-csi-replicator", + "tag": "v1.14.0", + "type": "image" + }, + { + "package": "quay.io/dell/container-storage-modules/podmon", + "tag": "v1.15.0", + "type": "image" + }, + { + "package": "quay.io/dell/container-storage-modules/csm-authorization-sidecar", + "tag": "v2.4.0", + "type": "image" + }, + { + "package": "quay.io/dell/container-storage-modules/csi-metadata-retriever", + "tag": "v1.13.0", + "type": "image" + }, + { + "package": "registry.k8s.io/sig-storage/snapshot-controller", + "tag": "v8.4.0", + "type": "image" + }, + { + "package": "docker.io/dellemc/csm-encryption", + "tag": "v0.6.0", + "type": "image" + } + ] + } +} diff --git a/input/config/x86_64/ubuntu/26.04/default_packages.json b/input/config/x86_64/ubuntu/26.04/default_packages.json new file mode 100644 index 0000000000..3bd0d40527 --- /dev/null +++ b/input/config/x86_64/ubuntu/26.04/default_packages.json @@ -0,0 +1,41 @@ +{ + "default_packages": { + "cluster": [ + {"package": "systemd", "type": "deb", "repo_name": "main"}, + {"package": "udev", "type": "deb", "repo_name": "main"}, + {"package": "linux-image-generic", "type": "deb", "repo_name": "main"}, + {"package": "initramfs-tools", "type": "deb", "repo_name": "main"}, + {"package": "live-boot", "type": "deb", "repo_name": "universe"}, + {"package": "initramfs-tools-core", "type": "deb", "repo_name": "main"}, + {"package": "squashfs-tools", "type": "deb", "repo_name": "main"}, + {"package": "nfs-common", "type": "deb", "repo_name": "main"}, + {"package": "nfs4-acl-tools", "type": "deb", "repo_name": "universe"}, + {"package": "network-manager", "type": "deb", "repo_name": "main"}, + {"package": "network-manager-gnome", "type": "deb", "repo_name": "main"}, + {"package": "iproute2", "type": "deb", "repo_name": "main"}, + {"package": "iputils-ping", "type": "deb", "repo_name": "main"}, + {"package": "curl", "type": "deb", "repo_name": "main"}, + {"package": "bash", "type": "deb", "repo_name": "main"}, + {"package": "coreutils", "type": "deb", "repo_name": "main"}, + {"package": "grep", "type": "deb", "repo_name": "main"}, + {"package": "sed", "type": "deb", "repo_name": "main"}, + {"package": "gawk", "type": "deb", "repo_name": "main"}, + {"package": "findutils", "type": "deb", "repo_name": "main"}, + {"package": "util-linux", "type": "deb", "repo_name": "main"}, + {"package": "kbd", "type": "deb", "repo_name": "main"}, + {"package": "lsof", "type": "deb", "repo_name": "main"}, + {"package": "cryptsetup", "type": "deb", "repo_name": "main"}, + {"package": "lvm2", "type": "deb", "repo_name": "main"}, + {"package": "dmsetup", "type": "deb", "repo_name": "main"}, + {"package": "rsyslog", "type": "deb", "repo_name": "main"}, + {"package": "chrony", "type": "deb", "repo_name": "main"}, + {"package": "sudo", "type": "deb", "repo_name": "main"}, + {"package": "gzip", "type": "deb", "repo_name": "main"}, + {"package": "wget", "type": "deb", "repo_name": "main"}, + {"package": "cloud-init", "type": "deb", "repo_name": "main"}, + {"package": "locales", "type": "deb", "repo_name": "main"}, + {"package": "gedit", "type": "deb", "repo_name": "universe"}, + {"package": "docker.io/dellhpcomniaaisolution/image-build-el10", "tag": "1.1", "type": "image" } + ] + } +} diff --git a/input/config/x86_64/ubuntu/26.04/ldms.json b/input/config/x86_64/ubuntu/26.04/ldms.json new file mode 100644 index 0000000000..ea2966695b --- /dev/null +++ b/input/config/x86_64/ubuntu/26.04/ldms.json @@ -0,0 +1,10 @@ +{ + "ldms": { + "cluster": [ + {"package": "python3-dev", "type": "deb", "repo_name": "main"}, + {"package": "cython3", "type": "deb", "repo_name": "universe"}, + {"package": "libssl3", "type": "deb", "repo_name": "main"}, + {"package": "ovis-ldms", "type": "deb", "repo_name": "ldms"} + ] + } +} diff --git a/input/config/x86_64/ubuntu/26.04/openldap.json b/input/config/x86_64/ubuntu/26.04/openldap.json new file mode 100644 index 0000000000..a3ef5a64d7 --- /dev/null +++ b/input/config/x86_64/ubuntu/26.04/openldap.json @@ -0,0 +1,10 @@ +{ + "openldap": { + "cluster": [ + {"package": "ldap-utils", "type": "deb", "repo_name": "main"}, + {"package": "libnss-ldapd", "type": "deb", "repo_name": "universe"}, + {"package": "sssd", "type": "deb", "repo_name": "main"}, + {"package": "libpam-mkhomedir", "type": "deb", "repo_name": "main"} + ] + } +} diff --git a/input/config/x86_64/ubuntu/26.04/openmpi.json b/input/config/x86_64/ubuntu/26.04/openmpi.json new file mode 100644 index 0000000000..7e9f66e465 --- /dev/null +++ b/input/config/x86_64/ubuntu/26.04/openmpi.json @@ -0,0 +1,14 @@ +{ + "openmpi": { + "cluster": [ + { "package": "openmpi", + "type": "tarball", + "url": "https://download.open-mpi.org/release/open-mpi/v{{ openmpi_version.split('.')[:2] | join('.') }}/openmpi-{{ openmpi_version }}.tar.gz" + }, + {"package": "libpmix-dev", "type": "deb", "repo_name": "universe"}, + {"package": "libmunge-dev", "type": "deb", "repo_name": "universe"}, + {"package": "g++", "type": "deb", "repo_name": "main"}, + {"package": "make", "type": "deb", "repo_name": "main"} + ] + } +} diff --git a/input/config/x86_64/ubuntu/26.04/service_k8s_v1.35.1.json b/input/config/x86_64/ubuntu/26.04/service_k8s_v1.35.1.json new file mode 100644 index 0000000000..ef1afb5dc4 --- /dev/null +++ b/input/config/x86_64/ubuntu/26.04/service_k8s_v1.35.1.json @@ -0,0 +1,118 @@ +{ + "service_k8s": { + "cluster": [ + { "package": "docker.io/library/busybox", "type": "image", "tag": "1.36" }, + { "package": "ufw", "type": "deb", "repo_name": "main" }, + { "package": "git", "type": "deb", "repo_name": "main"}, + { "package": "vim", "type": "deb", "repo_name": "main"}, + { "package": "fuse-overlayfs", "type": "deb", "repo_name": "universe"}, + { "package": "podman", "type": "deb", "repo_name": "universe"}, + { "package": "kubeadm", "type": "deb", "repo_name": "kubernetes-v1-35"}, + { "package": "kubelet", "type": "deb", "repo_name": "kubernetes-v1-35"}, + { "package": "cri-o", "type": "deb", "repo_name": "cri-o-v1-35"}, + { "package": "docker.io/victoriametrics/victoria-metrics", "type": "image", "tag": "v1.128.0" }, + { "package": "docker.io/victoriametrics/vmagent", "type": "image", "tag": "v1.128.0" }, + { "package": "docker.io/victoriametrics/vmstorage", "type": "image", "tag": "v1.128.0-cluster" }, + { "package": "docker.io/victoriametrics/vminsert", "type": "image", "tag": "v1.128.0-cluster" }, + { "package": "docker.io/victoriametrics/vmselect", "type": "image", "tag": "v1.128.0-cluster" }, + { "package": "docker.io/victoriametrics/victoria-logs", "type": "image", "tag": "v1.50.0" }, + { "package": "docker.io/victoriametrics/vlagent", "type": "image", "tag": "v1.50.0" }, + { "package": "docker.io/alpine/kubectl", "tag": "1.35.1", "type": "image" }, + { "package": "docker.io/curlimages/curl", "type": "image", "tag": "8.17.0" }, + { "package": "docker.io/rmohr/activemq", "type": "image", "tag": "5.15.9" }, + { "package": "docker.io/library/mysql", "type": "image", "tag": "9.3.0" }, + { "package": "docker.io/library/python", "type": "image", "tag": "3.12-slim" }, + { "package": "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver", "type": "image", "tag": "1.3" }, + { "package": "docker.io/dellhpcomniaaisolution/kafkapump", "type": "image", "tag": "1.3" }, + { "package": "docker.io/dellhpcomniaaisolution/victoriapump", "type": "image", "tag": "1.3" }, + { "package": "cryptography==45.0.7", "type": "pip_module" }, + { "package": "omsdk==1.2.518", "type": "pip_module" }, + { "package": "cffi==1.17.1", "type": "pip_module" }, + { "package": "prometheus_client==0.20.0", "type": "pip_module" }, + { "package": "kubernetes==33.1.0", "type": "pip_module" }, + { "package": "quay.io/strimzi/operator", "tag": "0.48.0", "type": "image" }, + { "package": "quay.io/strimzi/kafka", "tag": "0.48.0-kafka-4.1.0", "type": "image" }, + { "package": "docker.io/dellhpcomniaaisolution/ubuntu-ldms", "tag": "1.1", "type": "image" }, + { "package": "quay.io/dell/container-storage-modules/csm-metrics-powerscale", "tag": "v1.11.0", "type": "image" }, + { "package": "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector", "tag": "0.143.1", "type": "image" }, + { "package": "docker.io/nginxinc/nginx-unprivileged", "tag": "1.29", "type": "image" }, + { "package": "karavi-observability", "type": "git", "url": "https://github.com/dell/karavi-observability.git", "version": "v1.12.0" }, + { "package": "helm-charts", "type": "git", "url": "https://github.com/dell/helm-charts.git", "version": "container-storage-modules-1.9.2" }, + { "package": "quay.io/jetstack/cert-manager-controller", "tag": "v1.10.0", "type": "image" }, + { "package": "quay.io/jetstack/cert-manager-cainjector", "tag": "v1.10.0", "type": "image" }, + { "package": "quay.io/jetstack/cert-manager-webhook", "tag": "v1.10.0", "type": "image" }, + { "package": "quay.io/jetstack/cert-manager-acmesolver", "tag": "v1.10.0", "type": "image" }, + { "package": "cert-manager-v1.10.0", "type": "tarball", "url": "https://charts.jetstack.io/charts/cert-manager-v1.10.0.tgz" }, + { "package": "strimzi-kafka-operator-helm-3-chart-0.48.0", "type": "tarball", "url": "https://github.com/strimzi/strimzi-kafka-operator/releases/download/0.48.0/strimzi-kafka-operator-helm-3-chart-0.48.0.tgz" }, + { "package": "quay.io/strimzi/kafka-bridge", "tag": "0.33.1", "type": "image" }, + { "package": "docker.io/victoriametrics/operator", "tag": "v0.68.3", "type": "image" }, + { "package": "docker.io/victoriametrics/operator", "tag": "config-reloader-v0.68.3", "type": "image" }, + { "package": "victoria-metrics-operator-0.59.3", "type": "tarball", "url": "https://github.com/VictoriaMetrics/helm-charts/releases/download/victoria-metrics-operator-0.59.3/victoria-metrics-operator-0.59.3.tgz" }, + { "package": "docker.io/timberio/vector", "tag": "0.54.0-debian", "type": "image" }, + { "package": "apptainer", "type": "deb", "repo_name": "universe" }, + { "package": "open-iscsi", "type": "deb", "repo_name": "main" }, + { "package": "multipath-tools", "type": "deb", "repo_name": "main" }, + { "package": "sg3-utils", "type": "deb", "repo_name": "main" }, + { "package": "lsscsi", "type": "deb", "repo_name": "main" } + ] + }, + "service_kube_control_plane": { + "cluster": [ + { "package": "ghcr.io/kube-vip/kube-vip", "tag": "v0.8.9", "type": "image" }, + { "package": "docker.io/alpine/kubectl", "tag": "1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-apiserver", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-controller-manager", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-scheduler", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-proxy", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/coredns/coredns", "tag": "v1.13.1", "type": "image" }, + { "package": "registry.k8s.io/pause", "tag": "3.10.1", "type": "image" }, + { "package": "registry.k8s.io/etcd", "tag": "3.6.6-0", "type": "image" }, + { "package": "docker.io/calico/cni", "tag": "v3.31.4", "type": "image" }, + { "package": "docker.io/calico/kube-controllers", "tag": "v3.31.4", "type": "image" }, + { "package": "docker.io/calico/node", "tag": "v3.31.4", "type": "image" }, + { "package": "quay.io/metallb/speaker", "tag": "v0.15.3", "type": "image" }, + { "package": "kubectl", "type": "deb", "repo_name": "kubernetes-v1-35"}, + { "package": "prettytable==3.14.0", "type": "pip_module" }, + { "package": "python3", "type": "deb", "repo_name": "main" }, + { "package": "git", "type": "deb", "repo_name": "main"}, + { "package": "kubernetes==33.1.0", "type": "pip_module" }, + { "package": "PyMySQL==1.1.2", "type": "pip_module" } + + ] + }, + "service_kube_control_plane_first": { + "cluster": [ + { "package": "ghcr.io/kube-vip/kube-vip", "tag": "v0.8.9", "type": "image" }, + { "package": "registry.k8s.io/kube-apiserver", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-controller-manager", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-scheduler", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/kube-proxy", "tag": "v1.35.1", "type": "image" }, + { "package": "registry.k8s.io/coredns/coredns", "tag": "v1.13.1", "type": "image" }, + { "package": "docker.io/alpine/kubectl", "tag": "1.35.1", "type": "image" }, + { "package": "registry.k8s.io/pause", "tag": "3.10.1", "type": "image" }, + { "package": "registry.k8s.io/etcd", "tag": "3.6.6-0", "type": "image" }, + { "package": "docker.io/calico/cni", "tag": "v3.31.4", "type": "image" }, + { "package": "docker.io/calico/kube-controllers", "tag": "v3.31.4", "type": "image" }, + { "package": "docker.io/calico/node", "tag": "v3.31.4", "type": "image" }, + { "package": "quay.io/metallb/speaker", "tag": "v0.15.3", "type": "image" }, + { "package": "calico-v3.31.4","type": "manifest", "url": "https://raw.githubusercontent.com/projectcalico/calico/v3.31.4/manifests/calico.yaml" }, + { "package": "metallb-native-v0.15.3", "type": "manifest", "url": "https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml" }, + { "package": "helm-v3.20.1-amd64", "type": "tarball", "url": "https://get.helm.sh/helm-v3.20.1-linux-amd64.tar.gz" }, + { "package": "nfs-subdir-external-provisioner-4.0.18", "type": "tarball", "url": "https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/releases/download/nfs-subdir-external-provisioner-4.0.18/nfs-subdir-external-provisioner-4.0.18.tgz" }, + { "package": "kubectl", "type": "deb", "repo_name": "kubernetes-v1-35"}, + { "package": "prettytable==3.14.0", "type": "pip_module" }, + { "package": "python3", "type": "deb", "repo_name": "main" }, + { "package": "git", "type": "deb", "repo_name": "main"}, + { "package": "kubernetes==33.1.0", "type": "pip_module" }, + { "package": "PyMySQL==1.1.2", "type": "pip_module" } + ] + }, + + "service_kube_node": { + "cluster": [ + { "package": "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner", "tag": "v4.0.2", "type": "image" }, + { "package": "quay.io/metallb/speaker", "tag": "v0.15.3", "type": "image" }, + { "package": "quay.io/metallb/controller", "tag": "v0.15.3", "type": "image" } + ] + } +} diff --git a/input/config/x86_64/ubuntu/26.04/slurm_custom.json b/input/config/x86_64/ubuntu/26.04/slurm_custom.json new file mode 100644 index 0000000000..41acd7620f --- /dev/null +++ b/input/config/x86_64/ubuntu/26.04/slurm_custom.json @@ -0,0 +1,49 @@ +{ + "slurm_custom": { + "cluster": [ + {"package": "munge", "type": "deb", "repo_name": "main"}, + {"package": "ufw", "type": "deb", "repo_name": "main"}, + {"package": "libpmix2", "type": "deb", "repo_name": "universe"}, + {"package": "nvcr.io/nvidia/hpc-benchmarks", "tag": "25.09", "type": "image"}, + {"package": "apptainer", "type": "deb", "repo_name": "universe" }, + {"package": "open-iscsi", "type": "deb", "repo_name": "main"}, + {"package": "multipath-tools", "type": "deb", "repo_name": "main"}, + {"package": "sg3-utils", "type": "deb", "repo_name": "main"}, + {"package": "lsscsi", "type": "deb", "repo_name": "main"}, + {"package": "imb", "type": "tarball", "url": "https://github.com/intel/mpi-benchmarks/archive/refs/tags/IMB-v2021.8.tar.gz"}, + {"package": "osu-micro-benchmarks", "type": "tarball", "url": "https://mvapich.cse.ohio-state.edu/download/mvapich/osu-micro-benchmarks-7.5.tar.gz"}, + {"package": "likwid", "type": "tarball", "url": "https://github.com/RRZE-HPC/likwid/archive/refs/tags/v5.4.1.tar.gz"}, + {"package": "geopm", "type": "tarball", "url": "https://github.com/geopm/geopm/archive/refs/tags/v3.1.0.tar.gz"}, + {"package": "papi", "type": "tarball", "url": "https://github.com/icl-utk-edu/papi/releases/download/papi-7-2-0-t/papi-7.2.0.tar.gz"}, + {"package": "msr-safe", "type": "tarball", "url": "https://github.com/llnl/msr-safe/archive/refs/tags/v1.7.0.tar.gz"}, + {"package": "sionlib", "type": "tarball", "url": "https://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.7"} + ] + }, + "slurm_control_node": { + "cluster": [ + {"package": "slurm-smd-slurmctld", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "slurm-smd-slurmdbd", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "python3-pymysql", "type": "deb", "repo_name": "main"}, + {"package": "mariadb-server", "type": "deb", "repo_name": "universe"} + ] + }, + "slurm_node": { + "cluster": [ + {"package": "slurm-smd-slurmd", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "slurm-smd-libpam-slurm-adopt", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "linux-headers-generic", "type": "deb", "repo_name": "main"} + ] + }, + "login_node":{ + "cluster": [ + {"package": "slurm-smd-slurmd", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "slurm-smd-client", "type": "deb", "repo_name": "slurm_custom"} + ] + }, + "login_compiler_node":{ + "cluster": [ + {"package": "slurm-smd-client", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "slurm-smd-slurmd", "type": "deb", "repo_name": "slurm_custom"} + ] + } +} diff --git a/input/config/x86_64/ubuntu/26.04/ucx.json b/input/config/x86_64/ubuntu/26.04/ucx.json new file mode 100644 index 0000000000..3ad9ec8df6 --- /dev/null +++ b/input/config/x86_64/ubuntu/26.04/ucx.json @@ -0,0 +1,12 @@ +{ + "ucx": { + "cluster": [ + { "package": "ucx", + "type": "tarball", + "url": "https://github.com/openucx/ucx/releases/download/v{{ ucx_version }}/ucx-{{ ucx_version }}.tar.gz" + }, + {"package": "g++", "type": "deb", "repo_name": "main"}, + {"package": "make", "type": "deb", "repo_name": "main"} + ] + } +} diff --git a/input/local_repo_config.yml b/input/local_repo_config.yml index 52f32d4cb3..fc9b11bdd8 100644 --- a/input/local_repo_config.yml +++ b/input/local_repo_config.yml @@ -82,7 +82,43 @@ #---------------------------- # Same as above but for aarch64 architecture. # -# 6. rhel_subscription_repo_config_x86_64 +# 6. ubuntu_os_url_x86_64 +#----------------------------- +# Mandatory when using Ubuntu as the cluster OS. +# Contains APT repository URLs for main, universe, and multiverse for x86_64. +# Fields: +# url : Base URL of the repository (APT archive URL) +# gpgkey : GPG key URL (leave empty to disable gpgcheck) +# name : Name of the repository [ Allowed repo names: main, universe, multiverse ] +# policy : Repository sync policy. Allowed values: always, partial (OPTIONAL) +# caching : Enable or disable local caching. Allowed values: true, false (OPTIONAL) +# Notes: +# - Ubuntu uses APT repositories (deb format), not RPM. +# - All 3 repositories [ main, universe, multiverse ] entries are mandatory. +# +# 7. ubuntu_os_url_aarch64 +#---------------------------- +# Same as above but for aarch64 architecture. +# +# 8. sles_os_url_x86_64 +#----------------------------- +# Mandatory when SLES SCC registration is not active. +# Contains repository URLs for basesystem, server-applications, and development-tools for x86_64. +# Fields: +# url : Base URL of the repository +# gpgkey : GPG key URL (leave empty to disable gpgcheck) +# name : Name of the repository [ Allowed repo names: basesystem, server-applications, development-tools, desktop-applications, packagehub ] +# policy : Repository sync policy. Allowed values: always, partial (OPTIONAL) +# caching : Enable or disable local caching. Allowed values: true, false (OPTIONAL) +# Notes: +# - Do not use Jinja variables in this configuration. +# - At minimum, basesystem and server-applications entries are mandatory. +# +# 9. sles_os_url_aarch64 +#---------------------------- +# Same as above but for aarch64 architecture. +# +# 10. rhel_subscription_repo_config_x86_64 #------------------------------------------- # Optional configuration for overriding policy and caching settings for RHEL # subscription-based repositories on x86_64 architecture. @@ -105,12 +141,12 @@ # - Matching is done by repository name (e.g., appstream) # - Non-matching repositories are added as additional repos # -# 7. rhel_subscription_repo_config_aarch64 +# 11. rhel_subscription_repo_config_aarch64 #-------------------------------------------- # Same as above but for aarch64 architecture. # #### ADVANCE CONFIGURATIONS FOR LOCAL REPO ### -# 8. omnia_repo_url_rhel_x86_64 +# 12. omnia_repo_url_rhel_x86_64 #------------------------------- # Mandatory repository URLs for downloading RPMS for Omnia features on RHEL x86_64. # Each entry includes url, gpgkey, and name. @@ -126,10 +162,27 @@ # If not provided, uses repo_config from software_config.json # caching : Enable or disable local caching. Allowed values: true, false (OPTIONAL) # If not provided, defaults to true -# 9. omnia_repo_url_rhel_aarch64 +# 13. omnia_repo_url_rhel_aarch64 #-------------------------------- # Same as above but for RHEL aarch64. # +# 14. omnia_repo_url_ubuntu_x86_64 +#---------------------------------- +# Mandatory repository URLs for downloading packages for Omnia features on Ubuntu x86_64. +# Uses APT (deb) repositories. +# +# 15. omnia_repo_url_ubuntu_aarch64 +#----------------------------------- +# Same as above but for Ubuntu aarch64. +# +# 16. omnia_repo_url_sles_x86_64 +#-------------------------------- +# Mandatory repository URLs for downloading RPMS for Omnia features on SLES x86_64. +# +# 17. omnia_repo_url_sles_aarch64 +#--------------------------------- +# Same as above but for SLES aarch64. +# # 10. additional_repos_x86_64 #---------------------------- # Optional list of additional repository URLs for x86_64 architecture. @@ -166,6 +219,7 @@ user_registry: # user_repo_url_x86_64: # - { url: "", gpgkey: "", sslcacert: "", sslclientkey: "", sslclientcert: "", name: "slurm_custom" } user_repo_url_x86_64: + - { url: "http://100.98.68.136/ubuntu-slurm/", gpgkey: "", name: "slurm_custom", apt_distributions: "noble" } user_repo_url_aarch64: #Example: # rhel_os_url_x86_64: @@ -174,6 +228,22 @@ user_repo_url_aarch64: # - { url: "http://AppStream.com/AppStream/x86_64/os/", gpgkey: "http://AppStream.com/AppStream/x86_64/os/RPM-GPG-KEY", sslcacert: "", sslclientkey: "", sslclientcert: "", name: "appstream" } rhel_os_url_x86_64: rhel_os_url_aarch64: +#Example: +# ubuntu_os_url_x86_64: +# - { url: "http://archive.ubuntu.com/ubuntu/dists/plucky/main/", gpgkey: "", name: "main"} +# - { url: "http://archive.ubuntu.com/ubuntu/dists/plucky/universe/", gpgkey: "", name: "universe"} +# - { url: "http://archive.ubuntu.com/ubuntu/dists/plucky/multiverse/", gpgkey: "", name: "multiverse"} +ubuntu_os_url_x86_64: + - { url: "http://archive.ubuntu.com/ubuntu/", gpgkey: "", name: "main"} +ubuntu_os_url_aarch64: + - { url: "http://ports.ubuntu.com/ubuntu-ports/", gpgkey: "", name: "main"} +#Example: +# sles_os_url_x86_64: +# - { url: "http://smt.example.com/repo/SUSE/Products/SLE-Module-Basesystem/16/x86_64/", gpgkey: "", name: "basesystem"} +# - { url: "http://smt.example.com/repo/SUSE/Products/SLE-Module-Server-Applications/16/x86_64/", gpgkey: "", name: "server-applications"} +# - { url: "http://smt.example.com/repo/SUSE/Products/SLE-Module-Development-Tools/16/x86_64/", gpgkey: "", name: "development-tools"} +sles_os_url_x86_64: +sles_os_url_aarch64: # Example: # rhel_subscription_repo_config_x86_64: # - { url: "https://example.com/appstream", gpgkey: "", sslcacert: "", sslclientkey: "", sslclientcert: "", name: "appstream", policy: "always", caching: true } @@ -195,15 +265,35 @@ omnia_repo_url_rhel_x86_64: - { url: "https://dl.fedoraproject.org/pub/epel/10/Everything/x86_64/", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-10", name: "epel"} - { url: "https://pkgs.k8s.io/core:/stable:/v1.35/rpm/", gpgkey: "https://pkgs.k8s.io/core:/stable:/v1.35/rpm/repodata/repomd.xml.key", name: "kubernetes-v1-35"} - { url: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/rpm/", gpgkey: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/rpm/repodata/repomd.xml.key", name: "cri-o-v1-35"} - - { url: "https://linux.mellanox.com/public/repo/doca/3.2.1/rhel10/x86_64/", gpgkey: "https://linux.mellanox.com/public/repo/doca/3.2.1/rhel10/x86_64/repodata/repomd.xml.key", name: "doca"} - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel10/x86_64/", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel10/x86_64/repodata/repomd.xml.key", name: "cuda"} - { url: "https://developer.download.nvidia.com/hpc-sdk/rhel/x86_64", gpgkey: "https://developer.download.nvidia.com/hpc-sdk/rhel/RPM-GPG-KEY-NVIDIA-HPC-SDK", name: "nvidia-hpc-sdk"} omnia_repo_url_rhel_aarch64: - { url: "https://download.docker.com/linux/centos/10/aarch64/stable/", gpgkey: "https://download.docker.com/linux/centos/gpg", name: "docker-ce"} - { url: "https://dl.fedoraproject.org/pub/epel/10/Everything/aarch64/", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-10", name: "epel"} - - { url: "https://linux.mellanox.com/public/repo/doca/3.2.1/rhel10/arm64-sbsa/", gpgkey: "https://linux.mellanox.com/public/repo/doca/3.2.1/rhel10/arm64-sbsa/repodata/repomd.xml.key", name: "doca"} - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel10/sbsa/", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel10/sbsa/repodata/repomd.xml.key", name: "cuda"} - { url: "https://developer.download.nvidia.com/hpc-sdk/rhel/aarch64", gpgkey: "https://developer.download.nvidia.com/hpc-sdk/rhel/RPM-GPG-KEY-NVIDIA-HPC-SDK", name: "nvidia-hpc-sdk"} +# Making incorrect changes to this variable can cause omnia failure. Please edit cautiously. +omnia_repo_url_ubuntu_x86_64: + - { url: "https://download.docker.com/linux/ubuntu/", gpgkey: "https://download.docker.com/linux/ubuntu/gpg", name: "docker-ce", apt_distributions: "plucky", apt_components: "stable"} + - { url: "https://pkgs.k8s.io/core:/stable:/v1.35/deb/", gpgkey: "https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key", name: "kubernetes-v1-35"} + - { url: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/deb/", gpgkey: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/deb/Release.key", name: "cri-o-v1-35"} + - { url: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/x86_64/", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/x86_64/3bf863cc.pub", name: "cuda"} + - { url: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/amd64", gpgkey: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/DEB-GPG-KEY-NVIDIA-HPC-SDK", name: "nvidia-hpc-sdk"} +omnia_repo_url_ubuntu_aarch64: + - { url: "https://download.docker.com/linux/ubuntu/", gpgkey: "https://download.docker.com/linux/ubuntu/gpg", name: "docker-ce", apt_distributions: "plucky", apt_components: "stable"} + - { url: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/sbsa/", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/sbsa/3bf863cc.pub", name: "cuda"} + - { url: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/arm64", gpgkey: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/DEB-GPG-KEY-NVIDIA-HPC-SDK", name: "nvidia-hpc-sdk"} +# Making incorrect changes to this variable can cause omnia failure. Please edit cautiously. +omnia_repo_url_sles_x86_64: + - { url: "https://download.docker.com/linux/sles/16/x86_64/stable/", gpgkey: "https://download.docker.com/linux/sles/gpg", name: "docker-ce"} + - { url: "https://pkgs.k8s.io/core:/stable:/v1.35/rpm/", gpgkey: "https://pkgs.k8s.io/core:/stable:/v1.35/rpm/repodata/repomd.xml.key", name: "kubernetes-v1-35"} + - { url: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/rpm/", gpgkey: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/rpm/repodata/repomd.xml.key", name: "cri-o-v1-35"} + - { url: "https://developer.download.nvidia.com/compute/cuda/repos/sles16/x86_64/", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/sles16/x86_64/repodata/repomd.xml.key", name: "cuda"} + - { url: "https://developer.download.nvidia.com/hpc-sdk/sles/x86_64", gpgkey: "https://developer.download.nvidia.com/hpc-sdk/sles/RPM-GPG-KEY-NVIDIA-HPC-SDK", name: "nvidia-hpc-sdk"} +omnia_repo_url_sles_aarch64: + - { url: "https://download.docker.com/linux/sles/16/aarch64/stable/", gpgkey: "https://download.docker.com/linux/sles/gpg", name: "docker-ce"} + - { url: "https://developer.download.nvidia.com/compute/cuda/repos/sles16/sbsa/", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/sles16/sbsa/repodata/repomd.xml.key", name: "cuda"} + - { url: "https://developer.download.nvidia.com/hpc-sdk/sles/aarch64", gpgkey: "https://developer.download.nvidia.com/hpc-sdk/sles/RPM-GPG-KEY-NVIDIA-HPC-SDK", name: "nvidia-hpc-sdk"} # Example: # additional_repos_x86_64: # - { url: "https://rpm.grafana.com/", gpgkey: "", name: "grafana" } diff --git a/input_validation/validate_config.yml b/input_validation/validate_config.yml index dc9dfa3913..184add09ff 100644 --- a/input_validation/validate_config.yml +++ b/input_validation/validate_config.yml @@ -94,7 +94,9 @@ ansible.builtin.include_role: name: validate_subscription tasks_from: check_rhel_subscription.yml - when: "'local_repo' in (hostvars['localhost']['omnia_run_tags'] | default([]))" + when: + - "'local_repo' in (hostvars['localhost']['omnia_run_tags'] | default([]))" + - "hostvars['localhost']['cluster_os_type'] | default('') == 'rhel'" - name: Configure RHEL repository URLs hosts: localhost @@ -107,7 +109,9 @@ ansible.builtin.include_role: name: validate_subscription tasks_from: configure_rhel_os_urls.yml - when: "'local_repo' in (omnia_run_tags | default([]))" + when: + - "'local_repo' in (omnia_run_tags | default([]))" + - "cluster_os_type | default('') == 'rhel'" - name: Validate omnia input config hosts: localhost diff --git a/local_repo/roles/parse_and_download/tasks/process_rpm_repo.yml b/local_repo/roles/parse_and_download/tasks/process_rpm_repo.yml index 78de31f50e..7751071322 100644 --- a/local_repo/roles/parse_and_download/tasks/process_rpm_repo.yml +++ b/local_repo/roles/parse_and_download/tasks/process_rpm_repo.yml @@ -20,7 +20,7 @@ local_repo_config_path: "{{ local_repo_config_path }}" log_dir: "{{ base_path }}/{{ cluster_os_type }}/{{ cluster_os_version }}" key_path: "{{ project_input_path }}" - sub_urls: "{{ sub_final_repo_urls }}" + sub_urls: "{{ sub_final_repo_urls | default({}) }}" register: result - name: Process URL mirrors from local_repo_config diff --git a/local_repo/roles/validation/vars/main.yml b/local_repo/roles/validation/vars/main.yml index 7ea0aee858..31df5e1694 100644 --- a/local_repo/roles/validation/vars/main.yml +++ b/local_repo/roles/validation/vars/main.yml @@ -117,14 +117,20 @@ fail_msg: >- versions_fail_msg: "Versions were not defined for the following softwares: {{ failed_softwares | join(', ') }} in software_config.json. Refer examples/template_{{ cluster_os_type }}_software_config.json and define version details accordingly in {{ project_input_path }}/software_config.json" -cluster_os_type_fail_msg: "Failed. The supported values of cluster_os_type is Fedora" +cluster_os_type_fail_msg: "Failed. The supported values of cluster_os_type are rhel, ubuntu, sles" cluster_os_version_fail_msg_fedora: "Failed. The supported values of cluster_os_version is 38 when cluster_os_type is Fedora" # cross_os_support_fail_msg: "Cross-OS is not supported: control_plane_os '{{ control_plane_os }}' does not match cluster_os_type '{{ cluster_os_type }}'" valid_cluster_os_type: - - 'fedora' + - 'rhel' + - 'ubuntu' + - 'sles' rhel_valid_os_versions: - '10.0' - '10.1' +ubuntu_valid_os_versions: + - '26.04' +sles_valid_os_versions: + - '16.0' rocky_valid_os_versions: - '10.0' - '10.1' diff --git a/provision/{changed: b/provision/{changed: new file mode 100644 index 0000000000..e69de29bb2 From da6aed81442e71f9e585c81061175cbe96d1966d Mon Sep 17 00:00:00 2001 From: Sayuri Date: Mon, 29 Jun 2026 15:55:42 +0530 Subject: [PATCH 06/15] Build Image --- .../fetch_packages/tasks/fetch_pulp_repos.yml | 25 +++++ .../tasks/build_image_common.yml | 9 +- .../tasks/build_ubuntu_base_image.yml | 93 +++++++++++++++++++ .../roles/image_creation/tasks/main.yml | 6 ++ .../images/ubuntu-base-config.yaml.j2 | 30 ++++++ .../roles/image_creation/vars/main.yml | 11 +++ common/vars/openchami_image_cmd.yml | 6 +- 7 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 build_image_x86_64/roles/image_creation/tasks/build_ubuntu_base_image.yml create mode 100644 build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 diff --git a/build_image_x86_64/roles/fetch_packages/tasks/fetch_pulp_repos.yml b/build_image_x86_64/roles/fetch_packages/tasks/fetch_pulp_repos.yml index a919d5930b..bd72563ccd 100644 --- a/build_image_x86_64/roles/fetch_packages/tasks/fetch_pulp_repos.yml +++ b/build_image_x86_64/roles/fetch_packages/tasks/fetch_pulp_repos.yml @@ -37,3 +37,28 @@ ansible.builtin.debug: msg: "{{ rhel_x86_64_repos | to_nice_yaml(indent=2) }}" verbosity: 2 + + - name: Fetch pulp deb endpoints for ubuntu x86_64 + ansible.builtin.command: > + pulp deb distribution list --field name,base_url + register: pulp_deb_endpoints + changed_when: false + failed_when: false + + - name: Filter only x86_64 ubuntu deb distributions + ansible.builtin.set_fact: + pulp_x86_64_deb_distributions: >- + {{ (pulp_deb_endpoints.stdout | default('[]') | from_json) + | selectattr('name', 'match', '^x86_64') + | list }} + when: pulp_deb_endpoints.rc == 0 and pulp_deb_endpoints.stdout | default('') | length > 0 + + - name: Build ubuntu_x86_64_repos list from pulp deb distributions + ansible.builtin.set_fact: + ubuntu_x86_64_repos: >- + {{ pulp_x86_64_deb_distributions | default([]) | map('combine', {'gpg': ''}) | list }} + + - name: Debug ubuntu_x86_64_repos + ansible.builtin.debug: + msg: "{{ ubuntu_x86_64_repos | to_nice_yaml(indent=2) }}" + verbosity: 2 diff --git a/build_image_x86_64/roles/image_creation/tasks/build_image_common.yml b/build_image_x86_64/roles/image_creation/tasks/build_image_common.yml index 5d32246379..79d39889a0 100644 --- a/build_image_x86_64/roles/image_creation/tasks/build_image_common.yml +++ b/build_image_x86_64/roles/image_creation/tasks/build_image_common.yml @@ -28,9 +28,12 @@ rhel_tag: "{{ hostvars['localhost']['rhel_tag'] }}" oim_node_name: "{{ hostvars['localhost']['oim_node_name'] }}" domain_name: "{{ hostvars['localhost']['domain_name'] }}" - rhel_x86_64_repos: "{{ hostvars['localhost']['rhel_x86_64_repos'] }}" - x86_64_base_image_packages: "{{ hostvars['localhost']['x86_64_base_image_packages'] }}" - compute_images_dict: "{{ hostvars['localhost']['compute_images_dict'] }}" + rhel_x86_64_repos: "{{ hostvars['localhost']['rhel_x86_64_repos'] | default([]) }}" + ubuntu_x86_64_repos: "{{ hostvars['localhost']['ubuntu_x86_64_repos'] | default([]) }}" + ubuntu_tag: "{{ hostvars['localhost']['software_config']['cluster_os_version'] | default('24.04') }}" + x86_64_base_image_packages: "{{ hostvars['localhost']['x86_64_base_image_packages'] | default([]) }}" + x86_64_ubuntu_base_image_packages: "{{ hostvars['localhost']['x86_64_ubuntu_base_image_packages'] | default([]) }}" + compute_images_dict: "{{ hostvars['localhost']['compute_images_dict'] | default({}) }}" - name: Normalize build stream inputs for base image ansible.builtin.set_fact: diff --git a/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_base_image.yml b/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_base_image.yml new file mode 100644 index 0000000000..04363a5a23 --- /dev/null +++ b/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_base_image.yml @@ -0,0 +1,93 @@ +# Copyright 2026 Dell Inc. or its subsidiaries. All Rights Reserved. +# +# Licensed 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. +--- + +- name: Create ochami images directory + ansible.builtin.file: + path: "{{ openchami_work_dir }}/images" + state: directory + mode: "{{ dir_permissions_755 }}" + +- name: Create x86_64 ubuntu base image log file + ansible.builtin.file: + path: "{{ openchami_x86_64_ubuntu_base_image_log_path }}" + state: touch + mode: "{{ dir_permissions_644 }}" + +- name: Render x86_64 ubuntu base image build config + ansible.builtin.template: + src: "{{ role_path }}/templates/images/ubuntu-base-config.yaml.j2" + dest: "{{ openchami_work_dir }}/images/{{ ubuntu_x86_64_base_image_name }}-{{ ubuntu_tag }}.yaml" + mode: "{{ dir_permissions_644 }}" + +- name: Build and verify x86_64 ubuntu base osimage + block: + - name: Build x86_64 ubuntu base osimage + ansible.builtin.shell: + cmd: | + set -o pipefail + podman run --rm --device /dev/fuse --network host \ + {{ ochami_ubuntu_mounts | join(' ') }} \ + {{ ochami_x86_64_image | join(' ') }} \ + {{ ochami_base_command | join(' ') }} \ + > '{{ openchami_x86_64_ubuntu_base_image_log_path }}' 2>&1 + async: "{{ job_async }}" + poll: 0 + register: ubuntu_base_image_build + changed_when: true + + - name: Wait for x86_64 ubuntu base image build to complete + ansible.builtin.async_status: + jid: "{{ ubuntu_base_image_build.ansible_job_id }}" + register: ubuntu_job_result + until: ubuntu_job_result.finished + retries: "{{ job_retry }}" + delay: "{{ job_delay }}" + + - name: Verify the x86_64 ubuntu base osimage in registry + ansible.builtin.command: + cmd: "/usr/local/bin/regctl repo ls {{ oim_node_name }}.{{ domain_name }}:5000" + changed_when: false + register: verify_ubuntu_base_osimage + + - name: Fail if x86_64 ubuntu base osimage not created + ansible.builtin.fail: + msg: "Failed to build ubuntu base osimage {{ oim_node_name }}/{{ ubuntu_x86_64_base_image_name }}" + when: (oim_node_name + '/' + ubuntu_x86_64_base_image_name) not in verify_ubuntu_base_osimage.stdout_lines + + - name: Verify x86_64 ubuntu base osimage output + ansible.builtin.debug: + msg: "{{ verify_ubuntu_base_osimage.stdout_lines }}" + + rescue: + - name: Fail the build if the ubuntu base image build fails + ansible.builtin.fail: + msg: "{{ ubuntu_base_image_failure_msg }}" + + always: + - name: Set openchami SELinux context for Local flow + ansible.builtin.command: chcon -R system_u:object_r:container_file_t:s0 "{{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami" + changed_when: true + delegate_to: oim + connection: ssh + failed_when: false + when: hostvars['localhost']['omnia_share_option'] == 'Local' + + - name: Set openchami SELinux context for NFS internal flow + ansible.builtin.command: chcon -R system_u:object_r:container_file_t:s0 "{{ hostvars['localhost']['nfs_server_share_path'] }}/omnia/openchami" + changed_when: true + delegate_to: oim + connection: ssh + failed_when: false + when: (hostvars['localhost']['omnia_share_option'] == 'NFS' and hostvars['localhost']['nfs_type'] | default('') == 'internal') diff --git a/build_image_x86_64/roles/image_creation/tasks/main.yml b/build_image_x86_64/roles/image_creation/tasks/main.yml index ee36076cef..18e2f519f7 100644 --- a/build_image_x86_64/roles/image_creation/tasks/main.yml +++ b/build_image_x86_64/roles/image_creation/tasks/main.yml @@ -32,9 +32,15 @@ ansible.builtin.include_tasks: build_base_image.yml tags: base_image +- name: Invoking x86_64 build ubuntu base image playbook + ansible.builtin.include_tasks: build_ubuntu_base_image.yml + tags: ubuntu_base_image + when: hostvars['localhost']['software_config']['cluster_os_type'] | default('rhel') == 'ubuntu' + - name: Invoking x86_64 build rhel compute image playbooks ansible.builtin.include_tasks: build_compute_image.yml tags: compute_image + when: hostvars['localhost']['software_config']['cluster_os_type'] | default('rhel') == 'rhel' - name: Set S3 bucket ACLs for PowerScale backend ansible.builtin.include_tasks: set_s3_acl.yml diff --git a/build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 b/build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 new file mode 100644 index 0000000000..caa1ed28bc --- /dev/null +++ b/build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 @@ -0,0 +1,30 @@ +options: + layer_type: 'base' + name: '{{ ubuntu_x86_64_base_image_name }}' + publish_tags: '{{ ubuntu_tag }}' + pkg_manager: 'apt' + parent: 'ubuntu:{{ ubuntu_tag }}' + publish_registry: '{{ oim_node_name }}.{{ domain_name }}:5000/{{ oim_node_name }}' + registry_opts_push: + - '--tls-verify=false' + +repos: +{% for repo in ubuntu_x86_64_repos | default([]) %} +{% if repo.base_url | length > 1 %} + - alias: '{{ repo.name }}' + url: '{{ repo.base_url }}' +{% endif %} +{% if repo.gpg | default('') | length > 1 %} + gpg: '{{ repo.gpg }}' +{% endif %} +{% endfor %} + +packages: +{% for pkg in x86_64_ubuntu_base_image_packages | default([]) %} + - {{ pkg }} +{% endfor %} + +cmds: +{% for cmd in base_image_commands | default([]) %} + - cmd: "{{ cmd }}" +{% endfor %} diff --git a/build_image_x86_64/roles/image_creation/vars/main.yml b/build_image_x86_64/roles/image_creation/vars/main.yml index c7117d45e6..b918d4db3f 100644 --- a/build_image_x86_64/roles/image_creation/vars/main.yml +++ b/build_image_x86_64/roles/image_creation/vars/main.yml @@ -31,6 +31,10 @@ ochami_mounts: - --user 0 --privileged - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/usr/local/share/ca-certificates/pulp_webserver.crt:z - -v {{ openchami_work_dir }}/images/{{ rhel_x86_64_base_image_name }}-{{ rhel_tag }}.yaml:/home/builder/config.yaml:z +ochami_ubuntu_mounts: + - --user 0 --privileged + - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/usr/local/share/ca-certificates/pulp_webserver.crt:z + - -v {{ openchami_work_dir }}/images/{{ ubuntu_x86_64_base_image_name | default('ubuntu-x86_64_base') }}-{{ ubuntu_tag | default('24.04') }}.yaml:/home/builder/config.yaml:z ochami_compute_mounts: - --user 0 --privileged - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/usr/local/share/ca-certificates/pulp_webserver.crt:z @@ -45,6 +49,13 @@ ochami_base_command: # build_base_image.yml openchami_log_dir: "{{ oim_shared_path }}/omnia/log/openchami" openchami_x86_64_base_image_log_path: "{{ oim_shared_path }}/omnia/log/openchami/x86_64_base_image.log" +openchami_x86_64_ubuntu_base_image_log_path: "{{ oim_shared_path }}/omnia/log/openchami/x86_64_ubuntu_base_image.log" +# Ubuntu image defaults +ubuntu_x86_64_base_image_name: "ubuntu-x86_64_base" +ubuntu_tag: "24.04" +ubuntu_base_image_failure_msg: | + Ubuntu x86_64 base image build job failed or timed out. + Check logs at path {{ openchami_x86_64_ubuntu_base_image_log_path }} for details. # build_base_image.yml - image-build config template openchami_base_image_config_template: "{{ role_path }}/templates/images/rhel-base-config.yaml.j2" base_image_failure_msg: | diff --git a/common/vars/openchami_image_cmd.yml b/common/vars/openchami_image_cmd.yml index aa0ff89d06..965df680ce 100644 --- a/common/vars/openchami_image_cmd.yml +++ b/common/vars/openchami_image_cmd.yml @@ -18,8 +18,10 @@ rhel_x86_64_base_image_name: "rhel-x86_64_base" rhel_aarch64_base_image_name: "rhel-aarch64_base" base_image_commands: - - "dracut --add 'dmsquash-live livenet network-manager' --install '/usr/lib/systemd/systemd-sysroot-fstab-check' --kver $(basename /lib/modules/*) -N -f --logfile /tmp/dracut.log 2>/dev/null" # noqa: yaml[line-length] - - "echo DRACUT LOG:; cat /tmp/dracut.log" + # Disabled - dmsquash-live module may not exist in RHEL 10 or not needed for base image + # - "KVER=$(ls /lib/modules | head -1); dracut --add 'dmsquash-live livenet network-manager' --install '/usr/lib/systemd/systemd-sysroot-fstab-check' --kver $KVER -N -f --logfile /tmp/dracut.log 2>/dev/null" # noqa: yaml[line-length] + # - "echo DRACUT LOG:; cat /tmp/dracut.log" + - "echo 'Skipping dracut command for base image'" # x86_64 compute commands os_x86_64_compute_commands: From 40c7fc276ee99a3353faebf5fce8f59be10e9325 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Tue, 30 Jun 2026 13:03:07 +0530 Subject: [PATCH 07/15] Fix: Build Image --- .../image_creation/templates/images/rhel-compute-config.yaml.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_image_x86_64/roles/image_creation/templates/images/rhel-compute-config.yaml.j2 b/build_image_x86_64/roles/image_creation/templates/images/rhel-compute-config.yaml.j2 index a10790edf7..f8c123813d 100644 --- a/build_image_x86_64/roles/image_creation/templates/images/rhel-compute-config.yaml.j2 +++ b/build_image_x86_64/roles/image_creation/templates/images/rhel-compute-config.yaml.j2 @@ -1,5 +1,5 @@ options: - layer_type: base + layer_type: compute name: '{{ rhel_base_compute_image_name }}' publish_tags: '{{ rhel_tag }}' pkg_manager: dnf From 4ab9b93ebd2d2cee48b3598295b9ea844c9c9d23 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Fri, 3 Jul 2026 10:36:41 +0530 Subject: [PATCH 08/15] Ubuntu Boot Image --- .../fetch_packages/tasks/fetch_pulp_repos.yml | 40 ++++- .../tasks/build_ubuntu_compute_image.yml | 163 ++++++++++++++++++ .../roles/image_creation/tasks/main.yml | 6 + .../tasks/prepare_pulp_image.yml | 2 +- .../images/ubuntu-base-config.yaml.j2 | 7 + .../images/ubuntu-compute-config.yaml.j2 | 45 +++++ .../roles/image_creation/vars/main.yml | 6 +- .../library/module_utils/local_repo/config.py | 1 + common/library/modules/process_rpm_config.py | 3 + input/local_repo_config.yml | 26 ++- input/software_config.json | 4 +- input/storage_config.yml | 4 +- .../tasks/configure_bss_group.yml | 10 +- .../templates/bss/bss.yaml.j2 | 6 +- .../tasks/validate_image.yml | 6 +- 15 files changed, 302 insertions(+), 27 deletions(-) create mode 100644 build_image_x86_64/roles/image_creation/tasks/build_ubuntu_compute_image.yml create mode 100644 build_image_x86_64/roles/image_creation/templates/images/ubuntu-compute-config.yaml.j2 diff --git a/build_image_x86_64/roles/fetch_packages/tasks/fetch_pulp_repos.yml b/build_image_x86_64/roles/fetch_packages/tasks/fetch_pulp_repos.yml index bd72563ccd..798ce859ab 100644 --- a/build_image_x86_64/roles/fetch_packages/tasks/fetch_pulp_repos.yml +++ b/build_image_x86_64/roles/fetch_packages/tasks/fetch_pulp_repos.yml @@ -53,10 +53,46 @@ | list }} when: pulp_deb_endpoints.rc == 0 and pulp_deb_endpoints.stdout | default('') | length > 0 - - name: Build ubuntu_x86_64_repos list from pulp deb distributions + - name: Fetch pulp deb remotes with distribution info + ansible.builtin.command: > + pulp deb remote list --field name,distributions,components + register: pulp_deb_remotes + changed_when: false + failed_when: false + + - name: Build apt distribution map from pulp deb remotes + ansible.builtin.set_fact: + pulp_deb_remote_map: >- + {{ (pulp_deb_remotes.stdout | default('[]') | from_json) + | items2dict(key_name='name', value_name='distributions') }} + pulp_deb_comp_map: >- + {{ (pulp_deb_remotes.stdout | default('[]') | from_json) + | items2dict(key_name='name', value_name='components') }} + when: pulp_deb_remotes.rc == 0 and pulp_deb_remotes.stdout | default('') | length > 0 + + - name: Initialize ubuntu_x86_64_repos list + ansible.builtin.set_fact: + ubuntu_x86_64_repos: [] + + - name: Build ubuntu_x86_64_repos list with apt distribution info ansible.builtin.set_fact: ubuntu_x86_64_repos: >- - {{ pulp_x86_64_deb_distributions | default([]) | map('combine', {'gpg': ''}) | list }} + {{ ubuntu_x86_64_repos + [ + item | combine({ + 'gpg': '', + 'apt_dist': (pulp_deb_remote_map | default({}))[item.name] | default('') | regex_replace('^/$', 'flat-repo'), + 'apt_comp': ((pulp_deb_comp_map | default({}))[item.name] | default('') | string) + | regex_replace('^None$', 'flat-repo-component') + | regex_replace('^$', 'flat-repo-component') + }) + ] }} + loop: "{{ pulp_x86_64_deb_distributions | default([]) }}" + loop_control: + loop_var: item + + - name: Filter out repos with no apt_dist (no remote mapping) + ansible.builtin.set_fact: + ubuntu_x86_64_repos: "{{ ubuntu_x86_64_repos | selectattr('apt_dist', 'ne', '') | list }}" - name: Debug ubuntu_x86_64_repos ansible.builtin.debug: diff --git a/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_compute_image.yml b/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_compute_image.yml new file mode 100644 index 0000000000..62bfef69f8 --- /dev/null +++ b/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_compute_image.yml @@ -0,0 +1,163 @@ +# Copyright 2026 Dell Inc. or its subsidiaries. All Rights Reserved. +# +# Licensed 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. +--- + +- name: Set compute image suffix when build stream inputs present + ansible.builtin.set_fact: + compute_image_suffix: "_{{ build_stream_job_id }}-{{ image_key | default('') }}" + when: + - enable_build_stream | bool + - (build_stream_job_id | default('') | length) > 0 + - (image_key | default('') | length) > 0 + +- name: Ensure log directory exists + ansible.builtin.file: + path: "{{ openchami_log_dir }}" + state: directory + mode: "{{ dir_permissions_755 }}" + +- name: Create x86_64 ubuntu compute image log files + ansible.builtin.file: + path: "{{ openchami_log_dir }}/{{ item.key }}{{ compute_image_suffix }}_compute_image.log" + state: touch + mode: "{{ dir_permissions_644 }}" + loop: "{{ compute_images_dict | dict2items }}" + loop_control: + loop_var: item + +- name: Render ubuntu compute image build configs + ansible.builtin.template: + src: "{{ role_path }}/templates/images/ubuntu-compute-config.yaml.j2" + dest: "{{ openchami_work_dir }}/images/ubuntu-{{ item.key }}{{ compute_image_suffix }}-{{ ubuntu_tag }}.yaml" + mode: "{{ dir_permissions_644 }}" + vars: + ubuntu_base_compute_image_name: "ubuntu-{{ item.key }}{{ omnia_suffix }}{{ compute_image_suffix }}" + group_name: "{{ item.key }}" + compute_packages: "{{ item.value.packages }}" + functional_group: "{{ item.value.functional_group }}" + loop: "{{ compute_images_dict | dict2items }}" + loop_control: + loop_var: item + +- name: Build x86_64 ubuntu compute osimages in parallel + ansible.builtin.shell: + cmd: | + set -o pipefail + podman run --rm --device /dev/fuse --network host \ + -e S3_ACCESS={{ s3_access }} -e S3_SECRET={{ s3_secret }} \ + {{ aws_checksum_env }} --user 0 --privileged \ + -v {{ pulp_cert_host_path }}:/usr/local/share/ca-certificates/pulp_webserver.crt:z \ + -v {{ openchami_work_dir }}/images/ubuntu-{{ item.key }}{{ compute_image_suffix }}-{{ ubuntu_tag }}.yaml:/home/builder/config.yaml:z \ + -v {{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami/image-builder-installer.py:/usr/local/bin/installer.py:z \ + -v {{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami/image-builder-layer.py:/usr/local/bin/layer.py:z \ + -v {{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami/image-builder-publish.py:/usr/local/bin/publish.py:z \ + {{ ochami_x86_64_image | join(' ') }} \ + {{ ochami_base_command | join(' ') }} \ + > '{{ openchami_log_dir }}/{{ item.key }}{{ compute_image_suffix }}_compute_image.log' 2>&1 + async: "{{ job_async }}" + poll: 0 + loop: "{{ compute_images_dict | dict2items }}" + loop_control: + loop_var: item + register: ubuntu_compute_image_build_job + changed_when: true + +- name: Wait for all ubuntu compute image builds to finish + block: + - name: Display ubuntu image build jobs status + ansible.builtin.debug: + msg: "Waiting for ubuntu image build: {{ item.item.key }} (Job ID: {{ item.ansible_job_id }})" + loop: "{{ ubuntu_compute_image_build_job.results }}" + loop_control: + label: "{{ item.item.key }}" + + - name: Wait for all ubuntu compute image builds to complete + ansible.builtin.async_status: + jid: "{{ item.ansible_job_id }}" + register: ubuntu_job_result + until: ubuntu_job_result.finished + no_log: true + retries: "{{ job_retry }}" + delay: "{{ job_delay }}" + loop: "{{ ubuntu_compute_image_build_job.results }}" + loop_control: + label: "Building: {{ item.item.key }}" + + - name: Verify x86_64 ubuntu compute osimages in registry + ansible.builtin.command: + cmd: "/usr/local/bin/regctl repo ls {{ oim_node_name }}.{{ domain_name }}:5000" + changed_when: false + register: verify_ubuntu_compute_osimages + + - name: Verify x86_64 ubuntu compute osimages output + ansible.builtin.debug: + msg: "{{ verify_ubuntu_compute_osimages.stdout_lines }}" + + rescue: + - name: Identify failed ubuntu image builds + ansible.builtin.set_fact: + failed_images: > + {{ ubuntu_job_result.results + | selectattr('failed', 'defined') + | selectattr('failed', 'equalto', true) + | map(attribute='item.item.key') + | list }} + when: ubuntu_job_result.results is defined + + - name: Build failure message list + ansible.builtin.set_fact: + failure_msg_list: + - "x86_64 ubuntu compute image build job did not complete successfully." + - "Check logs at {{ openchami_log_dir }} for respective functional group for more details." + - "" + - "Failed images:" + + - name: Add failed image names to message + ansible.builtin.set_fact: + failure_msg_list: "{{ failure_msg_list + [' - ' + item] }}" + loop: "{{ failed_images | default(['Unknown - check all logs']) }}" + + - name: Add log paths section to message + ansible.builtin.set_fact: + failure_msg_list: "{{ failure_msg_list + ['', 'Check logs at ' + openchami_log_dir + ' for details:'] }}" + + - name: Add log file paths to message + ansible.builtin.set_fact: + failure_msg_list: "{{ failure_msg_list + [' - ' + openchami_log_dir + '/' + item + compute_image_suffix + '_compute_image.log'] }}" + loop: "{{ failed_images | default([]) }}" + + - name: Display x86_64 ubuntu compute image build failure details + ansible.builtin.debug: + msg: "{{ failure_msg_list }}" + + - name: Failed to build the x86_64 ubuntu compute image + ansible.builtin.fail: + msg: "x86_64 ubuntu compute image build failed. See details above." + + always: + - name: Set openchami SELinux context for Local flow + ansible.builtin.command: chcon -R system_u:object_r:container_file_t:s0 "{{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami" + changed_when: true + delegate_to: oim + connection: ssh + failed_when: false + when: hostvars['localhost']['omnia_share_option'] == 'Local' + + - name: Set openchami SELinux context for NFS internal flow + ansible.builtin.command: chcon -R system_u:object_r:container_file_t:s0 "{{ hostvars['localhost']['nfs_server_share_path'] }}/omnia/openchami" + changed_when: true + delegate_to: oim + connection: ssh + failed_when: false + when: (hostvars['localhost']['omnia_share_option'] == 'NFS' and hostvars['localhost']['nfs_type'] | default('') == 'internal') diff --git a/build_image_x86_64/roles/image_creation/tasks/main.yml b/build_image_x86_64/roles/image_creation/tasks/main.yml index 18e2f519f7..22a1687ab8 100644 --- a/build_image_x86_64/roles/image_creation/tasks/main.yml +++ b/build_image_x86_64/roles/image_creation/tasks/main.yml @@ -31,6 +31,7 @@ - name: Invoking x86_64 build base image playbook ansible.builtin.include_tasks: build_base_image.yml tags: base_image + when: hostvars['localhost']['software_config']['cluster_os_type'] | default('rhel') == 'rhel' - name: Invoking x86_64 build ubuntu base image playbook ansible.builtin.include_tasks: build_ubuntu_base_image.yml @@ -42,6 +43,11 @@ tags: compute_image when: hostvars['localhost']['software_config']['cluster_os_type'] | default('rhel') == 'rhel' +- name: Invoking x86_64 build ubuntu compute image playbooks + ansible.builtin.include_tasks: build_ubuntu_compute_image.yml + tags: ubuntu_compute_image + when: hostvars['localhost']['software_config']['cluster_os_type'] | default('rhel') == 'ubuntu' + - name: Set S3 bucket ACLs for PowerScale backend ansible.builtin.include_tasks: set_s3_acl.yml when: diff --git a/build_image_x86_64/roles/image_creation/tasks/prepare_pulp_image.yml b/build_image_x86_64/roles/image_creation/tasks/prepare_pulp_image.yml index 22f336b849..be961b2ff5 100644 --- a/build_image_x86_64/roles/image_creation/tasks/prepare_pulp_image.yml +++ b/build_image_x86_64/roles/image_creation/tasks/prepare_pulp_image.yml @@ -52,7 +52,7 @@ - name: Build full Podman image path for x86_64 ansible.builtin.set_fact: - pulp_x86_image: "{{ oim_pxe_ip }}:2225/{{ pulp_x86_64_image_name }}" + pulp_x86_image: "{{ pulp_x86_64_image_name if '/' in pulp_x86_64_image_name else oim_pxe_ip + ':2225/' + pulp_x86_64_image_name }}" - name: Pull and tag x86_64 image block: diff --git a/build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 b/build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 index caa1ed28bc..54224a5eb5 100644 --- a/build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 +++ b/build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 @@ -13,6 +13,10 @@ repos: {% if repo.base_url | length > 1 %} - alias: '{{ repo.name }}' url: '{{ repo.base_url }}' +{% if repo.apt_dist | default('') | length > 0 %} + apt_dist: '{{ repo.apt_dist }}' + apt_comp: '{{ repo.apt_comp | default('') }}' +{% endif %} {% endif %} {% if repo.gpg | default('') | length > 1 %} gpg: '{{ repo.gpg }}' @@ -20,11 +24,14 @@ repos: {% endfor %} packages: + - initramfs-tools + - linux-image-generic {% for pkg in x86_64_ubuntu_base_image_packages | default([]) %} - {{ pkg }} {% endfor %} cmds: + - cmd: "update-initramfs -c -k all" {% for cmd in base_image_commands | default([]) %} - cmd: "{{ cmd }}" {% endfor %} diff --git a/build_image_x86_64/roles/image_creation/templates/images/ubuntu-compute-config.yaml.j2 b/build_image_x86_64/roles/image_creation/templates/images/ubuntu-compute-config.yaml.j2 new file mode 100644 index 0000000000..e9bf4faf7f --- /dev/null +++ b/build_image_x86_64/roles/image_creation/templates/images/ubuntu-compute-config.yaml.j2 @@ -0,0 +1,45 @@ +options: + layer_type: base + name: '{{ ubuntu_base_compute_image_name }}' + publish_tags: '{{ ubuntu_tag }}' + pkg_manager: apt + parent: '{{ oim_node_name }}.{{ domain_name }}:5000/{{ oim_node_name }}/{{ ubuntu_x86_64_base_image_name }}:{{ ubuntu_tag }}' + registry_opts_pull: + - '--tls-verify=false' + publish_s3: '{{ s3_endpoint }}' + s3_prefix: '{{ group_name }}/{{ ubuntu_base_compute_image_name }}/' + s3_bucket: 'boot-images' + publish_registry: '{{ oim_node_name }}.{{ domain_name }}:5000/{{ oim_node_name }}' + registry_opts_push: + - '--tls-verify=false' + +repos: +{% for repo in ubuntu_x86_64_repos | default([]) %} +{% if repo.base_url | length > 1 %} + - alias: '{{ repo.name }}' + url: '{{ repo.base_url }}' +{% if repo.apt_dist | default('') | length > 0 %} + apt_dist: '{{ repo.apt_dist }}' + apt_comp: '{{ repo.apt_comp | default('') }}' +{% endif %} +{% endif %} +{% if repo.gpg | default('') | length > 1 %} + gpg: '{{ repo.gpg }}' +{% endif %} +{% endfor %} + +packages: +{% for pkg in compute_packages %} + - {{ pkg }} +{% endfor %} + +{% set command_var = functional_group + '_compute_commands' %} +{% set commands_list = lookup('vars', command_var, default=[]) %} +cmds: +{% if commands_list | length > 0 %} +{% for cmd in commands_list %} + - cmd: "{{ cmd }}" +{% endfor %} +{% else %} + [] +{% endif %} diff --git a/build_image_x86_64/roles/image_creation/vars/main.yml b/build_image_x86_64/roles/image_creation/vars/main.yml index b918d4db3f..5bf75ff9ab 100644 --- a/build_image_x86_64/roles/image_creation/vars/main.yml +++ b/build_image_x86_64/roles/image_creation/vars/main.yml @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. --- -pulp_x86_64_image_name: "dellhpcomniaaisolution/image-build-wolfi:1.1" +pulp_x86_64_image_name: "dellhpcomniaaisolution/image-build-el10:1.1" x86_64_local_tag: "x86_64-image-builder/ochami" pull_image_retries: "5" pull_image_delay: "10" @@ -35,6 +35,8 @@ ochami_ubuntu_mounts: - --user 0 --privileged - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/usr/local/share/ca-certificates/pulp_webserver.crt:z - -v {{ openchami_work_dir }}/images/{{ ubuntu_x86_64_base_image_name | default('ubuntu-x86_64_base') }}-{{ ubuntu_tag | default('24.04') }}.yaml:/home/builder/config.yaml:z + - -v {{ oim_shared_path }}/omnia/openchami/image-builder-installer.py:/usr/local/bin/installer.py:z + - -v {{ oim_shared_path }}/omnia/openchami/image-builder-layer.py:/usr/local/bin/layer.py:z ochami_compute_mounts: - --user 0 --privileged - -v {{ oim_shared_path }}/omnia/pulp/settings/certs/pulp_webserver.crt:/usr/local/share/ca-certificates/pulp_webserver.crt:z @@ -44,7 +46,7 @@ ochami_x86_64_image: - --entrypoint /bin/bash - "localhost/{{ x86_64_local_tag }}" ochami_base_command: - - -c 'update-ca-certificates && image-build --config /home/builder/config.yaml --log-level DEBUG' + - -c 'cp /usr/local/share/ca-certificates/pulp_webserver.crt /etc/pki/ca-trust/source/anchors/ && update-ca-trust && image-build --config /home/builder/config.yaml --log-level DEBUG' # build_base_image.yml openchami_log_dir: "{{ oim_shared_path }}/omnia/log/openchami" diff --git a/common/library/module_utils/local_repo/config.py b/common/library/module_utils/local_repo/config.py index de8e67b8c3..62c56d9e01 100644 --- a/common/library/module_utils/local_repo/config.py +++ b/common/library/module_utils/local_repo/config.py @@ -249,6 +249,7 @@ def _get_ca_cert_path(): "publish_repository": "pulp deb publication -t verbatim create --repository %s", "distribute_repository": "pulp deb distribution create --name %s --base-path %s --repository %s", "update_distribution": "pulp deb distribution update --name %s --base-path %s --repository %s", + "update_distribution_basepath": "pulp deb distribution update --name %s --base-path %s", "create_remote_cert": "pulp deb remote create --name %s --url %s --policy %s --ca-cert %s --client-cert %s --client-key %s", "update_remote_cert": "pulp deb remote update --name %s --url %s --policy %s --ca-cert %s --client-cert %s --client-key %s", "check_distribution": "pulp deb distribution show --name %s", diff --git a/common/library/modules/process_rpm_config.py b/common/library/modules/process_rpm_config.py index ccc18c53f2..d709619ca1 100644 --- a/common/library/modules/process_rpm_config.py +++ b/common/library/modules/process_rpm_config.py @@ -723,6 +723,9 @@ def create_distribution(repo, log, resync_repos=None, cluster_os_version="10.0") show_command = pulp_rpm_commands["check_distribution"] % repo_name create_command = pulp_rpm_commands["distribute_repository"] % (repo_name, base_path, repo_name) update_command = pulp_rpm_commands["update_distribution"] % (repo_name, base_path, repo_name) + # Use basepath-only update for deb to avoid repository/publication conflict + if cluster_os_type == "ubuntu": + update_command = pulp_rpm_commands.get("update_distribution_basepath", update_command) % (repo_name, base_path) log.info("Processing distribution for repository: '%s', Base path: '%s'", repo_name, base_path) # Check if distribution already exists diff --git a/input/local_repo_config.yml b/input/local_repo_config.yml index fc9b11bdd8..4de666de38 100644 --- a/input/local_repo_config.yml +++ b/input/local_repo_config.yml @@ -219,7 +219,7 @@ user_registry: # user_repo_url_x86_64: # - { url: "", gpgkey: "", sslcacert: "", sslclientkey: "", sslclientcert: "", name: "slurm_custom" } user_repo_url_x86_64: - - { url: "http://100.98.68.136/ubuntu-slurm/", gpgkey: "", name: "slurm_custom", apt_distributions: "noble" } + - { url: "http://100.98.68.136/ubuntu-slurm/", gpgkey: "", name: "slurm_custom", apt_distributions: "./", apt_components: "" } user_repo_url_aarch64: #Example: # rhel_os_url_x86_64: @@ -234,9 +234,15 @@ rhel_os_url_aarch64: # - { url: "http://archive.ubuntu.com/ubuntu/dists/plucky/universe/", gpgkey: "", name: "universe"} # - { url: "http://archive.ubuntu.com/ubuntu/dists/plucky/multiverse/", gpgkey: "", name: "multiverse"} ubuntu_os_url_x86_64: - - { url: "http://archive.ubuntu.com/ubuntu/", gpgkey: "", name: "main"} + - { url: "http://archive.ubuntu.com/ubuntu/", gpgkey: "", name: "main", apt_distributions: "plucky", apt_components: "main" } + - { url: "http://archive.ubuntu.com/ubuntu/", gpgkey: "", name: "restricted", apt_distributions: "plucky", apt_components: "restricted" } + - { url: "http://archive.ubuntu.com/ubuntu/", gpgkey: "", name: "universe", apt_distributions: "plucky", apt_components: "universe" } + - { url: "http://archive.ubuntu.com/ubuntu/", gpgkey: "", name: "multiverse", apt_distributions: "plucky", apt_components: "multiverse" } ubuntu_os_url_aarch64: - - { url: "http://ports.ubuntu.com/ubuntu-ports/", gpgkey: "", name: "main"} + - { url: "http://ports.ubuntu.com/ubuntu-ports/", gpgkey: "", name: "main", apt_distributions: "plucky", apt_components: "main" } + - { url: "http://ports.ubuntu.com/ubuntu-ports/", gpgkey: "", name: "restricted", apt_distributions: "plucky", apt_components: "restricted" } + - { url: "http://ports.ubuntu.com/ubuntu-ports/", gpgkey: "", name: "universe", apt_distributions: "plucky", apt_components: "universe" } + - { url: "http://ports.ubuntu.com/ubuntu-ports/", gpgkey: "", name: "multiverse", apt_distributions: "plucky", apt_components: "multiverse" } #Example: # sles_os_url_x86_64: # - { url: "http://smt.example.com/repo/SUSE/Products/SLE-Module-Basesystem/16/x86_64/", gpgkey: "", name: "basesystem"} @@ -275,14 +281,16 @@ omnia_repo_url_rhel_aarch64: # Making incorrect changes to this variable can cause omnia failure. Please edit cautiously. omnia_repo_url_ubuntu_x86_64: - { url: "https://download.docker.com/linux/ubuntu/", gpgkey: "https://download.docker.com/linux/ubuntu/gpg", name: "docker-ce", apt_distributions: "plucky", apt_components: "stable"} - - { url: "https://pkgs.k8s.io/core:/stable:/v1.35/deb/", gpgkey: "https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key", name: "kubernetes-v1-35"} - - { url: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/deb/", gpgkey: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/deb/Release.key", name: "cri-o-v1-35"} - - { url: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/x86_64/", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/x86_64/3bf863cc.pub", name: "cuda"} - - { url: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/amd64", gpgkey: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/DEB-GPG-KEY-NVIDIA-HPC-SDK", name: "nvidia-hpc-sdk"} + - { url: "https://pkgs.k8s.io/core:/stable:/v1.35/deb/", gpgkey: "https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key", name: "kubernetes-v1-35", apt_distributions: "./", apt_components: ""} + - { url: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/deb/", gpgkey: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/deb/Release.key", name: "cri-o-v1-35", apt_distributions: "./", apt_components: ""} + - { url: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/x86_64/", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/x86_64/3bf863cc.pub", name: "cuda", apt_distributions: "./", apt_components: ""} + - { url: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/amd64", gpgkey: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/DEB-GPG-KEY-NVIDIA-HPC-SDK", name: "nvidia-hpc-sdk", apt_distributions: "./", apt_components: ""} omnia_repo_url_ubuntu_aarch64: - { url: "https://download.docker.com/linux/ubuntu/", gpgkey: "https://download.docker.com/linux/ubuntu/gpg", name: "docker-ce", apt_distributions: "plucky", apt_components: "stable"} - - { url: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/sbsa/", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/sbsa/3bf863cc.pub", name: "cuda"} - - { url: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/arm64", gpgkey: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/DEB-GPG-KEY-NVIDIA-HPC-SDK", name: "nvidia-hpc-sdk"} + - { url: "https://pkgs.k8s.io/core:/stable:/v1.35/deb/", gpgkey: "https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key", name: "kubernetes-v1-35", apt_distributions: "./", apt_components: ""} + - { url: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/deb/", gpgkey: "https://download.opensuse.org/repositories/isv:/cri-o:/stable:/v1.35/deb/Release.key", name: "cri-o-v1-35", apt_distributions: "./", apt_components: ""} + - { url: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/sbsa/", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2604/sbsa/3bf863cc.pub", name: "cuda", apt_distributions: "./", apt_components: ""} + - { url: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/arm64", gpgkey: "https://developer.download.nvidia.com/hpc-sdk/ubuntu/DEB-GPG-KEY-NVIDIA-HPC-SDK", name: "nvidia-hpc-sdk", apt_distributions: "./", apt_components: ""} # Making incorrect changes to this variable can cause omnia failure. Please edit cautiously. omnia_repo_url_sles_x86_64: - { url: "https://download.docker.com/linux/sles/16/x86_64/stable/", gpgkey: "https://download.docker.com/linux/sles/gpg", name: "docker-ce"} diff --git a/input/software_config.json b/input/software_config.json index 877ba0c3dc..e5837dc42e 100644 --- a/input/software_config.json +++ b/input/software_config.json @@ -1,6 +1,6 @@ { - "cluster_os_type": "rhel", - "cluster_os_version": "10.0", + "cluster_os_type": "ubuntu", + "cluster_os_version": "26.04", "repo_config": "partial", "softwares": [ {"name": "default_packages", "arch": ["x86_64","aarch64"]}, diff --git a/input/storage_config.yml b/input/storage_config.yml index d5bc305f45..342f35e9c1 100644 --- a/input/storage_config.yml +++ b/input/storage_config.yml @@ -110,7 +110,7 @@ # # /mnt/vast/node001/tmp /tmp none bind 0 0 mounts: - name: "nfs_slurm" - source: "172.16.107.168:/mnt/share/omnia" + source: "100.96.20.223:/mnt/nfsuser/sayuri" mount_point: "/share_omnia" fs_type: "nfs" mnt_opts: "nosuid,rw,sync,hard,intr" @@ -118,7 +118,7 @@ mounts: functional_group_prefix: ["slurm", "login"] - name: "nfs_k8s" - source: "172.16.107.121:/mnt/share/omnia_k8s" + source: "100.96.20.223:/mnt/nfsuser/sayuri" mount_point: "/opt/omnia/k8s_mount" fs_type: "nfs" mnt_opts: "nosuid,rw,sync,hard,intr" diff --git a/provision/roles/configure_ochami/tasks/configure_bss_group.yml b/provision/roles/configure_ochami/tasks/configure_bss_group.yml index 6453fb4848..c1b10d4e4c 100644 --- a/provision/roles/configure_ochami/tasks/configure_bss_group.yml +++ b/provision/roles/configure_ochami/tasks/configure_bss_group.yml @@ -29,7 +29,7 @@ - name: Build image search pattern ansible.builtin.set_fact: image_search_pattern: >- - rhel-{{ functional_group_name }}{{ naming_suffix }} + {{ hostvars['localhost']['cluster_os_type'] | default('rhel') }}-{{ functional_group_name }}{{ naming_suffix }} - name: Verify image, kernel and initramfs in S3 (build stream and image-key) ansible.builtin.shell: | @@ -39,7 +39,7 @@ {% if hostvars['localhost']['kernel_version_override'] | default('') | length > 0 %} grep "{{ hostvars['localhost']['kernel_version_override'] }}" | \ {% endif %} - grep {{ hostvars['localhost']['cluster_os_version'] }} | sort -k1,2r | awk '{print $4}' | sed 's|s3://||' + sort -k1,2r | awk '{print $4}' | sed 's|s3://||' changed_when: false failed_when: false register: verify_s3_image_build_stream @@ -55,7 +55,7 @@ {% if hostvars['localhost']['kernel_version_override'] | default('') | length > 0 %} grep "{{ hostvars['localhost']['kernel_version_override'] }}" | \ {% endif %} - grep {{ hostvars['localhost']['cluster_os_version'] }} | sort -k1,2r | awk '{print $4}' | sed 's|s3://||' + sort -k1,2r | awk '{print $4}' | sed 's|s3://||' changed_when: false failed_when: false register: verify_s3_image @@ -65,7 +65,7 @@ - name: Set kernel and initrd variables (build stream) ansible.builtin.set_fact: kernel: "{{ verify_s3_image_build_stream.stdout_lines | select('search', 'vmlinuz') | list | first }}" - initrd: "{{ verify_s3_image_build_stream.stdout_lines | select('search', 'initramfs') | list | first }}" + initrd: "{{ verify_s3_image_build_stream.stdout_lines | select('search', 'initr') | list | first }}" when: - enable_build_stream - (compute_image_suffix | default('')) != '' @@ -73,7 +73,7 @@ - name: Set kernel and initrd variables (default) ansible.builtin.set_fact: kernel: "{{ verify_s3_image.stdout_lines | select('search', 'vmlinuz') | list | first }}" - initrd: "{{ verify_s3_image.stdout_lines | select('search', 'initramfs') | list | first }}" + initrd: "{{ verify_s3_image.stdout_lines | select('search', 'initr') | list | first }}" when: - not enable_build_stream diff --git a/provision/roles/configure_ochami/templates/bss/bss.yaml.j2 b/provision/roles/configure_ochami/templates/bss/bss.yaml.j2 index 8520902115..a796d870b4 100644 --- a/provision/roles/configure_ochami/templates/bss/bss.yaml.j2 +++ b/provision/roles/configure_ochami/templates/bss/bss.yaml.j2 @@ -11,13 +11,17 @@ initrd: "{{ s3_base_url }}/{{ initrd }}" and (compute_image_suffix | default('')) != '' else "" %} {% set img_suffix = naming_suffix | default('') %} +{% set cluster_os_type = hostvars['localhost']['cluster_os_type'] | default('rhel') %} {% set root_image_path = - "boot-images/%s/rhel-%s%s%s/rhel%s-rhel-%s%s%s-%s" % ( + "boot-images/%s/%s-%s%s%s/%s%s-%s-%s%s%s-%s" % ( functional_group_name, + cluster_os_type, functional_group_name, img_suffix, bs_suffix, + cluster_os_type, hostvars['localhost']['cluster_os_version'], + cluster_os_type, functional_group_name, img_suffix, bs_suffix, diff --git a/provision/roles/provision_validations/tasks/validate_image.yml b/provision/roles/provision_validations/tasks/validate_image.yml index 8745ec6a06..323961381f 100644 --- a/provision/roles/provision_validations/tasks/validate_image.yml +++ b/provision/roles/provision_validations/tasks/validate_image.yml @@ -46,7 +46,7 @@ - name: Build image search pattern for S3 validation ansible.builtin.set_fact: image_search_pattern: >- - rhel-{{ functional_group_name }}{{ naming_suffix }}{{ compute_image_suffix }} + {{ hostvars['localhost']['software_config']['cluster_os_type'] | default('rhel') }}-{{ functional_group_name }}{{ naming_suffix }}{{ compute_image_suffix }} - name: Verify image, kernel and initramfs in S3 ansible.builtin.shell: | @@ -56,7 +56,7 @@ {% if hostvars['localhost']['kernel_version_override'] | default('') | length > 0 %} grep "{{ hostvars['localhost']['kernel_version_override'] }}" | \ {% endif %} - grep {{ hostvars['localhost']['cluster_os_version'] }} | awk '{print $4}' | sed 's|s3://||' + awk '{print $4}' | sed 's|s3://||' changed_when: false failed_when: false register: verify_s3_image @@ -74,7 +74,7 @@ - name: Set kernel and initrd variables ansible.builtin.set_fact: kernel: "{{ verify_s3_image.stdout_lines | select('search', 'vmlinuz') | list | first }}" - initrd: "{{ verify_s3_image.stdout_lines | select('search', 'initramfs') | list | first }}" + initrd: "{{ verify_s3_image.stdout_lines | select('search', 'initr') | list | first }}" when: verify_s3_image.stdout_lines | length > 1 - name: Fail if kernel override did not match any S3 image From 32d9812c334d99918533450b66210f226d71bb22 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Tue, 7 Jul 2026 10:30:14 +0530 Subject: [PATCH 09/15] Misc --- common/library/modules/process_rpm_config.py | 33 +++++++++++++------- input/storage_config.yml | 2 +- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/common/library/modules/process_rpm_config.py b/common/library/modules/process_rpm_config.py index d709619ca1..837cab84b6 100644 --- a/common/library/modules/process_rpm_config.py +++ b/common/library/modules/process_rpm_config.py @@ -761,19 +761,21 @@ def create_distribution(repo, log, resync_repos=None, cluster_os_version="10.0") finally: log.info("Completed distribution creation/update for repository '%s'", repo.get("package", "unknown")) -def get_base_urls(log): +def get_base_urls(log, cluster_os_type="rhel"): """ - Fetch all distributions from Pulp RPM distribution. + Fetch all distributions from Pulp RPM/deb distribution. Args: log (logging.Logger): Logger instance for logging the process and errors. + cluster_os_type (str): The cluster OS type ('rhel' or 'ubuntu'). Returns: list: A list of dictionaries containing the base URLs and names of all distributions. Returns an empty list if there is an error. """ - command = ['pulp', 'rpm', 'distribution', 'list', '--field', 'base_url,name'] + dist_type = 'deb' if cluster_os_type == 'ubuntu' else 'rpm' + command = ['pulp', dist_type, 'distribution', 'list', '--field', 'base_url,name'] log.info(f"Executing command: {' '.join(command)}") result = subprocess.run(command,stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=True) @@ -797,19 +799,23 @@ def get_base_urls(log): return distributions -def create_yum_repo_file(distributions, log): +def create_yum_repo_file(distributions, log, cluster_os_type="rhel"): """ - Creates a new 'pulp.repo' file in /etc/yum.repos.d and adds multiple repositories. + Creates a new repo file for the package manager (yum.repos.d for RHEL, sources.list.d for Ubuntu). Args: distributions (list): A list of dictionaries containing the base URLs and names of all distributions. log (logging.Logger): Logger instance for logging the process and errors. + cluster_os_type (str): The cluster OS type ('rhel' or 'ubuntu'). Returns: None """ try: - repo_file_path = "/etc/yum.repos.d/pulp.repo" + if cluster_os_type == "ubuntu": + repo_file_path = "/etc/apt/sources.list.d/pulp.list" + else: + repo_file_path = "/etc/yum.repos.d/pulp.repo" log.info(f"Target repo file path: {repo_file_path}") # Validate input @@ -829,7 +835,10 @@ def create_yum_repo_file(distributions, log): for distribution in distributions: repo_name = distribution["name"] base_url = distribution["base_url"] - repo_entry = f""" + if cluster_os_type == "ubuntu": + repo_entry = f"deb [trusted=yes] {base_url} ./" + else: + repo_entry = f""" [{repo_name}] name={repo_name} repo baseurl={base_url} @@ -839,16 +848,16 @@ def create_yum_repo_file(distributions, log): repo_content += repo_entry.strip() + "\n\n" # Write all repositories at once - log.info("Writing all repository entries to pulp.repo file") + log.info("Writing all repository entries to repo file") with open(repo_file_path, 'w', encoding='utf-8') as repo_file: repo_file.write(repo_content.strip() + "\n") log.info(f"Created {repo_file_path} with {len(distributions)} repositories") except PermissionError: - log.error("Permission denied while writing to /etc/yum.repos.d/. Run with elevated privileges.") + log.error(f"Permission denied while writing to {repo_file_path}. Run with elevated privileges.") except Exception as e: - log.error(f"Unexpected error while creating YUM repo file: {e}") + log.error(f"Unexpected error while creating repo file: {e}") def validate_resync_repos(resync_repos, rpm_config, log): """ @@ -1492,13 +1501,13 @@ def manage_rpm_repositories_multiprocess(rpm_config, log, sw_archs=None, resync_ # and local_repo.yml runs again with already-synced repos. # Distributions must exist before we can fetch base_urls. log.info("Step 6: Ensuring pulp.repo file exists") - base_urls = get_base_urls(log) + base_urls = get_base_urls(log, cluster_os_type) if not base_urls: log.error("No base URLs retrieved from Pulp. Cannot create repo file.") return False, "Base URLs fetch failed — repo file not created." log.info(f"Fetched {len(base_urls)} base URLs from Pulp.") - create_yum_repo_file(base_urls, log) + create_yum_repo_file(base_urls, log, cluster_os_type) log.info("Successfully created/updated pulp.repo file with fetched base URLs.") # Return appropriate success message based on resync_repos and skip status diff --git a/input/storage_config.yml b/input/storage_config.yml index 342f35e9c1..7d5de4ccb3 100644 --- a/input/storage_config.yml +++ b/input/storage_config.yml @@ -139,7 +139,7 @@ mounts: source: "172.16.107.77:/share/vast" mount_point: "/mnt/vast" mount_params: "vast_rdma" - mount_on_oim: true + mount_on_oim: false functional_group_prefix: ["slurm_node", "login"] # -----------------------------Mount Params (Profiles)------------------------------- From 13a3db6cac926fc8245d3d29cd95da8c08198c71 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Wed, 8 Jul 2026 11:51:46 +0530 Subject: [PATCH 10/15] Ubuntu image booted --- .../fetch_packages/tasks/fetch_packages.yml | 1 + .../files/image-builder/installer.py | 386 ++++++++++++++++++ .../files/image-builder/layer.py | 235 +++++++++++ .../files/image-builder/publish.py | 191 +++++++++ .../tasks/build_ubuntu_base_image.yml | 10 + .../images/ubuntu-base-config.yaml.j2 | 13 +- .../build_image/common_functions.py | 2 +- .../modules/image_package_collector.py | 14 +- .../templates/bss/bss.yaml.j2 | 4 + 9 files changed, 845 insertions(+), 11 deletions(-) create mode 100644 build_image_x86_64/roles/image_creation/files/image-builder/installer.py create mode 100644 build_image_x86_64/roles/image_creation/files/image-builder/layer.py create mode 100644 build_image_x86_64/roles/image_creation/files/image-builder/publish.py diff --git a/build_image_x86_64/roles/fetch_packages/tasks/fetch_packages.yml b/build_image_x86_64/roles/fetch_packages/tasks/fetch_packages.yml index ba02905334..149429bd0f 100644 --- a/build_image_x86_64/roles/fetch_packages/tasks/fetch_packages.yml +++ b/build_image_x86_64/roles/fetch_packages/tasks/fetch_packages.yml @@ -26,6 +26,7 @@ - name: Set x86_64_base_image_packages ansible.builtin.set_fact: x86_64_base_image_packages: "{{ base_image_output.base_image_packages }}" + x86_64_ubuntu_base_image_packages: "{{ base_image_output.base_image_packages }}" - name: Debug package x86_64_base_image_packages ansible.builtin.debug: diff --git a/build_image_x86_64/roles/image_creation/files/image-builder/installer.py b/build_image_x86_64/roles/image_creation/files/image-builder/installer.py new file mode 100644 index 0000000000..18e380cd4a --- /dev/null +++ b/build_image_x86_64/roles/image_creation/files/image-builder/installer.py @@ -0,0 +1,386 @@ +import subprocess +import logging +import os +import pathmod +import tempfile +# Written Modules +from utils import cmd + +class Installer: + def __init__(self, pkg_man, cname, mname, helper_cname=None): + self.pkg_man = pkg_man + self.cname = cname + self.mname = mname + self.helper_cname = helper_cname # Container with dnf for --installroot (dnf builds) + + # Create temporary directory for logs, cache, etc. for package manager + os.makedirs(os.path.join(mname, "tmp"), exist_ok=True) + self.tdir = tempfile.mkdtemp(prefix="image-build-") + logging.info(f'Installer: Temporary directory for {self.pkg_man} created at {self.tdir}') + + if pkg_man == "dnf": + # DNF complains if the log directory is not present + os.makedirs(os.path.join(self.tdir, "dnf/log")) + + def install_repos(self, repos, repo_dest, proxy): + # check if there are repos passed for install + if repos is None or len(repos) == 0: + logging.info("REPOS: no repos passed to install\n") + return + + logging.info(f"REPOS: Installing these repos to {self.cname}") + for r in repos: + args = [] + logging.info(r['alias'] + ': ' + r['url']) + if self.pkg_man == "zypper": + args.append("-D") + args.append(os.path.join(self.mname, pathmod.sep_strip(repo_dest))) + args.append("addrepo") + args.append("-f") + args.append("-p") + if 'priority' in r: + args.append(r['priority']) + else: + args.append('99') + args.append(r['url']) + args.append(r['alias']) + elif self.pkg_man == "dnf": + # Write .repo file directly to the working container's mounted filesystem. + # The helper container's dnf will find these under --installroot. + repo_dir = os.path.join(self.mname, pathmod.sep_strip(repo_dest)) + os.makedirs(repo_dir, exist_ok=True) + repo_content = f'[{r["alias"]}]\n' + repo_content += f'name={r["alias"]}\n' + repo_content += f'baseurl={r["url"]}\n' + repo_content += 'enabled=1\n' + repo_content += 'gpgcheck=0\n' + if proxy != "": + repo_content += f'proxy={proxy}\n' + with open(os.path.join(repo_dir, f'{r["alias"]}.repo'), 'w') as f: + f.write(repo_content) + logging.info(f'Adding repo from: {r["url"]}') + if "gpg" in r and r["gpg"]: + keys_dir = os.path.join(self.mname, 'etc/pki/rpm-gpg') + os.makedirs(keys_dir, exist_ok=True) + subprocess.run( + ['curl', '-sk', r["gpg"], '-o', os.path.join(keys_dir, f'{r["alias"]}.gpg')], + check=False + ) + continue + elif self.pkg_man == "apt": + # Create apt sources.list.d dir and write repo file + apt_args = [self.cname, '--', '/bin/sh', '-c'] + repo_dir = pathmod.sep_strip(repo_dest) + repo_url = r['url'] + repo_alias = r['alias'] + apt_cmd = f'mkdir -p {repo_dir} && ' + apt_dist = r.get('apt_dist', '') + apt_comp = r.get('apt_comp', '') + # Flat repos: apt_dist is './' or '.', or comp is a sentinel placeholder + is_flat = apt_dist in ('./', '.') or apt_comp in ('', 'flat-repo-component') + if apt_dist and apt_comp and not is_flat: + apt_cmd += 'echo "deb [trusted=yes] ' + repo_url + ' ' + apt_dist + ' ' + apt_comp + '" > ' + repo_dir + '/' + repo_alias + '.list' + else: + apt_cmd += 'echo "deb [trusted=yes] ' + repo_url + ' ./" > ' + repo_dir + '/' + repo_alias + '.list' + apt_args.append(apt_cmd) + cmd(["buildah","run"] + apt_args) + if "gpg" in r: + gpg_args = [self.cname, '--', '/bin/sh', '-c', + f'curl -fsSL {r["gpg"]} | gpg --dearmor -o /usr/share/keyrings/{r["alias"]}-keyring.gpg'] + cmd(["buildah","run"] + gpg_args) + continue + elif self.pkg_man == "apk": + # Create apk repositories directory + args = [self.cname, '--', '/bin/sh', '-c', f'mkdir -p {pathmod.sep_strip(repo_dest)}'] + cmd(["buildah","run"] + args) + + # Add repo URL to repositories file + repo_file = os.path.join(pathmod.sep_strip(repo_dest), r['alias']) + args = [self.cname, '--', '/bin/sh', '-c', f'echo "{r["url"]}" > {repo_file}'] + cmd(["buildah","run"] + args) + + # Handle GPG key if provided + if "gpg" in r: + args = [self.cname, '--', '/bin/sh', '-c', 'mkdir -p etc/apk/keys'] + cmd(["buildah","run"] + args) + # Download and add GPG key + args = [self.cname, '--', '/bin/sh', '-c', f'curl -s {r["gpg"]} > etc/apk/keys/{r["alias"]}'] + cmd(["buildah","run"] + args) + return + + rc = cmd([self.pkg_man] + args) + if rc != 0: + raise Exception("Failed to install repo", r['alias'], r['url']) + + if proxy != "": + if r['url'].endswith('.repo'): + repo_name = r['url'].split('/')[-1].split('.repo')[0] + "*" + elif r['url'].startswith('https'): + repo_name = r['url'].split('https://')[1].replace('/','_') + elif r['url'].startswith('http'): + repo_name = r['url'].split('http://')[1].replace('/','_') + args = [] + args.append('config-manager') + args.append('--save') + args.append("--setopt=reposdir="+os.path.join(self.mname, pathmod.sep_strip(repo_dest))) + args.append("--setopt=logdir="+os.path.join(self.tdir, self.pkg_man, "log")) + args.append("--setopt=cachedir="+os.path.join(self.tdir, self.pkg_man, "cache")) + args.append('--setopt=*.proxy='+proxy) + args.append(repo_name) + + rc = cmd([self.pkg_man] + args) + if rc != 0: + raise Exception("Failed to set proxy for repo", r['alias'], r['url'], proxy) + + if "gpg" in r: + # Using rpm apparently works for both Yum- and Zypper-based distros. + args = [] + if proxy != "": + arg_env = os.environ.copy() + arg_env['https_proxy'] = proxy + args.append("--root="+self.mname) + args.append("--import") + args.append(r["gpg"]) + + rc = cmd(["rpm"] + args) + if rc != 0: + raise Exception("Failed to install gpg key for", r['alias'], "at URL", r['gpg']) + + def install_base_packages(self, packages, registry_loc, proxy): + # check if there are packages to install + if packages is None or len(packages) == 0: + logging.warn("PACKAGES: no packages passed to install\n") + return + + logging.info(f"PACKAGES: Installing these packages to {self.cname}") + logging.info("\n".join(packages)) + + args = [] + if self.pkg_man == "zypper": + args.append("-n") + args.append("-D") + args.append(os.path.join(self.mname, pathmod.sep_strip(registry_loc))) + args.append("-C") + args.append(self.tdir) + args.append("--no-gpg-checks") + args.append("--installroot") + args.append(self.mname) + args.append("install") + args.append("-l") + args.extend(packages) + elif self.pkg_man == "dnf": + env = os.environ.copy() + if proxy != "": + env['http_proxy'] = proxy + env['https_proxy'] = proxy + helper = self.helper_cname if self.helper_cname else self.cname + reposdir = os.path.join(self.mname, 'etc/yum.repos.d') + rc = cmd( + ["buildah", "run", + "--volume", f"{self.mname}:{self.mname}:z", + helper, "--", + "dnf", f"--installroot={self.mname}", + f"--setopt=reposdir={reposdir}", + "--setopt=logdir=/tmp", + "--setopt=cachedir=/tmp/dnf-cache", + "install", "-y", "--nogpgcheck"] + packages, + env=env + ) + if rc == 104: + raise Exception("Installing base packages failed") + if rc == 107: + logging.warn("one or more RPM postscripts failed to run") + return + elif self.pkg_man == "apt": + env = os.environ.copy() + if proxy != "": + env['http_proxy'] = proxy + env['https_proxy'] = proxy + # Disable SSL peer verification for apt (Pulp uses self-signed cert) + logging.info("Configuring apt: disable SSL verify for Pulp repos") + cmd(["buildah", "run", self.cname, "--", "bash", "-c", + 'echo \'Acquire::https::Verify-Peer "false";\' > /etc/apt/apt.conf.d/99no-ssl-verify'], + check=False, env=env) + # Run apt-get update with --allow-insecure-repositories for Pulp repos + rc = cmd(["buildah", "run", "--env", "DEBIAN_FRONTEND=noninteractive", + self.cname, "--", "apt-get", "update", + "--allow-insecure-repositories"], + check=False, env=env) + if rc != 0: + logging.warn("apt-get update returned non-zero, continuing anyway") + # Divert vgcfgbackup to prevent lvm2 postinst hang in container + # (vgcfgbackup spins at 100% CPU with no block devices) + logging.info("Diverting vgcfgbackup to prevent lvm2 postinst hang") + cmd(["buildah", "run", self.cname, "--", "bash", "-c", + 'dpkg-divert --local --rename --divert /sbin/vgcfgbackup.real --add /sbin/vgcfgbackup && ' + 'echo \'#!/bin/sh\nexit 0\' > /sbin/vgcfgbackup && chmod +x /sbin/vgcfgbackup'], + check=False, env=env) + # Run apt-get install with --allow-unauthenticated for Pulp repos + rc = cmd(["buildah", "run", "--env", "DEBIAN_FRONTEND=noninteractive", + self.cname, "--", "apt-get", "install", "-y", + "--no-install-recommends", "--allow-unauthenticated", + "-o", 'Dpkg::Options::=--force-overwrite', + "-o", 'Dpkg::Options::=--force-confdef', + "-o", 'Dpkg::Options::=--force-confold'] + packages, + check=False, env=env) + # Restore real vgcfgbackup after install + logging.info("Restoring real vgcfgbackup") + cmd(["buildah", "run", self.cname, "--", "bash", "-c", + 'dpkg-divert --remove --rename /sbin/vgcfgbackup 2>/dev/null; true'], + check=False, env=env) + if rc != 0: + logging.warn("apt-get install returned %d, attempting to fix broken packages", rc) + rc2 = cmd(["buildah", "run", "--env", "DEBIAN_FRONTEND=noninteractive", + self.cname, "--", "dpkg", "--configure", "-a", + "--force-overwrite", "--force-confdef", "--force-confold"], + check=False, env=env) + if rc2 != 0: + raise Exception("Installing base packages failed") + return + elif self.pkg_man == "apk": + env = os.environ.copy() + if proxy != "": + env['http_proxy'] = proxy + env['https_proxy'] = proxy + + args = [self.cname, '--', 'apk', 'add', '--root', self.mname, '--no-cache', '--no-verify'] + args.extend(packages) + rc = cmd(["buildah","run"] + args, env=env) + if rc != 0: + raise Exception("Installing base packages failed") + return + + rc = cmd([self.pkg_man] + args) + if rc == 104: + raise Exception("Installing base packages failed") + + if rc == 107: + logging.warn("one or more RPM postscripts failed to run") + + def remove_base_packages(self, remove_packages): + # check if there are packages to remove + if remove_packages is None or len(remove_packages) == 0: + logging.warn("REMOVE PACKAGES: no package passed to remove\n") + return + + logging.info(f"REMOVE PACKAGES: removing these packages from container {self.cname}") + logging.info("\n".join(remove_packages)) + for p in remove_packages: + args = [self.cname, '--', 'rpm', '-e', '--nodeps', p] + cmd(["buildah","run"] + args) + + def install_base_package_groups(self, package_groups, registry_loc, proxy): + # check if there are packages groups to install + if package_groups is None or len(package_groups) == 0: + logging.warn("PACKAGE GROUPS: no package groups passed to install\n") + return + + logging.info(f"PACKAGE GROUPS: Installing these package groups to {self.cname}") + logging.info("\n".join(package_groups)) + args = [] + + if self.pkg_man == "zypper": + logging.warn("zypper does not support package groups") + elif self.pkg_man == "dnf": + helper = self.helper_cname if self.helper_cname else self.cname + reposdir = os.path.join(self.mname, 'etc/yum.repos.d') + dnf_run = [ + "buildah", "run", + "--volume", f"{self.mname}:{self.mname}:z", + helper, "--", + "dnf", f"--installroot={self.mname}", + f"--setopt=reposdir={reposdir}", + "--setopt=logdir=/tmp", + "--setopt=cachedir=/tmp/dnf-cache", + "groupinstall", "-y", "--nogpgcheck" + ] + if proxy != "": + dnf_run.extend([f'--setopt=proxy={proxy}']) + dnf_run.extend(package_groups) + rc = cmd(dnf_run) + if rc == 104: + raise Exception("Installing package groups failed") + elif self.pkg_man == "apt": + logging.warn("apt does not support package groups") + return + elif self.pkg_man == "apk": + logging.warn("apk does not support package groups") + return + + def install_base_modules(self, modules, registry_loc, proxy): + # check if there are modules groups to install + if modules is None or len(modules) == 0: + logging.warn("PACKAGE MODULES: no modules passed to install\n") + return + logging.info(f"MODULES: Running these module commands for {self.cname}") + for mod_cmd, mod_list in modules.items(): + logging.info(mod_cmd + ": " + " ".join(mod_list)) + for mod_cmd, mod_list in modules.items(): + args = [] + if self.pkg_man == "zypper": + logging.warn("zypper does not support package groups") + return + elif self.pkg_man == "dnf": + helper = self.helper_cname if self.helper_cname else self.cname + reposdir = os.path.join(self.mname, 'etc/yum.repos.d') + dnf_run = [ + "buildah", "run", + "--volume", f"{self.mname}:{self.mname}:z", + helper, "--", + "dnf", f"--installroot={self.mname}", + f"--setopt=reposdir={reposdir}", + "--setopt=logdir=/tmp", + "--setopt=cachedir=/tmp/dnf-cache", + "module", mod_cmd, "-y", "--nogpgcheck" + ] + if proxy != "": + dnf_run.extend([f'--setopt=proxy={proxy}']) + dnf_run.extend(mod_list) + rc = cmd(dnf_run) + elif self.pkg_man == "apt": + logging.warn("apt does not support modules") + return + elif self.pkg_man == "apk": + logging.warn("apk does not support modules") + return + if rc != 0: + raise Exception("Failed to run module cmd", mod_cmd, ' '.join(mod_list)) + + + def install_base_commands(self, commands): + # check if there are commands to install + if commands is None or len(commands) == 0: + logging.warn("COMMANDS: no commands passed to run\n") + return + + logging.info(f"COMMANDS: running these commands in {self.cname}") + for c in commands: + logging.info(c['cmd']) + build_cmd = ["buildah","run"] + if 'buildah_extra_args' in c: + build_cmd.extend(c['buildah_extra_args']) + args = [self.cname, '--', 'bash', '-c', c['cmd']] + if 'loglevel' in c: + if c['loglevel'].upper() == "INFO": + loglevel = logging.info + elif c['loglevel'].upper() == "WARN": + loglevel = logging.warn + else: + loglevel = logging.error + else: + loglevel = logging.error + out = cmd(build_cmd + args, stderr_handler=loglevel) + + def install_base_copyfiles(self, copyfiles): + if copyfiles is None or len(copyfiles) == 0: + logging.warn("COPYFILES: no files to copy\n") + return + logging.info(f"COPYFILES: copying these files to {self.cname}") + for f in copyfiles: + args = [] + if 'opts' in f: + for o in f['opts']: + args.extend(o.split()) + logging.info(f['src'] + ' -> ' + f['dest']) + args += [ self.cname, f['src'], f['dest'] ] + out=cmd(["buildah","copy"] + args) diff --git a/build_image_x86_64/roles/image_creation/files/image-builder/layer.py b/build_image_x86_64/roles/image_creation/files/image-builder/layer.py new file mode 100644 index 0000000000..b07fb00b90 --- /dev/null +++ b/build_image_x86_64/roles/image_creation/files/image-builder/layer.py @@ -0,0 +1,235 @@ +from datetime import datetime +import sys +import os +# written modules +from image_config import ImageConfig +from utils import cmd, run_playbook +from publish import publish +import installer +import logging +from oscap import Oscap + + +class Layer: + def __init__(self, args, image_config): + self.args = args + self.image_config = image_config + self.logger = logging.getLogger(__name__) + + def buildah_handler(line): + out.append(line) + return out + + def _build_base(self, repos, modules, packages, package_groups, remove_packages, commands, copyfiles, oscap_options): + dt_string = datetime.now().strftime("%Y%m%d%H%M%S") + helper_cname = None + pulp_cert_host = "/usr/local/share/ca-certificates/pulp_webserver.crt" + + def cleanup(cname): + cmd(["buildah", "rm", cname]) + if helper_cname: + cmd(["buildah", "rm", helper_cname]) + + # container and mount name + def buildah_handler(line): + out.append(line) + + out = [] + cmd(["buildah", "from"] + self.args['registry_opts_pull'] + ["--name", self.args['name']+ dt_string, self.args['parent']], stdout_handler = buildah_handler) + cname = out[0] + + out = [] + cmd(["buildah", "mount"] + [cname], stdout_handler = buildah_handler) + mname = out[0] + + self.logger.info(f"Container: {cname} mounted at {mname}") + + if self.args['pkg_man'] == "dnf": + # For dnf: create a helper container that provides dnf --installroot capability. + # The working container (parent: scratch) stays clean; all package operations + # run via: buildah run --volume mname:mname:z -- dnf --installroot mname + helper_img = self.args.get('dnf_helper_image', 'registry.access.redhat.com/ubi10/ubi-init') + helper_cname = cname + "-helper" + cmd(["buildah", "from", "--name", helper_cname, helper_img]) + self.logger.info(f"DNF helper container: {helper_cname}") + if os.path.exists(pulp_cert_host): + self.logger.info(f"Injecting Pulp CA cert into helper {helper_cname}") + cmd(["buildah", "run", helper_cname, "--", "/bin/sh", "-c", + "mkdir -p /etc/pki/ca-trust/source/anchors"]) + cmd(["buildah", "copy", helper_cname, pulp_cert_host, + "/etc/pki/ca-trust/source/anchors/pulp_webserver.crt"]) + cmd(["buildah", "run", helper_cname, "--", "update-ca-trust"]) + elif self.args['pkg_man'] == "apt": + if os.path.exists(pulp_cert_host): + self.logger.info(f"Injecting Pulp CA cert into container {cname}") + cmd(["buildah", "run", cname, "--", "/bin/sh", "-c", + "apt-get -o Acquire::AllowInsecureRepositories=true update; apt-get install -y ca-certificates"]) + cmd(["buildah", "run", cname, "--", "/bin/sh", "-c", + "mkdir -p /usr/local/share/ca-certificates"]) + cmd(["buildah", "copy", cname, pulp_cert_host, + "/usr/local/share/ca-certificates/pulp_webserver.crt"]) + cmd(["buildah", "run", cname, "--", "update-ca-certificates"]) + elif self.args['pkg_man'] == "zypper": + if os.path.exists(pulp_cert_host): + self.logger.info(f"Injecting Pulp CA cert into container {cname}") + cmd(["buildah", "run", cname, "--", "/bin/sh", "-c", + "mkdir -p /etc/pki/ca-trust/source/anchors"]) + cmd(["buildah", "copy", cname, pulp_cert_host, + "/etc/pki/ca-trust/source/anchors/pulp_webserver.crt"]) + cmd(["buildah", "run", cname, "--", "update-ca-trust"]) + + if self.args['pkg_man'] == "zypper": + repo_dest = "/etc/zypp/repos.d" + elif self.args['pkg_man'] == "dnf": + repo_dest = "/etc/yum.repos.d" + elif self.args['pkg_man'] == "apk": + repo_dest = "/etc/apk/repositories.d" + elif self.args['pkg_man'] == "apt": + repo_dest = "/etc/apt/sources.list.d" + else: + self.logger.error("unsupported package manager") + + inst = None + try: + inst = installer.Installer(self.args['pkg_man'], cname, mname, helper_cname=helper_cname) + except Exception as e: + self.logger.error(f"Error preparing installer: {e}") + cleanup(cname) + sys.exit("Exiting now ...") + except KeyboardInterrupt: + self.logger.error(f"Keyboard Interrupt") + cleanup(cname) + sys.exit("Exiting now ...") + + # Install Repos + try: + inst.install_repos(repos, repo_dest, self.args['proxy']) + except Exception as e: + self.logger.error(f"Error installing repos: {e}") + cleanup(cname) + sys.exit("Exiting now ...") + except KeyboardInterrupt: + self.logger.error(f"Keyboard Interrupt") + cleanup(cname) + sys.exit("Exiting now ...") + + # Install Packages + try: + # Enable modules + inst.install_base_modules(modules, repo_dest, self.args['proxy']) + # Base Package Groups + inst.install_base_package_groups(package_groups, repo_dest, self.args['proxy']) + # Packages + inst.install_base_packages(packages, repo_dest, self.args['proxy']) + # Remove Packages + inst.remove_base_packages(remove_packages) + except Exception as e: + self.logger.error(f"Error installing packages: {e}") + cleanup(cname) + sys.exit("Exiting now ...") + except KeyboardInterrupt: + self.logger.error(f"Keyboard Interrupt") + cleanup(cname) + sys.exit("Exiting now ...") + + # Copy Files + try: + inst.install_base_copyfiles(copyfiles) + except Exception as e: + self.logger.error(f"Error running commands: {e}") + cleanup(cname) + sys.exit("Exiting now") + except KeyboardInterrupt: + self.logger.error(f"Keyboard Interrupt") + cleanup(cname) + sys.exit("Exiting now ...") + + # Run Commands + try: + inst.install_base_commands(commands) + if os.path.islink(mname + '/etc/resolv.conf'): + self.logger.info("removing resolv.conf link (this link breaks running a container)") + os.unlink(mname + '/etc/resolv.conf') + except Exception as e: + self.logger.error(f"Error running commands: {e}") + cleanup(cname) + sys.exit("Exiting now") + except KeyboardInterrupt: + self.logger.error(f"Keyboard Interrupt") + cleanup(cname) + sys.exit("Exiting now ...") + + # OpenSCAP + if self.args['install_scap'] or self.args['scap_benchmark'] or self.args['oval_eval']: + oscap = Oscap(oscap_options, self.args, inst) + if self.args['install_scap']: + oscap.install_scap() + oscap.check_install() + if self.args['scap_benchmark']: + oscap.run_oscap() + if self.args['oval_eval']: + oscap.run_oval_eval() + + if helper_cname: + cmd(["buildah", "rm", helper_cname]) + + return cname + + def _build_ansible(self, target, parent, ansible_groups, ansible_pb, ansible_inv, ansible_vars, ansible_verbosity): + cnames = {} + def buildah_handler(line): + out.append(line) + + out = [] + cmd(["buildah","from"] + self.args['registry_opts_pull'] + ["--name", target, parent], stdout_handler = buildah_handler) + container_name = out[0] + + cnames[container_name] = { + 'ansible_groups': ansible_groups, + 'ansible_pb': ansible_pb, + 'ansible_vars': ansible_vars + } + + try: + pb_res = run_playbook(cnames, ansible_inv, ansible_verbosity) + except Exception as e: + self.logger.error(e) + cmd(["buildah","rm"] + [target]) + self.logger.error("Exiting Now...") + sys.exit(1) + return container_name + + def build_layer(self): + print("BUILD LAYER".center(50, '-')) + + if self.args['layer_type'] == "base": + + repos = self.image_config.get_repos() + modules = self.image_config.get_modules() + packages = self.image_config.get_packages() + package_groups = self.image_config.get_package_groups() + remove_packages = self.image_config.get_remove_packages() + commands = self.image_config.get_commands() + copyfiles = self.image_config.get_copy_files() + oscap_options = self.image_config.get_oscap_options() + + cname = self._build_base(repos, modules, packages, package_groups, remove_packages, commands, copyfiles, oscap_options) + elif self.args['layer_type'] == "ansible": + layer_name = self.args['name'] + print("Layer_Name =", layer_name) + parent = self.args['parent'] + ansible_groups = self.args['ansible_groups'] + ansible_pb = self.args['ansible_pb'] + ansible_inv = self.args['ansible_inv'] + ansible_vars = self.args['ansible_vars'] + ansible_verbosity = self.args['ansible_verbosity'] + + cname = self._build_ansible(layer_name, parent, ansible_groups, ansible_pb, ansible_inv, ansible_vars, ansible_verbosity) + else: + self.logger.error("Unrecognized layer type") + sys.exit("Exiting now ...") + + # Publish the layer + self.logger.info("Publishing Layer") + publish(cname, self.args) + diff --git a/build_image_x86_64/roles/image_creation/files/image-builder/publish.py b/build_image_x86_64/roles/image_creation/files/image-builder/publish.py new file mode 100644 index 0000000000..56c4b25609 --- /dev/null +++ b/build_image_x86_64/roles/image_creation/files/image-builder/publish.py @@ -0,0 +1,191 @@ +import subprocess +import boto3 +import os +import tempfile +from datetime import datetime +# local imports +from utils import cmd, get_os +import logging + +def _generate_labels(args): + """Generate standard labels from configuration data""" + labels = {} + + # Add any user-provided labels + if 'labels' in args: + labels.update(args['labels']) + + # Basic metadata + labels['org.openchami.image.name'] = args['name'] + labels['org.openchami.image.type'] = args['layer_type'] + labels['org.openchami.image.parent'] = args['parent'] + if 'pkg_man' in args: + labels['org.openchami.image.package-manager'] = args['pkg_man'] + + # Version/tag information + if isinstance(args['publish_tags'], list): + labels['org.openchami.image.tags'] = ','.join(args['publish_tags']) + else: + labels['org.openchami.image.tags'] = args['publish_tags'] + + # Build information + labels['org.openchami.image.build-date'] = datetime.now().isoformat() + + # Repository information + if 'repos' in args: + repo_names = [repo['alias'] for repo in args['repos']] + labels['org.openchami.image.repositories'] = ','.join(repo_names) + + # Package information + if 'packages' in args: + labels['org.openchami.image.packages'] = ','.join(args['packages']) + + if 'package_groups' in args: + labels['org.openchami.image.package-groups'] = ','.join(args['package_groups']) + + return labels + +def publish(cname, args): + + layer_name = args['name'] + publish_tags = args['publish_tags'] + if type(publish_tags) is not list: + publish_tags = [publish_tags] + if 'credentials' in args: + credentials = args['credentials'] + parent = args['parent'] + + # Generate standard labels + print("Generating labels") + labels = _generate_labels(args) + print("Labels: " + str(labels)) + + if args['publish_local']: + print("Publishing to local storage") + for tag in publish_tags: + # Add labels if they exist + if labels: + label_args = [] + for key, value in labels.items(): + label_args.extend(['--label', f'{key}={value}']) + cmd(["buildah", "config"] + label_args + [cname], stderr_handler=logging.warn) + cmd(["buildah","commit", cname, layer_name+':'+tag], stderr_handler=logging.warn) + + if args['publish_s3']: + s3_prefix = args['s3_prefix'] + s3_bucket = args['s3_bucket'] + print("Publishing to S3 at " + s3_bucket) + for tag in publish_tags: + s3_push(cname, layer_name, credentials, tag, s3_prefix, s3_bucket) + + if args['publish_registry']: + registry_opts = args['registry_opts_push'] + publish_dest = args['publish_registry'] + print("Publishing to registry at " + publish_dest) + image_name = layer_name+':'+publish_tags[0] + # Add labels if they exist + if labels: + label_args = [] + for key, value in labels.items(): + label_args.extend(['--label', f'{key}={value}']) + cmd(["buildah", "config"] + label_args + [cname], stderr_handler=logging.warn) + cmd(["buildah", "commit", cname, image_name], stderr_handler=logging.warn) + for tag in publish_tags: + cmd(["buildah", "tag", image_name, layer_name+':'+tag], stderr_handler=logging.warn) + registry_push(layer_name, registry_opts, tag, publish_dest) + + # Clean up + cmd(["buildah", "rm", cname], stderr_handler=logging.warn) + if not args['publish_local'] and args['publish_registry']: + for tag in publish_tags: + cmd(["buildah","rmi", layer_name+':'+tag], stderr_handler=logging.warn) + if not parent == "scratch": + cmd(["buildah", "rmi", parent], stderr_handler=logging.warn) + +def push_file(fname, kname, s3, bucket_name): + print("Pushing " + fname + " as " + kname + " to " + bucket_name) + + bucket = s3.Bucket(bucket_name) + bucket.upload_file(Filename=fname,Key=kname) + +def squash_image(mname, tmpdir): + print("squashing container image") + args = ["mksquashfs"] + args.append(mname) + args.append(tmpdir + "/rootfs") + + process = subprocess.run(args, + stdout=subprocess.PIPE, + universal_newlines=True) + # if verbose: + # print(process.stdout) + +def s3_push(cname, layer_name, credentials, publish_tags, s3_prefix, s3_bucket): + + def buildah_handler(line): + out.append(line) + out = [] + cmd(["buildah", "mount", cname],stdout_handler = buildah_handler) + mdir = out[0] + + print(mdir) + + # Get s3 resource set + s3 = boto3.resource('s3', + endpoint_url=credentials['endpoint_url'], + aws_access_key_id=credentials['access_key'], + aws_secret_access_key=credentials['secret_key'], + verify=False, use_ssl=False) + + # Set initrd to be blank to act as sentinel in case no intrds are found + initrd = '' + + # Iterate over everything in /lib/modules and use the first initramfs or + # initrd found. + # + # TODO: Be smarter about chooding initramfs. This code only uses the first + # available one. + modules_dir = mdir+'/lib/modules/' + if not os.path.isdir(modules_dir): + logging.warning(f'No kernel modules directory found at {modules_dir}, skipping initramfs/vmlinuz upload') + return + kvers = os.listdir(modules_dir) + logging.info(f'Available kernel versions: {kvers}') + for kver in kvers: + if os.path.isfile(mdir+'/boot/initramfs-'+kver+'.img'): + initrd='initramfs-'+kver+'.img' + logging.info(f'Found initrd: {initrd}') + elif os.path.isfile(mdir+'/boot/initrd-'+kver): + initrd='initrd-'+kver + logging.info(f'Found initrd: {initrd}') + elif os.path.isfile(mdir+'/boot/initrd.img-'+kver): + initrd='initrd.img-'+kver + logging.info(f'Found initrd (Ubuntu): {initrd}') + else: + logging.warn(f'No initramfs found for {kver}, moving to next') + continue + vmlinuz='vmlinuz-'+kver + break + + # If no initramfses are found, return an error + # + # TODO: Should we continue without uploading if this fails? + if initrd == '': + raise Exception('No initramfs or initrd found in /boot for any of the available kernel versions') + + with tempfile.TemporaryDirectory() as tmpdir: + squash_image(mdir, tmpdir) + image_name = s3_prefix+get_os(mdir)+'-'+layer_name+'-'+publish_tags + print("Image Name: " + image_name) + print("initramfs: " + initrd ) + print("vmlinuz: " + vmlinuz ) + push_file(mdir+'/boot/'+initrd, 'efi-images/' + s3_prefix + initrd, s3, s3_bucket) + push_file(mdir+'/boot/'+vmlinuz, 'efi-images/' + s3_prefix + vmlinuz, s3, s3_bucket) + push_file(tmpdir + '/rootfs', image_name, s3, s3_bucket) + +def registry_push(layer_name, registry_opts, publish_tags, registry_endpoint): + + image_name = layer_name+':'+publish_tags + print("pushing layer " + layer_name + " to " + registry_endpoint +'/'+image_name) + args = registry_opts + [image_name, registry_endpoint +'/'+image_name] + cmd(["buildah", "push"] + args, stderr_handler=logging.warn) diff --git a/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_base_image.yml b/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_base_image.yml index 04363a5a23..54ac6965ed 100644 --- a/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_base_image.yml +++ b/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_base_image.yml @@ -13,6 +13,16 @@ # limitations under the License. --- +- name: Deploy patched image-builder scripts for Ubuntu builds + ansible.builtin.copy: + src: "{{ role_path }}/files/image-builder/{{ item.src }}" + dest: "{{ oim_shared_path }}/omnia/openchami/image-builder-{{ item.dest }}" + mode: "{{ dir_permissions_755 }}" + loop: + - { src: 'installer.py', dest: 'installer.py' } + - { src: 'layer.py', dest: 'layer.py' } + - { src: 'publish.py', dest: 'publish.py' } + - name: Create ochami images directory ansible.builtin.file: path: "{{ openchami_work_dir }}/images" diff --git a/build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 b/build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 index 54224a5eb5..e0b9e3068a 100644 --- a/build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 +++ b/build_image_x86_64/roles/image_creation/templates/images/ubuntu-base-config.yaml.j2 @@ -24,14 +24,21 @@ repos: {% endfor %} packages: - - initramfs-tools - - linux-image-generic + - curl + - util-linux + - dmsetup + - dracut-core + - dracut-network {% for pkg in x86_64_ubuntu_base_image_packages | default([]) %} +{% if pkg not in ('live-boot', 'initramfs-tools', 'initramfs-tools-core', 'linux-image-generic', 'dracut-network', 'dracut-live', 'dracut-core', 'curl', 'util-linux', 'dmsetup') %} - {{ pkg }} +{% endif %} {% endfor %} + - linux-image-generic cmds: - - cmd: "update-initramfs -c -k all" + - cmd: "echo '=== dmsquash-live module-setup.sh ===' && cat /usr/lib/dracut/modules.d/70dmsquash-live/module-setup.sh | head -30" + - cmd: "KVER=$(ls /lib/modules/ | head -1) && depmod ${KVER} && dracut --force --force-add 'dmsquash-live livenet' --kver ${KVER}" {% for cmd in base_image_commands | default([]) %} - cmd: "{{ cmd }}" {% endfor %} diff --git a/common/library/module_utils/build_image/common_functions.py b/common/library/module_utils/build_image/common_functions.py index d082f462df..72d292a4ed 100644 --- a/common/library/module_utils/build_image/common_functions.py +++ b/common/library/module_utils/build_image/common_functions.py @@ -128,7 +128,7 @@ def extract_rpm_package_names(cluster_items): return [] return [ item.get('package') for item in cluster_items - if item.get('type') == 'rpm' and item.get('package') + if item.get('type') in ('rpm', 'deb', 'rpm_repo', 'deb_repo') and item.get('package') ] diff --git a/common/library/modules/image_package_collector.py b/common/library/modules/image_package_collector.py index 1f40fffbf7..3ad27a679b 100644 --- a/common/library/modules/image_package_collector.py +++ b/common/library/modules/image_package_collector.py @@ -50,7 +50,7 @@ def get_additional_packages_for_role(additional_json_path, role_name, module): packages = [] for item in cluster_items: - if item.get('type') == 'rpm' and item.get('package'): + if item.get('type') in ('rpm', 'deb', 'rpm_repo', 'deb_repo') and item.get('package'): packages.append(item['package']) return packages @@ -98,12 +98,12 @@ def collect_packages_from_json(sw_data, fg_name=None, if "slurm_custom" in sw_data and "cluster" in sw_data["slurm_custom"]: for entry in sw_data["slurm_custom"]["cluster"]: - if entry.get("type") == "rpm" and "package" in entry: + if entry.get("type") in ("rpm", "deb", "rpm_repo", "deb_repo") and "package" in entry: packages.append(entry["package"]) if fg_name in sw_data and "cluster" in sw_data[fg_name]: for entry in sw_data[fg_name]["cluster"]: - if entry.get("type") == "rpm" and "package" in entry: + if entry.get("type") in ("rpm", "deb", "rpm_repo", "deb_repo") and "package" in entry: packages.append(entry["package"]) elif service_k8s_defined: @@ -111,24 +111,24 @@ def collect_packages_from_json(sw_data, fg_name=None, if "service_k8s" in sw_data and "cluster" in sw_data["service_k8s"]: for entry in sw_data["service_k8s"]["cluster"]: - if entry.get("type") == "rpm" and "package" in entry: + if entry.get("type") in ("rpm", "deb", "rpm_repo", "deb_repo") and "package" in entry: packages.append(entry["package"]) if fg_name in sw_data and "cluster" in sw_data[fg_name]: for entry in sw_data[fg_name]["cluster"]: - if entry.get("type") == "rpm" and "package" in entry: + if entry.get("type") in ("rpm", "deb", "rpm_repo", "deb_repo") and "package" in entry: packages.append(entry["package"]) else: for section_data in sw_data.values(): if isinstance(section_data, dict) and "cluster" in section_data: for entry in section_data["cluster"]: - if entry.get("type") == "rpm" and "package" in entry: + if entry.get("type") in ("rpm", "deb", "rpm_repo", "deb_repo") and "package" in entry: packages.append(entry["package"]) if "cluster" in sw_data and isinstance(sw_data["cluster"], list): for entry in sw_data["cluster"]: - if entry.get("type") == "rpm" and "package" in entry: + if entry.get("type") in ("rpm", "deb", "rpm_repo", "deb_repo") and "package" in entry: packages.append(entry["package"]) return packages diff --git a/provision/roles/configure_ochami/templates/bss/bss.yaml.j2 b/provision/roles/configure_ochami/templates/bss/bss.yaml.j2 index a796d870b4..efd2c4c280 100644 --- a/provision/roles/configure_ochami/templates/bss/bss.yaml.j2 +++ b/provision/roles/configure_ochami/templates/bss/bss.yaml.j2 @@ -28,7 +28,11 @@ initrd: "{{ s3_base_url }}/{{ initrd }}" hostvars['localhost']['cluster_os_version'] ) %} +{% if cluster_os_type == 'ubuntu' %} +params: "nosplash rd.live.image rd.live.ram rd.neednet=1 root=live:{{ s3_base_url }}/{{ root_image_path }} ip=dhcp console=tty0 console=ttyS0,115200 apparmor=0 ip6=off {{ bss_params_cloud_init }}" +{% else %} params: "nomodeset ro root=live:{{ s3_base_url }}/{{ root_image_path }} ip=dhcp rd.live.image rd.live.ram rd.neednet=1 {% if s3_configurations.provider | default('powerscale') == 'powerscale' %}rd.noverifyssl {% endif %}rd.driver.blacklist=ccp,edac_core,power_meter,ahci,megaraid_sas modprobe.blacklist=ccp,edac_core,power_meter,ahci,megaraid_sas libata.force=1:disable,2:disable,3:disable,4:disable rd.luks=0 rd.md=0 rd.dm=0 console=tty0 console=ttyS0,115200 selinux=0 apparmor=0 ip6=off {{ bss_params_cloud_init }}" +{% endif %} macs: {% for item in nodes %} {% if item.group == functional_group_name %} From 80acb97f1b0bad4d93956ec123e3e164f760fd83 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Wed, 8 Jul 2026 17:37:39 +0530 Subject: [PATCH 11/15] Fix: PXE Boot hostname configuration --- .../files/image-builder/installer.py | 27 +- .../tasks/configure_cloud_init_group.yml | 2 +- ...p-slurm_control_node_x86_64_ubuntu.yaml.j2 | 394 +++++++++++++ .../ci-group-slurm_node_x86_64_ubuntu.yaml.j2 | 526 ++++++++++++++++++ 4 files changed, 938 insertions(+), 11 deletions(-) create mode 100644 provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64_ubuntu.yaml.j2 create mode 100644 provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_x86_64_ubuntu.yaml.j2 diff --git a/build_image_x86_64/roles/image_creation/files/image-builder/installer.py b/build_image_x86_64/roles/image_creation/files/image-builder/installer.py index 18e380cd4a..19ac59b2ad 100644 --- a/build_image_x86_64/roles/image_creation/files/image-builder/installer.py +++ b/build_image_x86_64/roles/image_creation/files/image-builder/installer.py @@ -208,12 +208,16 @@ def install_base_packages(self, packages, registry_loc, proxy): check=False, env=env) if rc != 0: logging.warn("apt-get update returned non-zero, continuing anyway") - # Divert vgcfgbackup to prevent lvm2 postinst hang in container - # (vgcfgbackup spins at 100% CPU with no block devices) - logging.info("Diverting vgcfgbackup to prevent lvm2 postinst hang") - cmd(["buildah", "run", self.cname, "--", "bash", "-c", - 'dpkg-divert --local --rename --divert /sbin/vgcfgbackup.real --add /sbin/vgcfgbackup && ' - 'echo \'#!/bin/sh\nexit 0\' > /sbin/vgcfgbackup && chmod +x /sbin/vgcfgbackup'], + # Divert LVM commands to prevent lvm2 postinst hang in container + # (vgcfgbackup, vgchange, pvscan etc. hang with no block devices) + logging.info("Diverting LVM commands to prevent lvm2 postinst hang") + lvm_cmds = ['vgcfgbackup', 'vgchange', 'pvscan', 'vgscan', 'lvscan'] + divert_script = ' && '.join( + [f'dpkg-divert --local --rename --divert /sbin/{c}.real --add /sbin/{c} 2>/dev/null; ' + f'echo \'#!/bin/sh\\nexit 0\' > /sbin/{c} && chmod +x /sbin/{c}' + for c in lvm_cmds] + ) + cmd(["buildah", "run", self.cname, "--", "bash", "-c", divert_script], check=False, env=env) # Run apt-get install with --allow-unauthenticated for Pulp repos rc = cmd(["buildah", "run", "--env", "DEBIAN_FRONTEND=noninteractive", @@ -223,10 +227,13 @@ def install_base_packages(self, packages, registry_loc, proxy): "-o", 'Dpkg::Options::=--force-confdef', "-o", 'Dpkg::Options::=--force-confold'] + packages, check=False, env=env) - # Restore real vgcfgbackup after install - logging.info("Restoring real vgcfgbackup") - cmd(["buildah", "run", self.cname, "--", "bash", "-c", - 'dpkg-divert --remove --rename /sbin/vgcfgbackup 2>/dev/null; true'], + # Restore real LVM commands after install + logging.info("Restoring real LVM commands") + restore_script = '; '.join( + [f'dpkg-divert --remove --rename /sbin/{c} 2>/dev/null' + for c in lvm_cmds] + ) + '; true' + cmd(["buildah", "run", self.cname, "--", "bash", "-c", restore_script], check=False, env=env) if rc != 0: logging.warn("apt-get install returned %d, attempting to fix broken packages", rc) diff --git a/provision/roles/configure_ochami/tasks/configure_cloud_init_group.yml b/provision/roles/configure_ochami/tasks/configure_cloud_init_group.yml index a999c8b9ef..87bf179118 100644 --- a/provision/roles/configure_ochami/tasks/configure_cloud_init_group.yml +++ b/provision/roles/configure_ochami/tasks/configure_cloud_init_group.yml @@ -30,7 +30,7 @@ block: - name: Load ci group template - {{ functional_group_name }} ansible.builtin.template: - src: "cloud_init/ci-group-{{ functional_group_name }}.yaml.j2" + src: "cloud_init/ci-group-{{ functional_group_name }}{{ '_ubuntu' if hostvars['localhost']['cluster_os_type'] == 'ubuntu' else '' }}.yaml.j2" dest: "{{ cloud_init_dir }}/ci-group-{{ functional_group_name }}.yaml" mode: "{{ hostvars['localhost']['file_permissions_644'] }}" rescue: diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64_ubuntu.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64_ubuntu.yaml.j2 new file mode 100644 index 0000000000..4d5171d126 --- /dev/null +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64_ubuntu.yaml.j2 @@ -0,0 +1,394 @@ +- name: {{ functional_group_name }} + description: "{{ functional_group_name }}" + + file: + encoding: plain + content: | + ## template: jinja + #cloud-config + merge_how: + - name: list + settings: [append] + - name: dict + settings: [no_replace, recurse_list] + users: + - name: root + ssh_authorized_keys: "{{ read_ssh_key.stdout }}" + lock_passwd: false + hashed_passwd: "{{ hashed_password_output.stdout }}" + - name: {{ slurm_user }} + uid: {{ slurm_uid }} + system: true + no_create_home: true + shell: /sbin/nologin + disable_root: false + + write_files: + - path: /usr/local/bin/doca-install.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/doca-ofed/doca-install.sh.j2') | indent(12) }} + + - path: /usr/local/bin/configure-ib-network.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/doca-ofed/configure-ib-network.sh.j2') | indent(12) }} + + - path: /usr/local/bin/set-ssh.sh + permissions: '{{ file_mode_755 }}' + content: | + timedatectl set-timezone {{ hostvars['oim']['oim_timezone'] }} + sed -i 's/^#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config + sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config + sed -i 's/^PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config.d/50-cloud-init.conf + systemctl restart ssh + default_count=$(ip route | grep -c "^default") + if [ "$default_count" -le 1 ]; then + echo "Only one or no default route found. No action needed." + else + private_nic=$(ip route | grep "^default via {{ hostvars['localhost']['admin_nic_ip'] }}" | awk '{print $5}') + # Get all default routes + ip route | grep '^default' | while read -r line; do + nmcli con del "Wired Connection" + # Extract NIC name + nic=$(echo "$line" | awk '{print $5}') + + # Add the default route to the connection + if [ -n "$nic" ]; then + echo "Adding nmcli device $nic" + nmcli con add type ethernet ifname "$nic" con-name "$nic" ipv4.method auto + if [ "$nic" = "$private_nic" ]; then + nmcli con modify "$nic" ipv4.never-default yes + nmcli con delete "cloud-init $nic" + fi + nmcli con up "$nic" + else + echo "No connection found for device $nic" + fi + done + fi + + - path: /root/.ssh/config + permissions: '0600' + content: | + Host {{ slurm_control_ssh_patterns }} + IdentityFile {{ client_mount_path }}/slurm/ssh/oim_rsa + IdentitiesOnly yes +{% if cloud_init_groups_dict[functional_group_name].powervault_scripts is defined %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} + - path: /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh + permissions: '{{ file_mode_755 }}' + content: | + {{ pv_entry.content | indent(12) }} +{% endfor %} +{% endif %} + +{% if hostvars['localhost']['openldap_support'] %} + - path: /etc/sssd/sssd.conf + owner: root:root + permissions: '0600' + content: | + {{ lookup('template', 'templates/openldap/sssd.conf.j2') | indent(6) }} + + - path: /usr/local/bin/update_ldap_conf.sh + owner: root:root + permissions: '0755' + content: | + {{ lookup('template', 'templates/openldap/update_ldap_conf.sh.j2') | indent(12) }} +{% endif %} + +{% if ldms_support %} + - path: /root/ldms_sampler.sh + owner: root:root + permissions: '0755' + content: | + {{ lookup('template', 'templates/ldms/ldms_sampler.sh.j2') | indent(12) }} +{% endif %} + +{% if dns_enabled | default(false) | bool %} + - path: /etc/resolv.conf + owner: root:root + permissions: '0644' + content: | + search {{ domain_name }} + nameserver {{ admin_nic_ip }} + options timeout:1 attempts:2 +{% else %} + - path: /etc/hosts + append: true + content: | +{% for key in ip_name_map | sort %} + {{ ip_name_map[key] }} {{ key }} +{% endfor %} +{% endif %} + + - path: /root/init_slurm_db.sql + permissions: '{{ file_mode_600 }}' + content: | + SELECT VERSION(); + SHOW DATABASES; + CREATE DATABASE IF NOT EXISTS {{ apply_config['slurmdbd']['StorageLoc'] }}; + CREATE USER IF NOT EXISTS '{{ apply_config['slurmdbd']['SlurmUser'] }}'@'%' IDENTIFIED BY '{{ hostvars['localhost']['slurm_db_password'] }}'; + ALTER USER '{{ apply_config['slurmdbd']['SlurmUser'] }}'@'%' IDENTIFIED BY '{{ hostvars['localhost']['slurm_db_password'] }}'; + GRANT ALL PRIVILEGES ON {{ apply_config['slurmdbd']['StorageLoc'] }}.* TO '{{ apply_config['slurmdbd']['SlurmUser'] }}'@'%'; + FLUSH PRIVILEGES; + + - path: /root/omnia_slurm_scripts/00_munge_setup.sh + permissions: '{{ file_mode_755 }}' + content: | + chown -R {{ munge_user }}:{{ munge_group }} /etc/munge + chmod 700 /etc/munge + chmod {{ file_mode_400 }} /etc/munge/munge.key + systemctl enable munge + systemctl start munge + + - path: /root/omnia_slurm_scripts/01_mariadb_setup.sh + permissions: '{{ file_mode_755 }}' + content: | + #!/bin/bash + SLURMDBD_CONF="/etc/slurm/slurmdbd.conf" + SLURM_USER="{{ slurm_user }}" + SLURM_GROUP="{{ slurm_user }}" + # Function to extract value from slurm.conf + get_value_slurm_conf() { + local key="$1" + local default="$2" + local value + value=$(grep -iE "^\s*$key\s*=" "$SLURMDBD_CONF" | sed -E 's/^\s*[^=]+=//; s/#.*//; s/\s+$//') + echo "${value:-$default}" + } + chown -R {{ mysql_user }}:{{ mysql_group }} /var/lib/mysql + chown -R {{ slurm_user }}:{{ slurm_user }} /var/log/mariadb + chown -R {{ slurm_user }}:{{ slurm_user }} /etc/mysql/conf.d + chown -R {{ slurm_user }}:{{ slurm_user }} {{ slurm_ctld_log_dir_effective }} {{ slurmdbd_log_dir_effective }} + chmod {{ file_mode_755 }} /etc/mysql/conf.d /var/lib/mysql /var/log/mariadb {{ slurm_ctld_log_dir_effective }} {{ slurmdbd_log_dir_effective }} + + #firewall (Ubuntu uses ufw) + ufw --force enable + StoragePort=$(get_value_slurm_conf "StoragePort" "3306") + ufw allow "$StoragePort"/tcp + systemctl enable --now mariadb + systemctl start mariadb + mysql -u root < /root/init_slurm_db.sql + + - path: /root/omnia_slurm_scripts/02_slurmdbd_setup.sh + permissions: '{{ file_mode_755 }}' + content: | + #!/bin/bash + SLURMDBD_CONF="/etc/slurm/slurmdbd.conf" + SLURM_USER="{{ slurm_user }}" + SLURM_GROUP="{{ slurm_user }}" + # Function to extract value from slurm.conf + get_value_slurm_conf() { + local key="$1" + local default="$2" + local value + value=$(grep -iE "^\s*$key\s*=" "$SLURMDBD_CONF" | sed -E 's/^\s*[^=]+=//; s/#.*//; s/\s+$//') + echo "${value:-$default}" + } + chmod {{ file_mode_600 }} /etc/slurm/slurmdbd.conf + chown {{ slurm_user }}:{{ slurm_user }} /etc/slurm/slurmdbd.conf + #file PidFile + PidFile=$(get_value_slurm_conf "PidFile" "/var/run/slurmdbd.pid") + mkdir -pv $(dirname "$PidFile") + touch $PidFile + chown -v "$SLURM_USER:$SLURM_GROUP" "$PidFile" + chmod -v 0755 $PidFile + #file LogFile + LogFile=$(get_value_slurm_conf "LogFile" "/var/log/slurmdbd.log") + mkdir -pv $(dirname "$LogFile") + touch $LogFile + chown -v "$SLURM_USER:$SLURM_GROUP" "$LogFile" + chmod -v 0755 $LogFile + #firewall (Ubuntu uses ufw) + DbdPort=$(get_value_slurm_conf "DbdPort" "6819") + ufw allow "$DbdPort"/tcp + systemctl enable slurmdbd + systemctl start slurmdbd + + - path: /root/omnia_slurm_scripts/03_slurmctld_setup.sh + permissions: '{{ file_mode_755 }}' + content: | + #!/bin/bash + SLURM_CONF="/etc/slurm/slurm.conf" + SLURM_USER="{{ slurm_user }}" + SLURM_GROUP="{{ slurm_user }}" + # Function to extract value from slurm.conf + get_value_slurm_conf() { + local key="$1" + local default="$2" + local value + value=$(grep -iE "^\s*$key\s*=" "$SLURM_CONF" | sed -E 's/^\s*[^=]+=//; s/#.*//; s/\s+$//') + echo "${value:-$default}" + } + #dir StateSaveLocation + StateSaveLocation=$(get_value_slurm_conf "StateSaveLocation" "/var/spool/slurmctld") + mkdir -pv $StateSaveLocation + chown -v "$SLURM_USER:$SLURM_GROUP" $StateSaveLocation + chmod -v 0744 $StateSaveLocation + #file SlurmctldPidFile + SlurmctldPidFile=$(get_value_slurm_conf "SlurmctldPidFile" "/var/run/slurmctld.pid") + mkdir -pv $(dirname "$SlurmctldPidFile") + touch $SlurmctldPidFile + chown -v "$SLURM_USER:$SLURM_GROUP" "$SlurmctldPidFile" + chmod -v 0755 $SlurmctldPidFile + #file SlurmctldLogFile + SlurmctldLogFile=$(get_value_slurm_conf "SlurmctldLogFile" "/var/log/slurmctld.log") + mkdir -pv $(dirname "$SlurmctldLogFile") + touch $SlurmctldLogFile + chown -v "$SLURM_USER:$SLURM_GROUP" "$SlurmctldLogFile" + chmod -v 0755 $SlurmctldLogFile + #firewall (Ubuntu uses ufw) + SlurmctldPort=$(get_value_slurm_conf "SlurmctldPort" "6817") + ufw allow "$SlurmctldPort"/tcp + SrunPortRange=$(get_value_slurm_conf "SrunPortRange" "60001-63000") + ufw allow "$SrunPortRange"/tcp + systemctl enable slurmctld + systemctl start slurmctld + systemctl restart slurmctld + + - path: /root/omnia_slurm_scripts/04_track_file.sh + permissions: '{{ file_mode_755 }}' + content: | + #!/bin/bash + MARKER="/var/log/track/slurm_controller_track" + if [ -f "$MARKER" ]; then + echo "Slurm controller track file already exists. Skipping." + exit 0 + fi + + echo "Waiting for slurmctld to become active..." + while true; do + if systemctl is-active --quiet slurmctld; then + echo "Slurm controller is active." + touch "$MARKER" + exit 0 + else + echo "slurmctld is not active yet. Retrying in 5 seconds." + fi + sleep 5 + done + + - path: /tmp/apptainer_mirror.conf + permissions: '0644' + content: | + {{ lookup('template', 'templates/nodes/apptainer_mirror.conf.j2') | indent(12) }} + + runcmd: + - /usr/local/bin/set-ssh.sh + # DOCA prerequisites - moved early to ensure RDMA is ready before vendor_data mounts + - mkdir -p {{ client_mount_path }}/slurm/ssh + - mkdir -p {{ slurm_ctld_log_dir_effective }} {{ slurmdbd_log_dir_effective }} {{ slurm_ctld_pid_dir_effective }} {{ slurmdbd_pid_dir_effective }} {{ slurm_state_save_location_effective }} {% if slurm_sched_log_dir_effective %}{{ slurm_sched_log_dir_effective }} {% endif %}/etc/slurm {{ home_dir }} /etc/mysql/conf.d /etc/munge /var/lib/mysql /var/log/mariadb /cert /var/log/track /var/lib/packages + - echo "{{ cloud_init_nfs_path }}/cert /cert nfs defaults,_netdev 0 0" >> /etc/fstab + - mount -av + - cp /cert/pulp_webserver.crt /etc/pki/ca-trust/source/anchors && update-ca-trust + # Ubuntu: No dnf, skip gpgcheck config + # DOCA and IB configuration - now ready before vendor_data mounts + - bash /usr/local/bin/doca-install.sh || true + - bash /usr/local/bin/configure-ib-network.sh +{# Mount-specific runcmd entries - moved after DOCA to ensure RDMA is available #} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} +{% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} + - {{ cmd }} +{% endfor %} +{% endif %} +{% raw %} + {% if ds.meta_data.instance_data.v1.vendor_data.groups.ssh.host_mount_map %} + {% set mymounts = ds.meta_data.instance_data.v1.vendor_data.groups.ssh.host_mount_map.get(local_hostname, {}) %} + {% if mymounts %} + {% for mount in mymounts.get("mounts", []) %} + - mkdir -pv {{ mount[1] }} + - echo "{{ mount | join(' ') }}" >> /etc/fstab + {% endfor %} + - mount -av + {% for decoded_cmd in mymounts.get("runcmd", []) %} + - {{ decoded_cmd }} + {% endfor %} + {% else %} + - echo "No mount entries found for this host" + {% endif %} + {% endif %} +{% endraw %} +{% set fg_swap = cloud_init_groups_dict.get(functional_group_name, {}).get('swap', {}) %} +{% include 'configure_swap.yaml.j2' %} + - mount -av +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} + - bash /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh +{% endfor %} + # Ensure Slurm NFS root is mounted at client_mount_path (e.g. /share_omnia) + - mkdir -pv {{ client_mount_path }}/slurm/ssh + # Create directories for nfs and mount all + - mkdir -p {{ slurm_ctld_log_dir_effective }} {{ slurmdbd_log_dir_effective }} {{ slurm_ctld_pid_dir_effective }} {{ slurmdbd_pid_dir_effective }} {{ slurm_state_save_location_effective }} {% if slurm_sched_log_dir_effective %}{{ slurm_sched_log_dir_effective }} {% endif %}/etc/slurm {{ home_dir }} /etc/mysql/conf.d /etc/munge /var/lib/mysql /var/log/mariadb /cert /var/log/track /var/lib/packages + - echo "{{ cloud_init_nfs_path }}/$(hostname -s)/etc/slurm /etc/slurm nfs defaults,_netdev 0 0" >> /etc/fstab + - echo "{{ cloud_init_nfs_path }}/$(hostname -s)/etc/mysql/conf.d /etc/mysql/conf.d nfs defaults,_netdev 0 0" >> /etc/fstab + - echo "{{ cloud_init_nfs_path }}/$(hostname -s)/var/log/mariadb /var/log/mariadb nfs defaults,_netdev 0 0" >> /etc/fstab + - echo "{{ cloud_init_nfs_path }}/$(hostname -s)/var/log/slurm {{ slurm_ctld_log_dir_effective }} nfs defaults,_netdev 0 0" >> /etc/fstab +{% if slurmdbd_log_dir_effective != slurm_ctld_log_dir_effective %} + - echo "{{ cloud_init_nfs_path }}/$(hostname -s)/var/log/slurm {{ slurmdbd_log_dir_effective }} nfs defaults,_netdev 0 0" >> /etc/fstab +{% endif %} + - if ! mountpoint -q /var/lib/mysql; then echo "{{ cloud_init_nfs_path }}/$(hostname -s)/var/lib/mysql /var/lib/mysql nfs defaults,_netdev 0 0" >> /etc/fstab; fi + - if ! mountpoint -q {{ slurm_state_save_location_effective }}; then echo "{{ cloud_init_nfs_path }}/$(hostname -s)/var/spool/slurmctld {{ slurm_state_save_location_effective }} nfs defaults,_netdev 0 0" >> /etc/fstab; fi + - echo "{{ cloud_init_nfs_path }}/$(hostname -s)/etc/munge /etc/munge nfs defaults,_netdev 0 0" >> /etc/fstab + - echo "{{ trackfile_nfs_path }} /var/log/track nfs defaults,_netdev 0 0" >> /etc/fstab + - echo "{{ cloud_init_nfs_path }}/packages /var/lib/packages nfs defaults,_netdev 0 0" >> /etc/fstab + - echo "{{ cloud_init_nfs_path }}/ssh {{ client_mount_path }}/slurm/ssh nfs defaults,_netdev 0 0" >> /etc/fstab + - chmod {{ file_mode }} /etc/fstab + - mount -av + - chown -R {{ slurm_user }}:{{ slurm_user }} {{ home_dir }} + - chmod {{ file_mode_755 }} {{ home_dir }} + - chown -R {{ slurm_user }}:{{ slurm_user }} /etc/slurm + - chmod {{ file_mode_755 }} /etc/slurm + - chmod {{ file_mode }} /etc/slurm/slurm.conf + # Ubuntu: No SELinux, skip setenforce + - ['bash', '/root/omnia_slurm_scripts/00_munge_setup.sh'] + - ['bash', '/root/omnia_slurm_scripts/01_mariadb_setup.sh'] + - ['bash', '/root/omnia_slurm_scripts/02_slurmdbd_setup.sh'] + - ['bash', '/root/omnia_slurm_scripts/03_slurmctld_setup.sh'] + - ['bash', '/root/omnia_slurm_scripts/04_track_file.sh'] + + # Ubuntu: Use ufw instead of firewalld + - ufw allow ssh + - systemctl enable ssh + - systemctl start ssh + + - cp /cert/pulp_webserver.crt /etc/pki/ca-trust/source/anchors && update-ca-trust + # Ubuntu: No dnf, skip gpgcheck config + - mkdir -p /etc/containers/registries.conf.d + - mv /tmp/apptainer_mirror.conf /etc/containers/registries.conf.d/apptainer_mirror.conf + +{% if hostvars['localhost']['openldap_support'] %} + - /usr/local/bin/update_ldap_conf.sh + - mkdir /ldapcerts + - echo "{{ cloud_init_nfs_path_openldap }}/certs /ldapcerts nfs defaults,_netdev 0 0" >> /etc/fstab + # TODO: This mount may be redundant, remove this + - echo "{{ cloud_init_nfs_path_openldap }}/ldapuser /home nfs defaults,_netdev 0 0" >> /etc/fstab + - chmod {{ file_mode }} /etc/fstab + - mount -a + - yes | cp /ldapcerts/* /etc/openldap/certs + - umount /ldapcerts + + # Ubuntu: Use ufw instead of firewalld + - ufw allow {{ ldap_starttls_port }}/tcp + - ufw allow {{ ldap_ssl_port }}/tcp + + # Ubuntu: No authselect or setsebool (SELinux), use pam-auth-update instead + - pam-auth-update --enable mkhomedir + - systemctl enable --now sssd + - systemctl restart ssh +{% endif %} + +{% if ldms_support %} + - echo " Starting LDMS setup " | tee -a /var/log/ldms-cloudinit.log + + # Add NFS entry and mount + - mkdir -p {{ client_mount_path }} + - echo "{{ cloud_init_slurm_nfs_path }} {{ client_mount_path }} nfs defaults,_netdev 0 0" >> /etc/fstab + - mount -a + + - /root/ldms_sampler.sh +{% endif %} + - systemctl restart slurmdbd + - systemctl restart slurmctld + - echo "Cloud-Init has completed successfully." diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_x86_64_ubuntu.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_x86_64_ubuntu.yaml.j2 new file mode 100644 index 0000000000..c2b57421da --- /dev/null +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_x86_64_ubuntu.yaml.j2 @@ -0,0 +1,526 @@ +- name: {{ functional_group_name }} + description: "{{ functional_group_name }}" + + file: + encoding: plain + content: | + ## template: jinja + #cloud-config + merge_how: + - name: list + settings: [append] + - name: dict + settings: [no_replace, recurse_list] + users: + - name: root + ssh_authorized_keys: "{{ read_ssh_key.stdout }}" + lock_passwd: false + hashed_passwd: "{{ hashed_password_output.stdout }}" + - name: {{ slurm_user }} + uid: {{ slurm_uid }} + system: true + no_create_home: true + shell: /sbin/nologin + + disable_root: false + + write_files: + - path: /usr/local/bin/doca-install.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/doca-ofed/doca-install.sh.j2') | indent(12) }} + + - path: /usr/local/bin/configure-ib-network.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/doca-ofed/configure-ib-network.sh.j2') | indent(12) }} + + - path: /usr/local/bin/set-ssh.sh + permissions: '{{ file_mode_755 }}' + content: | + #!/bin/bash + timedatectl set-timezone {{ hostvars['oim']['oim_timezone'] }} + sed -i 's/^#PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config + sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config + sed -i 's/^PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config.d/50-cloud-init.conf + systemctl restart ssh + default_count=$(ip route | grep -c "^default") + if [ "$default_count" -le 1 ]; then + echo "Only one or no default route found. No action needed." + else + private_nic=$(ip route | grep "^default via {{ hostvars['localhost']['admin_nic_ip'] }}" | awk '{print $5}') + # Get all default routes + ip route | grep '^default' | while read -r line; do + nmcli con del "Wired Connection" + # Extract NIC name + nic=$(echo "$line" | awk '{prFint $5}') + + # Add the default route to the connection + if [ -n "$nic" ]; then + echo "Adding nmcli device $nic" + nmcli con add type ethernet ifname "$nic" con-name "$nic" ipv4.method auto + if [ "$nic" = "$private_nic" ]; then + nmcli con modify "$nic" ipv4.never-default yes + nmcli con delete "cloud-init $nic" + fi + nmcli con up "$nic" + else + echo "No connection found for device $nic" + fi + done + fi + + - path: /root/.ssh/config + permissions: '0600' + content: | + Host {{ slurm_control_ssh_patterns }} + IdentityFile {{ client_mount_path }}/slurm/ssh/oim_rsa + IdentitiesOnly yes + + +{% if hostvars['localhost']['openldap_support'] %} + - path: /etc/sssd/sssd.conf + owner: root:root + permissions: '0600' + content: | + {{ lookup('template', 'templates/openldap/sssd.conf.j2') | indent(6) }} + + - path: /usr/local/bin/update_ldap_conf.sh + owner: root:root + permissions: '0755' + content: | + {{ lookup('template', 'templates/openldap/update_ldap_conf.sh.j2') | indent(12) }} +{% endif %} + +{% if ldms_support %} + - path: /root/ldms_sampler.sh + owner: root:root + permissions: '0755' + content: | + {{ lookup('template', 'templates/ldms/ldms_sampler.sh.j2') | indent(12) }} +{% endif %} + +{% if slurm_node_present %} + - path: /usr/local/bin/slurm_cuda_coordinator.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/slurm_cuda_coordinator.sh.j2') | indent(12) }} + + - path: /usr/local/bin/install_cuda_driver.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/install_cuda_driver.sh.j2') | indent(12) }} + + - path: /usr/local/bin/install_nvidia_peermem.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/install_nvidia_peermem.sh.j2') | indent(12) }} + + - path: /usr/local/bin/install_dcgm.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/install_dcgm.sh.j2') | indent(12) }} + +{% if not login_compiler_node_present %} + - path: /usr/local/bin/generate_install_uuid.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/generate_install_uuid.sh.j2') | indent(12) }} + + - path: /usr/local/bin/cuda_lock_manager.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/cuda_lock_manager.sh.j2') | indent(12) }} + + - path: /usr/local/bin/install_cuda_toolkit.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/install_cuda_toolkit.sh.j2') | indent(12) }} +{% endif %} +{% endif %} + +{% if dns_enabled | default(false) | bool %} + - path: /etc/resolv.conf + owner: root:root + permissions: '0644' + content: | + search {{ domain_name }} + nameserver {{ admin_nic_ip }} + options timeout:1 attempts:2 +{% else %} + - path: /etc/hosts + append: true + content: | +{% for key in ip_name_map | sort %} + {{ ip_name_map[key] }} {{ key }} +{% endfor %} +{% endif %} + - path: /etc/profile.d/create_scratch.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/slurm/create_scratch.sh.j2') | indent(12) }} + + - path: /etc/default/slurmd + owner: root:root + permissions: '0644' + content: | + SLURMD_OPTIONS="{{ conf_server }}" + + - path: /usr/local/bin/configure_vast_installation.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/vast/configure_vast_installation.sh.j2') | indent(12) }} + + - path: /usr/local/bin/configure_dirs_and_mounts.sh + permissions: '{{ file_mode_755 }}' + content: | + #!/bin/bash + LOGFILE="/var/log/configure_dirs_and_mounts.log" + exec > >(tee -a "$LOGFILE") 2>&1 + + echo "[INFO] ===== Starting directory creation and NFS mounts for Pulp cert, Slurm and Munge =====" + + # Ensure Slurm NFS root is mounted at client_mount_path (e.g. /share_omnia) + mkdir -p {{ client_mount_path }}/slurm/ssh + echo "[INFO] Creating base directories for Pulp cert, Slurm and Munge" + mkdir -pv {{ slurm_slurmd_log_dir_effective }} {{ slurm_slurmd_pid_dir_effective }} {{ slurm_slurmd_spool_dir_effective }} {{ slurm_epilog_dirs_all | join(' ') }} /etc/munge /cert /var/log/track /var/lib/packages + + echo "[INFO] Updating /etc/fstab with NFS entries for Pulp cert, Slurm and Munge paths" + echo "{{ cloud_init_nfs_path }}/cert /cert nfs defaults,_netdev 0 0" >> /etc/fstab + echo "{{ cloud_init_nfs_path }}/$(hostname -s)/var/log/slurm {{ slurm_slurmd_log_dir_effective }} nfs defaults,_netdev 0 0" >> /etc/fstab + echo "{{ cloud_init_nfs_path }}/$(hostname -s)/var/spool/slurmd {{ slurm_slurmd_spool_dir_effective }} nfs defaults,_netdev 0 0" >> /etc/fstab + echo "{{ cloud_init_nfs_path }}/$(hostname -s)/etc/slurm/epilog.d /etc/slurm/epilog.d nfs defaults,_netdev 0 0" >> /etc/fstab + echo "{{ cloud_init_nfs_path }}/$(hostname -s)/etc/munge /etc/munge nfs defaults,_netdev 0 0" >> /etc/fstab + echo "{{ trackfile_nfs_path }} /var/log/track nfs defaults,_netdev 0 0" >> /etc/fstab + echo "{{ cloud_init_nfs_path }}/packages /var/lib/packages nfs defaults,_netdev 0 0" >> /etc/fstab + echo "{{ cloud_init_nfs_path }}/ssh {{ client_mount_path }}/slurm/ssh nfs defaults,_netdev 0 0" >> /etc/fstab + chmod {{ file_mode }} /etc/fstab + + echo "[INFO] Mounting all NFS entries from /etc/fstab" + mount -av + mkdir -p /etc/containers/registries.conf.d + mv /tmp/apptainer_mirror.conf /etc/containers/registries.conf.d/apptainer_mirror.conf + + echo "[INFO] ===== Completed directory creation and NFS mounts for Slurm and Munge =====" + + - path: /usr/local/bin/configure_slurmd_setup.sh + permissions: '{{ file_mode_755 }}' + content: | + #!/bin/bash + LOGFILE="/var/log/configure_slurmd_setup.log" + exec > >(tee -a "$LOGFILE") 2>&1 + + echo "[INFO] ===== Starting slurmd setup (service file, directories, epilog) =====" + + bash /usr/local/bin/check_slurm_controller_status.sh + + echo "[INFO] Setting ownership for Slurm directories" + chown -R {{ slurm_user }}:{{ slurm_user }} {{ slurm_slurmd_log_dir_effective }} + chown -R {{ slurm_user }}:{{ slurm_user }} {{ slurm_slurmd_pid_dir_effective }} + chown -R {{ slurm_user }}:{{ slurm_user }} {{ slurm_slurmd_spool_dir_effective }} + + echo "[INFO] Setting permissions for Slurm directories" + chmod {{ file_mode_755 }} {{ slurm_slurmd_log_dir_effective }} {{ slurm_slurmd_pid_dir_effective }} {{ slurm_slurmd_spool_dir_effective }} + + echo "[INFO] Ensuring Slurm epilog directory and logout script permissions" + chmod {{ file_mode_755 }} /etc/slurm/epilog.d/ + chmod {{ file_mode_755 }} /etc/slurm/epilog.d/logout_user.sh +{% for epath in slurm_epilog_custom_paths %} + + echo "[INFO] Checking custom epilog script: {{ epath }}" + if [ ! -f "{{ epath }}" ]; then + echo "[INFO] Creating stub epilog script at {{ epath }}" + mkdir -p "$(dirname '{{ epath }}')" + printf '#!/bin/bash\n# Custom epilog script placeholder\n# Add your epilog commands here\n' > "{{ epath }}" + chown {{ slurm_user }}:{{ slurm_user }} "{{ epath }}" + chmod {{ file_mode_755 }} "{{ epath }}" + fi +{% endfor %} + + + echo "[INFO] Creating and configuring slurmd spool directory" + mkdir -p {{ slurm_slurmd_spool_dir_effective }} + chmod {{ file_mode_755 }} {{ slurm_slurmd_spool_dir_effective }} + chown -R {{ slurm_user }}:{{ slurm_user }} {{ slurm_slurmd_spool_dir_effective }} + + echo "[INFO] ===== Completed slurmd setup =====" + + - path: /usr/local/bin/configure_munge_and_pam.sh + permissions: '{{ file_mode_755 }}' + content: | + #!/bin/bash + LOGFILE="/var/log/configure_munge_and_pam.log" + exec > >(tee -a "$LOGFILE") 2>&1 + + echo "[INFO] ===== Starting Munge key and PAM configuration =====" + + echo "[INFO] Setting ownership and permissions for Munge key" + chown -R {{ munge_user }}:{{ munge_group }} /etc/munge/munge.key + chmod {{ file_mode_400 }} /etc/munge/munge.key + + echo "[INFO] Updating PAM configuration for pam_slurm_adopt in /etc/pam.d/sshd" + sed -i '/^password\s\+include\s\+password-auth/i account required pam_slurm_adopt.so action_no_jobs=deny' /etc/pam.d/sshd + + echo "[INFO] ===== Completed Munge key and PAM configuration =====" + + + - path: /usr/local/bin/configure_firewall_and_services.sh + permissions: '{{ file_mode_755 }}' + content: | + #!/bin/bash + LOGFILE="/var/log/configure_firewall_and_services.log" + exec > >(tee -a "$LOGFILE") 2>&1 + + echo "[INFO] ===== Starting firewall and service configuration =====" + + # Ubuntu: Use ufw instead of firewalld + echo "[INFO] Enabling ufw firewall" + ufw --force enable + + # Default values in case parsing slurm.conf fails + DEFAULT_SRUN_RANGE="60001-63000" + DEFAULT_SLURMD_PORT="6818" + + CTLD_SLURM_DIR_MNT="/mnt/slurm_ctld_etc_slurm" + SLURM_CONF_PATH="$CTLD_SLURM_DIR_MNT/slurm.conf" + + echo "[INFO] Mounting controller slurm.conf from NFS: {{ cloud_init_nfs_path }}/{{ ctld_list[0] }}/etc/slurm -> $CTLD_SLURM_DIR_MNT" + mkdir -p "$CTLD_SLURM_DIR_MNT" + mount -t nfs "{{ cloud_init_nfs_path }}/{{ ctld_list[0] }}/etc/slurm" "$CTLD_SLURM_DIR_MNT" || { + echo "[WARN] Failed to mount controller slurm.conf directory, falling back to defaults." + SRUN_RANGE="$DEFAULT_SRUN_RANGE" + SLURMD_PORT="$DEFAULT_SLURMD_PORT" + } + + if [ -f "$SLURM_CONF_PATH" ]; then + echo "[INFO] Parsing SlurmdPort and SrunPortRange from $SLURM_CONF_PATH" + + SLURMD_PORT=$(grep -iE '^SlurmdPort=' "$SLURM_CONF_PATH" | sed -E 's/^SlurmdPort=//; s/#.*//; s/\s+$//') + SRUN_RANGE=$(grep -iE '^SrunPortRange=' "$SLURM_CONF_PATH" | sed -E 's/^SrunPortRange=//; s/#.*//; s/\s+$//') + + [ -z "$SLURMD_PORT" ] && SLURMD_PORT="$DEFAULT_SLURMD_PORT" && echo "[WARN] SlurmdPort not found in slurm.conf, using default $SLURMD_PORT" + [ -z "$SRUN_RANGE" ] && SRUN_RANGE="$DEFAULT_SRUN_RANGE" && echo "[WARN] SrunPortRange not found in slurm.conf, using default $SRUN_RANGE" + else + echo "[WARN] slurm.conf not found at $SLURM_CONF_PATH, using defaults." + SRUN_RANGE="$DEFAULT_SRUN_RANGE" + SLURMD_PORT="$DEFAULT_SLURMD_PORT" + fi + + echo "[INFO] Using SlurmdPort=$SLURMD_PORT and SrunPortRange=$SRUN_RANGE for firewall configuration" + + echo "[INFO] Configuring firewall rules for SSH and Slurm ports (Ubuntu: ufw)" + ufw allow ssh + ufw allow "${SRUN_RANGE}"/tcp + ufw allow "${SLURMD_PORT}"/tcp + + # Add PXE network to trusted zone for ORTE communication + echo "[INFO] Adding PXE network to trusted zone for ORTE communication" + # Calculate PXE subnet using admin IP and netmask bits + ADMIN_IP="{{ hostvars['localhost']['admin_nic_ip'] }}" + NETMASK_BITS="{{ hostvars['localhost']['admin_netmask_bits'] }}" + + # Convert IP to integer and calculate network address + ip_to_int() { + local IFS=. + read -r a b c d <<< "$1" + echo $(( (a << 24) + (b << 16) + (c << 8) + d )) + } + + int_to_ip() { + local ip=$1 + echo "$(( (ip >> 24) & 255 )).$(( (ip >> 16) & 255 )).$(( (ip >> 8) & 255 )).$(( ip & 255 ))" + } + + ADMIN_IP_INT=$(ip_to_int "$ADMIN_IP") + HOST_BITS=$(( 32 - NETMASK_BITS )) + HOST_MASK=$(( (1 << HOST_BITS) - 1 )) + NETWORK_MASK=$(( ~HOST_MASK & 0xFFFFFFFF )) + NETWORK_INT=$(( ADMIN_IP_INT & NETWORK_MASK )) + NETWORK_IP=$(int_to_ip "$NETWORK_INT") + + PXE_SUBNET="$NETWORK_IP/$NETMASK_BITS" + echo "[INFO] Admin IP: $ADMIN_IP, Netmask: /$NETMASK_BITS, PXE Subnet: $PXE_SUBNET" + ufw allow from "$PXE_SUBNET" + + echo "[INFO] Unmounting controller slurm.conf directory from $CTLD_SLURM_DIR_MNT" + umount "$CTLD_SLURM_DIR_MNT" 2>/dev/null || echo "[WARN] Failed to unmount $CTLD_SLURM_DIR_MNT (may not have been mounted)" + + echo "[INFO] Enabling and starting core services: ssh, munge, slurmd" + systemctl enable ssh + systemctl start ssh + systemctl enable munge + systemctl start munge + systemctl enable slurmd + systemctl start slurmd + + echo "[INFO] Reloading systemd daemon and restarting ssh" + systemctl daemon-reexec + systemctl restart ssh + systemctl restart slurmd + + echo "[INFO] ===== Completed firewall and service configuration =====" + + - path: /usr/local/bin/check_slurm_controller_status.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/slurm/check_slurm_controller_status.sh.j2') | indent(12) }} + + - path: /tmp/apptainer_mirror.conf + permissions: '0644' + content: | + {{ lookup('template', 'templates/nodes/apptainer_mirror.conf.j2') | indent(12) }} + + - path: /usr/local/bin/configure_ucx_openmpi_env.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/configure_ucx_openmpi_env.sh.j2') | indent(12) }} + + - path: /usr/local/bin/setup_doca_mpi_env.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/setup_doca_mpi_env.sh.j2') | indent(12) }} + + + # NVIDIA HPC SDK setup script (run manually: /usr/local/bin/setup_nvhpc_sdk.sh) + - path: /usr/local/bin/setup_nvhpc_sdk.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/setup_nvhpc_sdk.sh.j2') | indent(12) }} + +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} + - path: /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh + permissions: '{{ file_mode_755 }}' + content: | + {{ pv_entry.content | indent(12) }} +{% endfor %} + + + runcmd: + - /usr/local/bin/set-ssh.sh + - /usr/local/bin/configure_vast_installation.sh + # DOCA prerequisites - moved early to ensure RDMA is ready before vendor_data mounts + - /usr/local/bin/configure_dirs_and_mounts.sh + - cp /cert/pulp_webserver.crt /etc/pki/ca-trust/source/anchors && update-ca-trust + # Ubuntu: No dnf, skip gpgcheck config + # DOCA and IB configuration - now ready before vendor_data mounts + - bash /usr/local/bin/doca-install.sh || echo "DOCA install failed (non-critical)" + - bash /usr/local/bin/configure-ib-network.sh || echo "IB network configuration failed (non-critical)" +{% if hostvars['localhost']['openmpi_support'] %} + - bash /usr/local/bin/setup_doca_mpi_env.sh || echo "DOCA MPI environment setup failed (non-critical)" +{% endif %} + +{# Mount-specific runcmd entries - moved after DOCA to ensure RDMA is available #} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} +{% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} + - {{ cmd }} +{% endfor %} +{% endif %} +{% raw %} + {% if ds.meta_data.instance_data.v1.vendor_data.groups.ssh.host_mount_map %} + {% set mymounts = ds.meta_data.instance_data.v1.vendor_data.groups.ssh.host_mount_map.get(local_hostname, {}) %} + {% if mymounts %} + {% for mount in mymounts.get("mounts", []) %} + - mkdir -pv {{ mount[1] }} + - echo "{{ mount | join(' ') }}" >> /etc/fstab + {% endfor %} + - mount -av + {% for decoded_cmd in mymounts.get("runcmd", []) %} + - {{ decoded_cmd }} + {% endfor %} + {% else %} + - echo "No mount entries found for this host" + {% endif %} + {% endif %} +{% endraw %} +{% set fg_swap = cloud_init_groups_dict.get(functional_group_name, {}).get('swap', {}) %} +{% include 'configure_swap.yaml.j2' %} + - mount -av +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} + - bash /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh +{% endfor %} + # VAST storage: create subdirectory structure for compute node + - mkdir -pv {{ vast_mount_point }}/apps {{ vast_mount_point }}/slurm/hpc_tools {{ vast_mount_point }}/scratch {{ vast_mount_point }}/projects + - mkdir -pv {{ vast_mount_point }}/scratch/$(hostname -s)/tmp + - mkdir -pv /hpc_tools /apps /scratch /projects + - echo "{{ vast_mount_point }}/slurm/hpc_tools /hpc_tools none bind 0 0" >> /etc/fstab + - echo "{{ vast_mount_point }}/apps /apps none bind 0 0" >> /etc/fstab + - echo "{{ vast_mount_point }}/scratch /scratch none bind 0 0" >> /etc/fstab + - echo "{{ vast_mount_point }}/scratch/$(hostname -s)/tmp /tmp none bind 0 0" >> /etc/fstab + - echo "{{ vast_mount_point }}/projects /projects none bind 0 0" >> /etc/fstab + - mount -av + - chmod 1777 /tmp /scratch +{% if slurm_node_present %} + - /usr/local/bin/slurm_cuda_coordinator.sh || echo "CUDA coordinator setup failed (non-critical)" + - timeout 900 /usr/local/bin/install_cuda_driver.sh || echo "CUDA driver install failed or timed out (non-critical)" +{% if dcgm_support %} + - timeout 300 /usr/local/bin/install_dcgm.sh || echo "DCGM install failed or timed out (non-critical)" +{% endif %} + - timeout 600 /usr/local/bin/install_nvidia_peermem.sh || echo "NVIDIA peermem install failed or timed out (non-critical)" +{% endif %} + + - /usr/local/bin/configure_slurmd_setup.sh + - /usr/local/bin/configure_munge_and_pam.sh + + - /usr/local/bin/configure_firewall_and_services.sh +{% if hostvars['localhost']['openldap_support'] %} + - /usr/local/bin/update_ldap_conf.sh + - mkdir -p /ldapcerts || echo "LDAP cert directory already exists or creation failed (non-critical)" + - echo "{{ cloud_init_nfs_path_openldap }}/certs /ldapcerts nfs defaults,_netdev 0 0" >> /etc/fstab + - mkdir -pv {{ vast_mount_point }}/{{ openldap_dir_name }}/ldapuser /home + - echo "{{ vast_mount_point }}/{{ openldap_dir_name }}/ldapuser /home none bind 0 0" >> /etc/fstab + - chmod {{ file_mode }} /etc/fstab + - mount -av + - cp -f /ldapcerts/* /etc/openldap/certs/ || echo "LDAP cert copy failed (non-critical)" + - umount /ldapcerts || echo "LDAP cert unmount failed (non-critical)" + # Ubuntu: Use ufw instead of firewalld + - ufw allow {{ ldap_starttls_port }}/tcp || echo "Firewall LDAP port configuration failed (non-critical)" + - ufw allow {{ ldap_ssl_port }}/tcp || echo "Firewall LDAP SSL port configuration failed (non-critical)" + # Ubuntu: No SELinux, skip setenforce, authselect, setsebool (use pam-auth-update instead) + - pam-auth-update --enable mkhomedir + - systemctl enable --now sssd + - systemctl restart ssh +{% endif %} + +{% if hostvars['localhost']['ucx_support'] or hostvars['localhost']['openmpi_support'] or ldms_support %} + # Add NFS entry and mount + - mkdir -p {{ client_mount_path }} + - echo "{{ cloud_init_slurm_nfs_path }} {{ client_mount_path }} nfs defaults,_netdev 0 0" >> /etc/fstab + - mount -av +{% endif %} + # UCX and OpenMPI auto-compilation disabled + # DOCA UCX 1.20.0 and OpenMPI 4.1.9a1 used by default +{% if hostvars['localhost']['ucx_support'] %} + - echo "===== UCX Configuration =====" + - echo "UCX version specified in software_config.json (available for manual compilation)" + - echo "Default stack - DOCA UCX 1.20.0 (system default)" +{% endif %} +{% if hostvars['localhost']['openmpi_support'] %} + - echo "===== OpenMPI Configuration =====" + - echo "OpenMPI version specified in software_config.json (available for manual compilation)" + - echo "Default stack - DOCA OpenMPI 4.1.9a1 (system default)" +{% endif %} + +{% if ldms_support %} + - echo " Starting LDMS setup " | tee -a /var/log/ldms-cloudinit.log + - /root/ldms_sampler.sh || echo "LDMS setup failed (non-critical)" +{% endif %} + # NVIDIA HPC SDK: Script deployed to /usr/local/bin/setup_nvhpc_sdk.sh + # User must run manually after NVHPC is installed on compiler node + - echo "Run /usr/local/bin/setup_nvhpc_sdk.sh to setup NVIDIA HPC SDK" + - systemctl restart slurmd + - echo "Cloud-Init has completed successfully." From 46d6fa4e8c75472cde3c55ae63b11876c50e63a7 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Thu, 9 Jul 2026 11:19:15 +0530 Subject: [PATCH 12/15] Slurm Packages --- .../files/image-builder/installer.py | 69 +++++++++++++------ .../tasks/build_ubuntu_compute_image.yml | 16 ++++- .../images/ubuntu-compute-config.yaml.j2 | 5 +- .../modules/image_package_collector.py | 8 ++- 4 files changed, 68 insertions(+), 30 deletions(-) diff --git a/build_image_x86_64/roles/image_creation/files/image-builder/installer.py b/build_image_x86_64/roles/image_creation/files/image-builder/installer.py index 19ac59b2ad..8894aa4ee2 100644 --- a/build_image_x86_64/roles/image_creation/files/image-builder/installer.py +++ b/build_image_x86_64/roles/image_creation/files/image-builder/installer.py @@ -201,6 +201,12 @@ def install_base_packages(self, packages, registry_loc, proxy): cmd(["buildah", "run", self.cname, "--", "bash", "-c", 'echo \'Acquire::https::Verify-Peer "false";\' > /etc/apt/apt.conf.d/99no-ssl-verify'], check=False, env=env) + # Remove CUDA/nvidia repo sources inherited from base image + # These repos have broken/missing packages that cause apt-get install to fail + logging.info("Removing CUDA/nvidia repo sources to avoid broken dependencies") + cmd(["buildah", "run", self.cname, "--", "bash", "-c", + 'rm -f /etc/apt/sources.list.d/*cuda* /etc/apt/sources.list.d/*nvidia*'], + check=False, env=env) # Run apt-get update with --allow-insecure-repositories for Pulp repos rc = cmd(["buildah", "run", "--env", "DEBIAN_FRONTEND=noninteractive", self.cname, "--", "apt-get", "update", @@ -208,41 +214,62 @@ def install_base_packages(self, packages, registry_loc, proxy): check=False, env=env) if rc != 0: logging.warn("apt-get update returned non-zero, continuing anyway") - # Divert LVM commands to prevent lvm2 postinst hang in container - # (vgcfgbackup, vgchange, pvscan etc. hang with no block devices) - logging.info("Diverting LVM commands to prevent lvm2 postinst hang") - lvm_cmds = ['vgcfgbackup', 'vgchange', 'pvscan', 'vgscan', 'lvscan'] - divert_script = ' && '.join( - [f'dpkg-divert --local --rename --divert /sbin/{c}.real --add /sbin/{c} 2>/dev/null; ' - f'echo \'#!/bin/sh\\nexit 0\' > /sbin/{c} && chmod +x /sbin/{c}' - for c in lvm_cmds] - ) - cmd(["buildah", "run", self.cname, "--", "bash", "-c", divert_script], + # Divert lvm2 postinst script to prevent hang in container + # (lvm2 postinst runs vgscan/vgchange which hang with no block devices) + logging.info("Diverting lvm2 postinst script to prevent hang") + divert_postinst = "dpkg-divert --local --rename --divert /var/lib/dpkg/info/lvm2.postinst.real --add /var/lib/dpkg/info/lvm2.postinst 2>/dev/null || true" + replace_postinst = "echo '#!/bin/sh' > /var/lib/dpkg/info/lvm2.postinst && echo 'exit 0' >> /var/lib/dpkg/info/lvm2.postinst && chmod +x /var/lib/dpkg/info/lvm2.postinst" + postinst_script = f"{divert_postinst} && {replace_postinst}" + cmd(["buildah", "run", self.cname, "--", "bash", "-c", postinst_script], check=False, env=env) - # Run apt-get install with --allow-unauthenticated for Pulp repos + # Run apt-get install with --allow-unauthenticated and --fix-missing + # --fix-missing: skip packages that can't be fetched (e.g. 404 from broken repos) rc = cmd(["buildah", "run", "--env", "DEBIAN_FRONTEND=noninteractive", self.cname, "--", "apt-get", "install", "-y", "--no-install-recommends", "--allow-unauthenticated", + "--fix-missing", "-o", 'Dpkg::Options::=--force-overwrite', "-o", 'Dpkg::Options::=--force-confdef', "-o", 'Dpkg::Options::=--force-confold'] + packages, check=False, env=env) - # Restore real LVM commands after install - logging.info("Restoring real LVM commands") - restore_script = '; '.join( - [f'dpkg-divert --remove --rename /sbin/{c} 2>/dev/null' - for c in lvm_cmds] - ) + '; true' - cmd(["buildah", "run", self.cname, "--", "bash", "-c", restore_script], + # Restore real lvm2 postinst script after install + logging.info("Restoring real lvm2 postinst script") + restore_postinst = "dpkg-divert --remove --rename /var/lib/dpkg/info/lvm2.postinst 2>/dev/null || true" + cmd(["buildah", "run", self.cname, "--", "bash", "-c", restore_postinst], check=False, env=env) if rc != 0: logging.warn("apt-get install returned %d, attempting to fix broken packages", rc) + # Retry install with --fix-broken to resolve partial installs rc2 = cmd(["buildah", "run", "--env", "DEBIAN_FRONTEND=noninteractive", - self.cname, "--", "dpkg", "--configure", "-a", - "--force-overwrite", "--force-confdef", "--force-confold"], + self.cname, "--", "apt-get", "install", "-y", + "--fix-broken", "--fix-missing", + "--no-install-recommends", "--allow-unauthenticated", + "-o", 'Dpkg::Options::=--force-overwrite', + "-o", 'Dpkg::Options::=--force-confdef', + "-o", 'Dpkg::Options::=--force-confold'], check=False, env=env) if rc2 != 0: - raise Exception("Installing base packages failed") + logging.warn("apt-get --fix-broken returned %d, running dpkg --configure -a", rc2) + rc3 = cmd(["buildah", "run", "--env", "DEBIAN_FRONTEND=noninteractive", + self.cname, "--", "dpkg", "--configure", "-a", + "--force-overwrite", "--force-confdef", "--force-confold"], + check=False, env=env) + if rc3 != 0: + raise Exception("Installing base packages failed") + # Verify requested packages were actually installed + logging.info("Verifying requested packages were installed") + verify_cmd = " && ".join([f"dpkg -s {pkg} >/dev/null 2>&1" for pkg in packages]) + rc_verify = cmd(["buildah", "run", self.cname, "--", "bash", "-c", verify_cmd], + check=False, env=env) + if rc_verify != 0: + logging.error("Some requested packages were NOT installed after fix attempt") + # Log which packages are missing + for pkg in packages: + rc_pkg = cmd(["buildah", "run", self.cname, "--", "dpkg", "-s", pkg], + check=False, env=env) + if rc_pkg != 0: + logging.error(f"MISSING package: {pkg}") + raise Exception("Installing base packages failed - required packages missing") return elif self.pkg_man == "apk": env = os.environ.copy() diff --git a/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_compute_image.yml b/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_compute_image.yml index 62bfef69f8..554c823422 100644 --- a/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_compute_image.yml +++ b/build_image_x86_64/roles/image_creation/tasks/build_ubuntu_compute_image.yml @@ -50,6 +50,16 @@ loop_control: loop_var: item +- name: Deploy patched image-builder scripts for Ubuntu compute builds + ansible.builtin.copy: + src: "{{ role_path }}/files/image-builder/{{ item.src }}" + dest: "{{ oim_shared_path }}/omnia/openchami/image-builder-{{ item.dest }}" + mode: "{{ dir_permissions_755 }}" + loop: + - { src: 'installer.py', dest: 'installer.py' } + - { src: 'layer.py', dest: 'layer.py' } + - { src: 'publish.py', dest: 'publish.py' } + - name: Build x86_64 ubuntu compute osimages in parallel ansible.builtin.shell: cmd: | @@ -59,9 +69,9 @@ {{ aws_checksum_env }} --user 0 --privileged \ -v {{ pulp_cert_host_path }}:/usr/local/share/ca-certificates/pulp_webserver.crt:z \ -v {{ openchami_work_dir }}/images/ubuntu-{{ item.key }}{{ compute_image_suffix }}-{{ ubuntu_tag }}.yaml:/home/builder/config.yaml:z \ - -v {{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami/image-builder-installer.py:/usr/local/bin/installer.py:z \ - -v {{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami/image-builder-layer.py:/usr/local/bin/layer.py:z \ - -v {{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami/image-builder-publish.py:/usr/local/bin/publish.py:z \ + -v {{ oim_shared_path }}/omnia/openchami/image-builder-installer.py:/usr/local/bin/installer.py:z \ + -v {{ oim_shared_path }}/omnia/openchami/image-builder-layer.py:/usr/local/bin/layer.py:z \ + -v {{ oim_shared_path }}/omnia/openchami/image-builder-publish.py:/usr/local/bin/publish.py:z \ {{ ochami_x86_64_image | join(' ') }} \ {{ ochami_base_command | join(' ') }} \ > '{{ openchami_log_dir }}/{{ item.key }}{{ compute_image_suffix }}_compute_image.log' 2>&1 diff --git a/build_image_x86_64/roles/image_creation/templates/images/ubuntu-compute-config.yaml.j2 b/build_image_x86_64/roles/image_creation/templates/images/ubuntu-compute-config.yaml.j2 index e9bf4faf7f..558802f785 100644 --- a/build_image_x86_64/roles/image_creation/templates/images/ubuntu-compute-config.yaml.j2 +++ b/build_image_x86_64/roles/image_creation/templates/images/ubuntu-compute-config.yaml.j2 @@ -15,7 +15,7 @@ options: repos: {% for repo in ubuntu_x86_64_repos | default([]) %} -{% if repo.base_url | length > 1 %} +{% if repo.base_url | length > 1 and 'cuda' not in repo.name | lower and 'nvidia-hpc-sdk' not in repo.name | lower %} - alias: '{{ repo.name }}' url: '{{ repo.base_url }}' {% if repo.apt_dist | default('') | length > 0 %} @@ -40,6 +40,5 @@ cmds: {% for cmd in commands_list %} - cmd: "{{ cmd }}" {% endfor %} -{% else %} - [] {% endif %} + - cmd: "KVER=$(ls /lib/modules/ | head -1) && depmod ${KVER} && dracut --force --force-add 'dmsquash-live livenet' --kver ${KVER}" diff --git a/common/library/modules/image_package_collector.py b/common/library/modules/image_package_collector.py index 3ad27a679b..f46f4deb47 100644 --- a/common/library/modules/image_package_collector.py +++ b/common/library/modules/image_package_collector.py @@ -135,12 +135,12 @@ def collect_packages_from_json(sw_data, fg_name=None, def process_functional_group(fg_name, arch, os_version, input_project_dir, - software_map, allowed_softwares, module): + software_map, allowed_softwares, module, cluster_os_type="rhel"): """ Process a single functional group and return its package list. """ group_path = os.path.join( - input_project_dir, "config", arch, "rhel", os_version + input_project_dir, "config", arch, cluster_os_type, os_version ) if not os.path.isdir(group_path): @@ -229,6 +229,8 @@ def run_module(): if not os_version: module.fail_json(msg="cluster_os_version not found in software_config.json") + cluster_os_type = software_config.get("cluster_os_type", "rhel") + # Extract service_k8s version from software_config if not provided if not service_k8s_version: for sw in software_config.get("softwares", []): @@ -305,7 +307,7 @@ def run_module(): packages = process_functional_group( fg_name, arch, os_version, input_project_dir, - software_map, allowed_softwares, module + software_map, allowed_softwares, module, cluster_os_type ) # Add role-specific packages from additional_packages.json if enabled From ffd532679c2e5b6a132648066dd66fa843bc8497 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Thu, 9 Jul 2026 12:12:17 +0530 Subject: [PATCH 13/15] Fix: SSH issue in controller node --- .../ci-group-slurm_control_node_x86_64_ubuntu.yaml.j2 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64_ubuntu.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64_ubuntu.yaml.j2 index 4d5171d126..5b6bdfd540 100644 --- a/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64_ubuntu.yaml.j2 +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64_ubuntu.yaml.j2 @@ -278,6 +278,10 @@ runcmd: - /usr/local/bin/set-ssh.sh + # Ubuntu: Use ufw instead of firewalld - enable SSH early before NFS mounts + - ufw allow ssh + - systemctl enable ssh + - systemctl start ssh # DOCA prerequisites - moved early to ensure RDMA is ready before vendor_data mounts - mkdir -p {{ client_mount_path }}/slurm/ssh - mkdir -p {{ slurm_ctld_log_dir_effective }} {{ slurmdbd_log_dir_effective }} {{ slurm_ctld_pid_dir_effective }} {{ slurmdbd_pid_dir_effective }} {{ slurm_state_save_location_effective }} {% if slurm_sched_log_dir_effective %}{{ slurm_sched_log_dir_effective }} {% endif %}/etc/slurm {{ home_dir }} /etc/mysql/conf.d /etc/munge /var/lib/mysql /var/log/mariadb /cert /var/log/track /var/lib/packages @@ -348,11 +352,6 @@ - ['bash', '/root/omnia_slurm_scripts/03_slurmctld_setup.sh'] - ['bash', '/root/omnia_slurm_scripts/04_track_file.sh'] - # Ubuntu: Use ufw instead of firewalld - - ufw allow ssh - - systemctl enable ssh - - systemctl start ssh - - cp /cert/pulp_webserver.crt /etc/pki/ca-trust/source/anchors && update-ca-trust # Ubuntu: No dnf, skip gpgcheck config - mkdir -p /etc/containers/registries.conf.d From 78bdc89bde50653092988167310a5c17cb8620c1 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Thu, 9 Jul 2026 15:45:37 +0530 Subject: [PATCH 14/15] Fix: slurm client packages --- .../files/image-builder/installer.py | 55 +++++++++++++++---- examples/slurm_conf/slurm.conf | 2 +- examples/slurm_conf/slurmdbd.conf | 2 +- .../x86_64/ubuntu/26.04/slurm_custom.json | 1 + provision/roles/slurm_config/tasks/confs.yml | 4 +- provision/roles/slurm_config/vars/main.yml | 2 +- 6 files changed, 50 insertions(+), 16 deletions(-) diff --git a/build_image_x86_64/roles/image_creation/files/image-builder/installer.py b/build_image_x86_64/roles/image_creation/files/image-builder/installer.py index 8894aa4ee2..2cb3f9a9ad 100644 --- a/build_image_x86_64/roles/image_creation/files/image-builder/installer.py +++ b/build_image_x86_64/roles/image_creation/files/image-builder/installer.py @@ -214,14 +214,35 @@ def install_base_packages(self, packages, registry_loc, proxy): check=False, env=env) if rc != 0: logging.warn("apt-get update returned non-zero, continuing anyway") - # Divert lvm2 postinst script to prevent hang in container - # (lvm2 postinst runs vgscan/vgchange which hang with no block devices) - logging.info("Diverting lvm2 postinst script to prevent hang") - divert_postinst = "dpkg-divert --local --rename --divert /var/lib/dpkg/info/lvm2.postinst.real --add /var/lib/dpkg/info/lvm2.postinst 2>/dev/null || true" - replace_postinst = "echo '#!/bin/sh' > /var/lib/dpkg/info/lvm2.postinst && echo 'exit 0' >> /var/lib/dpkg/info/lvm2.postinst && chmod +x /var/lib/dpkg/info/lvm2.postinst" - postinst_script = f"{divert_postinst} && {replace_postinst}" - cmd(["buildah", "run", self.cname, "--", "bash", "-c", postinst_script], + # ===== FIX: Divert actual LVM BINARIES, not postinst script ===== + # LVM tools hang in containers with no block devices. + # dpkg-divert on the real binaries makes dpkg install them + # to diverted paths, leaving our /bin/true symlinks in place. + lvm_bins_to_divert = [ + 'vgcfgbackup', 'vgscan', 'vgchange', 'pvscan', + 'lvm', 'lvs', 'vgs', 'pvs', 'vgmknodes' + ] + + logging.info("Diverting LVM binaries to prevent hang in container build") + for lvm_bin in lvm_bins_to_divert: + divert_cmd = ( + f"dpkg-divert --local --rename --add /usr/sbin/{lvm_bin} 2>/dev/null; " + f"ln -sf /bin/true /usr/sbin/{lvm_bin}" + ) + cmd(["buildah", "run", self.cname, "--", "bash", "-c", divert_cmd], + check=False, env=env) + + # Also prevent any service starts during package install + logging.info("Installing policy-rc.d to prevent service starts during build") + policy_cmd = ( + "echo '#!/bin/sh' > /usr/sbin/policy-rc.d && " + "echo 'exit 101' >> /usr/sbin/policy-rc.d && " + "chmod +x /usr/sbin/policy-rc.d" + ) + cmd(["buildah", "run", self.cname, "--", "bash", "-c", policy_cmd], check=False, env=env) + # ===== END FIX ===== + # Run apt-get install with --allow-unauthenticated and --fix-missing # --fix-missing: skip packages that can't be fetched (e.g. 404 from broken repos) rc = cmd(["buildah", "run", "--env", "DEBIAN_FRONTEND=noninteractive", @@ -232,11 +253,23 @@ def install_base_packages(self, packages, registry_loc, proxy): "-o", 'Dpkg::Options::=--force-confdef', "-o", 'Dpkg::Options::=--force-confold'] + packages, check=False, env=env) - # Restore real lvm2 postinst script after install - logging.info("Restoring real lvm2 postinst script") - restore_postinst = "dpkg-divert --remove --rename /var/lib/dpkg/info/lvm2.postinst 2>/dev/null || true" - cmd(["buildah", "run", self.cname, "--", "bash", "-c", restore_postinst], + # ===== FIX: Restore diverted LVM binaries after install ===== + logging.info("Restoring diverted LVM binaries") + for lvm_bin in lvm_bins_to_divert: + restore_cmd = ( + f"rm -f /usr/sbin/{lvm_bin}; " + f"dpkg-divert --remove --rename /usr/sbin/{lvm_bin} 2>/dev/null || true" + ) + cmd(["buildah", "run", self.cname, "--", "bash", "-c", restore_cmd], + check=False, env=env) + + # Remove policy-rc.d so services can start normally on booted nodes + logging.info("Removing policy-rc.d") + cmd(["buildah", "run", self.cname, "--", "bash", "-c", + "rm -f /usr/sbin/policy-rc.d"], check=False, env=env) + # ===== END RESTORE ===== + if rc != 0: logging.warn("apt-get install returned %d, attempting to fix broken packages", rc) # Retry install with --fix-broken to resolve partial installs diff --git a/examples/slurm_conf/slurm.conf b/examples/slurm_conf/slurm.conf index 1957e285e6..d3ba8e240e 100644 --- a/examples/slurm_conf/slurm.conf +++ b/examples/slurm_conf/slurm.conf @@ -30,7 +30,7 @@ SlurmctldPort=6817 SlurmdPort=6818 # PLUGINS -PluginDir=/usr/lib64/slurm +PluginDir=/usr/lib/x86_64-linux-gnu/slurm ProctrackType=proctrack/cgroup PrologFlags=contain TaskPlugin=task/cgroup diff --git a/examples/slurm_conf/slurmdbd.conf b/examples/slurm_conf/slurmdbd.conf index a94b2dd3d4..ca8bf1f25d 100644 --- a/examples/slurm_conf/slurmdbd.conf +++ b/examples/slurm_conf/slurmdbd.conf @@ -12,7 +12,7 @@ DbdHost= DbdPort=6819 LogFile=/var/log/slurm/slurmdbd.log PidFile=/var/run/slurmdbd.pid -PluginDir=/usr/lib64/slurm +PluginDir=/usr/lib/x86_64-linux-gnu/slurm # Database Connection StorageType=accounting_storage/mysql diff --git a/input/config/x86_64/ubuntu/26.04/slurm_custom.json b/input/config/x86_64/ubuntu/26.04/slurm_custom.json index 41acd7620f..f43b9f577f 100644 --- a/input/config/x86_64/ubuntu/26.04/slurm_custom.json +++ b/input/config/x86_64/ubuntu/26.04/slurm_custom.json @@ -23,6 +23,7 @@ "cluster": [ {"package": "slurm-smd-slurmctld", "type": "deb", "repo_name": "slurm_custom"}, {"package": "slurm-smd-slurmdbd", "type": "deb", "repo_name": "slurm_custom"}, + {"package": "slurm-smd-client", "type": "deb", "repo_name": "slurm_custom"}, {"package": "python3-pymysql", "type": "deb", "repo_name": "main"}, {"package": "mariadb-server", "type": "deb", "repo_name": "universe"} ] diff --git a/provision/roles/slurm_config/tasks/confs.yml b/provision/roles/slurm_config/tasks/confs.yml index 7b188c3fe3..ad990b76bb 100644 --- a/provision/roles/slurm_config/tasks/confs.yml +++ b/provision/roles/slurm_config/tasks/confs.yml @@ -147,7 +147,7 @@ ansible.builtin.set_fact: apply_config: "{{ apply_config | default({}) | combine({'slurmdbd': (apply_config['slurmdbd'] - | combine({'DbdHost': ctld_list[0], 'StorageHost': ctld_list[0]}))}) }}" + | combine({'DbdHost': ctld_list[0], 'StorageHost': 'localhost'}))}) }}" when: ctld_list | length > 0 no_log: "{{ _no_log }}" @@ -222,7 +222,7 @@ - name: Slurm dbd - DbdHost and StorageHost ansible.builtin.set_fact: conf_merge_dict: "{{ conf_merge_dict - | combine({'slurmdbd': [{'DbdHost': ctld_list[0], 'StorageHost': ctld_list[0]}] + conf_merge_dict['slurmdbd']}) }}" + | combine({'slurmdbd': [{'DbdHost': ctld_list[0], 'StorageHost': 'localhost'}] + conf_merge_dict['slurmdbd']}) }}" when: "'slurmdbd' in conf_merge_dict" no_log: "{{ _no_log }}" diff --git a/provision/roles/slurm_config/vars/main.yml b/provision/roles/slurm_config/vars/main.yml index fa44bf824e..efd1aaea0b 100644 --- a/provision/roles/slurm_config/vars/main.yml +++ b/provision/roles/slurm_config/vars/main.yml @@ -99,7 +99,7 @@ mariadb: mariadb mysql: mysql root_user: root root_group: root -plugin_slurm_dir: "/usr/lib64/slurm" +plugin_slurm_dir: "{{ '/usr/lib/x86_64-linux-gnu/slurm' if ansible_os_family == 'Debian' else '/usr/lib64/slurm' }}" munge_key_cmd: "dd if=/dev/urandom bs=1 count=1024" slurm_ctld_parameters: ['enable_configless'] partitions: {} From 15b48d7c661e66d8d21fb036f415e719f1eb1536 Mon Sep 17 00:00:00 2001 From: Sayuri Date: Thu, 9 Jul 2026 19:06:00 +0530 Subject: [PATCH 15/15] Fix: sinfo --- provision/roles/slurm_config/tasks/confs.yml | 3 +-- provision/roles/slurm_config/vars/main.yml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/provision/roles/slurm_config/tasks/confs.yml b/provision/roles/slurm_config/tasks/confs.yml index ad990b76bb..0f99ff40d5 100644 --- a/provision/roles/slurm_config/tasks/confs.yml +++ b/provision/roles/slurm_config/tasks/confs.yml @@ -198,8 +198,7 @@ conf_merge_dict | default({}) | combine({ existing_conf_set.item.1: ( - ([existing_conf_set.stat.path] if existing_conf_set.stat.exists else []) - + [apply_config[existing_conf_set.item.1]] + [apply_config[existing_conf_set.item.1]] + ([parsed_configs_input.get(existing_conf_set.item.1)] if parsed_configs_input is defined and parsed_configs_input.get(existing_conf_set.item.1) else []) ) diff --git a/provision/roles/slurm_config/vars/main.yml b/provision/roles/slurm_config/vars/main.yml index efd1aaea0b..c6ca204ecd 100644 --- a/provision/roles/slurm_config/vars/main.yml +++ b/provision/roles/slurm_config/vars/main.yml @@ -99,7 +99,7 @@ mariadb: mariadb mysql: mysql root_user: root root_group: root -plugin_slurm_dir: "{{ '/usr/lib/x86_64-linux-gnu/slurm' if ansible_os_family == 'Debian' else '/usr/lib64/slurm' }}" +plugin_slurm_dir: "{{ '/usr/lib/x86_64-linux-gnu/slurm' if hostvars['localhost']['cluster_os_type'] == 'ubuntu' else '/usr/lib64/slurm' }}" munge_key_cmd: "dd if=/dev/urandom bs=1 count=1024" slurm_ctld_parameters: ['enable_configless'] partitions: {}