OCP Sandbox API Pattern
Complete developer reference — Sandbox API manages namespaces and RHSSO users per order
How It Works
For every order, Sandbox API:
- Selects a cluster from the pool (same as Scheduler-Only)
- Creates one OCP namespace per entry in your
sandboxes:list — the namespace name is generated from the catalog name, the entry suffix, and the order GUID - Creates an RHSSO user account (
sandbox_username) with a generated password (sandbox_password) — requireskeycloak: "yes"incloud_selector. Sandbox API supports RHSSO only, not RHBK. - Grants the user edit access to the primary namespace
- Applies resource quota to each namespace based on your AgV quota variables
- Injects all the sandbox variables (namespace names, user credentials, cluster URLs, SA token) into the AgnosticD run
- On destroy: deletes the namespaces (and all in-namespace resources) and the RHSSO user account
Your Ansible roles then deploy lab content directly into the ready-made namespaces. You do not need a ocp4_workload_tenant_namespace role — that work has already been done.
When to Use This Pattern
Choose the OCP Sandbox API pattern when your lab meets most of these criteria:
Good fit
- Each order gets its own isolated namespace(s)
- You want Sandbox API to own namespace and user lifecycle
- Your lab deploys into namespaces (not cluster-wide resources)
- No shared cluster services required (no dedicated Keycloak/Gitea instance)
- RHSSO authentication is sufficient — Sandbox API creates an RHSSO user when
keycloak: "yes"is incloud_selector - You prefer simpler AgV configuration with fewer roles
- Single-team or single-namespace lab topology
- Short or medium duration labs where cluster lifecycle is straightforward
Poor fit — use Scheduler-Only instead
- Multiple tenants sharing one cluster with complex isolation requirements
- Need RHBK (Red Hat Build of Keycloak) — Sandbox API only supports RHSSO, not RHBK
- Need per-tenant Gitea org and repo mirroring
- Need ArgoCD GitOps managing tenant workloads
- Need 5+ namespaces per tenant with custom naming
- Cluster-wide resources that must be managed per-tenant
Simpler operation, less flexibility
The OCP Sandbox API pattern requires fewer Ansible roles and less AgV configuration. The tradeoff is that you get what Sandbox API creates — RHSSO users (not RHBK), standard namespace names, and basic quota. If you need RHBK or custom namespace topology, use Scheduler-Only instead.
How does Sandbox API pick a cluster? How do I get the API URL and token?
Your
Full explanation with variable reference →
cloud_selector tags are matched against cluster annotations in the Sandbox API pool database. All matching clusters with available capacity are eligible — one is picked at random. After selection, sandbox_openshift_api_url, sandbox_openshift_ingress_domain, sandbox_openshift_console_url, and cluster_admin_agnosticd_sa_token are injected automatically — along with the namespace and RHSSO user if configured.
Full explanation with variable reference →
Complete AgV common.yaml — Annotated
The following is a complete, production-ready common.yaml for the OCP Sandbox API pattern. It shows a two-namespace setup (primary user namespace + secondary tools namespace) with Showroom. Adapt the role names and variables for your specific catalog item.
Namespace naming convention
Namespace names are generated by the Sandbox API as
sandbox-{guid}-{namespace_suffix}. For example, with namespace_suffix: user and GUID abc12, the namespace will be sandbox-abc12-user. This is the value provided as sandbox_openshift_namespace in Ansible. For a second entry with var: sandbox_tools, the namespace is sandbox-abc12-tools, available as sandbox_tools_namespace.
---
# ============================================================
# AgnosticV — common.yaml
# Pattern: OCP Sandbox API
# Sandbox API creates namespaces AND an RHSSO user per order.
# Simpler for labs that deploy into sandbox-managed namespaces.
# ============================================================
# ── 1. INCLUDES ──────────────────────────────────────────────
#include /includes/agd-v2-mapping.yaml
#include /includes/sandbox-api.yaml
#include /includes/catalog-icon-openshift.yaml
#include /includes/terms-of-service.yaml
#include /includes/parameters/purpose.yaml
#include /includes/parameters/salesforce-id.yaml
# ── 2. MANDATORY VARS ────────────────────────────────────────
# cloud_provider: none — uses pre-provisioned OCP cluster from sandbox pool.
# config: namespace — AgnosticD namespace config runs workloads on provision
# and remove_workloads in order on destroy.
cloud_provider: none
config: namespace
# ── 3. COLLECTIONS ───────────────────────────────────────────
requirements_content:
collections:
- name: https://github.com/agnosticd/namespaced_workloads.git
type: git
version: main
- name: https://github.com/agnosticd/core_workloads.git
type: git
version: main
# ── 4. WORKLOAD ORDER ────────────────────────────────────────
# Sandbox API has already created the namespaces and RHSSO user.
# Your roles just deploy lab content into the ready-made namespaces.
workloads:
- my_collection.ocp4_workload_my_lab_setup # Deploy your lab resources
- agnosticd.showroom.ocp4_workload_showroom # Showroom tab UI (optional)
# ── 5. DESTROY ORDER ─────────────────────────────────────────
# Sandbox API automatically deletes the namespaces and RHSSO user.
# Only list roles that created resources OUTSIDE namespaces.
# In-namespace resources are cleaned up when the namespace is deleted.
remove_workloads:
- agnosticd.showroom.ocp4_workload_showroom
- my_collection.ocp4_workload_my_lab_setup
# ── 6. ROLE CONFIGURATION ────────────────────────────────────
# Use sandbox-provided variables directly — no tenant_* roles needed.
# sandbox_openshift_namespace = primary namespace created by Sandbox API
# sandbox_username = RHSSO username (provided when keycloak: yes)
# sandbox_password = RHSSO user password from RHDP vault
my_lab_setup_namespace: "{{ sandbox_openshift_namespace }}"
my_lab_setup_username: "{{ sandbox_username }}"
my_lab_setup_password: "{{ sandbox_password }}"
my_lab_setup_api_url: "{{ sandbox_openshift_api_url }}"
my_lab_setup_ingress_domain: "{{ sandbox_openshift_ingress_domain }}"
# Secondary namespace — only if you declared a second entry in sandboxes below
# Var name: sandbox_openshift_{alias}_namespace
my_lab_setup_tools_namespace: "{{ sandbox_openshift_tools_namespace }}"
# ── 7. SHOWROOM ──────────────────────────────────────────────
ocp4_workload_showroom_content_git_repo: https://github.com/myorg/my-lab-showroom
ocp4_workload_showroom_content_git_repo_ref: main
ocp4_workload_showroom_namespace: "showroom-{{ guid }}"
ocp4_workload_showroom_openshift_api_url: "{{ sandbox_openshift_api_url }}"
ocp4_workload_showroom_openshift_api_token: "{{ cluster_admin_agnosticd_sa_token }}"
# ── 8. METADATA (__meta__) ───────────────────────────────────
# The sandboxes: entry MUST be under __meta__ — not at top level.
#
# namespace_suffix: determines the namespace name.
# Format: <catalog-item-dir>-<suffix>-<guid>
# e.g. mylab-user-abc12, mylab-tools-abc12
#
# keycloak: "yes" → Sandbox API creates an RHSSO user (sandbox_username/password).
# Only valid on clusters with RHSSO installed. NOT compatible with RHBK.
# Omit this tag if you do not need a user (namespace-only orders).
#
# cloud_selector tags must match a cluster in the Sandbox API pool.
__meta__:
asset_uuid: your-asset-uuid-here
owners:
maintainer:
- name: Your Name
email: you@redhat.com
deployer:
scm_url: https://github.com/agnosticd/agnosticd-v2
scm_ref: main
execution_environment:
image: quay.io/agnosticd/ee-multicloud:chained-2025-12-17
pull: missing
catalog:
namespace: "babylon-catalog-{{ stage | default('?') }}"
display_name: "My Lab (Shared Cluster)"
category: Workshops
multiuser: false
reportingLabels:
primaryBU: Hybrid_Platforms
sandbox_api:
actions:
destroy: {}
sandboxes:
# ── PRIMARY NAMESPACE ───────────────────────────────────────
# alias: primary — gives this entry a name so the second entry
# can reference it with cluster_condition: same('primary').
# Without alias, you cannot express same-cluster constraints.
#
# namespace_suffix: user — Sandbox API creates namespace named:
# sandbox-{guid}-user e.g. sandbox-abc12-user
# This becomes: sandbox_openshift_namespace in Ansible.
#
# keycloak: "yes" — Sandbox API creates an RHSSO user named
# sandbox-{guid} with a generated password.
# Variables: sandbox_username, sandbox_password
- kind: OcpSandbox
alias: primary
namespace_suffix: user
cloud_selector:
cloud: cnv-dedicated-shared
demo: my-lab
purpose: prod
keycloak: "yes"
quota:
limits.cpu: "10"
requests.cpu: "10"
limits.memory: 20Gi
requests.memory: 20Gi
requests.storage: 100Gi
# ── SECOND NAMESPACE (same cluster) ─────────────────────────
# alias: tools — name for this entry (for future cluster_condition refs).
#
# cluster_condition: same('primary') — CRITICAL.
# This tells the Sandbox API scheduler that this namespace MUST
# land on the SAME cluster as the entry with alias 'primary'.
# Without this, the scheduler is free to pick any available cluster
# — your two namespaces could end up on different clusters.
# DSL options: same('alias'), different('alias'), child('alias')
#
# var: sandbox_tools — sets the Ansible variable prefix for this entry.
# Without var, the second sandbox uses a generated prefix.
# With var: sandbox_tools, you get: sandbox_tools_namespace,
# sandbox_tools_openshift_api_url, etc.
#
# No keycloak: yes — the RHSSO user was already created by the
# primary entry. Adding it again on the same cluster would fail.
- kind: OcpSandbox
alias: tools
var: sandbox_tools
namespace_suffix: tools
cluster_condition: same('primary')
cloud_selector:
cloud: cnv-dedicated-shared
demo: my-lab
purpose: prod
quota:
limits.cpu: "4"
requests.cpu: "4"
limits.memory: 8Gi
requests.memory: 8Gi
Section-by-section breakdown
| Section | Key variable(s) | What it does / Why it matters |
|---|---|---|
| 1. sandboxes | sandboxes[].namesandboxes[].namespace_suffix |
Each entry causes Sandbox API to create one namespace. The name field is used to derive the variable prefix for that namespace (e.g., name: tools → sandbox_openshift_tools_namespace). The first entry's namespace is always sandbox_openshift_namespace (no name prefix). You can have 1–5 entries depending on your lab topology. |
| 2. workloads | workloads: |
Only your lab-specific roles and Showroom. You do not need ocp4_workload_tenant_namespace, ocp4_workload_tenant_keycloak_user, or ocp4_workload_tenant_gitea — Sandbox API handled those concerns. |
| 3. Role configuration | my_lab_setup_* |
Map sandbox-provided variables to your role's expected variable names. Your role should define what variable names it expects — this section maps sandbox vars to those names. Keeps your role reusable across different provisioning patterns. |
| 4. Quota | quota_requests_cpuquota_requests_memoryquota_limits_cpuquota_limits_memoryquota_pods |
Sandbox API reads these standard quota vars and applies a ResourceQuota to each namespace it creates. Set these conservatively — over-allocation wastes cluster capacity and can prevent other orders from being scheduled. |
| 5. Showroom | showroom_user_data |
Pass sandbox-provided values into Showroom tab configuration. The username, password, and console_url are injected directly from sandbox vars — no derivation needed. |
| 6. remove_workloads | remove_workloads: |
Only list roles that created resources outside of namespaces, or that need explicit cleanup before namespace deletion. Sandbox API automatically deletes the namespaces and RHSSO user — you do not need to handle those. Keep this list short. |