From 9bd59a5a86c31f29c49b7bb4d8e16c576d80c846 Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 16:44:53 +1000 Subject: [PATCH 01/14] Add ocp4_workload_s4 role and integrate S4 storage with Quay - New role: ocp4_workload_s4 deploys S4 (Super Simple Storage Service) via GitOps - S4 provides S3-compatible object storage using Ceph RADOS Gateway - Supports optional S3 bucket creation with configurable bucket list - Modified ocp4_workload_quay_operator to use S4 storage backend instead of Noobaa - Uses RadosGWStorage driver for internal Kubernetes service endpoint - Refactored S4 user info messages to use loop pattern for cleaner code - Updated GitOps role to use debug output (temporary for testing) Co-Authored-By: Claude Sonnet 4.5 --- .../tasks/workload.yml | 18 +- .../defaults/main.yml | 20 ++ roles/ocp4_workload_quay_operator/readme.adoc | 37 ++- .../tasks/workload.yml | 79 +++--- .../templates/config.yaml.j2 | 14 + .../templates/quay_registry.yaml.j2 | 2 +- .../templates/s4_credentials_secret.yaml.j2 | 10 + roles/ocp4_workload_s4/defaults/main.yml | 109 ++++++++ roles/ocp4_workload_s4/meta/main.yml | 18 ++ roles/ocp4_workload_s4/readme.adoc | 242 ++++++++++++++++++ roles/ocp4_workload_s4/tasks/main.yml | 11 + .../tasks/remove_workload.yml | 51 ++++ roles/ocp4_workload_s4/tasks/workload.yml | 177 +++++++++++++ .../templates/application.yaml.j2 | 123 +++++++++ .../templates/bucket-job.yaml.j2 | 80 ++++++ 15 files changed, 945 insertions(+), 46 deletions(-) create mode 100644 roles/ocp4_workload_quay_operator/templates/s4_credentials_secret.yaml.j2 create mode 100644 roles/ocp4_workload_s4/defaults/main.yml create mode 100644 roles/ocp4_workload_s4/meta/main.yml create mode 100644 roles/ocp4_workload_s4/readme.adoc create mode 100644 roles/ocp4_workload_s4/tasks/main.yml create mode 100644 roles/ocp4_workload_s4/tasks/remove_workload.yml create mode 100644 roles/ocp4_workload_s4/tasks/workload.yml create mode 100644 roles/ocp4_workload_s4/templates/application.yaml.j2 create mode 100644 roles/ocp4_workload_s4/templates/bucket-job.yaml.j2 diff --git a/roles/ocp4_workload_openshift_gitops/tasks/workload.yml b/roles/ocp4_workload_openshift_gitops/tasks/workload.yml index f7d0dc6..fc0b483 100644 --- a/roles/ocp4_workload_openshift_gitops/tasks/workload.yml +++ b/roles/ocp4_workload_openshift_gitops/tasks/workload.yml @@ -89,11 +89,15 @@ ignore_errors: true # yamllint disable rule:line-length -- name: Save AgnosticD User data - block: - - name: Print project information - agnosticd.core.agnosticd_user_info: - msg: "OpenShift GitOps ArgoCD: https://openshift-gitops-server-openshift-gitops.{{ _ocp4_workload_openshift_gitops_domain }}" - data: - openshift_gitops_server: "https://openshift-gitops-server-openshift-gitops.{{ _ocp4_workload_openshift_gitops_domain }}" +- name: Display OpenShift GitOps information + ansible.builtin.debug: + msg: + - "=========================================" + - "OpenShift GitOps (ArgoCD) Deployment Complete" + - "=========================================" + - "ArgoCD URL: https://openshift-gitops-server-openshift-gitops.{{ _ocp4_workload_openshift_gitops_domain }}" + - "" + - "To get the admin password, run:" + - " oc get secret openshift-gitops-cluster -n openshift-gitops -o jsonpath='{.data.admin\\.password}' | base64 -d" + - "=========================================" # yamllint enable rule:line-length diff --git a/roles/ocp4_workload_quay_operator/defaults/main.yml b/roles/ocp4_workload_quay_operator/defaults/main.yml index 7213105..4ed699c 100644 --- a/roles/ocp4_workload_quay_operator/defaults/main.yml +++ b/roles/ocp4_workload_quay_operator/defaults/main.yml @@ -119,3 +119,23 @@ ocp4_workload_quay_operator_registry_enable_clairpostgres: false # Startup probe override (disabled by default) ocp4_workload_quay_operator_registry_startup_probe_update: false ocp4_workload_quay_operator_registry_startup_probe_failure_threshold: 30 + +# -------------------------------- +# S3 Storage Configuration (S4) +# -------------------------------- +# Quay uses S4 storage for object storage backend + +# S4 S3 endpoint configuration +ocp4_workload_quay_operator_s4_namespace: s4 +ocp4_workload_quay_operator_s4_bucket_name: quay-registry + +# S4 S3 credentials (should match S4 deployment) +ocp4_workload_quay_operator_s4_access_key: s4admin +ocp4_workload_quay_operator_s4_secret_key: s4secret + +# S3 endpoint - uses internal service endpoint +# Format: http://s4..svc.cluster.local:7480 +ocp4_workload_quay_operator_s4_endpoint: "http://s4.{{ ocp4_workload_quay_operator_s4_namespace }}.svc.cluster.local:7480" + +# S3 region +ocp4_workload_quay_operator_s4_region: us-east-1 diff --git a/roles/ocp4_workload_quay_operator/readme.adoc b/roles/ocp4_workload_quay_operator/readme.adoc index d0e5d07..185d9a3 100644 --- a/roles/ocp4_workload_quay_operator/readme.adoc +++ b/roles/ocp4_workload_quay_operator/readme.adoc @@ -5,7 +5,8 @@ * This role can ** install the Quay Operator ** use a previously installed Red Hat Quay Operator to deploy a Quay Registry into an OpenShift Cluster. -* The cluster *must* have OpenShift Container Storage installed. +* The cluster *must* have S4 storage deployed (using `ocp4_workload_s4` role). +* Quay uses S4 S3-compatible storage backend instead of OpenShift Container Storage (Noobaa). * The role consists of the following tasks files: ** Tasks: link:./tasks/pre_workload.yml[pre_workload.yml] - Sets up an @@ -26,6 +27,40 @@ *** This role removes the Red Hat Quay Registry project (and therefore Red Hat Quay Registry) *** Debug task will print out: `remove_workload Tasks completed successfully.` +== Prerequisites + +=== S4 Storage + +This role *requires* S4 storage to be deployed first. S4 provides S3-compatible object storage for Quay. + +Deploy S4 before deploying Quay: + +[source,yaml] +---- +workloads: +- agnosticd.core_workloads.ocp4_workload_s4 +- agnosticd.core_workloads.ocp4_workload_quay_operator + +# S4 configuration +ocp4_workload_s4_buckets: +- quay-registry # Required bucket for Quay + +# S4 credentials (must match Quay configuration) +ocp4_workload_s4_access_key_id: s4admin +ocp4_workload_s4_secret_access_key: s4secret +---- + +=== S4 Configuration Variables + +If you need to customize the S4 integration, these variables control the S3 storage backend: + +* `ocp4_workload_quay_operator_s4_namespace`: Namespace where S4 is deployed (default: `s4`) +* `ocp4_workload_quay_operator_s4_bucket_name`: S3 bucket name for Quay (default: `quay-registry`) +* `ocp4_workload_quay_operator_s4_access_key`: S3 access key (default: `s4admin`) +* `ocp4_workload_quay_operator_s4_secret_key`: S3 secret key (default: `s4secret`) +* `ocp4_workload_quay_operator_s4_endpoint`: S3 endpoint URL (default: auto-configured internal endpoint) +* `ocp4_workload_quay_operator_s4_region`: S3 region (default: `us-east-1`) + == Review the defaults variable file * This file link:./defaults/main.yml[./defaults/main.yml] contains all the variables you need to define to control the deployment of your workload. diff --git a/roles/ocp4_workload_quay_operator/tasks/workload.yml b/roles/ocp4_workload_quay_operator/tasks/workload.yml index 8020534..02d8e55 100644 --- a/roles/ocp4_workload_quay_operator/tasks/workload.yml +++ b/roles/ocp4_workload_quay_operator/tasks/workload.yml @@ -1,18 +1,19 @@ --- -# Quay needs OpenShift Container Storage (Noobaa in particular) -# Check that the correct storage class exists on the cluster -- name: Retrieve Bucket Class +# Quay uses S4 storage for object storage backend +# Verify S4 is deployed and available +- name: Check S4 service exists kubernetes.core.k8s_info: - api_version: noobaa.io/v1alpha1 - kind: BucketClass - namespace: openshift-storage - register: r_bucket_class + api_version: v1 + kind: Service + name: s4 + namespace: "{{ ocp4_workload_quay_operator_s4_namespace }}" + register: r_s4_service -- name: Assert that there is a Bucket Storage Class +- name: Assert that S4 service exists ansible.builtin.assert: that: - - r_bucket_class.resources | length == 1 - fail_msg: Quay must be installed on a cluster with OpenShift Container Storage configured - and a Bucket Class deployed. + - r_s4_service.resources | length == 1 + fail_msg: "S4 storage service not found in namespace {{ ocp4_workload_quay_operator_s4_namespace }}. Deploy S4 first using ocp4_workload_s4 role." - name: Install Quay Operator when: ocp4_workload_quay_operator_install_operator | bool @@ -58,12 +59,22 @@ ansible.builtin.set_fact: _ocp4_workload_quay_operator_registry_route: "{{ ocp4_workload_quay_operator_registry_hostname }}.{{ openshift_cluster_ingress_domain }}" + - name: Delete existing config bundle secret to force recreation + kubernetes.core.k8s: + state: absent + api_version: v1 + kind: Secret + name: config-bundle + namespace: "{{ ocp4_workload_quay_operator_registry_namespace }}" + ignore_errors: true + - name: Create Quay Registry Resources kubernetes.core.k8s: state: present definition: "{{ lookup('template', item ) | from_yaml }}" loop: - quay_namespace.yaml.j2 + - s4_credentials_secret.yaml.j2 - config_bundle_secret.yaml.j2 - quay_registry.yaml.j2 @@ -167,23 +178,20 @@ state: present definition: "{{ lookup('template', 'quay-admin-token-secret.yml.j2') | from_yaml }}" - - name: Save user data for Quay console URL - agnosticd.core.agnosticd_user_info: - msg: "Red Hat Quay is available at {{ r_quay_registry.resources[0].status.registryEndpoint }}" - data: - quay_console_url: "{{ r_quay_registry.resources[0].status.registryEndpoint }}" - - - name: Save user data for Quay admin user - when: ocp4_workload_quay_operator_registry_configure_admin | bool - agnosticd.core.agnosticd_user_info: - msg: >- - "A Quay Super User '{{ ocp4_workload_quay_operator_registry_admin_user }}' has been created." - "The super user password is {{ _ocp4_workload_quay_operator_registry_admin_password }}". - "The token for the super user is {{ _ocp4_workload_quay_operator_registry_admin_token }}". - data: - quay_admin_username: "{{ ocp4_workload_quay_operator_registry_admin_user }}" - quay_admin_password: "{{ _ocp4_workload_quay_operator_registry_admin_password }}" - quay_admin_token: "{{ _ocp4_workload_quay_operator_registry_admin_token }}" + - name: Display Quay deployment information + ansible.builtin.debug: + msg: + - "=========================================" + - "Red Hat Quay Deployment Complete" + - "=========================================" + - "Quay Registry URL: {{ r_quay_registry.resources[0].status.registryEndpoint }}" + - "Admin Username: {{ ocp4_workload_quay_operator_registry_admin_user }}" + - "Admin Password: {{ _ocp4_workload_quay_operator_registry_admin_password }}" + - "Admin Token: {{ _ocp4_workload_quay_operator_registry_admin_token }}" + - "" + - "Storage Backend: S4 (S3-compatible)" + - "S3 Bucket: {{ ocp4_workload_quay_operator_s4_bucket_name }}" + - "=========================================" # Only for old versions of Quay. Newer versions don't have a config editor anymore - name: Get and save Quay config editor credentials secret @@ -197,13 +205,10 @@ namespace: "{{ ocp4_workload_quay_operator_registry_namespace }}" register: r_config_editor_secret - - name: Save user data for Quay config editor - agnosticd.core.agnosticd_user_info: - msg: >- - "Red Hat Quay Config is available at {{ r_quay_registry.resources[0].status.configEditorEndpoint }}." - "- Config User: quayconfig." - "- Config Password: {{ r_config_editor_secret.resources[0].data.password | b64decode }}." - data: - quay_config_url: "{{ r_quay_registry.resources[0].status.configEditorEndpoint }}" - quay_config_username: "quayconfig" - quay_config_password: "{{ r_config_editor_secret.resources[0].data.password | b64decode }}" + - name: Display Quay config editor information + ansible.builtin.debug: + msg: + - "Red Hat Quay Config Editor" + - " URL: {{ r_quay_registry.resources[0].status.configEditorEndpoint }}" + - " Username: quayconfig" + - " Password: {{ r_config_editor_secret.resources[0].data.password | b64decode }}" diff --git a/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 b/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 index 394ef0e..bb552cb 100644 --- a/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 +++ b/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 @@ -6,3 +6,17 @@ SUPER_USERS: - {{ ocp4_workload_quay_operator_registry_admin_user }} FEATURE_USER_INITIALIZE: true {% endif %} +# S4 Storage Configuration +DISTRIBUTED_STORAGE_CONFIG: + s4storage: + - RadosGWStorage + - hostname: s4.{{ ocp4_workload_quay_operator_s4_namespace }}.svc.cluster.local + port: 7480 + is_secure: false + bucket_name: {{ ocp4_workload_quay_operator_s4_bucket_name }} + storage_path: /datastorage/registry + access_key: {{ ocp4_workload_quay_operator_s4_access_key }} + secret_key: {{ ocp4_workload_quay_operator_s4_secret_key }} +DISTRIBUTED_STORAGE_DEFAULT_LOCATIONS: [] +DISTRIBUTED_STORAGE_PREFERENCE: +- s4storage diff --git a/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 b/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 index 56c68f5..e58cc00 100644 --- a/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 +++ b/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 @@ -10,7 +10,7 @@ spec: - kind: postgres managed: true - kind: objectstorage - managed: true + managed: false - kind: redis managed: true - kind: tls diff --git a/roles/ocp4_workload_quay_operator/templates/s4_credentials_secret.yaml.j2 b/roles/ocp4_workload_quay_operator/templates/s4_credentials_secret.yaml.j2 new file mode 100644 index 0000000..ff037fa --- /dev/null +++ b/roles/ocp4_workload_quay_operator/templates/s4_credentials_secret.yaml.j2 @@ -0,0 +1,10 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: s4-storage-credentials + namespace: {{ ocp4_workload_quay_operator_registry_namespace }} +type: Opaque +stringData: + AWS_ACCESS_KEY_ID: {{ ocp4_workload_quay_operator_s4_access_key }} + AWS_SECRET_ACCESS_KEY: {{ ocp4_workload_quay_operator_s4_secret_key }} diff --git a/roles/ocp4_workload_s4/defaults/main.yml b/roles/ocp4_workload_s4/defaults/main.yml new file mode 100644 index 0000000..45a53b7 --- /dev/null +++ b/roles/ocp4_workload_s4/defaults/main.yml @@ -0,0 +1,109 @@ +--- +# S4 (Super Simple Storage Service) workload configuration + +# -------------------------------------------------- +# Namespace configuration +# -------------------------------------------------- +ocp4_workload_s4_namespace: s4 +ocp4_workload_s4_namespace_create: true + +# -------------------------------------------------- +# ArgoCD Application configuration +# -------------------------------------------------- +ocp4_workload_s4_application_name: s4 +ocp4_workload_s4_gitops_namespace: openshift-gitops + +# Helm chart configuration +ocp4_workload_s4_chart_repo: https://github.com/rh-aiservices-bu/s4 +ocp4_workload_s4_chart_revision: main +ocp4_workload_s4_chart_path: charts/s4 + +# -------------------------------------------------- +# S4 Deployment configuration +# -------------------------------------------------- +# Image configuration +ocp4_workload_s4_image_repository: quay.io/rh-aiservices-bu/s4 +ocp4_workload_s4_image_tag: latest +ocp4_workload_s4_image_pull_policy: Always + +# S3 credentials +ocp4_workload_s4_access_key_id: s4admin +ocp4_workload_s4_secret_access_key: s4secret + +# Authentication configuration +# Username and password can be passed in as parameters. +# If not provided, username defaults to 'admin' and password is auto-generated. +ocp4_workload_s4_auth_enabled: true +ocp4_workload_s4_auth_username: admin # Default username (can be overridden) +ocp4_workload_s4_auth_password: "" # Pass in a password or leave empty for auto-generation +ocp4_workload_s4_auth_password_length: 16 # Length of auto-generated password +ocp4_workload_s4_auth_jwt_expiration_hours: 8 +ocp4_workload_s4_auth_cookie_require_https: true + +# -------------------------------------------------- +# Storage configuration +# -------------------------------------------------- +# RGW data volume (Ceph/SQLite storage) +ocp4_workload_s4_storage_data_size: 10Gi +ocp4_workload_s4_storage_data_storage_class: "" # Empty for default +ocp4_workload_s4_storage_data_access_mode: ReadWriteOnce + +# Local storage volume (optional, for local file browser) +ocp4_workload_s4_storage_local_enabled: false +ocp4_workload_s4_storage_local_size: 50Gi +ocp4_workload_s4_storage_local_storage_class: "" +ocp4_workload_s4_storage_local_access_mode: ReadWriteOnce +ocp4_workload_s4_storage_local_paths: "" # Comma-separated paths + +# Storage limits +ocp4_workload_s4_storage_max_file_size_gb: 20 +ocp4_workload_s4_storage_max_concurrent_transfers: 2 + +# -------------------------------------------------- +# Resource configuration +# -------------------------------------------------- +ocp4_workload_s4_resources_requests_cpu: 250m +ocp4_workload_s4_resources_requests_memory: 512Mi +ocp4_workload_s4_resources_limits_cpu: 2000m +ocp4_workload_s4_resources_limits_memory: 2Gi + +# -------------------------------------------------- +# Route configuration +# -------------------------------------------------- +ocp4_workload_s4_route_enabled: true +ocp4_workload_s4_route_host: "" # Auto-generated if empty +ocp4_workload_s4_route_tls_termination: edge +ocp4_workload_s4_route_tls_insecure_policy: Redirect + +# S3 API Route (enabled by default for S3 API access) +ocp4_workload_s4_route_s3_enabled: true +ocp4_workload_s4_route_s3_host: "" # Auto-generated if empty + +# -------------------------------------------------- +# Bucket creation configuration +# -------------------------------------------------- +# List of S3 buckets to create automatically +# If empty or not defined, no buckets will be created +# Example: ['datasets', 'ml-models', 'backups'] +ocp4_workload_s4_buckets: [] + +# -------------------------------------------------- +# ArgoCD sync configuration +# -------------------------------------------------- +ocp4_workload_s4_sync_policy_automated: true +ocp4_workload_s4_sync_policy_self_heal: true +ocp4_workload_s4_sync_policy_prune: true +ocp4_workload_s4_sync_retry_limit: 5 + +# -------------------------------------------------- +# User info configuration +# -------------------------------------------------- +ocp4_workload_s4_enable_user_info_messages: true +ocp4_workload_s4_enable_user_info_data: true + +# -------------------------------------------------- +# Wait for deployment +# -------------------------------------------------- +ocp4_workload_s4_wait_for_deployment: true +ocp4_workload_s4_wait_retries: 60 +ocp4_workload_s4_wait_delay: 10 diff --git a/roles/ocp4_workload_s4/meta/main.yml b/roles/ocp4_workload_s4/meta/main.yml new file mode 100644 index 0000000..aeaf302 --- /dev/null +++ b/roles/ocp4_workload_s4/meta/main.yml @@ -0,0 +1,18 @@ +--- +galaxy_info: + role_name: ocp4_workload_s4 + author: Red Hat GPTE + description: | + Deploy S4 (Super Simple Storage Service) on OpenShift using GitOps. + S4 provides S3-compatible object storage with a modern web UI. + license: MIT + min_ansible_version: "2.9" + platforms: [] + galaxy_tags: + - ocp + - openshift + - s3 + - storage + - gitops + - argocd +dependencies: [] diff --git a/roles/ocp4_workload_s4/readme.adoc b/roles/ocp4_workload_s4/readme.adoc new file mode 100644 index 0000000..51c2dc0 --- /dev/null +++ b/roles/ocp4_workload_s4/readme.adoc @@ -0,0 +1,242 @@ += ocp4_workload_s4 - Deploy S4 Storage Service + +== Role overview + +* This role deploys S4 (Super Simple Storage Service) on OpenShift using GitOps/ArgoCD +* S4 provides S3-compatible object storage with a modern web UI +* Includes Ceph RADOS Gateway (RGW) backed by filesystem storage +* Supports optional automatic S3 bucket creation + +== Features + +* GitOps-based deployment using OpenShift GitOps (ArgoCD) +* S3-compatible API endpoint (port 7480) +* Modern React-based web UI (port 5000) +* Optional authentication for web UI +* Configurable persistent storage +* Optional automatic bucket creation +* OpenShift Route integration for external access +* Production-ready resource limits and health checks + +== Deployment + +This role assumes OpenShift GitOps is already installed in the `openshift-gitops` namespace. + +The role performs the following tasks: + +* Creates the S4 namespace (default: `s4`) +* Deploys an ArgoCD Application resource pointing to the S4 Helm chart +* Waits for the Application to sync and become healthy +* Optionally creates S3 bucket(s) using Kubernetes Jobs +* Reports access information to users (URLs, credentials) + +== Variables + +=== Namespace Configuration + +* `ocp4_workload_s4_namespace`: Namespace for S4 deployment (default: `s4`) +* `ocp4_workload_s4_namespace_create`: Create the namespace (default: `true`) + +=== ArgoCD Configuration + +* `ocp4_workload_s4_application_name`: ArgoCD Application name (default: `s4`) +* `ocp4_workload_s4_gitops_namespace`: OpenShift GitOps namespace (default: `openshift-gitops`) +* `ocp4_workload_s4_chart_repo`: Helm chart repository URL (default: `https://github.com/rh-aiservices-bu/s4`) +* `ocp4_workload_s4_chart_revision`: Git branch/tag (default: `main`) +* `ocp4_workload_s4_chart_path`: Path to chart in repo (default: `charts/s4`) + +=== S3 Credentials + +* `ocp4_workload_s4_access_key_id`: S3 access key (default: `s4admin`) +* `ocp4_workload_s4_secret_access_key`: S3 secret key (default: `s4secret`) + +=== Authentication + +Username and password can be passed in as parameters. If not provided, username defaults to `admin` and password is auto-generated. + +* `ocp4_workload_s4_auth_enabled`: Enable web UI authentication (default: `true`) +* `ocp4_workload_s4_auth_username`: UI username (default: `admin`, can be overridden) +* `ocp4_workload_s4_auth_password`: UI password (pass in custom password or leave empty for auto-generation) +* `ocp4_workload_s4_auth_password_length`: Length of auto-generated password (default: `16`) +* `ocp4_workload_s4_auth_jwt_expiration_hours`: JWT token expiration (default: `8`) + +=== Storage Configuration + +* `ocp4_workload_s4_storage_data_size`: RGW data volume size (default: `10Gi`) +* `ocp4_workload_s4_storage_data_storage_class`: Storage class for data (default: empty = default class) +* `ocp4_workload_s4_storage_local_enabled`: Enable local storage volume (default: `false`) +* `ocp4_workload_s4_storage_local_size`: Local storage volume size (default: `50Gi`) +* `ocp4_workload_s4_storage_max_file_size_gb`: Max file size in GB (default: `20`) + +=== Resource Limits + +* `ocp4_workload_s4_resources_requests_cpu`: CPU request (default: `250m`) +* `ocp4_workload_s4_resources_requests_memory`: Memory request (default: `512Mi`) +* `ocp4_workload_s4_resources_limits_cpu`: CPU limit (default: `2000m`) +* `ocp4_workload_s4_resources_limits_memory`: Memory limit (default: `2Gi`) + +=== Route Configuration + +* `ocp4_workload_s4_route_enabled`: Enable OpenShift Route for UI (default: `true`) +* `ocp4_workload_s4_route_host`: Custom hostname (default: auto-generated) +* `ocp4_workload_s4_route_tls_termination`: TLS termination (default: `edge`) +* `ocp4_workload_s4_route_s3_enabled`: Enable Route for S3 API (default: `true`) + +=== Bucket Creation + +* `ocp4_workload_s4_buckets`: List of S3 bucket names to create (default: `[]`) +** If empty or not defined, no buckets will be created +** Example: `['datasets', 'ml-models', 'backups']` + +=== Sync Policy + +* `ocp4_workload_s4_sync_policy_automated`: Enable automated sync (default: `true`) +* `ocp4_workload_s4_sync_policy_self_heal`: Enable self-healing (default: `true`) +* `ocp4_workload_s4_sync_policy_prune`: Enable resource pruning (default: `true`) + +== Example Usage + +=== Basic Deployment + +[source,yaml] +---- +- name: Deploy S4 + hosts: localhost + tasks: + - name: Include S4 workload + include_role: + name: ocp4_workload_s4 +---- + +=== With Bucket Creation + +[source,yaml] +---- +- name: Deploy S4 with buckets + hosts: localhost + tasks: + - name: Include S4 workload + include_role: + name: ocp4_workload_s4 + vars: + ocp4_workload_s4_buckets: + - my-data-bucket + - ml-models + - datasets + - backups +---- + +=== Custom Configuration + +[source,yaml] +---- +- name: Deploy S4 with custom settings + hosts: localhost + tasks: + - name: Include S4 workload + include_role: + name: ocp4_workload_s4 + vars: + ocp4_workload_s4_namespace: object-storage + ocp4_workload_s4_storage_data_size: 100Gi + ocp4_workload_s4_storage_data_storage_class: ocs-storagecluster-ceph-rbd + ocp4_workload_s4_access_key_id: my-access-key + ocp4_workload_s4_secret_access_key: my-secret-key + ocp4_workload_s4_route_s3_enabled: true + ocp4_workload_s4_buckets: + - production-data +---- + +=== Custom Authentication Credentials + +[source,yaml] +---- +- name: Deploy S4 with custom credentials + hosts: localhost + tasks: + - name: Include S4 workload + include_role: + name: ocp4_workload_s4 + vars: + ocp4_workload_s4_auth_username: myuser + ocp4_workload_s4_auth_password: MySecureP@ssw0rd + ocp4_workload_s4_access_key_id: custom-access-key + ocp4_workload_s4_secret_access_key: custom-secret-key-123456 +---- + +== Accessing S4 + +After deployment, users will receive: + +* *Web UI URL*: Access the modern web interface +* *UI Credentials*: Username and password for UI login +* *S3 Access Key*: For S3 API authentication +* *S3 Secret Key*: For S3 API authentication +* *S3 Endpoint (internal)*: For pod-to-pod communication +* *S3 Endpoint (external)*: If S3 route is enabled + +== Using S3 API + +You can use any S3-compatible client (AWS CLI, boto3, mc, etc.): + +[source,bash] +---- +# Using AWS CLI +aws configure set aws_access_key_id s4admin +aws configure set aws_secret_access_key s4secret +aws --endpoint-url https://s3-route-url s3 ls + +# Using MinIO Client (mc) +mc alias set mys4 https://s3-route-url s4admin s4secret +mc ls mys4 +mc mb mys4/mybucket +mc cp file.txt mys4/mybucket/ +---- + +== Removal + +To remove the S4 deployment: + +[source,yaml] +---- +- name: Remove S4 + hosts: localhost + tasks: + - name: Include S4 workload + include_role: + name: ocp4_workload_s4 + vars: + ACTION: destroy +---- + +This will: + +* Delete bucket creation jobs +* Delete the ArgoCD Application (which removes all S4 resources) +* Delete the S4 namespace + +NOTE: Bucket data is stored in the persistent volumes. Removing the workload will delete the PVCs and all data unless you have external backups. + +== Predefined Variables + +The following variables are always available: + +* `openshift_console_url`: The URL of the OpenShift console +* `openshift_api_url`: The OpenShift API endpoint URL +* `openshift_cluster_ingress_domain`: The domain used for ingress controllers + +== S4 Architecture + +S4 combines several components in a single container: + +* *Ceph RADOS Gateway (RGW)*: Provides S3-compatible API +* *SQLite Backend*: Lightweight metadata storage (single replica only) +* *React Web UI*: Modern interface for file management +* *File Browser*: Browse and manage files/objects + +The deployment uses: + +* Kubernetes Deployment (1 replica - SQLite limitation) +* PersistentVolumeClaim for RGW data storage +* OpenShift Route for external access +* Service for internal cluster access diff --git a/roles/ocp4_workload_s4/tasks/main.yml b/roles/ocp4_workload_s4/tasks/main.yml new file mode 100644 index 0000000..23308e3 --- /dev/null +++ b/roles/ocp4_workload_s4/tasks/main.yml @@ -0,0 +1,11 @@ +--- +# -------------------------------------------------- +# Do not modify this file +# -------------------------------------------------- +- name: Running workload provision tasks + when: ACTION == "provision" + ansible.builtin.include_tasks: workload.yml + +- name: Running workload removal tasks + when: ACTION == "destroy" + ansible.builtin.include_tasks: remove_workload.yml diff --git a/roles/ocp4_workload_s4/tasks/remove_workload.yml b/roles/ocp4_workload_s4/tasks/remove_workload.yml new file mode 100644 index 0000000..e0488f3 --- /dev/null +++ b/roles/ocp4_workload_s4/tasks/remove_workload.yml @@ -0,0 +1,51 @@ +--- +# -------------------------------------------------- +# S4 Workload Removal Tasks +# -------------------------------------------------- + +- name: Delete bucket creation jobs + kubernetes.core.k8s: + state: absent + api_version: batch/v1 + kind: Job + namespace: "{{ ocp4_workload_s4_namespace }}" + label_selectors: + - "app.kubernetes.io/component=bucket-creator" + +- name: Delete ArgoCD Application + kubernetes.core.k8s: + state: absent + api_version: argoproj.io/v1alpha1 + kind: Application + name: "{{ ocp4_workload_s4_application_name }}" + namespace: "{{ ocp4_workload_s4_gitops_namespace }}" + +- name: Wait for Application deletion + kubernetes.core.k8s_info: + api_version: argoproj.io/v1alpha1 + kind: Application + name: "{{ ocp4_workload_s4_application_name }}" + namespace: "{{ ocp4_workload_s4_gitops_namespace }}" + register: r_application + retries: 30 + delay: 10 + until: r_application.resources | length == 0 + +- name: Delete S4 namespace + when: ocp4_workload_s4_namespace_create | bool + kubernetes.core.k8s: + state: absent + api_version: v1 + kind: Namespace + name: "{{ ocp4_workload_s4_namespace }}" + +- name: Wait for namespace deletion + when: ocp4_workload_s4_namespace_create | bool + kubernetes.core.k8s_info: + api_version: v1 + kind: Namespace + name: "{{ ocp4_workload_s4_namespace }}" + register: r_namespace + retries: 60 + delay: 5 + until: r_namespace.resources | length == 0 diff --git a/roles/ocp4_workload_s4/tasks/workload.yml b/roles/ocp4_workload_s4/tasks/workload.yml new file mode 100644 index 0000000..c1734fb --- /dev/null +++ b/roles/ocp4_workload_s4/tasks/workload.yml @@ -0,0 +1,177 @@ +--- +# -------------------------------------------------- +# S4 Workload Deployment Tasks +# -------------------------------------------------- + +- name: Set internal variables + ansible.builtin.set_fact: + _ocp4_workload_s4_auth_password: >- + {{ ocp4_workload_s4_auth_password + if ocp4_workload_s4_auth_password | length > 0 + else lookup('password', '/dev/null length={{ ocp4_workload_s4_auth_password_length }} chars=ascii_letters,digits') }} + _ocp4_workload_s4_route_url: "" + _ocp4_workload_s4_s3_endpoint_internal: "http://s4.{{ ocp4_workload_s4_namespace }}.svc.cluster.local:7480" + +- name: Create S4 namespace + when: ocp4_workload_s4_namespace_create | bool + kubernetes.core.k8s: + state: present + definition: + apiVersion: v1 + kind: Namespace + metadata: + name: "{{ ocp4_workload_s4_namespace }}" + labels: + argocd.argoproj.io/managed-by: "{{ ocp4_workload_s4_gitops_namespace }}" + +- name: Create ArgoCD Application for S4 + kubernetes.core.k8s: + state: present + definition: "{{ lookup('template', 'application.yaml.j2') | from_yaml }}" + +- name: Wait for S4 Application to sync + when: ocp4_workload_s4_wait_for_deployment | bool + kubernetes.core.k8s_info: + api_version: argoproj.io/v1alpha1 + kind: Application + name: "{{ ocp4_workload_s4_application_name }}" + namespace: "{{ ocp4_workload_s4_gitops_namespace }}" + register: r_application + retries: "{{ ocp4_workload_s4_wait_retries }}" + delay: "{{ ocp4_workload_s4_wait_delay }}" + until: + - r_application.resources is defined + - r_application.resources | length > 0 + - r_application.resources[0].status is defined + - r_application.resources[0].status.sync is defined + - r_application.resources[0].status.sync.status == 'Synced' + - r_application.resources[0].status.health is defined + - r_application.resources[0].status.health.status == 'Healthy' + +- name: Wait for S4 deployment to be ready + when: ocp4_workload_s4_wait_for_deployment | bool + kubernetes.core.k8s_info: + api_version: apps/v1 + kind: Deployment + name: s4 + namespace: "{{ ocp4_workload_s4_namespace }}" + register: r_s4_deployment + retries: "{{ ocp4_workload_s4_wait_retries }}" + delay: "{{ ocp4_workload_s4_wait_delay }}" + until: + - r_s4_deployment.resources is defined + - r_s4_deployment.resources | length > 0 + - r_s4_deployment.resources[0].status is defined + - r_s4_deployment.resources[0].status.readyReplicas is defined + - r_s4_deployment.resources[0].status.readyReplicas | int == 1 + +- name: Get S4 route + when: ocp4_workload_s4_route_enabled | bool + kubernetes.core.k8s_info: + api_version: route.openshift.io/v1 + kind: Route + name: s4 + namespace: "{{ ocp4_workload_s4_namespace }}" + register: r_s4_route + retries: 30 + delay: 5 + until: + - r_s4_route.resources is defined + - r_s4_route.resources | length > 0 + - r_s4_route.resources[0].spec.host is defined + +- name: Set S4 route URL + when: + - ocp4_workload_s4_route_enabled | bool + - r_s4_route.resources | length > 0 + ansible.builtin.set_fact: + _ocp4_workload_s4_route_url: "https://{{ r_s4_route.resources[0].spec.host }}" + +- name: Get S3 API route (if enabled) + when: ocp4_workload_s4_route_s3_enabled | bool + kubernetes.core.k8s_info: + api_version: route.openshift.io/v1 + kind: Route + name: s4-api + namespace: "{{ ocp4_workload_s4_namespace }}" + register: r_s4_api_route + retries: 30 + delay: 5 + until: + - r_s4_api_route.resources is defined + - r_s4_api_route.resources | length > 0 + - r_s4_api_route.resources[0].spec.host is defined + +- name: Set S3 API endpoint URL + when: + - ocp4_workload_s4_route_s3_enabled | bool + - r_s4_api_route.resources | length > 0 + ansible.builtin.set_fact: + _ocp4_workload_s4_s3_endpoint_external: "https://{{ r_s4_api_route.resources[0].spec.host }}" + +- name: Create S3 bucket(s) + when: ocp4_workload_s4_buckets | default([]) | length > 0 + block: + - name: Create buckets + kubernetes.core.k8s: + state: present + definition: "{{ lookup('template', 'bucket-job.yaml.j2') | from_yaml }}" + loop: "{{ ocp4_workload_s4_buckets }}" + loop_control: + loop_var: bucket_name + + - name: Wait for bucket creation job(s) to complete + kubernetes.core.k8s_info: + api_version: batch/v1 + kind: Job + namespace: "{{ ocp4_workload_s4_namespace }}" + label_selectors: + - "app.kubernetes.io/component=bucket-creator" + register: r_bucket_jobs + retries: 30 + delay: 5 + until: + - r_bucket_jobs.resources is defined + - r_bucket_jobs.resources | length > 0 + - r_bucket_jobs.resources | selectattr('status.succeeded', 'defined') | selectattr('status.succeeded', 'equalto', 1) | list | length == (ocp4_workload_s4_buckets | length) + +- name: Report S4 information to user + when: ocp4_workload_s4_enable_user_info_messages | bool + block: + - name: Set S4 user info messages + ansible.builtin.set_fact: + _s4_user_info_messages: + - msg: "S4 Web UI: {{ _ocp4_workload_s4_route_url }}" + when: "{{ _ocp4_workload_s4_route_url | length > 0 }}" + - msg: "S4 UI Login: {{ ocp4_workload_s4_auth_username }} / {{ _ocp4_workload_s4_auth_password }}" + when: "{{ ocp4_workload_s4_auth_enabled | bool }}" + - msg: "S3 Access Key: {{ ocp4_workload_s4_access_key_id }}" + when: true + - msg: "S3 Secret Key: {{ ocp4_workload_s4_secret_access_key }}" + when: true + - msg: "S3 Endpoint (internal): {{ _ocp4_workload_s4_s3_endpoint_internal }}" + when: true + - msg: "S3 Endpoint (external): {{ _ocp4_workload_s4_s3_endpoint_external }}" + when: "{{ ocp4_workload_s4_route_s3_enabled | bool and _ocp4_workload_s4_s3_endpoint_external is defined }}" + - msg: "S3 Buckets Created: {{ ocp4_workload_s4_buckets | join(', ') }}" + when: "{{ ocp4_workload_s4_buckets | default([]) | length > 0 }}" + + - name: Print S4 information + when: item.when | bool + agnosticd_user_info: + msg: "{{ item.msg }}" + loop: "{{ _s4_user_info_messages }}" + +- name: Save S4 data for user + when: ocp4_workload_s4_enable_user_info_data | bool + agnosticd_user_info: + data: + s4_web_ui_url: "{{ _ocp4_workload_s4_route_url }}" + s4_ui_username: "{{ ocp4_workload_s4_auth_username }}" + s4_ui_password: "{{ _ocp4_workload_s4_auth_password }}" + s4_s3_access_key_id: "{{ ocp4_workload_s4_access_key_id }}" + s4_s3_secret_access_key: "{{ ocp4_workload_s4_secret_access_key }}" + s4_s3_endpoint_internal: "{{ _ocp4_workload_s4_s3_endpoint_internal }}" + s4_s3_endpoint_external: "{{ _ocp4_workload_s4_s3_endpoint_external | default('') }}" + s4_buckets: "{{ ocp4_workload_s4_buckets | default([]) }}" + s4_namespace: "{{ ocp4_workload_s4_namespace }}" diff --git a/roles/ocp4_workload_s4/templates/application.yaml.j2 b/roles/ocp4_workload_s4/templates/application.yaml.j2 new file mode 100644 index 0000000..77d431c --- /dev/null +++ b/roles/ocp4_workload_s4/templates/application.yaml.j2 @@ -0,0 +1,123 @@ +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: {{ ocp4_workload_s4_application_name }} + namespace: {{ ocp4_workload_s4_gitops_namespace }} + labels: + app.kubernetes.io/name: s4 + app.kubernetes.io/component: application +spec: + project: default + source: + repoURL: {{ ocp4_workload_s4_chart_repo }} + targetRevision: {{ ocp4_workload_s4_chart_revision }} + path: {{ ocp4_workload_s4_chart_path }} + helm: + values: | + # Image configuration + image: + repository: {{ ocp4_workload_s4_image_repository }} + tag: {{ ocp4_workload_s4_image_tag }} + pullPolicy: {{ ocp4_workload_s4_image_pull_policy }} + + # S3 backend configuration + s3: + endpoint: 'http://localhost:7480' + region: 'us-east-1' + accessKeyId: {{ ocp4_workload_s4_access_key_id }} + secretAccessKey: {{ ocp4_workload_s4_secret_access_key }} + + # Authentication configuration + auth: + enabled: {{ ocp4_workload_s4_auth_enabled | lower }} +{% if ocp4_workload_s4_auth_enabled %} + username: {{ ocp4_workload_s4_auth_username }} + password: {{ _ocp4_workload_s4_auth_password }} + jwtExpirationHours: {{ ocp4_workload_s4_auth_jwt_expiration_hours }} + cookieRequireHttps: {{ ocp4_workload_s4_auth_cookie_require_https | lower }} +{% endif %} + + # Storage configuration + storage: + localPaths: '{{ ocp4_workload_s4_storage_local_paths }}' + maxFileSizeGB: {{ ocp4_workload_s4_storage_max_file_size_gb }} + maxConcurrentTransfers: {{ ocp4_workload_s4_storage_max_concurrent_transfers }} + + # RGW data volume + data: + size: {{ ocp4_workload_s4_storage_data_size }} +{% if ocp4_workload_s4_storage_data_storage_class | length > 0 %} + storageClass: {{ ocp4_workload_s4_storage_data_storage_class }} +{% endif %} + accessMode: {{ ocp4_workload_s4_storage_data_access_mode }} + + # Local storage volume + localStorage: + enabled: {{ ocp4_workload_s4_storage_local_enabled | lower }} +{% if ocp4_workload_s4_storage_local_enabled %} + size: {{ ocp4_workload_s4_storage_local_size }} +{% if ocp4_workload_s4_storage_local_storage_class | length > 0 %} + storageClass: {{ ocp4_workload_s4_storage_local_storage_class }} +{% endif %} + accessMode: {{ ocp4_workload_s4_storage_local_access_mode }} +{% endif %} + + # Resource limits and requests + resources: + requests: + cpu: {{ ocp4_workload_s4_resources_requests_cpu }} + memory: {{ ocp4_workload_s4_resources_requests_memory }} + limits: + cpu: {{ ocp4_workload_s4_resources_limits_cpu }} + memory: {{ ocp4_workload_s4_resources_limits_memory }} + + # Service configuration + service: + type: ClusterIP + port: 5000 + s3Port: 7480 + + # OpenShift Route configuration + route: + enabled: {{ ocp4_workload_s4_route_enabled | lower }} +{% if ocp4_workload_s4_route_enabled %} +{% if ocp4_workload_s4_route_host | length > 0 %} + host: {{ ocp4_workload_s4_route_host }} +{% endif %} + tls: + termination: {{ ocp4_workload_s4_route_tls_termination }} + insecureEdgeTerminationPolicy: {{ ocp4_workload_s4_route_tls_insecure_policy }} +{% endif %} + + # S3 API Route + s3Api: + enabled: {{ ocp4_workload_s4_route_s3_enabled | lower }} +{% if ocp4_workload_s4_route_s3_enabled %} +{% if ocp4_workload_s4_route_s3_host | length > 0 %} + host: {{ ocp4_workload_s4_route_s3_host }} +{% endif %} + tls: + termination: {{ ocp4_workload_s4_route_tls_termination }} + insecureEdgeTerminationPolicy: {{ ocp4_workload_s4_route_tls_insecure_policy }} +{% endif %} + + destination: + server: https://kubernetes.default.svc + namespace: {{ ocp4_workload_s4_namespace }} + + syncPolicy: +{% if ocp4_workload_s4_sync_policy_automated %} + automated: + prune: {{ ocp4_workload_s4_sync_policy_prune | lower }} + selfHeal: {{ ocp4_workload_s4_sync_policy_self_heal | lower }} +{% endif %} + syncOptions: + - CreateNamespace=true + - RespectIgnoreDifferences=true + retry: + limit: {{ ocp4_workload_s4_sync_retry_limit }} + backoff: + duration: 5s + factor: 2 + maxDuration: 3m diff --git a/roles/ocp4_workload_s4/templates/bucket-job.yaml.j2 b/roles/ocp4_workload_s4/templates/bucket-job.yaml.j2 new file mode 100644 index 0000000..21021c4 --- /dev/null +++ b/roles/ocp4_workload_s4/templates/bucket-job.yaml.j2 @@ -0,0 +1,80 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: create-bucket-{{ bucket_name }} + namespace: {{ ocp4_workload_s4_namespace }} + labels: + app.kubernetes.io/name: s4 + app.kubernetes.io/component: bucket-creator + app.kubernetes.io/bucket: {{ bucket_name }} +spec: + backoffLimit: 5 + ttlSecondsAfterFinished: 600 + template: + metadata: + labels: + app.kubernetes.io/name: s4 + app.kubernetes.io/component: bucket-creator + spec: + restartPolicy: OnFailure + serviceAccountName: s4 + containers: + - name: create-bucket + image: quay.io/minio/mc:latest + command: + - /bin/sh + - -c + - | + set -e + echo "Configuring S3 client..." + mc alias set s4 http://s4.{{ ocp4_workload_s4_namespace }}.svc.cluster.local:7480 \ + $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY --insecure + + echo "Waiting for S3 service to be ready..." + MAX_RETRIES=60 + RETRY=0 + until mc ls s4 --insecure 2>/dev/null; do + RETRY=$((RETRY+1)) + if [ $RETRY -gt $MAX_RETRIES ]; then + echo "ERROR: S3 service did not become ready after $MAX_RETRIES attempts" + echo "Attempting bucket creation anyway..." + break + fi + echo "S3 service not ready yet (attempt $RETRY/$MAX_RETRIES), waiting..." + sleep 5 + done + + echo "Creating bucket: {{ bucket_name }}" + if mc ls s4/{{ bucket_name }} --insecure 2>/dev/null; then + echo "Bucket {{ bucket_name }} already exists" + else + mc mb s4/{{ bucket_name }} --insecure + echo "Bucket {{ bucket_name }} created successfully" + fi + + echo "Verifying bucket exists..." + mc ls s4/{{ bucket_name }} --insecure + echo "Bucket creation complete" + env: + - name: AWS_ACCESS_KEY_ID + value: {{ ocp4_workload_s4_access_key_id }} + - name: AWS_SECRET_ACCESS_KEY + value: {{ ocp4_workload_s4_secret_access_key }} + - name: HOME + value: /tmp + - name: MC_CONFIG_DIR + value: /tmp/.mc + volumeMounts: + - name: mc-config + mountPath: /tmp + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 256Mi + volumes: + - name: mc-config + emptyDir: {} From 1ce7296593f3720a1f76b0f34f120402190a0fe6 Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 17:02:03 +1000 Subject: [PATCH 02/14] Make S4 storage opt-in for Quay operator with full backward compatibility - Add ocp4_workload_quay_operator_use_s4_storage boolean (default: false) - When false: preserves exact original Noobaa/OCS behavior from main branch - When true: enables new S4 storage backend functionality - Separate conditional code paths ensure zero impact on existing deployments - Restored original agnosticd_user_info calls for proper AgnosticD integration - Updated documentation to explain both storage backend options - No additional steps or overhead for default Noobaa usage This ensures existing workloads continue working without any changes while allowing users to opt-in to S4 storage by explicitly setting the boolean. Co-Authored-By: Claude Sonnet 4.5 --- .../defaults/main.yml | 8 ++ roles/ocp4_workload_quay_operator/readme.adoc | 42 +++++-- .../tasks/workload.yml | 112 ++++++++++++------ .../templates/config.yaml.j2 | 2 + .../templates/quay_registry.yaml.j2 | 2 +- 5 files changed, 121 insertions(+), 45 deletions(-) diff --git a/roles/ocp4_workload_quay_operator/defaults/main.yml b/roles/ocp4_workload_quay_operator/defaults/main.yml index 4ed699c..7a9ef86 100644 --- a/roles/ocp4_workload_quay_operator/defaults/main.yml +++ b/roles/ocp4_workload_quay_operator/defaults/main.yml @@ -120,9 +120,17 @@ ocp4_workload_quay_operator_registry_enable_clairpostgres: false ocp4_workload_quay_operator_registry_startup_probe_update: false ocp4_workload_quay_operator_registry_startup_probe_failure_threshold: 30 +# -------------------------------- +# Storage Backend Configuration +# -------------------------------- +# Set to true to use S4 storage, false to use Noobaa (OCS) +# Default: false (uses Noobaa/OpenShift Container Storage) +ocp4_workload_quay_operator_use_s4_storage: false + # -------------------------------- # S3 Storage Configuration (S4) # -------------------------------- +# Only used when ocp4_workload_quay_operator_use_s4_storage: true # Quay uses S4 storage for object storage backend # S4 S3 endpoint configuration diff --git a/roles/ocp4_workload_quay_operator/readme.adoc b/roles/ocp4_workload_quay_operator/readme.adoc index 185d9a3..4da562d 100644 --- a/roles/ocp4_workload_quay_operator/readme.adoc +++ b/roles/ocp4_workload_quay_operator/readme.adoc @@ -5,8 +5,8 @@ * This role can ** install the Quay Operator ** use a previously installed Red Hat Quay Operator to deploy a Quay Registry into an OpenShift Cluster. -* The cluster *must* have S4 storage deployed (using `ocp4_workload_s4` role). -* Quay uses S4 S3-compatible storage backend instead of OpenShift Container Storage (Noobaa). +* By default, the cluster *must* have OpenShift Container Storage (Noobaa) installed. +* Optionally, S4 S3-compatible storage can be used instead of Noobaa. * The role consists of the following tasks files: ** Tasks: link:./tasks/pre_workload.yml[pre_workload.yml] - Sets up an @@ -29,11 +29,29 @@ == Prerequisites -=== S4 Storage +=== Storage Backend Options -This role *requires* S4 storage to be deployed first. S4 provides S3-compatible object storage for Quay. +This role supports two storage backends for Quay: -Deploy S4 before deploying Quay: +1. **Noobaa/OpenShift Container Storage** (default) +2. **S4 Storage** (optional, S3-compatible) + +==== Option 1: Noobaa Storage (Default) + +The cluster *must* have OpenShift Container Storage installed with Noobaa. + +[source,yaml] +---- +workloads: +- agnosticd.core_workloads.ocp4_workload_quay_operator + +# Uses default storage (Noobaa/OCS) +# No additional configuration required +---- + +==== Option 2: S4 Storage (Optional) + +To use S4 storage instead of Noobaa, S4 must be deployed first using the `ocp4_workload_s4` role. [source,yaml] ---- @@ -41,6 +59,9 @@ workloads: - agnosticd.core_workloads.ocp4_workload_s4 - agnosticd.core_workloads.ocp4_workload_quay_operator +# Enable S4 storage backend +ocp4_workload_quay_operator_use_s4_storage: true + # S4 configuration ocp4_workload_s4_buckets: - quay-registry # Required bucket for Quay @@ -48,12 +69,19 @@ ocp4_workload_s4_buckets: # S4 credentials (must match Quay configuration) ocp4_workload_s4_access_key_id: s4admin ocp4_workload_s4_secret_access_key: s4secret + +# Quay S4 settings (optional, uses defaults if not specified) +ocp4_workload_quay_operator_s4_namespace: s4 +ocp4_workload_quay_operator_s4_bucket_name: quay-registry +ocp4_workload_quay_operator_s4_access_key: s4admin +ocp4_workload_quay_operator_s4_secret_key: s4secret ---- -=== S4 Configuration Variables +=== S4 Storage Configuration Variables -If you need to customize the S4 integration, these variables control the S3 storage backend: +When using S4 storage (`ocp4_workload_quay_operator_use_s4_storage: true`), these variables control the S3 storage backend: +* `ocp4_workload_quay_operator_use_s4_storage`: Enable S4 storage backend (default: `false`) * `ocp4_workload_quay_operator_s4_namespace`: Namespace where S4 is deployed (default: `s4`) * `ocp4_workload_quay_operator_s4_bucket_name`: S3 bucket name for Quay (default: `quay-registry`) * `ocp4_workload_quay_operator_s4_access_key`: S3 access key (default: `s4admin`) diff --git a/roles/ocp4_workload_quay_operator/tasks/workload.yml b/roles/ocp4_workload_quay_operator/tasks/workload.yml index 02d8e55..6bf7918 100644 --- a/roles/ocp4_workload_quay_operator/tasks/workload.yml +++ b/roles/ocp4_workload_quay_operator/tasks/workload.yml @@ -1,19 +1,37 @@ --- -# Quay uses S4 storage for object storage backend -# Verify S4 is deployed and available -- name: Check S4 service exists - kubernetes.core.k8s_info: - api_version: v1 - kind: Service - name: s4 - namespace: "{{ ocp4_workload_quay_operator_s4_namespace }}" - register: r_s4_service - -- name: Assert that S4 service exists - ansible.builtin.assert: - that: - - r_s4_service.resources | length == 1 - fail_msg: "S4 storage service not found in namespace {{ ocp4_workload_quay_operator_s4_namespace }}. Deploy S4 first using ocp4_workload_s4 role." +# Validate storage backend based on configuration +- name: Validate storage backend + block: + - name: Check S4 service exists + when: ocp4_workload_quay_operator_use_s4_storage | bool + kubernetes.core.k8s_info: + api_version: v1 + kind: Service + name: s4 + namespace: "{{ ocp4_workload_quay_operator_s4_namespace }}" + register: r_s4_service + + - name: Assert that S4 service exists + when: ocp4_workload_quay_operator_use_s4_storage | bool + ansible.builtin.assert: + that: + - r_s4_service.resources | length == 1 + fail_msg: "S4 storage service not found in namespace {{ ocp4_workload_quay_operator_s4_namespace }}. Deploy S4 first using ocp4_workload_s4 role." + + - name: Check Noobaa BucketClass exists + when: not (ocp4_workload_quay_operator_use_s4_storage | bool) + kubernetes.core.k8s_info: + api_version: noobaa.io/v1alpha1 + kind: BucketClass + namespace: openshift-storage + register: r_bucket_class + + - name: Assert that Noobaa BucketClass exists + when: not (ocp4_workload_quay_operator_use_s4_storage | bool) + ansible.builtin.assert: + that: + - r_bucket_class.resources | length == 1 + fail_msg: "Quay must be installed on a cluster with OpenShift Container Storage configured - and a Bucket Class deployed." - name: Install Quay Operator when: ocp4_workload_quay_operator_install_operator | bool @@ -59,7 +77,20 @@ ansible.builtin.set_fact: _ocp4_workload_quay_operator_registry_route: "{{ ocp4_workload_quay_operator_registry_hostname }}.{{ openshift_cluster_ingress_domain }}" + # Original Noobaa flow - unchanged from main branch + - name: Create Quay Registry Resources + when: not (ocp4_workload_quay_operator_use_s4_storage | bool) + kubernetes.core.k8s: + state: present + definition: "{{ lookup('template', item ) | from_yaml }}" + loop: + - quay_namespace.yaml.j2 + - config_bundle_secret.yaml.j2 + - quay_registry.yaml.j2 + + # S4 storage flow - new conditional logic - name: Delete existing config bundle secret to force recreation + when: ocp4_workload_quay_operator_use_s4_storage | bool kubernetes.core.k8s: state: absent api_version: v1 @@ -68,7 +99,8 @@ namespace: "{{ ocp4_workload_quay_operator_registry_namespace }}" ignore_errors: true - - name: Create Quay Registry Resources + - name: Create Quay Registry Resources (S4 mode) + when: ocp4_workload_quay_operator_use_s4_storage | bool kubernetes.core.k8s: state: present definition: "{{ lookup('template', item ) | from_yaml }}" @@ -178,20 +210,23 @@ state: present definition: "{{ lookup('template', 'quay-admin-token-secret.yml.j2') | from_yaml }}" - - name: Display Quay deployment information - ansible.builtin.debug: - msg: - - "=========================================" - - "Red Hat Quay Deployment Complete" - - "=========================================" - - "Quay Registry URL: {{ r_quay_registry.resources[0].status.registryEndpoint }}" - - "Admin Username: {{ ocp4_workload_quay_operator_registry_admin_user }}" - - "Admin Password: {{ _ocp4_workload_quay_operator_registry_admin_password }}" - - "Admin Token: {{ _ocp4_workload_quay_operator_registry_admin_token }}" - - "" - - "Storage Backend: S4 (S3-compatible)" - - "S3 Bucket: {{ ocp4_workload_quay_operator_s4_bucket_name }}" - - "=========================================" + - name: Save user data for Quay console URL + agnosticd.core.agnosticd_user_info: + msg: "Red Hat Quay is available at {{ r_quay_registry.resources[0].status.registryEndpoint }}" + data: + quay_console_url: "{{ r_quay_registry.resources[0].status.registryEndpoint }}" + + - name: Save user data for Quay admin user + when: ocp4_workload_quay_operator_registry_configure_admin | bool + agnosticd.core.agnosticd_user_info: + msg: >- + "A Quay Super User '{{ ocp4_workload_quay_operator_registry_admin_user }}' has been created." + "The super user password is {{ _ocp4_workload_quay_operator_registry_admin_password }}". + "The token for the super user is {{ _ocp4_workload_quay_operator_registry_admin_token }}". + data: + quay_admin_username: "{{ ocp4_workload_quay_operator_registry_admin_user }}" + quay_admin_password: "{{ _ocp4_workload_quay_operator_registry_admin_password }}" + quay_admin_token: "{{ _ocp4_workload_quay_operator_registry_admin_token }}" # Only for old versions of Quay. Newer versions don't have a config editor anymore - name: Get and save Quay config editor credentials secret @@ -205,10 +240,13 @@ namespace: "{{ ocp4_workload_quay_operator_registry_namespace }}" register: r_config_editor_secret - - name: Display Quay config editor information - ansible.builtin.debug: - msg: - - "Red Hat Quay Config Editor" - - " URL: {{ r_quay_registry.resources[0].status.configEditorEndpoint }}" - - " Username: quayconfig" - - " Password: {{ r_config_editor_secret.resources[0].data.password | b64decode }}" + - name: Save user data for Quay config editor + agnosticd.core.agnosticd_user_info: + msg: >- + "Red Hat Quay Config is available at {{ r_quay_registry.resources[0].status.configEditorEndpoint }}." + "- Config User: quayconfig." + "- Config Password: {{ r_config_editor_secret.resources[0].data.password | b64decode }}." + data: + quay_config_url: "{{ r_quay_registry.resources[0].status.configEditorEndpoint }}" + quay_config_username: "quayconfig" + quay_config_password: "{{ r_config_editor_secret.resources[0].data.password | b64decode }}" diff --git a/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 b/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 index bb552cb..ba7aef0 100644 --- a/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 +++ b/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 @@ -6,6 +6,7 @@ SUPER_USERS: - {{ ocp4_workload_quay_operator_registry_admin_user }} FEATURE_USER_INITIALIZE: true {% endif %} +{% if ocp4_workload_quay_operator_use_s4_storage | bool %} # S4 Storage Configuration DISTRIBUTED_STORAGE_CONFIG: s4storage: @@ -20,3 +21,4 @@ DISTRIBUTED_STORAGE_CONFIG: DISTRIBUTED_STORAGE_DEFAULT_LOCATIONS: [] DISTRIBUTED_STORAGE_PREFERENCE: - s4storage +{% endif %} diff --git a/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 b/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 index e58cc00..6ed6f49 100644 --- a/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 +++ b/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 @@ -10,7 +10,7 @@ spec: - kind: postgres managed: true - kind: objectstorage - managed: false + managed: {{ 'false' if ocp4_workload_quay_operator_use_s4_storage | bool else 'true' }} - kind: redis managed: true - kind: tls From 3d345a4a3f0846abc2598a6b263dcdd574327e7b Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 17:05:50 +1000 Subject: [PATCH 03/14] Revert changes to ocp4_workload_openshift_gitops role Remove testing changes to GitOps role - restore original agnosticd_user_info. This role is unchanged from main branch. Co-Authored-By: Claude Sonnet 4.5 --- .../tasks/workload.yml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/roles/ocp4_workload_openshift_gitops/tasks/workload.yml b/roles/ocp4_workload_openshift_gitops/tasks/workload.yml index fc0b483..f7d0dc6 100644 --- a/roles/ocp4_workload_openshift_gitops/tasks/workload.yml +++ b/roles/ocp4_workload_openshift_gitops/tasks/workload.yml @@ -89,15 +89,11 @@ ignore_errors: true # yamllint disable rule:line-length -- name: Display OpenShift GitOps information - ansible.builtin.debug: - msg: - - "=========================================" - - "OpenShift GitOps (ArgoCD) Deployment Complete" - - "=========================================" - - "ArgoCD URL: https://openshift-gitops-server-openshift-gitops.{{ _ocp4_workload_openshift_gitops_domain }}" - - "" - - "To get the admin password, run:" - - " oc get secret openshift-gitops-cluster -n openshift-gitops -o jsonpath='{.data.admin\\.password}' | base64 -d" - - "=========================================" +- name: Save AgnosticD User data + block: + - name: Print project information + agnosticd.core.agnosticd_user_info: + msg: "OpenShift GitOps ArgoCD: https://openshift-gitops-server-openshift-gitops.{{ _ocp4_workload_openshift_gitops_domain }}" + data: + openshift_gitops_server: "https://openshift-gitops-server-openshift-gitops.{{ _ocp4_workload_openshift_gitops_domain }}" # yamllint enable rule:line-length From 8cb4fef9407cffb5ffb3e5632b395467aaae30d5 Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 17:20:05 +1000 Subject: [PATCH 04/14] Remove config bundle deletion step Config bundle will always be created fresh during new installations, no need to delete existing secret first. Co-Authored-By: Claude Sonnet 4.5 --- roles/ocp4_workload_quay_operator/tasks/workload.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/roles/ocp4_workload_quay_operator/tasks/workload.yml b/roles/ocp4_workload_quay_operator/tasks/workload.yml index 6bf7918..3b15f73 100644 --- a/roles/ocp4_workload_quay_operator/tasks/workload.yml +++ b/roles/ocp4_workload_quay_operator/tasks/workload.yml @@ -89,16 +89,6 @@ - quay_registry.yaml.j2 # S4 storage flow - new conditional logic - - name: Delete existing config bundle secret to force recreation - when: ocp4_workload_quay_operator_use_s4_storage | bool - kubernetes.core.k8s: - state: absent - api_version: v1 - kind: Secret - name: config-bundle - namespace: "{{ ocp4_workload_quay_operator_registry_namespace }}" - ignore_errors: true - - name: Create Quay Registry Resources (S4 mode) when: ocp4_workload_quay_operator_use_s4_storage | bool kubernetes.core.k8s: From 30bd204c888944be174cfd0502a5f25790380de6 Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 17:28:13 +1000 Subject: [PATCH 05/14] Add agnosticd.core prefix to agnosticd_user_info calls in S4 role Use fully qualified collection name for agnosticd_user_info module calls to ensure proper module resolution. Co-Authored-By: Claude Sonnet 4.5 --- roles/ocp4_workload_s4/tasks/workload.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/ocp4_workload_s4/tasks/workload.yml b/roles/ocp4_workload_s4/tasks/workload.yml index c1734fb..7f69c7f 100644 --- a/roles/ocp4_workload_s4/tasks/workload.yml +++ b/roles/ocp4_workload_s4/tasks/workload.yml @@ -158,13 +158,13 @@ - name: Print S4 information when: item.when | bool - agnosticd_user_info: + agnosticd.core.agnosticd_user_info: msg: "{{ item.msg }}" loop: "{{ _s4_user_info_messages }}" - name: Save S4 data for user when: ocp4_workload_s4_enable_user_info_data | bool - agnosticd_user_info: + agnosticd.core.agnosticd_user_info: data: s4_web_ui_url: "{{ _ocp4_workload_s4_route_url }}" s4_ui_username: "{{ ocp4_workload_s4_auth_username }}" From b995fed3d07c8a95513ebc004f5627a189eb8fa0 Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 17:31:36 +1000 Subject: [PATCH 06/14] Rename variable to ocp4_workload_quay_operator_s4_storage_enabled Renamed from ocp4_workload_quay_operator_use_s4_storage for better naming consistency with other enabled/disabled boolean variables. Updated in: - defaults/main.yml - tasks/workload.yml - templates/config.yaml.j2 - templates/quay_registry.yaml.j2 - readme.adoc Co-Authored-By: Claude Sonnet 4.5 --- roles/ocp4_workload_quay_operator/defaults/main.yml | 4 ++-- roles/ocp4_workload_quay_operator/readme.adoc | 6 +++--- roles/ocp4_workload_quay_operator/tasks/workload.yml | 12 ++++++------ .../templates/config.yaml.j2 | 2 +- .../templates/quay_registry.yaml.j2 | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/roles/ocp4_workload_quay_operator/defaults/main.yml b/roles/ocp4_workload_quay_operator/defaults/main.yml index 7a9ef86..bd63e34 100644 --- a/roles/ocp4_workload_quay_operator/defaults/main.yml +++ b/roles/ocp4_workload_quay_operator/defaults/main.yml @@ -125,12 +125,12 @@ ocp4_workload_quay_operator_registry_startup_probe_failure_threshold: 30 # -------------------------------- # Set to true to use S4 storage, false to use Noobaa (OCS) # Default: false (uses Noobaa/OpenShift Container Storage) -ocp4_workload_quay_operator_use_s4_storage: false +ocp4_workload_quay_operator_s4_storage_enabled: false # -------------------------------- # S3 Storage Configuration (S4) # -------------------------------- -# Only used when ocp4_workload_quay_operator_use_s4_storage: true +# Only used when ocp4_workload_quay_operator_s4_storage_enabled: true # Quay uses S4 storage for object storage backend # S4 S3 endpoint configuration diff --git a/roles/ocp4_workload_quay_operator/readme.adoc b/roles/ocp4_workload_quay_operator/readme.adoc index 4da562d..00d591f 100644 --- a/roles/ocp4_workload_quay_operator/readme.adoc +++ b/roles/ocp4_workload_quay_operator/readme.adoc @@ -60,7 +60,7 @@ workloads: - agnosticd.core_workloads.ocp4_workload_quay_operator # Enable S4 storage backend -ocp4_workload_quay_operator_use_s4_storage: true +ocp4_workload_quay_operator_s4_storage_enabled: true # S4 configuration ocp4_workload_s4_buckets: @@ -79,9 +79,9 @@ ocp4_workload_quay_operator_s4_secret_key: s4secret === S4 Storage Configuration Variables -When using S4 storage (`ocp4_workload_quay_operator_use_s4_storage: true`), these variables control the S3 storage backend: +When using S4 storage (`ocp4_workload_quay_operator_s4_storage_enabled: true`), these variables control the S3 storage backend: -* `ocp4_workload_quay_operator_use_s4_storage`: Enable S4 storage backend (default: `false`) +* `ocp4_workload_quay_operator_s4_storage_enabled`: Enable S4 storage backend (default: `false`) * `ocp4_workload_quay_operator_s4_namespace`: Namespace where S4 is deployed (default: `s4`) * `ocp4_workload_quay_operator_s4_bucket_name`: S3 bucket name for Quay (default: `quay-registry`) * `ocp4_workload_quay_operator_s4_access_key`: S3 access key (default: `s4admin`) diff --git a/roles/ocp4_workload_quay_operator/tasks/workload.yml b/roles/ocp4_workload_quay_operator/tasks/workload.yml index 3b15f73..5fc977b 100644 --- a/roles/ocp4_workload_quay_operator/tasks/workload.yml +++ b/roles/ocp4_workload_quay_operator/tasks/workload.yml @@ -3,7 +3,7 @@ - name: Validate storage backend block: - name: Check S4 service exists - when: ocp4_workload_quay_operator_use_s4_storage | bool + when: ocp4_workload_quay_operator_s4_storage_enabled | bool kubernetes.core.k8s_info: api_version: v1 kind: Service @@ -12,14 +12,14 @@ register: r_s4_service - name: Assert that S4 service exists - when: ocp4_workload_quay_operator_use_s4_storage | bool + when: ocp4_workload_quay_operator_s4_storage_enabled | bool ansible.builtin.assert: that: - r_s4_service.resources | length == 1 fail_msg: "S4 storage service not found in namespace {{ ocp4_workload_quay_operator_s4_namespace }}. Deploy S4 first using ocp4_workload_s4 role." - name: Check Noobaa BucketClass exists - when: not (ocp4_workload_quay_operator_use_s4_storage | bool) + when: not (ocp4_workload_quay_operator_s4_storage_enabled | bool) kubernetes.core.k8s_info: api_version: noobaa.io/v1alpha1 kind: BucketClass @@ -27,7 +27,7 @@ register: r_bucket_class - name: Assert that Noobaa BucketClass exists - when: not (ocp4_workload_quay_operator_use_s4_storage | bool) + when: not (ocp4_workload_quay_operator_s4_storage_enabled | bool) ansible.builtin.assert: that: - r_bucket_class.resources | length == 1 @@ -79,7 +79,7 @@ # Original Noobaa flow - unchanged from main branch - name: Create Quay Registry Resources - when: not (ocp4_workload_quay_operator_use_s4_storage | bool) + when: not (ocp4_workload_quay_operator_s4_storage_enabled | bool) kubernetes.core.k8s: state: present definition: "{{ lookup('template', item ) | from_yaml }}" @@ -90,7 +90,7 @@ # S4 storage flow - new conditional logic - name: Create Quay Registry Resources (S4 mode) - when: ocp4_workload_quay_operator_use_s4_storage | bool + when: ocp4_workload_quay_operator_s4_storage_enabled | bool kubernetes.core.k8s: state: present definition: "{{ lookup('template', item ) | from_yaml }}" diff --git a/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 b/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 index ba7aef0..08800d5 100644 --- a/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 +++ b/roles/ocp4_workload_quay_operator/templates/config.yaml.j2 @@ -6,7 +6,7 @@ SUPER_USERS: - {{ ocp4_workload_quay_operator_registry_admin_user }} FEATURE_USER_INITIALIZE: true {% endif %} -{% if ocp4_workload_quay_operator_use_s4_storage | bool %} +{% if ocp4_workload_quay_operator_s4_storage_enabled | bool %} # S4 Storage Configuration DISTRIBUTED_STORAGE_CONFIG: s4storage: diff --git a/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 b/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 index 6ed6f49..8b246f2 100644 --- a/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 +++ b/roles/ocp4_workload_quay_operator/templates/quay_registry.yaml.j2 @@ -10,7 +10,7 @@ spec: - kind: postgres managed: true - kind: objectstorage - managed: {{ 'false' if ocp4_workload_quay_operator_use_s4_storage | bool else 'true' }} + managed: {{ 'false' if ocp4_workload_quay_operator_s4_storage_enabled | bool else 'true' }} - kind: redis managed: true - kind: tls From 1145af814ad671abda1d85eecd69c0b3bcb48fb4 Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 17:34:25 +1000 Subject: [PATCH 07/14] Remove unused S4 credentials secret and simplify resource creation - Removed s4_credentials_secret.yaml.j2 template (unused) - S4 credentials are embedded directly in config bundle secret via config.yaml.j2 - Consolidated duplicate resource creation tasks into single unconditional task - Both Noobaa and S4 modes now create identical resources (namespace, config, registry) - Storage backend differentiation happens in config.yaml.j2 template based on s4_storage_enabled flag This simplifies the logic and removes unnecessary overhead. Co-Authored-By: Claude Sonnet 4.5 --- .../ocp4_workload_quay_operator/tasks/workload.yml | 14 -------------- .../templates/s4_credentials_secret.yaml.j2 | 10 ---------- 2 files changed, 24 deletions(-) delete mode 100644 roles/ocp4_workload_quay_operator/templates/s4_credentials_secret.yaml.j2 diff --git a/roles/ocp4_workload_quay_operator/tasks/workload.yml b/roles/ocp4_workload_quay_operator/tasks/workload.yml index 5fc977b..cd494dd 100644 --- a/roles/ocp4_workload_quay_operator/tasks/workload.yml +++ b/roles/ocp4_workload_quay_operator/tasks/workload.yml @@ -77,26 +77,12 @@ ansible.builtin.set_fact: _ocp4_workload_quay_operator_registry_route: "{{ ocp4_workload_quay_operator_registry_hostname }}.{{ openshift_cluster_ingress_domain }}" - # Original Noobaa flow - unchanged from main branch - name: Create Quay Registry Resources - when: not (ocp4_workload_quay_operator_s4_storage_enabled | bool) - kubernetes.core.k8s: - state: present - definition: "{{ lookup('template', item ) | from_yaml }}" - loop: - - quay_namespace.yaml.j2 - - config_bundle_secret.yaml.j2 - - quay_registry.yaml.j2 - - # S4 storage flow - new conditional logic - - name: Create Quay Registry Resources (S4 mode) - when: ocp4_workload_quay_operator_s4_storage_enabled | bool kubernetes.core.k8s: state: present definition: "{{ lookup('template', item ) | from_yaml }}" loop: - quay_namespace.yaml.j2 - - s4_credentials_secret.yaml.j2 - config_bundle_secret.yaml.j2 - quay_registry.yaml.j2 diff --git a/roles/ocp4_workload_quay_operator/templates/s4_credentials_secret.yaml.j2 b/roles/ocp4_workload_quay_operator/templates/s4_credentials_secret.yaml.j2 deleted file mode 100644 index ff037fa..0000000 --- a/roles/ocp4_workload_quay_operator/templates/s4_credentials_secret.yaml.j2 +++ /dev/null @@ -1,10 +0,0 @@ ---- -apiVersion: v1 -kind: Secret -metadata: - name: s4-storage-credentials - namespace: {{ ocp4_workload_quay_operator_registry_namespace }} -type: Opaque -stringData: - AWS_ACCESS_KEY_ID: {{ ocp4_workload_quay_operator_s4_access_key }} - AWS_SECRET_ACCESS_KEY: {{ ocp4_workload_quay_operator_s4_secret_key }} From 5355ef9d5d1079cf86f6b2f754cd91f96913097d Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 17:42:17 +1000 Subject: [PATCH 08/14] Update S4 image tag to 0.3.2 and optimize pull policy - Changed image tag from 'latest' to '0.3.2' for version pinning - Changed pull policy from 'Always' to 'IfNotPresent' (best practice for versioned images) - Ensures consistent deployments with specific S4 version Co-Authored-By: Claude Sonnet 4.5 --- roles/ocp4_workload_s4/defaults/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/ocp4_workload_s4/defaults/main.yml b/roles/ocp4_workload_s4/defaults/main.yml index 45a53b7..a289b81 100644 --- a/roles/ocp4_workload_s4/defaults/main.yml +++ b/roles/ocp4_workload_s4/defaults/main.yml @@ -23,8 +23,8 @@ ocp4_workload_s4_chart_path: charts/s4 # -------------------------------------------------- # Image configuration ocp4_workload_s4_image_repository: quay.io/rh-aiservices-bu/s4 -ocp4_workload_s4_image_tag: latest -ocp4_workload_s4_image_pull_policy: Always +ocp4_workload_s4_image_tag: 0.3.2 +ocp4_workload_s4_image_pull_policy: IfNotPresent # S3 credentials ocp4_workload_s4_access_key_id: s4admin From 9c8ea83ee40769a0007b22f97a20f007e91b35ad Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 17:44:49 +1000 Subject: [PATCH 09/14] Update S4 Helm chart revision to v0.3.2 - Changed chart_revision from 'main' to 'v0.3.2' to match image tag - Ensures Helm chart and container image versions are aligned - Provides stable, versioned deployment Co-Authored-By: Claude Sonnet 4.5 --- roles/ocp4_workload_s4/defaults/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/ocp4_workload_s4/defaults/main.yml b/roles/ocp4_workload_s4/defaults/main.yml index a289b81..f74172d 100644 --- a/roles/ocp4_workload_s4/defaults/main.yml +++ b/roles/ocp4_workload_s4/defaults/main.yml @@ -15,7 +15,7 @@ ocp4_workload_s4_gitops_namespace: openshift-gitops # Helm chart configuration ocp4_workload_s4_chart_repo: https://github.com/rh-aiservices-bu/s4 -ocp4_workload_s4_chart_revision: main +ocp4_workload_s4_chart_revision: v0.3.2 ocp4_workload_s4_chart_path: charts/s4 # -------------------------------------------------- From 896a87a34770b075a8d3e3ac904aace17b4d1678 Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 17:48:43 +1000 Subject: [PATCH 10/14] Rename S3 route variable to include 'api' for clarity Renamed ocp4_workload_s4_route_s3_enabled to ocp4_workload_s4_route_s3_api_enabled to make it clear this controls the S3 API route, not just any S3 route. Updated in: - defaults/main.yml - tasks/workload.yml - templates/application.yaml.j2 - readme.adoc Co-Authored-By: Claude Sonnet 4.5 --- roles/ocp4_workload_s4/defaults/main.yml | 2 +- roles/ocp4_workload_s4/readme.adoc | 4 ++-- roles/ocp4_workload_s4/tasks/workload.yml | 6 +++--- roles/ocp4_workload_s4/templates/application.yaml.j2 | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/roles/ocp4_workload_s4/defaults/main.yml b/roles/ocp4_workload_s4/defaults/main.yml index f74172d..b9ca500 100644 --- a/roles/ocp4_workload_s4/defaults/main.yml +++ b/roles/ocp4_workload_s4/defaults/main.yml @@ -76,7 +76,7 @@ ocp4_workload_s4_route_tls_termination: edge ocp4_workload_s4_route_tls_insecure_policy: Redirect # S3 API Route (enabled by default for S3 API access) -ocp4_workload_s4_route_s3_enabled: true +ocp4_workload_s4_route_s3_api_enabled: true ocp4_workload_s4_route_s3_host: "" # Auto-generated if empty # -------------------------------------------------- diff --git a/roles/ocp4_workload_s4/readme.adoc b/roles/ocp4_workload_s4/readme.adoc index 51c2dc0..4862d55 100644 --- a/roles/ocp4_workload_s4/readme.adoc +++ b/roles/ocp4_workload_s4/readme.adoc @@ -80,7 +80,7 @@ Username and password can be passed in as parameters. If not provided, username * `ocp4_workload_s4_route_enabled`: Enable OpenShift Route for UI (default: `true`) * `ocp4_workload_s4_route_host`: Custom hostname (default: auto-generated) * `ocp4_workload_s4_route_tls_termination`: TLS termination (default: `edge`) -* `ocp4_workload_s4_route_s3_enabled`: Enable Route for S3 API (default: `true`) +* `ocp4_workload_s4_route_s3_api_enabled`: Enable Route for S3 API (default: `true`) === Bucket Creation @@ -142,7 +142,7 @@ Username and password can be passed in as parameters. If not provided, username ocp4_workload_s4_storage_data_storage_class: ocs-storagecluster-ceph-rbd ocp4_workload_s4_access_key_id: my-access-key ocp4_workload_s4_secret_access_key: my-secret-key - ocp4_workload_s4_route_s3_enabled: true + ocp4_workload_s4_route_s3_api_enabled: true ocp4_workload_s4_buckets: - production-data ---- diff --git a/roles/ocp4_workload_s4/tasks/workload.yml b/roles/ocp4_workload_s4/tasks/workload.yml index 7f69c7f..2343c4e 100644 --- a/roles/ocp4_workload_s4/tasks/workload.yml +++ b/roles/ocp4_workload_s4/tasks/workload.yml @@ -88,7 +88,7 @@ _ocp4_workload_s4_route_url: "https://{{ r_s4_route.resources[0].spec.host }}" - name: Get S3 API route (if enabled) - when: ocp4_workload_s4_route_s3_enabled | bool + when: ocp4_workload_s4_route_s3_api_enabled | bool kubernetes.core.k8s_info: api_version: route.openshift.io/v1 kind: Route @@ -104,7 +104,7 @@ - name: Set S3 API endpoint URL when: - - ocp4_workload_s4_route_s3_enabled | bool + - ocp4_workload_s4_route_s3_api_enabled | bool - r_s4_api_route.resources | length > 0 ansible.builtin.set_fact: _ocp4_workload_s4_s3_endpoint_external: "https://{{ r_s4_api_route.resources[0].spec.host }}" @@ -152,7 +152,7 @@ - msg: "S3 Endpoint (internal): {{ _ocp4_workload_s4_s3_endpoint_internal }}" when: true - msg: "S3 Endpoint (external): {{ _ocp4_workload_s4_s3_endpoint_external }}" - when: "{{ ocp4_workload_s4_route_s3_enabled | bool and _ocp4_workload_s4_s3_endpoint_external is defined }}" + when: "{{ ocp4_workload_s4_route_s3_api_enabled | bool and _ocp4_workload_s4_s3_endpoint_external is defined }}" - msg: "S3 Buckets Created: {{ ocp4_workload_s4_buckets | join(', ') }}" when: "{{ ocp4_workload_s4_buckets | default([]) | length > 0 }}" diff --git a/roles/ocp4_workload_s4/templates/application.yaml.j2 b/roles/ocp4_workload_s4/templates/application.yaml.j2 index 77d431c..c445cd8 100644 --- a/roles/ocp4_workload_s4/templates/application.yaml.j2 +++ b/roles/ocp4_workload_s4/templates/application.yaml.j2 @@ -92,8 +92,8 @@ spec: # S3 API Route s3Api: - enabled: {{ ocp4_workload_s4_route_s3_enabled | lower }} -{% if ocp4_workload_s4_route_s3_enabled %} + enabled: {{ ocp4_workload_s4_route_s3_api_enabled | lower }} +{% if ocp4_workload_s4_route_s3_api_enabled %} {% if ocp4_workload_s4_route_s3_host | length > 0 %} host: {{ ocp4_workload_s4_route_s3_host }} {% endif %} From c461565a03f1867ad2bd481aa3ddf133499ab1f0 Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 17:54:08 +1000 Subject: [PATCH 11/14] Rename S3 route host variable to include 'api' for consistency Renamed ocp4_workload_s4_route_s3_host to ocp4_workload_s4_route_s3_api_host to match the naming convention of ocp4_workload_s4_route_s3_api_enabled. Updated in: - defaults/main.yml - templates/application.yaml.j2 Co-Authored-By: Claude Sonnet 4.5 --- roles/ocp4_workload_s4/defaults/main.yml | 2 +- roles/ocp4_workload_s4/templates/application.yaml.j2 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/ocp4_workload_s4/defaults/main.yml b/roles/ocp4_workload_s4/defaults/main.yml index b9ca500..10dbf3a 100644 --- a/roles/ocp4_workload_s4/defaults/main.yml +++ b/roles/ocp4_workload_s4/defaults/main.yml @@ -77,7 +77,7 @@ ocp4_workload_s4_route_tls_insecure_policy: Redirect # S3 API Route (enabled by default for S3 API access) ocp4_workload_s4_route_s3_api_enabled: true -ocp4_workload_s4_route_s3_host: "" # Auto-generated if empty +ocp4_workload_s4_route_s3_api_host: "" # Auto-generated if empty # -------------------------------------------------- # Bucket creation configuration diff --git a/roles/ocp4_workload_s4/templates/application.yaml.j2 b/roles/ocp4_workload_s4/templates/application.yaml.j2 index c445cd8..7801f2b 100644 --- a/roles/ocp4_workload_s4/templates/application.yaml.j2 +++ b/roles/ocp4_workload_s4/templates/application.yaml.j2 @@ -94,8 +94,8 @@ spec: s3Api: enabled: {{ ocp4_workload_s4_route_s3_api_enabled | lower }} {% if ocp4_workload_s4_route_s3_api_enabled %} -{% if ocp4_workload_s4_route_s3_host | length > 0 %} - host: {{ ocp4_workload_s4_route_s3_host }} +{% if ocp4_workload_s4_route_s3_api_host | length > 0 %} + host: {{ ocp4_workload_s4_route_s3_api_host }} {% endif %} tls: termination: {{ ocp4_workload_s4_route_tls_termination }} From 030a009cbfc85724859ce06ddc25601b4c7883d2 Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 17:57:30 +1000 Subject: [PATCH 12/14] Rename S3 endpoint variables to include 'api' for consistency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renamed internal variables for clarity: - _ocp4_workload_s4_s3_endpoint_internal → _ocp4_workload_s4_s3_api_endpoint_internal - _ocp4_workload_s4_s3_endpoint_external → _ocp4_workload_s4_s3_api_endpoint_external Also renamed user data output fields: - s4_s3_endpoint_internal → s4_s3_api_endpoint_internal - s4_s3_endpoint_external → s4_s3_api_endpoint_external All S3-related variables now consistently include 'api' in their names. Co-Authored-By: Claude Sonnet 4.5 --- roles/ocp4_workload_s4/tasks/workload.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/roles/ocp4_workload_s4/tasks/workload.yml b/roles/ocp4_workload_s4/tasks/workload.yml index 2343c4e..d73f3fd 100644 --- a/roles/ocp4_workload_s4/tasks/workload.yml +++ b/roles/ocp4_workload_s4/tasks/workload.yml @@ -10,7 +10,7 @@ if ocp4_workload_s4_auth_password | length > 0 else lookup('password', '/dev/null length={{ ocp4_workload_s4_auth_password_length }} chars=ascii_letters,digits') }} _ocp4_workload_s4_route_url: "" - _ocp4_workload_s4_s3_endpoint_internal: "http://s4.{{ ocp4_workload_s4_namespace }}.svc.cluster.local:7480" + _ocp4_workload_s4_s3_api_endpoint_internal: "http://s4.{{ ocp4_workload_s4_namespace }}.svc.cluster.local:7480" - name: Create S4 namespace when: ocp4_workload_s4_namespace_create | bool @@ -107,7 +107,7 @@ - ocp4_workload_s4_route_s3_api_enabled | bool - r_s4_api_route.resources | length > 0 ansible.builtin.set_fact: - _ocp4_workload_s4_s3_endpoint_external: "https://{{ r_s4_api_route.resources[0].spec.host }}" + _ocp4_workload_s4_s3_api_endpoint_external: "https://{{ r_s4_api_route.resources[0].spec.host }}" - name: Create S3 bucket(s) when: ocp4_workload_s4_buckets | default([]) | length > 0 @@ -149,10 +149,10 @@ when: true - msg: "S3 Secret Key: {{ ocp4_workload_s4_secret_access_key }}" when: true - - msg: "S3 Endpoint (internal): {{ _ocp4_workload_s4_s3_endpoint_internal }}" + - msg: "S3 Endpoint (internal): {{ _ocp4_workload_s4_s3_api_endpoint_internal }}" when: true - - msg: "S3 Endpoint (external): {{ _ocp4_workload_s4_s3_endpoint_external }}" - when: "{{ ocp4_workload_s4_route_s3_api_enabled | bool and _ocp4_workload_s4_s3_endpoint_external is defined }}" + - msg: "S3 Endpoint (external): {{ _ocp4_workload_s4_s3_api_endpoint_external }}" + when: "{{ ocp4_workload_s4_route_s3_api_enabled | bool and _ocp4_workload_s4_s3_api_endpoint_external is defined }}" - msg: "S3 Buckets Created: {{ ocp4_workload_s4_buckets | join(', ') }}" when: "{{ ocp4_workload_s4_buckets | default([]) | length > 0 }}" @@ -171,7 +171,7 @@ s4_ui_password: "{{ _ocp4_workload_s4_auth_password }}" s4_s3_access_key_id: "{{ ocp4_workload_s4_access_key_id }}" s4_s3_secret_access_key: "{{ ocp4_workload_s4_secret_access_key }}" - s4_s3_endpoint_internal: "{{ _ocp4_workload_s4_s3_endpoint_internal }}" - s4_s3_endpoint_external: "{{ _ocp4_workload_s4_s3_endpoint_external | default('') }}" + s4_s3_api_endpoint_internal: "{{ _ocp4_workload_s4_s3_api_endpoint_internal }}" + s4_s3_api_endpoint_external: "{{ _ocp4_workload_s4_s3_api_endpoint_external | default('') }}" s4_buckets: "{{ ocp4_workload_s4_buckets | default([]) }}" s4_namespace: "{{ ocp4_workload_s4_namespace }}" From 10b45b0671add0f8b14a90e58a5afb649a67eb13 Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 18:10:38 +1000 Subject: [PATCH 13/14] Hard code wait retry and delay values in S4 role Removed configurable variables and hard-coded values directly: - Application/Deployment waits: 60 retries, 10 second delay - Route waits: 30 retries, 5 second delay (already hard-coded) - Bucket job waits: 30 retries, 5 second delay (already hard-coded) Removed from defaults/main.yml: - ocp4_workload_s4_wait_retries - ocp4_workload_s4_wait_delay Kept ocp4_workload_s4_wait_for_deployment boolean flag to enable/disable waiting. Co-Authored-By: Claude Sonnet 4.5 --- roles/ocp4_workload_s4/defaults/main.yml | 2 -- roles/ocp4_workload_s4/tasks/workload.yml | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/roles/ocp4_workload_s4/defaults/main.yml b/roles/ocp4_workload_s4/defaults/main.yml index 10dbf3a..f0475c3 100644 --- a/roles/ocp4_workload_s4/defaults/main.yml +++ b/roles/ocp4_workload_s4/defaults/main.yml @@ -105,5 +105,3 @@ ocp4_workload_s4_enable_user_info_data: true # Wait for deployment # -------------------------------------------------- ocp4_workload_s4_wait_for_deployment: true -ocp4_workload_s4_wait_retries: 60 -ocp4_workload_s4_wait_delay: 10 diff --git a/roles/ocp4_workload_s4/tasks/workload.yml b/roles/ocp4_workload_s4/tasks/workload.yml index d73f3fd..c0a6d86 100644 --- a/roles/ocp4_workload_s4/tasks/workload.yml +++ b/roles/ocp4_workload_s4/tasks/workload.yml @@ -37,8 +37,8 @@ name: "{{ ocp4_workload_s4_application_name }}" namespace: "{{ ocp4_workload_s4_gitops_namespace }}" register: r_application - retries: "{{ ocp4_workload_s4_wait_retries }}" - delay: "{{ ocp4_workload_s4_wait_delay }}" + retries: 60 + delay: 10 until: - r_application.resources is defined - r_application.resources | length > 0 @@ -56,8 +56,8 @@ name: s4 namespace: "{{ ocp4_workload_s4_namespace }}" register: r_s4_deployment - retries: "{{ ocp4_workload_s4_wait_retries }}" - delay: "{{ ocp4_workload_s4_wait_delay }}" + retries: 60 + delay: 10 until: - r_s4_deployment.resources is defined - r_s4_deployment.resources | length > 0 From 90640038b8b2c2ea3facd665383b94739e2fe024 Mon Sep 17 00:00:00 2001 From: treddy08 Date: Fri, 13 Mar 2026 19:37:25 +1000 Subject: [PATCH 14/14] Remove 'route_' from S3 variable names for simplicity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renamed variables by removing redundant 'route_' prefix: - ocp4_workload_s4_route_s3_api_enabled → ocp4_workload_s4_s3_api_enabled - ocp4_workload_s4_route_s3_api_host → ocp4_workload_s4_s3_api_host These variables already clearly relate to S3 API functionality, so the 'route_' prefix adds unnecessary verbosity. The variables still control route creation for the S3 API. Updated in: - defaults/main.yml - tasks/workload.yml - templates/application.yaml.j2 - readme.adoc Co-Authored-By: Claude Sonnet 4.5 --- roles/ocp4_workload_s4/defaults/main.yml | 4 ++-- roles/ocp4_workload_s4/readme.adoc | 4 ++-- roles/ocp4_workload_s4/tasks/workload.yml | 6 +++--- roles/ocp4_workload_s4/templates/application.yaml.j2 | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/roles/ocp4_workload_s4/defaults/main.yml b/roles/ocp4_workload_s4/defaults/main.yml index f0475c3..914edee 100644 --- a/roles/ocp4_workload_s4/defaults/main.yml +++ b/roles/ocp4_workload_s4/defaults/main.yml @@ -76,8 +76,8 @@ ocp4_workload_s4_route_tls_termination: edge ocp4_workload_s4_route_tls_insecure_policy: Redirect # S3 API Route (enabled by default for S3 API access) -ocp4_workload_s4_route_s3_api_enabled: true -ocp4_workload_s4_route_s3_api_host: "" # Auto-generated if empty +ocp4_workload_s4_s3_api_enabled: true +ocp4_workload_s4_s3_api_host: "" # Auto-generated if empty # -------------------------------------------------- # Bucket creation configuration diff --git a/roles/ocp4_workload_s4/readme.adoc b/roles/ocp4_workload_s4/readme.adoc index 4862d55..54ed711 100644 --- a/roles/ocp4_workload_s4/readme.adoc +++ b/roles/ocp4_workload_s4/readme.adoc @@ -80,7 +80,7 @@ Username and password can be passed in as parameters. If not provided, username * `ocp4_workload_s4_route_enabled`: Enable OpenShift Route for UI (default: `true`) * `ocp4_workload_s4_route_host`: Custom hostname (default: auto-generated) * `ocp4_workload_s4_route_tls_termination`: TLS termination (default: `edge`) -* `ocp4_workload_s4_route_s3_api_enabled`: Enable Route for S3 API (default: `true`) +* `ocp4_workload_s4_s3_api_enabled`: Enable Route for S3 API (default: `true`) === Bucket Creation @@ -142,7 +142,7 @@ Username and password can be passed in as parameters. If not provided, username ocp4_workload_s4_storage_data_storage_class: ocs-storagecluster-ceph-rbd ocp4_workload_s4_access_key_id: my-access-key ocp4_workload_s4_secret_access_key: my-secret-key - ocp4_workload_s4_route_s3_api_enabled: true + ocp4_workload_s4_s3_api_enabled: true ocp4_workload_s4_buckets: - production-data ---- diff --git a/roles/ocp4_workload_s4/tasks/workload.yml b/roles/ocp4_workload_s4/tasks/workload.yml index c0a6d86..58ace22 100644 --- a/roles/ocp4_workload_s4/tasks/workload.yml +++ b/roles/ocp4_workload_s4/tasks/workload.yml @@ -88,7 +88,7 @@ _ocp4_workload_s4_route_url: "https://{{ r_s4_route.resources[0].spec.host }}" - name: Get S3 API route (if enabled) - when: ocp4_workload_s4_route_s3_api_enabled | bool + when: ocp4_workload_s4_s3_api_enabled | bool kubernetes.core.k8s_info: api_version: route.openshift.io/v1 kind: Route @@ -104,7 +104,7 @@ - name: Set S3 API endpoint URL when: - - ocp4_workload_s4_route_s3_api_enabled | bool + - ocp4_workload_s4_s3_api_enabled | bool - r_s4_api_route.resources | length > 0 ansible.builtin.set_fact: _ocp4_workload_s4_s3_api_endpoint_external: "https://{{ r_s4_api_route.resources[0].spec.host }}" @@ -152,7 +152,7 @@ - msg: "S3 Endpoint (internal): {{ _ocp4_workload_s4_s3_api_endpoint_internal }}" when: true - msg: "S3 Endpoint (external): {{ _ocp4_workload_s4_s3_api_endpoint_external }}" - when: "{{ ocp4_workload_s4_route_s3_api_enabled | bool and _ocp4_workload_s4_s3_api_endpoint_external is defined }}" + when: "{{ ocp4_workload_s4_s3_api_enabled | bool and _ocp4_workload_s4_s3_api_endpoint_external is defined }}" - msg: "S3 Buckets Created: {{ ocp4_workload_s4_buckets | join(', ') }}" when: "{{ ocp4_workload_s4_buckets | default([]) | length > 0 }}" diff --git a/roles/ocp4_workload_s4/templates/application.yaml.j2 b/roles/ocp4_workload_s4/templates/application.yaml.j2 index 7801f2b..715e54c 100644 --- a/roles/ocp4_workload_s4/templates/application.yaml.j2 +++ b/roles/ocp4_workload_s4/templates/application.yaml.j2 @@ -92,10 +92,10 @@ spec: # S3 API Route s3Api: - enabled: {{ ocp4_workload_s4_route_s3_api_enabled | lower }} -{% if ocp4_workload_s4_route_s3_api_enabled %} -{% if ocp4_workload_s4_route_s3_api_host | length > 0 %} - host: {{ ocp4_workload_s4_route_s3_api_host }} + enabled: {{ ocp4_workload_s4_s3_api_enabled | lower }} +{% if ocp4_workload_s4_s3_api_enabled %} +{% if ocp4_workload_s4_s3_api_host | length > 0 %} + host: {{ ocp4_workload_s4_s3_api_host }} {% endif %} tls: termination: {{ ocp4_workload_s4_route_tls_termination }}