Squash Orchestrator¶
Squash Orchestrator is the distributed execution component of the Squash stack. It receives jobs from Squash TM (signed JWT RS512), routes them via SSH to the test runner, collects results, and returns them to Squash TM for aggregation into campaigns.
Source of truth
This page is drawn from the perfshop-orchestrator block of the compose files and the four bind-mounted YAML configuration files: squash-orchestrator/pools.yaml, sshee.yaml, arranger.yaml, squashtf.yaml.
Architecture — OpenTestFactory¶
Squash Orchestrator is a reference implementation of the OpenTestFactory (OTF) framework developed by Squashtest and Henix. The framework is modular: several "services" (eventbus, sshee, arranger, workflow) communicate with each other through an internal event bus, and each service has its own configuration.
flowchart LR
STM["perfshop-testmgmt<br/>(Squash TM)"]
subgraph ORCH["perfshop-orchestrator"]
direction TB
EB(["eventbus"])
AR["arranger<br/>(receives HTTP jobs)"]
WF["workflow<br/>(runs the step sequence)"]
SSHEE["sshee<br/>(SSH executor engine)"]
AR --> EB
WF --> EB
SSHEE --> EB
EB --> WF
EB --> SSHEE
end
TR["perfshop-test-runner<br/>(OpenSSH server)"]
STM -->|"POST /jobs<br/>JWT RS512"| AR
SSHEE -->|"SSH :22<br/>user=root password=perfshop"| TR
The perfshop-orchestrator service¶
perfshop-orchestrator:
image: squashtest/squash-orchestrator:latest
container_name: perfshop-orchestrator
depends_on:
perfshop-testmgmt:
condition: service_healthy
perfshop-test-runner:
condition: service_started
environment:
- SQUASH_JWT_SECRET=${SQUASH_JWT_SECRET}
- SQUASH_TM_URL=http://perfshop-testmgmt:8080/squash
- SQUASH_TM_USER=${SQUASH_ADMIN_LOGIN:-admin}
- SQUASH_TM_PASSWORD=${SQUASH_ADMIN_PASSWORD:-Squash2026*}
volumes:
- ./squash-orchestrator/pools.yaml:/etc/squashtf/pools.yaml:ro
- ./squash-orchestrator/sshee.yaml:/etc/squashtf/sshee.yaml:ro
- ./squash-orchestrator/arranger.yaml:/etc/squashtf/arranger.yaml:ro
- ./squash-orchestrator/squashtf.yaml:/etc/squashtf/squashtf.yaml:ro
- ./squash-seed/trusted_key.pub:/etc/squashtf/trusted_key.pub:ro
Environment variables¶
| Variable | Role |
|---|---|
SQUASH_JWT_SECRET |
Same secret as perfshop-testmgmt — used to verify JWTs signed by Squash TM |
SQUASH_TM_URL |
Internal URL of Squash TM (for result callbacks) |
SQUASH_TM_USER / _PASSWORD |
Account used to post results back to Squash TM |
The four YAML files¶
pools.yaml — execution pool definition¶
pools:
default:
- host: perfshop-test-runner
port: 22
username: root
password: perfshop
tags:
- linux
- robotframework
namespaces: "default"
A single pool is defined, named default, containing a single target: perfshop-test-runner on SSH port 22 with user root and password perfshop.
| Field | Value | Effect |
|---|---|---|
host |
perfshop-test-runner |
Internal Docker DNS |
port |
22 |
Standard SSH port of the test runner container |
username: root / password: perfshop |
— | Credentials defined in the test runner Dockerfile |
tags |
[linux, robotframework] |
Routing tags — a job declaring runs-on: robotframework will be routed to this pool |
namespaces: "default" |
— | Forces registration in the "default" namespace that the Java agentchannel uses to route workflows |
SSH password authentication
The test runner accepts SSH authentication by password (hard-coded in the Dockerfile). This is acceptable because the container is not exposed externally (port 22 only on the internal Docker network), but would not be suitable for public exposure. The Dockerfile documents this explicitly: "Root access with password 'perfshop' — pedagogical use only".
sshee.yaml — SSH Executor Engine¶
apiVersion: opentestfactory.org/v1alpha1
kind: SSHServiceConfig
current-context: default
contexts:
- context:
port: 443
host: 127.0.0.1
ssl_context: adhoc
logfile: sshee.log
eventbus:
endpoint: https://127.0.0.1:38368
token: reuse
targets: [default]
name: default
- context:
port: 7786
host: 127.0.0.1
ssl_context: disabled
trusted_authorities:
- /etc/squashtf/*
logfile: sshee.log
enable_insecure_login: true
eventbus:
endpoint: http://127.0.0.1:38368
token: reuse
targets: [default]
name: allinone
- context:
port: 9365
host: 127.0.0.1
ssl_context: disabled
# ...
name: insecure
Three contexts are declared:
| Context | Port | SSL | Usage |
|---|---|---|---|
default |
443 | adhoc (self-signed certificate generated at startup) |
Primary mode, HTTPS self-signed on eventbus https://127.0.0.1:38368 |
allinone |
7786 | disabled |
"All-in-one" mode where eventbus, arranger, and sshee run in the same process with SSL disabled; trusted_authorities reads the public key from /etc/squashtf/* |
insecure |
9365 | disabled |
Explicit insecure mode, for debugging |
The connection between sshee and the internal eventbus goes through local HTTP (127.0.0.1) — this is intra-container loopback, not the Docker network. All OpenTestFactory sub-services run in the same container.
arranger.yaml — job scheduler¶
apiVersion: opentestfactory.org/v1beta2
kind: ServiceConfig
current-context: default
contexts:
- context:
port: 443
host: 127.0.0.1
ssl_context: adhoc
logfile: arranger.log
eventbus:
endpoint: https://127.0.0.1:38368
token: reuse
max_jobs: 1024
max_job_steps: 10240
max_workers: 4
default_timeout_minutes: 360
name: default
# ... similar allinone and insecure contexts
The arranger is the HTTP frontend that receives jobs from Squash TM. It exposes the API that accepts POST /jobs requests and places them onto the internal eventbus for processing by the workflow engine.
| Parameter | Value | Effect |
|---|---|---|
max_jobs |
1024 | Cap on the number of jobs simultaneously pending |
max_job_steps |
10240 | Cap on the total number of steps in a job |
max_workers |
4 | Number of concurrent workers dequeuing jobs |
default_timeout_minutes |
360 (6 hours) | Default timeout per job |
pending_timeout_minutes (allinone context) |
5 | Cap on the wait time before execution |
squashtf.yaml — workflow engine configuration¶
eventbus: python3 -m opentf.core.eventbus
services:
- ${{ CORE }}/core
- ${{ CORE }}/qualitygate
plugins:
- ${{ CORE }}/plugins
- /app/plugins
- ${{ CORE }}/../squash/orchestrator
- /app/tm-connector
aggregated:
- actionprovider
- cucumber
- cypress
- robotframework
- junit
- postman
- skf
- soapui
- playwright
disabled:
- HelloWorld
- localpublisher
- dummygenerator
- agentchannel
This is the manifest of the workflow engine that ties all plugins together.
9 aggregated plugins¶
| Plugin | Usage |
|---|---|
actionprovider |
Base plugin exposing unit actions |
cucumber |
Cucumber BDD tests |
cypress |
Cypress E2E tests |
robotframework |
Robot Framework tests — the main plugin used by PerfShop |
junit |
JUnit tests |
postman |
Postman/Newman tests |
skf |
Squash Keyword Framework (keyword-driven tests) |
soapui |
SoapUI tests |
playwright |
Playwright E2E tests |
All plugins are present in the official image — PerfShop does not curate them, this is the vendor's standard configuration. Students can therefore experiment with any of them without reconfiguration.
4 disabled plugins¶
| Disabled plugin | Why? |
|---|---|
HelloWorld |
Example plugin with no value |
localpublisher |
Local publisher, replaced by the Squash TM connection |
dummygenerator |
Fake data generator, useless |
agentchannel |
CRITICAL — the Java agentchannel answers "not found" before sshee and cancels the workflow. Documented at the top of the file. Without this disable, no job executes. |
agentchannel disabled — real-world case
The comment at the top of squashtf.yaml is explicit: "agentchannel disabled: it answers 'not found' before sshee and cancels the workflow. sshee handles SSH channels directly via sshee.yaml". This is an interesting pedagogical discovery — it shows how a bad dispatch order in an event bus can silently block an entire system, and how explicitly disabling the offender fixes the problem.
The JWT RS512 job format¶
Squash TM signs its jobs in RS512 (RSA SHA-512) with the private key trusted_key.pem (stored in the Squash TM container); the orchestrator verifies with trusted_key.pub (bind-mounted at /etc/squashtf/trusted_key.pub).
sequenceDiagram
autonumber
participant STM as Squash TM
participant AR as orchestrator<br/>arranger
participant SSHEE as orchestrator<br/>sshee
participant TR as perfshop-test-runner
STM->>STM: Generates jobspec<br/>(script, repo, commit, env vars)
STM->>STM: Signs with trusted_key.pem<br/>(RS512)
STM->>AR: POST /jobs<br/>Authorization: Bearer <JWT>
AR->>AR: Verifies JWT with trusted_key.pub
alt Invalid JWT
AR-->>STM: 401 Unauthorized
else Valid JWT
AR->>AR: Places on eventbus (pending)
AR-->>STM: 200 Accepted, job_id=...
end
AR->>SSHEE: Dispatch job (pool=default)
SSHEE->>TR: SSH root@perfshop-test-runner<br/>(password perfshop)
SSHEE->>TR: SCP script.robot
SSHEE->>TR: Exec robot script.robot
TR-->>SSHEE: Exit code + stdout/stderr
SSHEE->>AR: Result (through eventbus)
AR->>STM: POST /squash/api/rest/executions/...<br/>{status:PASS|FAIL, log:...}
Key points:
- Mutual authentication: Squash TM proves its identity with its private key, the orchestrator verifies with the public key. Without this bind-mounted public key, no job can be accepted.
- SSH channel: once the job is accepted, the orchestrator opens a real SSH connection to the test runner (no event bus, no external queue). It's simple and robust.
- Result return: the orchestrator uses
SQUASH_TM_URL+SQUASH_TM_USER/PASSWORDto post results back to the Squash TM REST API.
Startup order¶
The orchestrator depends on two services:
flowchart LR
STM[("perfshop-testmgmt<br/>healthy")] --> ORCH
TR[("perfshop-test-runner<br/>started")] --> ORCH
ORCH["perfshop-orchestrator<br/>(starts)"]
perfshop-testmgmt: service_healthy— to be able to post results backperfshop-test-runner: service_started— the orchestrator does not wait for any particular healthcheck of the runner (it will open an SSH connection to it when needed)
Volumes¶
| Volume | Mount point | Content |
|---|---|---|
./squash-orchestrator/pools.yaml (bind RO) |
/etc/squashtf/pools.yaml |
SSH pool definitions |
./squash-orchestrator/sshee.yaml (bind RO) |
/etc/squashtf/sshee.yaml |
SSH executor engine contexts |
./squash-orchestrator/arranger.yaml (bind RO) |
/etc/squashtf/arranger.yaml |
Arranger configuration (max_jobs, max_workers) |
./squash-orchestrator/squashtf.yaml (bind RO) |
/etc/squashtf/squashtf.yaml |
Workflow engine manifest (plugins) |
./squash-seed/trusted_key.pub (bind RO) |
/etc/squashtf/trusted_key.pub |
RSA public key for verifying JWTs |
Ports¶
The perfshop-orchestrator service exposes no port to the host — it is only reachable from the internal Docker network. HTTPS port 443 (arranger) and HTTP port 38368 (internal eventbus) are intra-container loopback.
Going further¶
- Squash TM — emitter of JWT jobs
- Test Runner — SSH target of jobs
- QA Stack — Overview — complete workflow