Skip to content
Merged
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 @@ -10,11 +10,11 @@ s3_dir_name: "rhel-{{ item.key }}"
cluster_name: "{{ oim_node_name }}"
cluster_domain: "{{ domain_name }}"
group_name: "{{ item.key }}"
rhel_base_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 {{ openchami_work_dir }}/images/{{ rhel_base_compute_image_name }}-{{ rhel_tag }}.yaml:/home/builder/config.yaml:z
rhel_base_compute_mounts: -e AWS_REQUEST_CHECKSUM_CALCULATION=when_required -e AWS_RESPONSE_CHECKSUM_VALIDATION=when_required --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 {{ openchami_work_dir }}/images/{{ rhel_base_compute_image_name }}-{{ rhel_tag }}.yaml:/home/builder/config.yaml:z
image_build_name: {{ ochami_aarch64_image | join (' ') }}
rhel_base_compute_command_options: {{ ochami_base_command | join (' ') }}
minio_s3_username: "{{ minio_s3_username }}"
minio_s3_password: "{{ minio_s3_password }}"
minio_s3_username: "{{ s3_access_id | default('admin', true) }}"
minio_s3_password: "{{ s3_secret_key }}"
{% set s3_prefix_suffix = '' %}
s3_prefix_suffix: "{{ s3_prefix_suffix }}"
# Override OpenCHAMI defaults to ensure correct mount path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,6 @@
msg: "x86_64 compute image build failed. See details above."

always:
- name: Remove generated compute images templates
ansible.builtin.file:
path: "{{ openchami_dir }}/{{ item.key }}{{ compute_image_suffix }}_compute_images.yaml"
state: absent
loop: "{{ compute_images_dict | dict2items }}"
loop_control:
loop_var: item

