Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ repos:
{% if repo.base_url | length > 1 %}
- alias: '{{ repo.name }}'
url: '{{ repo.base_url }}'
sslverify: false
{% endif %}
{% if repo.gpg | length > 1 %}
gpg: '{{ repo.gpg }}'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ repos:
{% if repo.base_url | length > 1 %}
- alias: '{{ repo.name }}'
url: '{{ repo.base_url }}'
sslverify: false
{% endif %}
{% if repo.gpg | length > 1 %}
gpg: '{{ repo.gpg }}'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"x86_64": [
"slurm_control_node", "slurm_node", "login_node", "login_compiler_node",
"service_kube_control_plane", "service_kube_control_plane_first", "service_kube_node",
"compute_kube_control_plane", "compute_kube_control_plane_first", "compute_kube_node",
"os"
],
"aarch64": [
Expand Down Expand Up @@ -96,6 +97,11 @@
files["storage_config"],
files["high_availability_config"],
],
"compute_rke2": [
files["omnia_config"],
files["storage_config"],
files["high_availability_config"],
],
"storage": [files["storage_config"]],
"prepare_oim": [
files["network_spec"],
Expand Down Expand Up @@ -191,6 +197,9 @@
"service_kube_control_plane_first_x86_64": "management",
"service_kube_control_plane_x86_64": "management",
"service_kube_node_x86_64": "management",
"compute_kube_control_plane_first_x86_64": "compute",
"compute_kube_control_plane_x86_64": "compute",
"compute_kube_node_x86_64": "compute",
"login_node_x86_64": "management",
"login_node_aarch64": "management",
"login_compiler_node_x86_64": "management",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,39 @@
],
"additionalProperties": false
}
},
"compute_rke2_k8s_cluster_ha": {
"type": "array",
"description": "High Availability (HA) configuration for the compute RKE2 Kubernetes cluster.",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"cluster_name": {
"type": "string",
"minLength": 1,
"description": "Required. Name of the compute RKE2 cluster. Must match the cluster name in omnia_config.yml."
},
"enable_k8s_ha": {
"type": "boolean",
"description": "Mandatory. Enable HA for the compute RKE2 cluster."
},
"virtual_ip_address": {
"type": "string",
"description": "Mandatory. Virtual IP address for the compute RKE2 cluster API endpoint.",
"allOf": [
{ "pattern": "^[0-9.]+$" },
{ "format": "ipv4" }
]
}
},
"required": [
"cluster_name",
"enable_k8s_ha",
"virtual_ip_address"
],
"additionalProperties": false
}
}
},
"required": [
Expand Down
120 changes: 120 additions & 0 deletions common/library/module_utils/input_validation/schema/omnia_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,126 @@
}
]
}
},
"service_rke2_k8s_cluster": {
"type": "array",
"description": "List of RKE2 Kubernetes cluster configurations.",
"items": {
"type": "object",
"properties": {
"cluster_name": {
"type": "string",
"minLength": 1,
"description": "Unique name for the RKE2 service cluster."
},
"deployment": {
"type": "boolean"
},
"k8s_cni": {
"enum": ["calico", "canal", "cilium", "flannel"],
"description": "K8s CNI plugin for the RKE2 cluster."
},
"pod_external_ip_range": {
"description": "IP range for LoadBalancer external IPs.",
"type": "string",
"pattern": "^(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)-(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9]{1,2}$|^$"
},
"k8s_service_addresses": {
"type": "string",
"pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9]{1,2}$",
"description": "CIDR for K8s service IPs."
},
"k8s_pod_network_cidr": {
"type": "string",
"pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9]{1,2}$",
"description": "CIDR for K8s pod network."
},
"nfs_storage_name": {
"type": "string",
"description": "The NFS client server name mentioned in storage_config.yml"
},
"csi_powerscale_driver_secret_file_path": {
"description": "Absolute file path for the secret.yaml file.",
"type": "string",
"pattern": "^(|/?([a-zA-Z0-9._-]+/)*[a-zA-Z0-9._-]+\\.yaml)$"
},
"csi_powerscale_driver_values_file_path": {
"description": "File path for the values.yaml file.",
"type": "string",
"pattern": "^(|/?([a-zA-Z0-9._-]+/)*[a-zA-Z0-9._-]+\\.yaml)$"
}
},
"required": [
"cluster_name",
"k8s_cni",
"k8s_service_addresses",
"k8s_pod_network_cidr",
"pod_external_ip_range"
],
"allOf": [
{
"if": {
"properties": {
"csi_powerscale_driver_secret_file_path": {
"type": "string",
"minLength": 1
}
},
"required": ["csi_powerscale_driver_secret_file_path"]
},
"then": {
"required": ["csi_powerscale_driver_values_file_path"]
}
}
]
}
},
"compute_rke2_k8s_cluster": {
"type": "array",
"description": "List of RKE2-based compute Kubernetes cluster configurations.",
"items": {
"type": "object",
"properties": {
"cluster_name": {
"type": "string",
"minLength": 1,
"description": "Unique name for the RKE2 compute cluster."
},
"deployment": {
"type": "boolean"
},
"k8s_cni": {
"enum": ["calico", "canal", "cilium", "flannel"],
"description": "K8s CNI plugin for the compute RKE2 cluster."
},
"pod_external_ip_range": {
"description": "IP range for LoadBalancer external IPs.",
"type": "string",
"pattern": "^(?:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)-(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9]{1,2}$|^$"
},
"k8s_service_addresses": {
"type": "string",
"pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9]{1,2}$",
"description": "CIDR for K8s service IPs."
},
"k8s_pod_network_cidr": {
"type": "string",
"pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/[0-9]{1,2}$",
"description": "CIDR for K8s pod network."
},
"nfs_storage_name": {
"type": "string",
"description": "The NFS client server name mentioned in storage_config.yml"
}
},
"required": [
"cluster_name",
"k8s_cni",
"k8s_service_addresses",
"k8s_pod_network_cidr",
"pod_external_ip_range"
]
}
}
},
"required": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,35 @@ def validate_software_config(
)
)

