Advanced CI integration
This page covers CI options beyond one job on one assembly: how an assembly is chosen when a job starts, how to test on several assemblies at once, and how to book an assembly from a job that does not use the vHaaS runner.
If you are new to running pipelines on vHaaS, start with Basic CI Integration.
Choosing an approach
The vHaaS runner books the assembly, runs your script on its VM, and releases it afterwards — all automatically. In exchange, your script must run on that VM, in PowerShell. Use it for test suites that run on the VM with hardware access.
The vHaaS API does none of this for you: your job books, connects, and releases explicitly. In exchange, the job can run anywhere and do anything. Use it to orchestrate several assemblies, to drive vHaaS from a CI system other than GitLab, or when a session must outlive a single job.
Advanced options on the vHaaS runner
These options assume a working basic CI integration, with a vHaaS Access Token stored as the
masked CI/CD variable VEHAAS_TOKEN, your organization ID stored as VEHAAS_ORGANIZATION_ID,
and access to every assembly you reference.
Assembly selection
ASSEMBLY_REF takes a single assembly reference or a comma-separated list.
Candidate lists
A list is a fallback list, not a fan-out. vHaaS books one assembly from the candidates and your job runs on that one:
hardware-test:
tags:
- vHaaS
variables:
ASSEMBLY_REF: "ASSEMBLY-1004, ASSEMBLY-1005, ASSEMBLY-1006"
SESSION_DURATION: 30
SESSION_TIMEOUT: 15
script:
- python -m pytest tests/
Whitespace around the commas is ignored. The order is an order of preference: vHaaS tries each
reference in turn and books the first one it can. SESSION_TIMEOUT bounds how long the job
waits before failing.
Use a candidate list when your tests run equally well on any of several assemblies. To run on all of them, see Parallel test runs.
Identifying the allocated assembly
Inside the job, $env:ASSEMBLY_REF still holds the list you passed in — not the assembly you
were given. Read the allocated reference from the session instead:
$headers = @{ "private-token" = $env:VEHAAS_TOKEN }
$uri = "https://vhaas.vector.cloud/api/v3/organizations/$env:VEHAAS_ORGANIZATION_ID/assembly-sessions/$env:SESSION_ID"
$session = Invoke-RestMethod -Uri $uri -Headers $headers
Write-Host "Running on $($session.assembly_ref)"
Do this whenever your tests need to know which hardware they are talking to — for example to load a per-assembly configuration file.
The runner exposes the booked VM to the job through SESSION_ID, VM_HOSTNAME, VM_IP,
VM_USERNAME, VM_PASSWORD and more — see the
job environment reference for the
full list.
Do not print VM_PASSWORD
Job logs are visible to everyone who can view the pipeline. Never echo the password or pass it on a command line.
Parallel test runs on multiple assemblies
To test on several assemblies at the same time, use GitLab's
parallel:matrix with one
assembly per entry. Each generated job books its own session:
hardware-test:
tags:
- vHaaS
parallel:
matrix:
- ASSEMBLY_REF: ["ASSEMBLY-1004", "ASSEMBLY-1005", "ASSEMBLY-1006"]
variables:
SESSION_DURATION: 30
SESSION_TIMEOUT: 15
script:
- Write-Host "Session $env:SESSION_ID on $env:VM_HOSTNAME"
- python -m pytest tests/ --junit-xml=report.xml
artifacts:
name: "report-$ASSEMBLY_REF"
when: always
paths:
- report.xml
reports:
junit: report.xml
This is the difference from a candidate list: a list books one of the assemblies, a matrix books all of them.
Keep in mind:
- Each job books separately. If one assembly stays busy past its
SESSION_TIMEOUT, that job fails while the others pass. SESSION_DURATIONandSESSION_TIMEOUTapply per job, not to the matrix as a whole.- The number of vHaaS jobs running at the same time is limited by the runner's capacity. A large matrix queues rather than failing. Contact support if you need more parallel capacity.
Naming artifacts per assembly, as above, keeps the results distinguishable when the matrix jobs finish.
Troubleshooting
| Symptom | Likely cause | Solution |
|---|---|---|
Error: SESSION_DURATION is not set or empty, or the same for SESSION_TIMEOUT or ASSEMBLY_REF |
The variable is missing from the job | Define all three, in variables: or as CI/CD variables |
Error: VEHAAS_TOKEN is not set |
The CI/CD variable has a different name | The variable must be named exactly VEHAAS_TOKEN |
Error: this veHaaS deployment requires VEHAAS_ORGANIZATION_ID. |
Without it the runner falls back to an API version the cloud does not serve | Add VEHAAS_ORGANIZATION_ID as a CI/CD variable |
No virtual machines found for assembly with reference ... |
The assembly has no virtual machine marked as its default GitLab runner VM | Contact support to have one assigned |
Error: session request failed after 3 attempts |
Transient backend problem | Retry the job; contact support if it persists |
| Commands that work locally are not found | The script runs in PowerShell on Windows, not a Linux shell | Use PowerShell syntax; apt-get, pip3 and similar are unavailable |
| One matrix job fails while the others pass | That assembly was not free within SESSION_TIMEOUT |
Raise SESSION_TIMEOUT, or shrink the matrix |
Booking an assembly without the vHaaS runner
Book through the API when your job cannot run on the assembly's VM — for example when one job orchestrates several assemblies, when you use a CI system other than GitLab, or when a session must outlive a single job.
The API queues the request and waits for the assembly, the same way the runner does.
Prerequisites
You need:
- A vHaaS Access Token permitted to book the assembly
- Your organization ID
- A job that can reach
https://vhaas.vector.cloudover HTTPS curlandjqavailable in the job image
Steps
1. Request a session
-
Send the token in the
private-tokenheader.put_in_queuemakes vHaaS wait for a free assembly instead of failing immediately, anddurationis an ISO-8601 duration —PT30Mis 30 minutes.JOB=$(curl -sS -X POST \ -H "private-token: $VEHAAS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "put_in_queue": true, "duration": "PT30M", "request_profile": {"assembly_ref": ["ASSEMBLY-1004", "ASSEMBLY-1005"]} }' \ "https://vhaas.vector.cloud/api/v3/organizations/$VEHAAS_ORGANIZATION_ID/jobs") JOB_ID=$(echo "$JOB" | jq -r '.job_id') -
The request profile is the JSON description of what to book. It carries only
assembly_ref— a single reference, or a list of up to 100 — so it expresses exactly what a candidate list on the runner expresses, and nothing more. There is no matching on devices, labels, or clusters. With a list, vHaaS tries each reference in turn and books the first one it can.
2. Wait for the assembly
-
The job holds no session until one is allocated. Poll until
session_idis set:for i in $(seq 1 60); do JOB=$(curl -sS -H "private-token: $VEHAAS_TOKEN" \ "https://vhaas.vector.cloud/api/v3/organizations/$VEHAAS_ORGANIZATION_ID/jobs/$JOB_ID") SESSION_ID=$(echo "$JOB" | jq -r '.session_id // empty') [ -n "$SESSION_ID" ] && break ERR=$(echo "$JOB" | jq -r '.error_msg // empty') if [ -n "$ERR" ]; then echo "Booking failed: $ERR" >&2; exit 1; fi sleep 15 done [ -z "$SESSION_ID" ] && { echo "No assembly became available" >&2; exit 1; }
3. Read the assembly and its virtual machine
-
The session names the assembly that was allocated:
-
Its virtual machines are listed by assembly reference, and credentials are readable while the session is active:
VM_ID=$(curl -sS -H "private-token: $VEHAAS_TOKEN" \ "https://vhaas.vector.cloud/api/v3/organizations/$VEHAAS_ORGANIZATION_ID/virtual-machines?assembly_refs=$ASSEMBLY_REF" \ | jq -r '.items[0].virtual_machine_id') curl -sS -H "private-token: $VEHAAS_TOKEN" \ "https://vhaas.vector.cloud/api/v3/organizations/$VEHAAS_ORGANIZATION_ID/virtual-machines/$VM_ID/credentials" -
Keep credentials out of the job log
Assign the response to a variable and never echo it. Anyone who can view the pipeline can read its log.
4. Run your tests
- Connect to the VM and run your suite, or drive the hardware over the network directly. This step is entirely yours — vHaaS only guarantees exclusive access for the session's duration.
5. Release the session
-
Release as soon as the tests finish, so the assembly returns to the pool:
-
Always release in
after_scriptRun the release even when the tests fail — in GitLab, an
after_scriptblock is the reliable place. A session that is never released stays booked until its duration expires, blocking everyone else.
Troubleshooting
| Symptom | Likely cause | Solution |
|---|---|---|
403 Forbidden on any /api/v2.0/ path |
The cloud service does not serve the legacy API | Use the /api/v3/ endpoints shown above |
session_id stays empty until the loop ends |
No candidate assembly became free | Add more references to request_profile.assembly_ref, or extend the polling loop |
400 Bad Request on the job request |
duration is not an ISO-8601 duration, or is below the minimum session length |
Use the PT30M form and at least 10 minutes |
404 Not Found when reading credentials |
The session is not active, or the token may not read that VM | Read credentials only after session_id is set and before the session ends |
409 Conflict on release, "already ended or about to end" |
The session had already finished | Harmless — the assembly is already free |
| Assembly still booked after the pipeline ended | The release call never ran | Move it into after_script so it also runs when tests fail |