Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@
" is not currently supported and is reserved for future use. Please remove or update this role"
" to avoid configuration errors.")

# Mapping file and software_config.json consistency validation messages
SERVICE_K8S_FUNCTIONAL_GROUP_WITHOUT_SOFTWARE_MSG = (
"Service Kubernetes functional groups (service_kube_node_* or service_kube_control_plane_*) "
"are defined in the PXE mapping file, but 'service_k8s' is not configured in software_config.json. "
"Please add 'service_k8s' to the 'softwares' list in software_config.json to deploy the service cluster."
)
SLURM_FUNCTIONAL_GROUP_WITHOUT_SOFTWARE_MSG = (
"Slurm functional groups (slurm_control_node_* or slurm_node_*) "
"are defined in the PXE mapping file, but 'slurm_custom' is not configured in software_config.json. "
"Please add 'slurm_custom' to the 'softwares' list in software_config.json to deploy the Slurm cluster."
)

# Functional Groups Config Validation Messages

EMPTY_OR_SYNTAX_ERROR_FUNCTIONAL_GROUPS_CONFIG_MSG = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,89 @@ def validate_aarch64_local_path_compatibility(pxe_mapping_file_path):
if aarch64_found:
raise ValueError(en_us_validation_msg.PXE_MAPPING_AARCH64_LOCAL_PATH_MSG)

def validate_functional_groups_software_consistency(pxe_mapping_file_path, software_config_json, logger):
"""
Validates that functional groups in the PXE mapping file have corresponding
software configured in software_config.json.

This ensures that:
- If service_kube_node_* or service_kube_control_plane_* functional groups exist
in the mapping file, then 'service_k8s' must be in software_config.json
- If slurm_control_node_* or slurm_node_* functional groups exist in the mapping file,
then 'slurm_custom' must be in software_config.json

Args:
pxe_mapping_file_path (str): Path to the PXE mapping file.
software_config_json (dict): Parsed software_config.json data.
logger (Logger): Logger instance for logging messages.

Raises:
ValueError: If functional groups are defined without corresponding software.
"""
if not pxe_mapping_file_path or not os.path.isfile(pxe_mapping_file_path):
return

# Read the mapping file to find functional groups
with open(pxe_mapping_file_path, "r", encoding="utf-8") as fh:
raw_lines = fh.readlines()

non_comment_lines = [ln for ln in raw_lines if ln.strip()]
if not non_comment_lines:
return

reader = csv.DictReader(non_comment_lines)
fieldname_map = {fn.strip().upper(): fn for fn in reader.fieldnames}
fg_col = fieldname_map.get("FUNCTIONAL_GROUP_NAME")

if not fg_col:
return

# Track which functional groups are found
has_service_k8s_fg = False
has_slurm_fg = False

for row in reader:
fg_name = row.get(fg_col, "").strip() if row.get(fg_col) else ""
if not fg_name:
continue

# Check for service k8s functional groups
if fg_name.startswith('service_kube_node_') or fg_name.startswith('service_kube_control_plane_'):
has_service_k8s_fg = True
logger.info(f"Found service k8s functional group in mapping file: {fg_name}")

# Check for slurm functional groups
if fg_name.startswith('slurm_control_node_') or fg_name.startswith('slurm_node_'):
has_slurm_fg = True
logger.info(f"Found slurm functional group in mapping file: {fg_name}")

# Get list of software names from software_config.json
software_names = []
if software_config_json and "softwares" in software_config_json:
software_names = [sw.get("name", "") for sw in software_config_json.get("softwares", [])]

logger.info(f"Software configured in software_config.json: {software_names}")

# Validate service_k8s and slurm_custom, collecting all errors
consistency_errors = []

if has_service_k8s_fg and "service_k8s" not in software_names:
logger.error("Service k8s functional groups found but service_k8s not in software_config.json")
consistency_errors.append(en_us_validation_msg.SERVICE_K8S_FUNCTIONAL_GROUP_WITHOUT_SOFTWARE_MSG)

if has_slurm_fg and "slurm_custom" not in software_names:
logger.error("Slurm functional groups found but slurm_custom not in software_config.json")
consistency_errors.append(en_us_validation_msg.SLURM_FUNCTIONAL_GROUP_WITHOUT_SOFTWARE_MSG)

if consistency_errors:
raise ValueError(" | ".join(consistency_errors))

# Log success
if has_service_k8s_fg and "service_k8s" in software_names:
logger.info("✓ Service k8s functional groups validated: service_k8s found in software_config.json")
if has_slurm_fg and "slurm_custom" in software_names:
logger.info("✓ Slurm functional groups validated: slurm_custom found in software_config.json")

def validate_provision_config(
input_file_path, data, logger, module, omnia_base_dir, module_utils_base, project_name
):
Expand Down Expand Up @@ -993,6 +1076,7 @@ def validate_provision_config(
validate_parent_service_tag_hierarchy(pxe_mapping_file_path)
validate_slurm_login_compiler_prefix(pxe_mapping_file_path)
validate_aarch64_local_path_compatibility(pxe_mapping_file_path)
validate_functional_groups_software_consistency(pxe_mapping_file_path, software_config_json, logger)

# Validate ADMIN_IPs against network_spec.yml ranges
# network_spec_path = create_file_path(input_file_path, file_names["network_spec"])
Expand Down
Loading
Loading