- name: Set openchami SELinux context
ansible.builtin.command: chcon -R system_u:object_r:container_file_t:s0 "{{ oim_shared_path }}/omnia/openchami"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ s3_dir_name: "rhel-{{ item.key }}"
cluster_name: "{{ oim_node_name }}"
cluster_domain: "{{ domain_name }}"
group_name: "{{ item.key }}"
rhel_base_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 {{ openchami_work_dir }}/images/{{ rhel_base_compute_image_name }}-{{ rhel_tag }}.yaml:/home/builder/config.yaml:z
rhel_base_compute_mounts: -e AWS_REQUEST_CHECKSUM_CALCULATION=when_required -e AWS_RESPONSE_CHECKSUM_VALIDATION=when_required --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 {{ openchami_work_dir }}/images/{{ rhel_base_compute_image_name }}-{{ rhel_tag }}.yaml:/home/builder/config.yaml:z
image_build_name: {{ ochami_x86_64_image | join (' ') }}
rhel_base_compute_command_options: {{ ochami_base_command | join (' ') }}
minio_s3_username: "{{ minio_s3_username }}"
minio_s3_password: "{{ minio_s3_password }}"
minio_s3_username: "{{ s3_access_id | default('admin', true) }}"
minio_s3_password: "{{ s3_secret_key }}"
{% set s3_prefix_suffix = '' %}
s3_prefix_suffix: "{{ s3_prefix_suffix }}"
# Override OpenCHAMI defaults to ensure correct mount path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"prepare_oim": [
files["network_spec"],
files["software_config"],
files["storage_config"],
files["build_stream_config"]
],
# "high_availability": [files["high_availability_config"]],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,17 @@
"pattern": "^[^\\\\\\-'\"]+$",
"description": "Password for MySQL Database. Length must be between 2 and 128 characters and must not contain backslashes (\\), hyphens (-), single quotes ('), or double quotes (\\\")."
},
"minio_s3_password": {
"s3_secret_key": {
"minLength": 5,
"maxLength": 128,
"pattern": "^(?!admin$)[^\\\\\\-'\"]+$",
"description": "Password for Minio S3 bucket. Should not be kept 'admin. Length must be between 5 and 128 characters and must not contain backslashes (\\), hyphens (-), single quotes ('), or double quotes (\\\")."
"pattern": "^(?!admin$)[^\\\\'\"]+$",
"description": "S3 Secret Key for storage backend (MinIO password or Dell PowerScale S3 Secret Key). Should not be kept 'admin'. Length must be between 5 and 128 characters and must not contain backslashes (\\), single quotes ('), or double quotes (\\\")."
},
"s3_access_id": {
"minLength": 1,
"maxLength": 128,
"pattern": "^[^\\\\\\-'\"]+$",
"description": "S3 Access Key ID (required when s3_configurations.provider is 'powerscale'). Length must be between 1 and 128 characters and must not contain backslashes (\\), hyphens (-), single quotes ('), or double quotes (\\\")."
},
"csi_username": {
"minLength": 4,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,25 @@
"required": ["filename", "size", "functional_group_prefix"],
"additionalProperties": false
}
},
"s3_configurations": {
"type": "object",
"description": "S3-compatible storage configuration for OpenCHAMI image repository.",
"properties": {
"provider": {
"type": "string",
"description": "S3 storage provider: 'powerscale' (Dell PowerScale) or 'minio' (local MinIO container)",
"enum": ["powerscale", "minio"],
"default": "powerscale"
},
"endpoint_url": {
"type": "string",
"description": "S3 endpoint URL. Required for powerscale (e.g., https://10.43.1.11:9021). Leave empty for minio.",
"pattern": "^https?://[a-zA-Z0-9.-]+(:[0-9]+)?(/.*)?$|^$"
}
},
"required": ["provider"],
"additionalProperties": false
}
},
"required": [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,28 @@ def validate_storage_config(
# Validate duplicate mount points per functional group and group across mounts and powervault_config
errors.extend(_validate_duplicate_mount_points(data))

# Validate s3_configurations: endpoint_url is required when provider is "powerscale", must be empty when provider is "minio"
if "s3_configurations" in data:
s3_config = data["s3_configurations"]
provider = s3_config.get("provider", "")
endpoint_url = s3_config.get("endpoint_url", "")
if provider == "powerscale" and not endpoint_url:
errors.append(
create_error_msg(
"storage_config",
"s3_configurations.endpoint_url",
"endpoint_url is required when provider is 'powerscale'. Please provide a valid S3 endpoint URL (e.g., https://10.43.1.11:9021)."
)
)
elif provider == "minio" and endpoint_url:
errors.append(
create_error_msg(
"storage_config",
"s3_configurations.endpoint_url",
"endpoint_url must be empty when provider is 'minio'. The MinIO endpoint is auto-configured locally."
)
)

return errors


Expand Down
1 change: 0 additions & 1 deletion common/vars/common_vars.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,3 @@ file_permissions_600: "0600"
file_permissions_400: "0400"
job_retry: "120"
job_delay: "30"
minio_s3_username: "admin"
21 changes: 21 additions & 0 deletions input/storage_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,24 @@ mount_params:
# size: "2G"
# maxsize: "4G"
# functional_group_prefix: ["slurm_node"]

# ============================================================
# OpenCHAMI S3 Storage Configuration
# ============================================================
# s3_configurations: Configures the S3-compatible storage backend for OpenCHAMI image repository.
#
# provider: Selects which S3-compatible storage service to use.
# - "powerscale": Use Dell PowerScale as external S3 storage (default)
# - "minio": Use MinIO container deployed locally on OIM
#
# endpoint_url: S3 endpoint URL.
# - Required when provider is "powerscale" (e.g., "https://10.43.1.11:9021")
# - Leave empty ("") when provider is "minio" (auto-configured to local MinIO)
#
# Credentials:
# - s3_access_id and s3_secret_key are prompted during prepare_oim credential setup
# - For "minio" provider: s3_access_id defaults to "admin" if not provided
# - For "powerscale" provider: s3_access_id is prompted as conditional mandatory
s3_configurations:
provider: "powerscale"
endpoint_url: ""
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

[Unit]
Description=Top-level target for Omnia Core and OpenCHAMI
Requires=omnia_core.service openchami.target pulp.service registry.service minio.service {{ auth_service }} {{ build_stream_service }} {{ playbook_watcher_service }} {{ omnia_postgres_service }}
Requires=omnia_core.service openchami.target pulp.service registry.service{% if hostvars['localhost']['s3_configurations']['provider'] != 'powerscale' %} minio.service{% endif %} {{ auth_service }} {{ build_stream_service }} {{ playbook_watcher_service }} {{ omnia_postgres_service }}
After=network.target
Wants=network-online.target

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
# limitations under the License.
---

- name: Display selected storage backend
ansible.builtin.debug:
msg: "OpenCHAMI image repository backend: {{ storage_backend | upper }}"

- name: Import packages task
ansible.builtin.import_tasks: packages.yml

Expand All @@ -22,8 +26,9 @@
- name: Import hosts task
ansible.builtin.import_tasks: hosts.yml

- name: Import minio task
ansible.builtin.import_tasks: minio.yml
- name: Import minio task (MinIO backend only)
ansible.builtin.include_tasks: minio.yml
when: storage_backend == 'minio'

- name: Import registry task
ansible.builtin.import_tasks: registry.yml
Expand All @@ -44,4 +49,4 @@
ansible.builtin.import_tasks: s3_bucket.yml

- name: Import policy update tasks
ansible.builtin.import_tasks: policy_update.yml
ansible.builtin.include_tasks: policy_update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,30 @@
dest: "{{ s3_work_dir }}/s3-public-read-efi.json"
mode: "{{ file_perm_rw }}"

- name: Update the boot policy
- name: Update the boot policy (NFS/MinIO)
ansible.builtin.command: >
s3cmd setpolicy {{ s3_work_dir }}/s3-public-read-boot.json s3://boot-images
--host={{ cluster_boot_ip }}:9000
--host-bucket={{ cluster_boot_ip }}:9000
changed_when: true
when: storage_backend == 'minio'

- name: Update the efi policy
- name: Update the efi policy (NFS/MinIO)
ansible.builtin.command: >
s3cmd setpolicy {{ s3_work_dir }}/s3-public-read-efi.json s3://efi
--host={{ cluster_boot_ip }}:9000
--host-bucket={{ cluster_boot_ip }}:9000
changed_when: true
when: storage_backend == 'minio'

- name: Update the boot policy (S3/PowerScale)
ansible.builtin.command: >
s3cmd setpolicy {{ s3_work_dir }}/s3-public-read-boot.json s3://boot-images
changed_when: true
when: storage_backend == 'powerscale'

- name: Update the efi policy (S3/PowerScale)
ansible.builtin.command: >
s3cmd setpolicy {{ s3_work_dir }}/s3-public-read-efi.json s3://efi
changed_when: true
when: storage_backend == 'powerscale'
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,37 @@
# limitations under the License.
---

# === PowerScale endpoint validation (S3 backend only) ===
- name: Validate PowerScale S3 endpoint configuration
ansible.builtin.assert:
that:
- s3_configurations is defined
- s3_configurations.endpoint_url is defined
- s3_access_id is defined
- s3_access_id | length > 0
- s3_secret_key is defined
fail_msg: "{{ powerscale_validation_fail_msg }}"
when: storage_backend == 'powerscale'

- name: Test PowerScale endpoint reachability
ansible.builtin.uri:
url: "{{ s3_configurations.endpoint_url }}"
method: GET
validate_certs: false
status_code: [200, 403, 404, 405]
timeout: 10
register: ps_endpoint_check
failed_when: false
when: storage_backend == 'powerscale'

- name: Fail if PowerScale unreachable
ansible.builtin.fail:
msg: "{{ powerscale_unreachable_msg }}"
when:
- storage_backend == 'powerscale'
- ps_endpoint_check.status is not defined or ps_endpoint_check.status not in [200, 403, 404, 405]

# === EXISTING TASKS (UNCHANGED -- work for both backends via ~/.s3cfg) ===
- name: Import EPEL GPG key
ansible.builtin.rpm_key:
key: "{{ epel10_gpg_key }}"
Expand Down Expand Up @@ -70,3 +101,14 @@
- name: Verify s3 bucket output
ansible.builtin.debug:
msg: "{{ s3_bucket_output_final.stdout_lines }}"

# === PowerScale-specific post-creation tasks (S3 backend only) ===
- name: Update publish_s3 in rhel-base-compute.yaml.j2 to PowerScale endpoint
ansible.builtin.replace:
path: /opt/omnia/openchami/deployment-recipes/dell/podman-quadlets/roles/image/templates/images/rhel-base-compute.yaml.j2
regexp: "^(\\s*publish_s3:\\s*)'http://\\{\\{\\s*cluster_name\\s*\\}\\}\\.\\{\\{\\s*cluster_domain\\s*\\}\\}:9000'(.*)$"
replace: "\\1'{{ s3_configurations.endpoint_url }}'\\2"
backup: true
when: storage_backend == 'powerscale'
delegate_to: localhost
connection: local
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@
ansible.builtin.fail:
msg: "{{ network_spec_syntax_fail_msg }} Error: {{ include_network_spec.message }}"

- name: Include storage_config.yml
block:
- name: Include storage_config.yml file
ansible.builtin.include_vars:
file: "{{ hostvars['localhost']['input_project_dir'] }}/storage_config.yml"
no_log: true
rescue:
- name: Set default storage backend if storage_config.yml not found
ansible.builtin.set_fact:
s3_configurations:
provider: "powerscale"
endpoint_url: ""

- name: Parse network_spec data
ansible.builtin.set_fact:
network_data: "{{ network_data | default({}) | combine({item.key: item.value}) }}"
Expand Down Expand Up @@ -114,12 +127,16 @@
{{ (admin_nic_ip + '/' + network_data.admin_network.netmask_bits) | ansible.utils.ipaddr('netmask') }}
coredhcp_lease_duration: "{{ default_lease_time }}s"

- name: Set minio_username and minio_password
- name: Set s3_access_id and s3_secret_key
ansible.builtin.set_fact:
minio_s3_username: "{{ hostvars['localhost']['minio_s3_username'] }}"
minio_s3_password: "{{ hostvars['localhost']['minio_s3_password'] }}"
s3_access_id: "{{ hostvars['localhost']['s3_access_id'] | default('admin', true) }}"
s3_secret_key: "{{ hostvars['localhost']['s3_secret_key'] }}"
no_log: true

- name: Set storage backend fact
ansible.builtin.set_fact:
storage_backend: "{{ s3_configurations.provider | lower }}"

- name: Deploy openchami configs
block:
- name: Install and configure openchami
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ PublishPort=9000:9000
PublishPort=9001:9001

# Environemnt Variables
Environment=MINIO_ROOT_USER={{ minio_s3_username }}
Environment=MINIO_ROOT_PASSWORD={{ minio_s3_password }}
Environment=MINIO_ROOT_USER={{ s3_access_id }}
Environment=MINIO_ROOT_PASSWORD={{ s3_secret_key }}

# Command to run in container
Exec=server /data --console-address :9001
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
# Setup endpoint
[default]
access_key = {{ s3_access_id }}
secret_key = {{ s3_secret_key }}
{% if storage_backend == 'powerscale' %}
host_base = {{ s3_configurations.endpoint_url | regex_replace('^https?://', '') }}
host_bucket = {{ s3_configurations.endpoint_url | regex_replace('^https?://', '') }}
use_https = {{ 'True' if s3_configurations.endpoint_url.startswith('https') else 'False' }}
check_ssl_certificate = False
check_ssl_hostname = False
{% else %}
host_base = {{ cluster_name }}.{{ cluster_domain }}:9000
host_bucket = {{ cluster_name }}.{{ cluster_domain }}:9000
bucket_location = us-east-1
use_https = False

# Setup access keys
access_key = {{ minio_s3_username }}
secret_key = {{ minio_s3_password }}

# Enable S3 v4 signature APIs
check_ssl_certificate = False
check_ssl_hostname = False
{% endif %}
signature_v2 = False
bucket_location = us-east-1
human_readable_sizes = True
multipart_chunk_size_mb = 50
11 changes: 11 additions & 0 deletions prepare_oim/roles/deploy_containers/openchami/vars/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,14 @@ coredhcp_tmp_lease_duration: "5m"
coredhcp_cache_validity: "30s"
coredhcp_custom_ipxe: "default"
coredhcp_tftp_single_port_mode: true

# PowerScale S3 endpoint error messages
powerscale_unreachable_msg: |
Cannot reach PowerScale S3 endpoint: {{ s3_configurations.endpoint_url }}
Check: network connectivity, S3 service enabled, firewall rules

powerscale_validation_fail_msg: |
PowerScale S3 backend requires:
- s3_configurations.endpoint_url in storage_config.yml
- s3_access_id (PowerScale Access Key -- prompted by prepare_oim)
- s3_secret_key (PowerScale Secret Key -- prompted by prepare_oim)
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ bmc_username: ""
bmc_password: ""

# Prepare_oim credentials
minio_s3_password: ""
s3_access_id: ""
s3_secret_key: ""
pulp_password: ""
docker_username: ""
docker_password: ""
Expand Down
5 changes: 4 additions & 1 deletion utils/credential_utility/roles/update_config/vars/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,11 @@ omnia_credentials:
- { username: docker_username, password: docker_password }
mandatory:
- { password: pulp_password }
- { password: minio_s3_password }
- { password: s3_secret_key }
conditional_mandatory:
# PowerScale S3 Access Key -- only prompted when storage provider is 'powerscale'
- username: s3_access_id
condition: "{{ s3_configurations.provider == 'powerscale' }}"
- username: build_stream_auth_username
password: build_stream_auth_password
condition: "{{ enable_build_stream | default(false) | bool }}"
Expand Down
Loading
Loading