# Ensure ldms is not configured without service_k8s in softwares
if "ldms" in software_names and "service_k8s" not in software_names:
# Ensure service_k8s and service_rke2 are not both present
if "service_k8s" in software_names and "service_rke2" in software_names:
errors.append(
create_error_msg(
"Validation Error: ",
"service_k8s and service_rke2",
"cannot both be present in softwares. Use service_k8s for kubeadm or service_rke2 for RKE2, not both."
)
)

# RKE2 packages are only available for x86_64; reject any other arch explicitly
for rke2_sw_name in ["service_rke2", "compute_rke2"]:
if rke2_sw_name in software_names:
rke2_entry = next(
(s for s in data.get("softwares", []) if s.get("name") == rke2_sw_name), {}
)
rke2_arch = rke2_entry.get("arch", ["x86_64"])
unsupported_archs = [a for a in rke2_arch if a != "x86_64"]
if unsupported_archs:
errors.append(
create_error_msg(
"Validation Error: ",
rke2_sw_name,
f"is only supported on x86_64. Unsupported arch(es): {', '.join(unsupported_archs)}."
)
)

# Ensure ldms is not configured without service_k8s or service_rke2 in softwares
if "ldms" in software_names and "service_k8s" not in software_names and "service_rke2" not in software_names:
errors.append(
create_error_msg(
"Validation Error: ",
Expand All @@ -234,7 +261,7 @@ def validate_software_config(
)

# Check for required subgroups when specific software names are present
software_requiring_subgroups = ["additional_packages", "slurm_custom", "service_k8s"]
software_requiring_subgroups = ["additional_packages", "slurm_custom", "service_k8s", "service_rke2", "compute_rke2"]
for software_name in software_requiring_subgroups:
if software_name in software_names:
if software_name not in data or not data[software_name]:
Expand Down Expand Up @@ -553,6 +580,22 @@ def get_matching_clusters_for_nfs(nfs_name, omnia_config):
):
matching_clusters["service_k8s_cluster"] = svc

# Service RKE2
for svc in omnia_config.get("service_rke2_k8s_cluster", []):
if (
svc.get("nfs_storage_name") == nfs_name
and svc.get("deployment") is True
):
matching_clusters["service_rke2_k8s_cluster"] = svc

# Compute RKE2
for compute in omnia_config.get("compute_rke2_k8s_cluster", []):
if (
compute.get("nfs_storage_name") == nfs_name
and compute.get("deployment") is True
):
matching_clusters["compute_rke2_k8s_cluster"] = compute

# Slurm
for slurm in omnia_config.get("slurm_cluster", []):
if slurm.get("nfs_storage_name") == nfs_name:
Expand Down Expand Up @@ -1463,6 +1506,14 @@ def validate_k8s(data, admin_networks, softwares, ha_config, tag_names, errors,
cluster_set["service_k8s_cluster"] = data.get(
"service_k8s_cluster", [])

if "service_rke2" in softwares and "service_rke2" in tag_names:
cluster_set["service_rke2_k8s_cluster"] = data.get(
"service_rke2_k8s_cluster", [])

if "compute_rke2" in softwares and "compute_rke2" in tag_names:
cluster_set["compute_rke2_k8s_cluster"] = data.get(
"compute_rke2_k8s_cluster", [])

for k8s_cluster_type, k8s_clusters in cluster_set.items():
deployments_list = [k.get('deployment', False) for k in k8s_clusters]
true_count = deployments_list.count(True)
Expand Down Expand Up @@ -1636,7 +1687,7 @@ def validate_omnia_config(
input_file_path, file_names["high_availability_config"])
with open(ha_config_path, "r", encoding="utf-8") as f:
ha_config = yaml.safe_load(f)
for k in ["service_k8s_cluster_ha"]:
for k in ["service_k8s_cluster_ha", "compute_rke2_k8s_cluster_ha"]:
ha_config[k] = [xha["cluster_name"] for xha in ha_config.get(k, [])]
validate_k8s(data, admin_networks, sw_list, ha_config, tag_names,
errors, st_config, module, input_file_path, logger)
Expand Down
2 changes: 1 addition & 1 deletion common/library/module_utils/local_repo/download_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def sanitize_path(path: str) -> str:
full_url,
stream=True,
headers=headers,
verify=PULP_SSL_CA_CERT,
verify=False,
timeout=(30, 600)
) as r:

Expand Down
2 changes: 1 addition & 1 deletion common/library/module_utils/local_repo/software_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ def parse_repo_urls(repo_config, local_repo_config_path,
seen_urls.add(rendered_url)

# # Skip reachability check for URLs containing k8s, cri-o, oneapi, snoopy, nvidia
if not any(skip_str in rendered_url for skip_str in ["k8s", "cri-o", "oneapi", "snoopy", "nvidia"]):
if not any(skip_str in rendered_url for skip_str in ["k8s", "cri-o", "oneapi", "snoopy", "nvidia", "rancher"]):
if not is_remote_url_reachable(rendered_url):
logger.error(f"OMNIA repo URL unreachable: {rendered_url}")
return rendered_url, False
Expand Down
Loading
Loading