Skip to content

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_DURATION and SESSION_TIMEOUT apply 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.cloud over HTTPS
  • curl and jq available in the job image

Steps

1. Request a session

Send the token in the private-token header. put_in_queue makes vHaaS wait for a free assembly instead of failing immediately, and duration is an ISO-8601 durationPT30M is 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_id is 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:

ASSEMBLY_REF=$(curl -sS -H "private-token: $VEHAAS_TOKEN" \
  "https://vhaas.vector.cloud/api/v3/organizations/$VEHAAS_ORGANIZATION_ID/assembly-sessions/$SESSION_ID" \
  | jq -r '.assembly_ref')

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:

curl -sS -X DELETE -H "private-token: $VEHAAS_TOKEN" \
  "https://vhaas.vector.cloud/api/v3/organizations/$VEHAAS_ORGANIZATION_ID/assembly-sessions/$SESSION_ID"

Always release in after_script

Run the release even when the tests fail — in GitLab, an after_script block 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