Krrishj18/osmo mission runner - #366
Conversation
…IA OSMO Replace the OpenStack-Nova spawn/reap backend with OSMO workflow submission. The GitHub side is unchanged (self-hosted/airstack-ephemeral labels, single-use JIT runner tokens, same-repo fork guard) and the one-job-per-worker destroy-after model is preserved; only the spawn target moved from creating a Nova VM to submitting an OSMO workflow. orchestrator.py: submit/query/cancel/list via the osmo CLI, job_id -> workflow_id state, re-login-on-auth-failure, orphan sweep via osmo workflow list; drop floating-IP/boot-volume/placement/keypair/security-group logic. runner.Dockerfile + runner-entrypoint.sh + runner-workflow.yaml.j2: prebaked privileged docker-in-docker + GPU GitHub runner image/task (replaces cloud-init.yaml.j2). config.example.yaml, setup.sh, airstack-orchestrator.service, requirements.txt: OSMO service-account token auth, install the osmo CLI, drop openstacksdk. Docs (AGENTS.md, tests/README.md, orchestrator README) updated to OSMO. Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve uuid/live name after submit (OSMO returns name-only + suffix), default config to the Keycloak-backed airstack pool and Harbor runner image, and add scripts to build/push airstack-ci-runner on OSMO DinD. Co-authored-by: Cursor <cursoragent@cursor.com>
|
/pytest -m build_docker |
|
Running Note: |
Test Metrics —
|
| Test | Pass | Fail | Skip | Rate |
|---|---|---|---|---|
| TestColconBuilds.test_colcon_build_gcs | 0 | 1 | 0 | 0% |
| TestColconBuilds.test_colcon_build_ms_airsim | 0 | 1 | 0 | 0% |
| TestColconBuilds.test_colcon_build_robot | 0 | 1 | 0 | 0% |
| TestColconBuilds.test_colcon_test_robot | 0 | 1 | 0 | 0% |
| TestDockerBuilds.test_build_gcs | 0 | 1 | 0 | 0% |
| TestDockerBuilds.test_build_isaac_sim | 0 | 1 | 0 | 0% |
| TestDockerBuilds.test_build_ms_airsim | 0 | 1 | 0 | 0% |
| TestDockerBuilds.test_build_robot_desktop | 0 | 1 | 0 | 0% |
Metrics
| Test | Metric | Value |
|---|---|---|
| TestDockerBuilds.test_build_robot_desktop | duration_s | 7.979s |
| TestDockerBuilds.test_build_gcs | duration_s | 45.39s |
| TestDockerBuilds.test_build_isaac_sim | duration_s | 133.3s |
| TestDockerBuilds.test_build_ms_airsim | duration_s | 1.287s |
| TestColconBuilds.test_colcon_build_robot | duration_s | 1.508s |
| TestColconBuilds.test_colcon_test_robot | duration_s | 2.837s |
| TestColconBuilds.test_colcon_build_gcs | duration_s | 1.894s |
| TestColconBuilds.test_colcon_build_ms_airsim | duration_s | 1.342s |
|
/pytest -m build_docker |
|
Running Note: |
Test Metrics —
|
Fills in the empty ci_cd.md stub with an end-to-end guide to how CI runs the full AirStack stack on ephemeral OSMO GPU pods: architecture and job lifecycle diagrams, runner pod anatomy, the three trigger paths, what each pytest mark catches, the metrics regression gate, the security model, and layer-by-layer troubleshooting. Adds the page to the mkdocs nav (it was previously unreachable) and cross-links it from tests/README.md and the testing index. Co-authored-by: Cursor <cursoragent@cursor.com>
Every build_docker and build_packages test failed on the OSMO backend because the inner dockerd kept its data-root on the pod's overlayfs rootfs. Linux rejects a directory on overlayfs as an overlay upperdir, so image pulls still succeeded -- containerd unpacks layers with plain writes -- while every build step needing a real mount died with "mount source: overlay ... err: invalid argument", surfacing as unrelated-looking apt-get and WORKDIR failures. runner-entrypoint.sh now picks a storage backend by attempting a real overlay mount rather than trusting the filesystem type, preferring a loopback ext4 data-root (real overlay2, sparse, dies with the pod) and falling back to a pod-mounted filesystem, fuse-overlayfs, then vfs. vfs is a last resort only: it copies the whole filesystem per layer and would exhaust the storage request on the sim images. Also bumps the GitHub Actions runner to 2.336.0, since 2.334.0 stops being able to run jobs on 2026-08-10. Co-authored-by: Cursor <cursoragent@cursor.com>
Versioned cache_from entries always miss on PRs because VERSION is forced up; add a stable cache_* tag published only by docker-build.yml so system tests can reuse layers without writing the shared cache. Co-authored-by: Cursor <cursoragent@cursor.com>
Skip full compose rebuilds when a service's content fingerprint matches the previous versioned image label; registry-retag instead and only rebuild services whose Docker inputs changed. Co-authored-by: Cursor <cursoragent@cursor.com>
docker_image_plan was feeding NUM_ROBOTS with a trailing comment into compose config, which broke strconv.Atoi for deploy.replicas. Co-authored-by: Cursor <cursoragent@cursor.com>
Publish successful images even when a sibling (e.g. isaac-sim) fails, and still cosign whatever was retagged or pushed in the same run. Co-authored-by: Cursor <cursoragent@cursor.com>
Seeded gcs/ms-airsim/robot images carry content-fingerprint labels; this bump should registry-retag those digests without rebuilding. Co-authored-by: Cursor <cursoragent@cursor.com>
|
/pytest -m build_docker |
|
Running Note: |
Test Metrics —
|
| Test | Pass | Fail | Skip | Rate |
|---|---|---|---|---|
| TestColconBuilds.test_colcon_build_gcs | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_build_ms_airsim | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_build_robot | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_test_robot | 0 | 1 | 0 | 0% |
| TestDockerBuilds.test_build_gcs | 1 | 0 | 0 | 100% |
| TestDockerBuilds.test_build_isaac_sim | 0 | 1 | 0 | 0% |
| TestDockerBuilds.test_build_ms_airsim | 1 | 0 | 0 | 100% |
| TestDockerBuilds.test_build_robot_desktop | 1 | 0 | 0 | 100% |
Metrics
| Test | Metric | Value |
|---|---|---|
| TestDockerBuilds.test_build_robot_desktop | duration_s | 3222s |
| TestDockerBuilds.test_build_gcs | duration_s | 907.2s |
| TestDockerBuilds.test_build_isaac_sim | duration_s | 1727s |
| TestDockerBuilds.test_build_ms_airsim | duration_s | 618.5s |
| TestColconBuilds.test_colcon_build_robot | duration_s | 248.1s |
| TestColconBuilds.test_colcon_test_robot | duration_s | 57.72s |
| TestColconBuilds.test_colcon_build_gcs | duration_s | 153s |
| TestColconBuilds.test_colcon_build_ms_airsim | duration_s | 16.52s |
docker
Metrics
| Test | Metric | Value |
|---|---|---|
| docker.gcs | image_size_mb | 2060MB |
| docker.ms-airsim | image_size_mb | 4071MB |
Isaac's PX4 ubuntu.sh fails dpkg configure on the NVIDIA base; pre-fix ca-certificates, drop software-properties-common, and skip NuttX/Gazebo like ms-airsim. Pin pytest<8.1 and disable launch_testing for colcon unit tests so ROS Jazzy's outdated pytest hook no longer aborts CI. Co-authored-by: Cursor <cursoragent@cursor.com>
Bring OSMO CI, floating cache, retag, and isaac/pytest fixes onto the mission-runner PR so /pytest can validate them without merging to develop. Co-authored-by: Cursor <cursoragent@cursor.com>
|
/pytest -m "build_docker or build_packages" |
|
Running Note: |
Test Metrics —
|
| Test | Pass | Fail | Skip | Rate |
|---|---|---|---|---|
| TestColconBuilds.test_colcon_build_gcs | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_build_ms_airsim | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_build_robot | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_test_robot | 0 | 1 | 0 | 0% |
| TestDockerBuilds.test_build_gcs | 1 | 0 | 0 | 100% |
| TestDockerBuilds.test_build_isaac_sim | 1 | 0 | 0 | 100% |
| TestDockerBuilds.test_build_ms_airsim | 1 | 0 | 0 | 100% |
| TestDockerBuilds.test_build_robot_desktop | 1 | 0 | 0 | 100% |
Metrics
| Test | Metric | Value |
|---|---|---|
| TestDockerBuilds.test_build_robot_desktop | duration_s | 2969s |
| TestDockerBuilds.test_build_gcs | duration_s | 516.2s |
| TestDockerBuilds.test_build_isaac_sim | duration_s | 1751s |
| TestDockerBuilds.test_build_ms_airsim | duration_s | 519.7s |
| TestColconBuilds.test_colcon_build_robot | duration_s | 325.2s |
| TestColconBuilds.test_colcon_test_robot | duration_s | 54.53s |
| TestColconBuilds.test_colcon_build_gcs | duration_s | 67.8s |
| TestColconBuilds.test_colcon_build_ms_airsim | duration_s | 13.54s |
docker
Metrics
| Test | Metric | Value |
|---|---|---|
| docker.gcs | image_size_mb | 2060MB |
| docker.isaac-sim | image_size_mb | 1.138e+04MB |
| docker.ms-airsim | image_size_mb | 4076MB |
A single quoted blob made pytest treat "-p no:launch_testing" as part of the -m expression, which broke lidar_point_cloud_filter colcon tests. Co-authored-by: Cursor <cursoragent@cursor.com>
|
/pytest -m build_packages |
|
Running Note: |
Test Metrics —
|
| Test | Pass | Fail | Skip | Rate |
|---|---|---|---|---|
| TestColconBuilds.test_colcon_build_gcs | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_build_ms_airsim | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_build_robot | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_test_robot | 0 | 1 | 0 | 0% |
Metrics
| Test | Metric | Value |
|---|---|---|
| TestColconBuilds.test_colcon_build_robot | duration_s | 183.1s |
| TestColconBuilds.test_colcon_test_robot | duration_s | 40.71s |
| TestColconBuilds.test_colcon_build_gcs | duration_s | 65.41s |
| TestColconBuilds.test_colcon_build_ms_airsim | duration_s | 13.44s |
Nested single quotes around 'not linter' terminated the outer bash -ic string early, so pytest saw 'not' as a path. Use shlex.quote for the whole command and list-form pytest_args in the YAML. Co-authored-by: Cursor <cursoragent@cursor.com>
|
/pytest -m build_packages |
|
Running Note: |
Test Metrics —
|
| Test | Pass | Fail | Skip | Rate |
|---|---|---|---|---|
| TestColconBuilds.test_colcon_build_gcs | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_build_ms_airsim | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_build_robot | 1 | 0 | 0 | 100% |
| TestColconBuilds.test_colcon_test_robot | 0 | 1 | 0 | 0% |
Metrics
| Test | Metric | Value |
|---|---|---|
| TestColconBuilds.test_colcon_build_robot | duration_s | 185.8s |
| TestColconBuilds.test_colcon_test_robot | duration_s | 39.54s |
| TestColconBuilds.test_colcon_build_gcs | duration_s | 64.84s |
| TestColconBuilds.test_colcon_build_ms_airsim | duration_s | 13.73s |
colcon --pytest-args is a single nargs='*' option, so repeating it dropped -p and pytest treated no:launch_testing as a file path. Set PYTEST_ADDOPTS with docker exec -e instead. Co-authored-by: Cursor <cursoragent@cursor.com>
|
/pytest -m build_packages |
|
Running Note: |
Test Metrics —
|
| Test | Pass | Fail | Skip | Rate |
|---|---|---|---|---|
| pytest.internal | 0 | 1 | 0 | 0% |
Metrics
| Test | Metric | Value |
|---|---|---|
| pytest.internal | duration_s | 0s |
conftest functions named pytest_* are registered as hooks. pytest_addopts_env caused PluginValidationError and exit code 3. Co-authored-by: Cursor <cursoragent@cursor.com>
|
/pytest -m build_packages |
|
Running Note: |
Pull and retag cache_* images instead of baking isaac/airsim on every colcon/pytest iteration. /pytest --no-image-build does the same for other marks. compose up --no-build when AIRSTACK_NO_IMAGE_BUILD=1. Co-authored-by: Cursor <cursoragent@cursor.com>
|
/pytest -m build_packages |
|
Running Note: |
What features did you add and/or bugs did you address?
Which GitHub issue does this address?
Additional description if not fully described in the GitHub issue
Please add videos and images to demonstrate the feature. Please upload videos to somewhere persistent (e.g. YouTube or Vimeo) for archival purposes.
How did you implement it?
How do you run and use it?
What commands and button presses do you use to manually launch the stack to use your new feature?
Write a detailed procedure with EXACT BASH COMMANDS so that another maintainer can replicate and understand the benefits of your feature, and reproduce the videos and images you added above.
Testing with PyTest
What pytests did you add to ensure the feature is reliable and robust? What metrics are used?
What's the exact command to run the pytests that test your feature? i.e.
airstack test -m ...What are the expected results of the tests? What should a maintainer look at to understand whether the test succeeded?
Documentation
Was mkdocs.yml updated? (y/n)
Do the docs have sufficient scope such that a newcomer can easily reproduce and use your feature?
Is there sufficient visual media?
Versioning
.envfile according to semantic versioning?