Skip to content

rhpds/ftl

Repository files navigation

FTL (Finish The Labs)

Automated grading and solving for Red Hat Demo Platform (RHDP) labs.

FTL Image GHCR Image

Architecture

  Laptop                              Bastion Host
  ──────                              ────────────
  export OCP_API_URL=...              export OPENSHIFT_CLUSTER_INGRESS_DOMAIN=...
  grade_lab lab user1 --podman        grade_lab lab user1 --ansible
       │                                   │
       ▼                                   ▼
  ghcr.io/rhpds/ftl               ansible-playbook
  (container)                     (direct)
       │                                   │
       └──────────────┬────────────────────┘
                      ▼
              OCP / AAP APIs

  User passwords auto-discovered from Showroom ConfigMap — no need to set manually.

Quick Start

# OCP-based labs (--podman from laptop)
# User passwords are discovered automatically from the cluster — no PASSWORD needed
export OCP_API_URL="https://api.cluster-xxx.dynamic.redhatworkshops.io:6443"
export OCP_ADMIN_PASSWORD="<admin-password>"
export OPENSHIFT_CLUSTER_INGRESS_DOMAIN="apps.cluster-xxx.dynamic.redhatworkshops.io"

grade_lab <lab-name> user1 --podman    # single user
grade_lab <lab-name> all   --podman    # all users in parallel (load test)
# AAP-based labs (RIPU)
export AAP_HOSTNAME="https://controller-xxx.apps.example.com"
export AAP_PASSWORD="<aap-password>"

grade_lab automating-ripu-with-ansible 1 --podman

Solve then verify:

solve_lab <lab-name> user1 --podman
grade_lab <lab-name> user1 --podman    # expect: SUCCESS 0 Errors

Running Modes

Option 1: Direct podman run (no setup required)

No FTL repo needed — just podman and your cluster credentials:

# See available labs
podman run --rm ghcr.io/rhpds/ftl list

# Show help and auth options
podman run --rm ghcr.io/rhpds/ftl --help

# Grade with username/password
podman run --rm \
    -e OPENSHIFT_API_URL=https://api.cluster-xxxxx.dynamic.redhatworkshops.io:6443 \
    -e OPENSHIFT_USERNAME=admin \
    -e OPENSHIFT_PASSWORD=<admin-password> \
    -e OPENSHIFT_CLUSTER_INGRESS_DOMAIN=apps.cluster-xxxxx.dynamic.redhatworkshops.io \
    -v ~/ftl-reports:/tmp/grading_dir \
    ghcr.io/rhpds/ftl grade mcp-with-openshift user1 1

# Grade with mounted kubeconfig
podman run --rm \
    -v ~/.kube/config:/home/runner/.kube/config:ro \
    -e OPENSHIFT_CLUSTER_INGRESS_DOMAIN=apps.cluster-xxxxx.dynamic.redhatworkshops.io \
    -v ~/ftl-reports:/tmp/grading_dir \
    ghcr.io/rhpds/ftl grade mcp-with-openshift user1 1

# Grade with token
podman run --rm \
    -e OPENSHIFT_API_URL=https://api.cluster-xxxxx.dynamic.redhatworkshops.io:6443 \
    -e OCP_TOKEN=sha256~xxx \
    -e OPENSHIFT_CLUSTER_INGRESS_DOMAIN=apps.cluster-xxxxx.dynamic.redhatworkshops.io \
    -v ~/ftl-reports:/tmp/grading_dir \
    ghcr.io/rhpds/ftl grade mcp-with-openshift user1 1

Reports are saved to ~/ftl-reports/ on your laptop via the -v mount.

Option 2: Wrapper scripts (multi-user + auto credential discovery)

Uses the grade_lab/solve_lab wrapper scripts — handles credential discovery from Showroom ConfigMaps, multi-user parallel grading, and report saving automatically.

# Clone FTL and add to PATH (first time only)
git clone https://github.com/rhpds/ftl.git ~/ftl
echo 'export PATH="$HOME/ftl/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc

# Set credentials — user passwords are auto-discovered from Showroom ConfigMaps
export OCP_API_URL="https://api.cluster-xxx.dynamic.redhatworkshops.io:6443"
export OCP_ADMIN_PASSWORD="<admin-password>"
export OPENSHIFT_CLUSTER_INGRESS_DOMAIN="apps.cluster-xxx.dynamic.redhatworkshops.io"

