OCP Sandbox API Pattern

Complete developer reference — Sandbox API manages namespaces and RHSSO users per order

How It Works

For every order, Sandbox API:

  1. Selects a cluster from the pool (same as Scheduler-Only)
  2. 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
  3. Creates an RHSSO user account (sandbox_username) with a generated password (sandbox_password) — requires keycloak: "yes" in cloud_selector. Sandbox API supports RHSSO only, not RHBK.
  4. Grants the user edit access to the primary namespace
  5. Applies resource quota to each namespace based on your AgV quota variables
  6. Injects all the sandbox variables (namespace names, user credentials, cluster URLs, SA token) into the AgnosticD run
  7. 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.

SANDBOX API Runs per ORDER — does more in this pattern Schedule cluster from pool Create namespace(s) per sandboxes: entry Create RHSSO user (if keycloak: yes) Apply ResourceQuota + inject all vars On destroy: deletes namespaces + RHSSO user AGNOSTICD ROLES Configured via AgV common.yaml Namespaces already exist — no tenant_namespace role needed RHSSO user already exists — use sandbox_username / sandbox_password Your roles: deploy lab content into sandbox namespaces Showroom (optional): use sandbox vars for tab URLs Only destroy non-namespace resources in remove_workloads

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 in cloud_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 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[].name
sandboxes[].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: toolssandbox_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_cpu
quota_requests_memory
quota_limits_cpu
quota_limits_memory
quota_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.

← Previous: Scheduler-Only — Mistakes Next: OCP Sandbox API — Reference →