grade_lab mcp-with-openshift user1 1 --podman

--ansible (Bastion)

Requires ansible-playbook. Runs FTL directly on the bastion host.

# Install FTL (first time only)
git clone https://github.com/rhpds/ftl.git ~/ftl
bash ~/ftl/bin/setup_ftl
echo 'export PATH="$HOME/ftl/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc

export OPENSHIFT_CLUSTER_INGRESS_DOMAIN="apps.cluster-xxx.example.com"
grade_lab mcp-with-openshift user1 1 --ansible

Load Testing

Use all as the user — automatically discovers users from showroom namespaces and runs in parallel:

# All users, single module
grade_lab mcp-with-openshift all 1 --podman

# All users, all modules
grade_lab mcp-with-openshift all --podman

Users are discovered from showroom-*-userN namespaces in the cluster. Each user’s password is read from their showroom-userdata ConfigMap automatically.

Available Labs

Lab Description Modules Checkpoints

mcp-with-openshift

MCP servers, LibreChat, Gitea, LiteMaaS

4

35

ocp4-getting-started

Parksmap, S2I builds, MongoDB, Tekton pipelines

3

30

automating-ripu-with-ansible

RHEL in-place upgrades via AAP 2.6

3

57

Each lab README has the exact export + grade_lab/solve_lab commands for that specific lab.

Environment Variables

Variable Description Required for

OCP_API_URL

OCP API URL — used to discover user credentials from cluster

--podman, OCP labs

OCP_ADMIN_PASSWORD

OCP admin password — only for credential discovery

--podman, OCP labs

OPENSHIFT_CLUSTER_INGRESS_DOMAIN

OCP cluster apps domain

OCP labs

PASSWORD

User password — auto-discovered from Showroom ConfigMap when OCP_API_URL is set. Only set manually for bastion (--ansible) mode.

Bastion only

LAB_USER

Student username (auto-set from arg)

Auto

AAP_HOSTNAME

AAP Controller URL

RIPU

AAP_PASSWORD

AAP password

RIPU

AAP_USERNAME

AAP username (default: lab-user)

RIPU

GITEA_ADMIN_USER

Gitea admin username — auto-discovered from Showroom ConfigMap

Override only

GITEA_ADMIN_PASSWORD

Gitea admin password — auto-discovered from Showroom ConfigMap

Override only

FTL_IMAGE

Override container image (default: ghcr.io/rhpds/ftl:latest)

Dev only

FTL_REPORT_DIR

Local directory for grading reports (default: ~/ftl-reports)

--podman only

Developer Guide

Creating a New Lab

cp -r labs/lab-template labs/my-new-lab
# Edit grade_module_01.yml and solve_module_01.yml
grade_lab my-new-lab student 1 --podman

Key Rules

  • Use kubernetes.core.k8s_info — never oc CLI (crashes on arm64 emulation)

  • Provide full Deployment spec on creation — partial patches fail if object doesn’t exist

  • For S2I: create ImageStream BEFORE BuildConfig

See Grader Roles Reference for full details.

Container Image

Based on ubi9/ubi-minimal with multi-arch oc client support (amd64 + arm64).

What’s baked in: Generic grader/solver roles (roles/), plugins, ansible config.

What’s cloned at runtime: Lab content (labs/) — no image rebuild needed when graders change.

Primary registry: ghcr.io/rhpds/ftl — also mirrored to quay.io/rhpds/ftl.

Images are tagged with both latest and a date tag (e.g. 2026-02-25) on every release.

# Build and push to both registries with latest + date tag
DATE_TAG=$(date +%Y-%m-%d)
podman build -t ghcr.io/rhpds/ftl:latest  -t ghcr.io/rhpds/ftl:${DATE_TAG} \
             -t quay.io/rhpds/ftl:latest  -t quay.io/rhpds/ftl:${DATE_TAG} .

podman push ghcr.io/rhpds/ftl:latest
podman push ghcr.io/rhpds/ftl:${DATE_TAG}
podman push quay.io/rhpds/ftl:latest
podman push quay.io/rhpds/ftl:${DATE_TAG}

# Test with local labs (no push needed)
grade_lab <lab> user1 1 --podman --local

# Pin to a specific date tag
FTL_IMAGE=ghcr.io/rhpds/ftl:2026-02-25 grade_lab <lab> user1 --podman

License

Apache-2.0

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors