rosotacom-dev 2.5.dev7__tar.gz → 2.5.dev10__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/PKG-INFO +29 -1
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/README.md +28 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/cli.py +260 -28
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom_dev.egg-info/PKG-INFO +29 -1
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_cli.py +264 -3
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/deployment-configuration.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/ffmpeg-keyframes.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/findings/README.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/forensics-report.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/link-trace.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/rfcs/0003-metric-backbone.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/rfcs/0004-network-profiles.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/testing.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/install.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/justfile +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/run_session_in_container.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/session-configuration.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/forensics.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/profiles.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/status_eval.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom_dev.egg-info/SOURCES.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom_dev.egg-info/scm_file_list.json +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/stop_session_in_container.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_concurrency.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_forensics.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_link_trace.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_status_eval.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_status_overview.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_transit.py +0 -0
- {rosotacom_dev-2.5.dev7 → rosotacom_dev-2.5.dev10}/tests/unit/test_video_quality.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rosotacom-dev
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.dev10
|
|
4
4
|
Summary: Host CLI for ROS OTA communication sessions.
|
|
5
5
|
Author: develNor
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -494,6 +494,34 @@ in this mode — there is no staging to undo, and the workdir is your repository
|
|
|
494
494
|
The run manifest records which mode and which version the peers ran, so a result
|
|
495
495
|
can be attributed to an artefact rather than to a working copy.
|
|
496
496
|
|
|
497
|
+
#### How the peers are reached: `--peer-exec`
|
|
498
|
+
|
|
499
|
+
`--peer-ssh` gives the orchestrator a shell on the peer, which is more than a
|
|
500
|
+
run needs and more than some machines should hand out. `--peer-exec` names the
|
|
501
|
+
transport instead:
|
|
502
|
+
|
|
503
|
+
```bash
|
|
504
|
+
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
505
|
+
--install-mode checkout \
|
|
506
|
+
--peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt \
|
|
507
|
+
--peer-exec b='remote-rosotacom robot'
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
The command is run with the script as its final argument — the contract
|
|
511
|
+
`ssh host <script>` already has — so anything of that shape can carry a peer: a
|
|
512
|
+
wrapper that logs what a run asks for, a container exec, or a forced command
|
|
513
|
+
that accepts some scripts and refuses the rest. rosotacom does not know or care
|
|
514
|
+
which; it only stops assuming that reaching a peer means having a shell on it.
|
|
515
|
+
|
|
516
|
+
Two restrictions, both load-bearing. It applies to `--install-mode checkout`
|
|
517
|
+
only, because the staging modes push a tar stream and a file write by taking
|
|
518
|
+
the ssh client's own argv apart, and a transport that promises no more than
|
|
519
|
+
"run this script" cannot carry them. And a peer takes either `--peer-ssh` or
|
|
520
|
+
`--peer-exec`, never both: leaving it ambiguous hides which one carried the run.
|
|
521
|
+
|
|
522
|
+
`-t` and `-o BatchMode=yes` are dropped rather than forwarded. They are options
|
|
523
|
+
of one client, and a transport that is not ssh never agreed to understand them.
|
|
524
|
+
|
|
497
525
|
### Live status / debugging overview
|
|
498
526
|
|
|
499
527
|
Enable a continuously-updated, per-topic pipeline overview by setting
|
|
@@ -449,6 +449,34 @@ in this mode — there is no staging to undo, and the workdir is your repository
|
|
|
449
449
|
The run manifest records which mode and which version the peers ran, so a result
|
|
450
450
|
can be attributed to an artefact rather than to a working copy.
|
|
451
451
|
|
|
452
|
+
#### How the peers are reached: `--peer-exec`
|
|
453
|
+
|
|
454
|
+
`--peer-ssh` gives the orchestrator a shell on the peer, which is more than a
|
|
455
|
+
run needs and more than some machines should hand out. `--peer-exec` names the
|
|
456
|
+
transport instead:
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
460
|
+
--install-mode checkout \
|
|
461
|
+
--peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt \
|
|
462
|
+
--peer-exec b='remote-rosotacom robot'
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
The command is run with the script as its final argument — the contract
|
|
466
|
+
`ssh host <script>` already has — so anything of that shape can carry a peer: a
|
|
467
|
+
wrapper that logs what a run asks for, a container exec, or a forced command
|
|
468
|
+
that accepts some scripts and refuses the rest. rosotacom does not know or care
|
|
469
|
+
which; it only stops assuming that reaching a peer means having a shell on it.
|
|
470
|
+
|
|
471
|
+
Two restrictions, both load-bearing. It applies to `--install-mode checkout`
|
|
472
|
+
only, because the staging modes push a tar stream and a file write by taking
|
|
473
|
+
the ssh client's own argv apart, and a transport that promises no more than
|
|
474
|
+
"run this script" cannot carry them. And a peer takes either `--peer-ssh` or
|
|
475
|
+
`--peer-exec`, never both: leaving it ambiguous hides which one carried the run.
|
|
476
|
+
|
|
477
|
+
`-t` and `-o BatchMode=yes` are dropped rather than forwarded. They are options
|
|
478
|
+
of one client, and a transport that is not ssh never agreed to understand them.
|
|
479
|
+
|
|
452
480
|
### Live status / debugging overview
|
|
453
481
|
|
|
454
482
|
Enable a continuously-updated, per-topic pipeline overview by setting
|
|
@@ -234,6 +234,19 @@ class OtaSmokePeer:
|
|
|
234
234
|
#: control centre runs it under a different account than a laptop does — and
|
|
235
235
|
#: a single workdir would silently be wrong on all but one of them.
|
|
236
236
|
checkout: str | None = None
|
|
237
|
+
#: How to reach this peer, when `ssh <alias> <script>` is not allowed to be
|
|
238
|
+
#: the answer. The command is given the script as its final argument, the
|
|
239
|
+
#: same contract ssh has, so anything with that shape can carry a peer:
|
|
240
|
+
#: a wrapper that logs, a container exec, or a capability that accepts only
|
|
241
|
+
#: some scripts and refuses the rest.
|
|
242
|
+
#:
|
|
243
|
+
#: This exists because "give the orchestrator a shell on the peer" is a poor
|
|
244
|
+
#: trade for a machine that is only meant to run one repository's test. An
|
|
245
|
+
#: SSH alias grants everything that account can do, forever, to whoever
|
|
246
|
+
#: holds the key; the operations a run actually needs are a short, fixed
|
|
247
|
+
#: list. Naming the transport lets the narrow thing be substituted without
|
|
248
|
+
#: this file having to know what narrow means.
|
|
249
|
+
exec_command: str | None = None
|
|
237
250
|
|
|
238
251
|
|
|
239
252
|
@dataclass(frozen=True)
|
|
@@ -1027,6 +1040,10 @@ def _parse_peer_checkout_overrides(overrides: list[str] | None) -> dict[str, str
|
|
|
1027
1040
|
return parse_assignments(overrides, option="--peer-checkout")
|
|
1028
1041
|
|
|
1029
1042
|
|
|
1043
|
+
def _parse_peer_exec_overrides(overrides: list[str] | None) -> dict[str, str]:
|
|
1044
|
+
return parse_assignments(overrides, option="--peer-exec")
|
|
1045
|
+
|
|
1046
|
+
|
|
1030
1047
|
def _deployment_config(runtime: RuntimeConfig) -> DeploymentConfig | None:
|
|
1031
1048
|
return load_deployment(runtime.deployment)
|
|
1032
1049
|
|
|
@@ -1563,8 +1580,31 @@ def _ota_plan_from_bindings(
|
|
|
1563
1580
|
install_pin: str | None = None,
|
|
1564
1581
|
checkouts: Mapping[str, str] | None = None,
|
|
1565
1582
|
project: str | None = None,
|
|
1583
|
+
exec_commands: Mapping[str, str] | None = None,
|
|
1566
1584
|
) -> OtaSmokePlan:
|
|
1567
1585
|
_ota_validate_install_mode(install_mode)
|
|
1586
|
+
if exec_commands:
|
|
1587
|
+
unknown = sorted(set(exec_commands) - set(bindings))
|
|
1588
|
+
if unknown:
|
|
1589
|
+
raise RuntimeError(f"--peer-exec names a peer the session does not have: {', '.join(unknown)}")
|
|
1590
|
+
# Staging modes send a tar stream and a file write, not a command, and
|
|
1591
|
+
# both take the ssh client's own argv apart to do it. A transport that
|
|
1592
|
+
# only promises "run this script" cannot carry them, and quietly
|
|
1593
|
+
# writing the peer's files onto the orchestrator instead — which is
|
|
1594
|
+
# what the local branch of the staging helpers would do — is the worst
|
|
1595
|
+
# of the available outcomes.
|
|
1596
|
+
if install_mode != "checkout":
|
|
1597
|
+
raise RuntimeError(
|
|
1598
|
+
f"--peer-exec requires --install-mode checkout (got {install_mode!r}): the other modes copy a "
|
|
1599
|
+
"tree to the peer, which a command transport cannot carry."
|
|
1600
|
+
)
|
|
1601
|
+
both = sorted(name for name in exec_commands if bindings[name].ssh)
|
|
1602
|
+
if both:
|
|
1603
|
+
raise RuntimeError(
|
|
1604
|
+
"--peer-exec and --peer-ssh both name "
|
|
1605
|
+
+ ", ".join(both)
|
|
1606
|
+
+ "; a peer is reached one way, and leaving it ambiguous hides which one carried the run."
|
|
1607
|
+
)
|
|
1568
1608
|
if install_mode == "checkout":
|
|
1569
1609
|
if not checkouts or not project:
|
|
1570
1610
|
raise RuntimeError("--install-mode checkout requires --peer-checkout for every peer.")
|
|
@@ -1602,6 +1642,7 @@ def _ota_plan_from_bindings(
|
|
|
1602
1642
|
ssh=binding.ssh,
|
|
1603
1643
|
address=binding.address,
|
|
1604
1644
|
checkout=(checkouts or {}).get(name) if install_mode == "checkout" else None,
|
|
1645
|
+
exec_command=(exec_commands or {}).get(name),
|
|
1605
1646
|
)
|
|
1606
1647
|
for name, binding in bindings.items()
|
|
1607
1648
|
}
|
|
@@ -1619,14 +1660,19 @@ def _ota_plan_from_bindings(
|
|
|
1619
1660
|
def _ota_write_state(instance: SessionInstance, plan: OtaSmokePlan) -> OtaSmokePlan:
|
|
1620
1661
|
path = instance.host_dir / "ota-deployment.yaml"
|
|
1621
1662
|
payload = {
|
|
1622
|
-
"schema_version":
|
|
1663
|
+
"schema_version": 4,
|
|
1623
1664
|
"workdir": plan.workdir,
|
|
1624
1665
|
"rosotacom": plan.rosotacom,
|
|
1625
1666
|
"project": plan.project,
|
|
1626
1667
|
"install_mode": plan.install_mode,
|
|
1627
1668
|
"install_pin": plan.install_pin,
|
|
1628
1669
|
"peers": {
|
|
1629
|
-
name: {
|
|
1670
|
+
name: {
|
|
1671
|
+
"address": peer.address,
|
|
1672
|
+
"ssh": peer.ssh,
|
|
1673
|
+
"checkout": peer.checkout,
|
|
1674
|
+
"exec": peer.exec_command,
|
|
1675
|
+
}
|
|
1630
1676
|
for name, peer in sorted(plan.peers.items())
|
|
1631
1677
|
},
|
|
1632
1678
|
}
|
|
@@ -1637,7 +1683,7 @@ def _ota_write_state(instance: SessionInstance, plan: OtaSmokePlan) -> OtaSmokeP
|
|
|
1637
1683
|
def _ota_load_state(path_arg: str) -> OtaSmokePlan:
|
|
1638
1684
|
path = Path(path_arg).expanduser().resolve()
|
|
1639
1685
|
raw = _load_yaml_file(path)
|
|
1640
|
-
if raw.get("schema_version") !=
|
|
1686
|
+
if raw.get("schema_version") != 4:
|
|
1641
1687
|
raise RuntimeError(f"Unsupported OTA deployment state: {path}")
|
|
1642
1688
|
peers_raw = raw.get("peers")
|
|
1643
1689
|
if not isinstance(peers_raw, dict) or len(peers_raw) != 2:
|
|
@@ -1651,6 +1697,7 @@ def _ota_load_state(path_arg: str) -> OtaSmokePlan:
|
|
|
1651
1697
|
address=str(peer_raw["address"]),
|
|
1652
1698
|
ssh=str(peer_raw["ssh"]) if peer_raw.get("ssh") else None,
|
|
1653
1699
|
checkout=str(peer_raw["checkout"]) if peer_raw.get("checkout") else None,
|
|
1700
|
+
exec_command=str(peer_raw["exec"]) if peer_raw.get("exec") else None,
|
|
1654
1701
|
)
|
|
1655
1702
|
install_pin = raw.get("install_pin")
|
|
1656
1703
|
return OtaSmokePlan(
|
|
@@ -1682,7 +1729,32 @@ def _ota_quote_cmd(parts: list[str]) -> str:
|
|
|
1682
1729
|
return shlex.join(parts)
|
|
1683
1730
|
|
|
1684
1731
|
|
|
1732
|
+
def _ota_peer_is_remote(peer: OtaSmokePeer) -> bool:
|
|
1733
|
+
"""Does this peer run somewhere other than the orchestrator?
|
|
1734
|
+
|
|
1735
|
+
Asked as a question about the peer rather than about SSH. Every caller that
|
|
1736
|
+
used to read ``peer.ssh`` for this meant "is it over there", and each one
|
|
1737
|
+
that kept reading it after a second transport existed would have taken the
|
|
1738
|
+
local branch for a machine on the other side of the room.
|
|
1739
|
+
"""
|
|
1740
|
+
return bool(peer.ssh or peer.exec_command)
|
|
1741
|
+
|
|
1742
|
+
|
|
1743
|
+
def _ota_peer_target(peer: OtaSmokePeer) -> str:
|
|
1744
|
+
"""How to name this peer's location in output meant for a human."""
|
|
1745
|
+
if peer.exec_command:
|
|
1746
|
+
return peer.exec_command
|
|
1747
|
+
return peer.ssh or "local shell"
|
|
1748
|
+
|
|
1749
|
+
|
|
1685
1750
|
def _ota_remote_argv(peer: OtaSmokePeer, script: str, *, tty: bool = False, batch: bool = False) -> list[str]:
|
|
1751
|
+
# A named transport wins over the SSH alias, and it takes the script as its
|
|
1752
|
+
# last argument because that is the contract `ssh host <script>` already
|
|
1753
|
+
# has. `tty` and `batch` are dropped on purpose rather than guessed at:
|
|
1754
|
+
# they are options of one particular client, and a transport that is not
|
|
1755
|
+
# ssh has no obligation to understand them.
|
|
1756
|
+
if peer.exec_command:
|
|
1757
|
+
return [*shlex.split(peer.exec_command), script]
|
|
1686
1758
|
if peer.ssh:
|
|
1687
1759
|
argv = ["ssh"]
|
|
1688
1760
|
if batch:
|
|
@@ -2194,7 +2266,12 @@ def _ota_write_manifest(
|
|
|
2194
2266
|
"install_mode": plan.install_mode,
|
|
2195
2267
|
"install_pin": plan.install_pin,
|
|
2196
2268
|
"peers": {
|
|
2197
|
-
name: {
|
|
2269
|
+
name: {
|
|
2270
|
+
"ssh_configured": bool(peer.ssh),
|
|
2271
|
+
"exec_configured": bool(peer.exec_command),
|
|
2272
|
+
"address": peer.address,
|
|
2273
|
+
}
|
|
2274
|
+
for name, peer in plan.peers.items()
|
|
2198
2275
|
},
|
|
2199
2276
|
},
|
|
2200
2277
|
)
|
|
@@ -2319,6 +2396,30 @@ def _infer_active_ota_smoke_run(
|
|
|
2319
2396
|
)
|
|
2320
2397
|
|
|
2321
2398
|
|
|
2399
|
+
def _ota_latest_state_for(
|
|
2400
|
+
runtime: RuntimeConfig, target: InteractiveSmokeTarget, instance_id: str | None
|
|
2401
|
+
) -> str | None:
|
|
2402
|
+
"""The newest `ota-deployment.yaml` for this target, if one is on disk.
|
|
2403
|
+
|
|
2404
|
+
Instances are laid out `<instances>/<date>/<session>_<time>_<instance-id>/`,
|
|
2405
|
+
so a named instance can be matched by suffix and an unnamed one by
|
|
2406
|
+
modification time. Returns None rather than raising: not finding a state is
|
|
2407
|
+
a normal outcome (nothing was ever started here), and the caller has a
|
|
2408
|
+
command line to fall back to.
|
|
2409
|
+
"""
|
|
2410
|
+
root = _session_instances_root(runtime)
|
|
2411
|
+
if not root.is_dir():
|
|
2412
|
+
return None
|
|
2413
|
+
candidates = sorted(
|
|
2414
|
+
(path for path in root.glob("*/*/ota-deployment.yaml")),
|
|
2415
|
+
key=lambda path: path.stat().st_mtime,
|
|
2416
|
+
reverse=True,
|
|
2417
|
+
)
|
|
2418
|
+
if instance_id:
|
|
2419
|
+
candidates = [path for path in candidates if path.parent.name.endswith(f"_{instance_id}")]
|
|
2420
|
+
return str(candidates[0]) if candidates else None
|
|
2421
|
+
|
|
2422
|
+
|
|
2322
2423
|
def _resolve_ota_smoke_context(
|
|
2323
2424
|
args: argparse.Namespace,
|
|
2324
2425
|
) -> tuple[RuntimeConfig, OtaSmokePlan, InteractiveSmokeTarget]:
|
|
@@ -2327,6 +2428,21 @@ def _resolve_ota_smoke_context(
|
|
|
2327
2428
|
getattr(args, "target", None), runtime, getattr(args, "target_type", "auto")
|
|
2328
2429
|
)
|
|
2329
2430
|
state_file = getattr(args, "state_file", None)
|
|
2431
|
+
if not state_file and getattr(args, "stop", False):
|
|
2432
|
+
# Stopping has to reach the run that exists, and the only record of how
|
|
2433
|
+
# that run was deployed is the state a start wrote. Reconstructing a
|
|
2434
|
+
# plan from the command line instead means guessing the install mode,
|
|
2435
|
+
# and the default guess is `source` — which points the stop at
|
|
2436
|
+
# `/tmp/rosotacom_ota/source/.venv/bin/rosotacom` for peers that were
|
|
2437
|
+
# started from their own checkouts. Observed on 2026-08-11: every peer
|
|
2438
|
+
# stop failed silently (they are best-effort), the containers stayed up,
|
|
2439
|
+
# and the only visible action was a cleanup removing a staging directory
|
|
2440
|
+
# that had never been created. Usually the live tmux session carries the
|
|
2441
|
+
# state path; when it does not — a killed session, a run started from
|
|
2442
|
+
# another terminal — the instance directory still does.
|
|
2443
|
+
state_file = _ota_latest_state_for(runtime, target, getattr(args, "instance_id", None))
|
|
2444
|
+
if state_file:
|
|
2445
|
+
print(f"OTA smoke: stopping the run recorded in {state_file}")
|
|
2330
2446
|
if state_file:
|
|
2331
2447
|
plan = _ota_load_state(state_file)
|
|
2332
2448
|
else:
|
|
@@ -2339,6 +2455,7 @@ def _resolve_ota_smoke_context(
|
|
|
2339
2455
|
)
|
|
2340
2456
|
install_mode = str(getattr(args, "install_mode", None) or "source")
|
|
2341
2457
|
checkouts = _parse_peer_checkout_overrides(getattr(args, "peer_checkout", None))
|
|
2458
|
+
exec_commands = _parse_peer_exec_overrides(getattr(args, "peer_exec", None))
|
|
2342
2459
|
project: str | None = None
|
|
2343
2460
|
if install_mode == "checkout":
|
|
2344
2461
|
if not runtime.rosotacom_config:
|
|
@@ -2346,10 +2463,12 @@ def _resolve_ota_smoke_context(
|
|
|
2346
2463
|
local_checkout, project = _ota_checkout_project_path(runtime.rosotacom_config)
|
|
2347
2464
|
for name, path in sorted(checkouts.items()):
|
|
2348
2465
|
binding = bindings.get(name)
|
|
2349
|
-
|
|
2466
|
+
remote = binding is not None and (binding.ssh or name in exec_commands)
|
|
2467
|
+
if binding is not None and not remote and Path(path).resolve() != local_checkout:
|
|
2350
2468
|
raise RuntimeError(
|
|
2351
2469
|
f"--peer-checkout {name}={path} names the peer that runs on this machine, but the active "
|
|
2352
|
-
f"project lives in {local_checkout}. Point it there, or give that peer
|
|
2470
|
+
f"project lives in {local_checkout}. Point it there, or give that peer a transport "
|
|
2471
|
+
"(--peer-ssh or --peer-exec)."
|
|
2353
2472
|
)
|
|
2354
2473
|
plan = _ota_plan_from_bindings(
|
|
2355
2474
|
bindings,
|
|
@@ -2358,6 +2477,7 @@ def _resolve_ota_smoke_context(
|
|
|
2358
2477
|
install_pin=getattr(args, "install_pin", None),
|
|
2359
2478
|
checkouts=checkouts,
|
|
2360
2479
|
project=project,
|
|
2480
|
+
exec_commands=exec_commands,
|
|
2361
2481
|
)
|
|
2362
2482
|
plan_peers = set(plan.peers)
|
|
2363
2483
|
target_peers = set(_peer_keys_from_cfg(target.cfg))
|
|
@@ -2389,7 +2509,7 @@ def _ota_network_sudo_passwords(
|
|
|
2389
2509
|
return {peer.name: "" for peer in plan.peers.values()}
|
|
2390
2510
|
passwords: dict[str, str] = {}
|
|
2391
2511
|
for peer in plan.peers.values():
|
|
2392
|
-
target = peer
|
|
2512
|
+
target = _ota_peer_target(peer)
|
|
2393
2513
|
passwords[peer.name] = getpass.getpass(f"sudo password for {peer.name} ({target}) [network shaping only]: ")
|
|
2394
2514
|
return passwords
|
|
2395
2515
|
|
|
@@ -2489,8 +2609,8 @@ def _ota_preflight(
|
|
|
2489
2609
|
sudo_mode = _validate_ota_sudo_mode(sudo_mode)
|
|
2490
2610
|
sudo_passwords = sudo_passwords or {}
|
|
2491
2611
|
for peer in plan.peers.values():
|
|
2492
|
-
if peer
|
|
2493
|
-
_ota_run(peer, "true", label=f"{peer.name}:
|
|
2612
|
+
if _ota_peer_is_remote(peer):
|
|
2613
|
+
_ota_run(peer, "true", label=f"{peer.name}: reachable", dry_run=dry_run, batch=True)
|
|
2494
2614
|
required = ["python3", "docker", "tar"]
|
|
2495
2615
|
if require_tmux:
|
|
2496
2616
|
required.append("tmux")
|
|
@@ -2595,6 +2715,12 @@ def _ota_stage_tree(peer: OtaSmokePeer, source: Path, destination: str, *, dry_r
|
|
|
2595
2715
|
"-",
|
|
2596
2716
|
".",
|
|
2597
2717
|
]
|
|
2718
|
+
# Reached only in the staging install modes, which `--peer-exec` refuses.
|
|
2719
|
+
# Kept as a check rather than a comment because the failure it prevents is
|
|
2720
|
+
# silent: the local branch below would copy the peer's tree onto the
|
|
2721
|
+
# orchestrator and report success.
|
|
2722
|
+
if peer.exec_command:
|
|
2723
|
+
raise RuntimeError(f"Cannot stage files to {peer.name} over a command transport; use --install-mode checkout.")
|
|
2598
2724
|
if not peer.ssh:
|
|
2599
2725
|
print(f"+ {label}: copy {source} -> {destination}")
|
|
2600
2726
|
if not dry_run:
|
|
@@ -2616,7 +2742,13 @@ def _ota_stage_tree(peer: OtaSmokePeer, source: Path, destination: str, *, dry_r
|
|
|
2616
2742
|
|
|
2617
2743
|
|
|
2618
2744
|
def _ota_stage_text(peer: OtaSmokePeer, text: str, destination: str, *, dry_run: bool, label: str) -> None:
|
|
2619
|
-
|
|
2745
|
+
# Reached only in the staging install modes, which `--peer-exec` refuses.
|
|
2746
|
+
# Kept as a check rather than a comment because the failure it prevents is
|
|
2747
|
+
# silent: the local branch below would copy the peer's tree onto the
|
|
2748
|
+
# orchestrator and report success.
|
|
2749
|
+
if peer.exec_command:
|
|
2750
|
+
raise RuntimeError(f"Cannot stage files to {peer.name} over a command transport; use --install-mode checkout.")
|
|
2751
|
+
print(f"+ {label}: write {destination} on {_ota_peer_target(peer)}")
|
|
2620
2752
|
if dry_run:
|
|
2621
2753
|
return
|
|
2622
2754
|
if peer.ssh:
|
|
@@ -3159,7 +3291,7 @@ def _ota_verify_isolation(
|
|
|
3159
3291
|
published = _ota_run(source, publish, label=f"{source_name}: publish isolation probe", dry_run=dry_run, check=False)
|
|
3160
3292
|
if published.returncode != 0:
|
|
3161
3293
|
_ota_print_failure_output(f"{source_name}: publish isolation probe", published)
|
|
3162
|
-
errors.append(f"{source_name}: isolation probe
|
|
3294
|
+
errors.append(f"{source_name}: isolation probe did not advertise (probe-publish output above names the cause)")
|
|
3163
3295
|
return errors
|
|
3164
3296
|
_print_completed_output(published)
|
|
3165
3297
|
check = _ota_rosotacom_command(plan, _ota_probe_check_parts(target, receiver_name, peer_args), receiver)
|
|
@@ -3594,6 +3726,17 @@ def _list_ota_smoke(args: argparse.Namespace) -> int:
|
|
|
3594
3726
|
|
|
3595
3727
|
|
|
3596
3728
|
def _ota_cleanup_hosts(plan: OtaSmokePlan, *, dry_run: bool) -> None:
|
|
3729
|
+
if plan.state_path is None:
|
|
3730
|
+
# No recorded state means this plan came from the command line, so its
|
|
3731
|
+
# install mode is a default rather than a fact about the run. Removing a
|
|
3732
|
+
# workdir on that basis is a destructive act taken on a guess: it is how
|
|
3733
|
+
# a stop that reached no peer still reported doing something. Say what
|
|
3734
|
+
# is missing instead.
|
|
3735
|
+
print(
|
|
3736
|
+
"OTA smoke: skipping cleanup — no deployment state for this run, so its install mode is unknown. "
|
|
3737
|
+
"Pass --state-file if a workdir really needs removing."
|
|
3738
|
+
)
|
|
3739
|
+
return
|
|
3597
3740
|
if plan.install_mode == "checkout":
|
|
3598
3741
|
# The workdir is the user's repository here. `rm -rf` on it would delete
|
|
3599
3742
|
# a checkout with its untracked work — bags, instance artefacts, local
|
|
@@ -6282,8 +6425,17 @@ def _stop_smoke_topic_publishers(containers: dict[str, str], specs: list[SmokeTo
|
|
|
6282
6425
|
)
|
|
6283
6426
|
|
|
6284
6427
|
|
|
6428
|
+
# How long the graph may take to report the probe publisher. A loaded graph
|
|
6429
|
+
# (e.g. a control centre with hundreds of topics) can take well over the old
|
|
6430
|
+
# fixed 10 s to discover a new publisher, and that delay is not a defect.
|
|
6431
|
+
_PROBE_ADVERTISE_TIMEOUT_S = 60.0
|
|
6432
|
+
# The probe must outlive the advertise wait plus the peer's absence check, or
|
|
6433
|
+
# the absence check passes trivially against an already-stopped publisher.
|
|
6434
|
+
_PROBE_DURATION_S = 120.0
|
|
6435
|
+
|
|
6436
|
+
|
|
6285
6437
|
def _publish_isolation_probe(
|
|
6286
|
-
container_name: str, ros_setup: str, topic: str, *, rate: float = 5.0, duration: float =
|
|
6438
|
+
container_name: str, ros_setup: str, topic: str, *, rate: float = 5.0, duration: float = _PROBE_DURATION_S
|
|
6287
6439
|
) -> None:
|
|
6288
6440
|
"""Publish a local-only topic in the container's local application domain,
|
|
6289
6441
|
detached, for `duration` seconds (self-stops via `timeout`)."""
|
|
@@ -6312,6 +6464,45 @@ def _topic_present(container_name: str, ros_setup: str, topic: str) -> bool:
|
|
|
6312
6464
|
return topic in names
|
|
6313
6465
|
|
|
6314
6466
|
|
|
6467
|
+
def _isolation_probe_running(container_name: str, topic: str) -> bool:
|
|
6468
|
+
"""Whether the probe publisher for `topic` is still alive in the container."""
|
|
6469
|
+
result = subprocess.run(
|
|
6470
|
+
["docker", "exec", container_name, "pgrep", "-f", f"ros2 topic pub {topic}"],
|
|
6471
|
+
capture_output=True,
|
|
6472
|
+
text=True,
|
|
6473
|
+
check=False,
|
|
6474
|
+
)
|
|
6475
|
+
return result.returncode == 0
|
|
6476
|
+
|
|
6477
|
+
|
|
6478
|
+
def _wait_for_probe_advertisement(
|
|
6479
|
+
container_name: str,
|
|
6480
|
+
ros_setup: str,
|
|
6481
|
+
topic: str,
|
|
6482
|
+
*,
|
|
6483
|
+
timeout_s: float,
|
|
6484
|
+
log_line: Callable[[str], None] | None = None,
|
|
6485
|
+
) -> str:
|
|
6486
|
+
"""Poll until `topic` is reported by the container's local graph.
|
|
6487
|
+
|
|
6488
|
+
Returns "advertised", "publisher-gone" (the probe process exited or never
|
|
6489
|
+
started), or "timeout" (the publisher is alive but the graph did not report
|
|
6490
|
+
the topic within `timeout_s`). Only "publisher-gone" points at a publisher
|
|
6491
|
+
defect; a loaded graph reports late, which is what "timeout" captures.
|
|
6492
|
+
"""
|
|
6493
|
+
deadline = time.monotonic() + timeout_s
|
|
6494
|
+
while True:
|
|
6495
|
+
if log_line is not None:
|
|
6496
|
+
log_line(f"Waiting for isolation probe {topic} to advertise in {container_name}")
|
|
6497
|
+
if _topic_present(container_name, ros_setup, topic):
|
|
6498
|
+
return "advertised"
|
|
6499
|
+
if not _isolation_probe_running(container_name, topic):
|
|
6500
|
+
return "publisher-gone"
|
|
6501
|
+
if time.monotonic() >= deadline:
|
|
6502
|
+
return "timeout"
|
|
6503
|
+
time.sleep(1)
|
|
6504
|
+
|
|
6505
|
+
|
|
6315
6506
|
def _verify_isolation(
|
|
6316
6507
|
pub_container: str,
|
|
6317
6508
|
pub_setup: str,
|
|
@@ -6326,15 +6517,18 @@ def _verify_isolation(
|
|
|
6326
6517
|
log_line(f"Starting isolation probe {topic} in {pub_container}")
|
|
6327
6518
|
_publish_isolation_probe(pub_container, pub_setup, topic)
|
|
6328
6519
|
try:
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
if
|
|
6337
|
-
return [
|
|
6520
|
+
outcome = _wait_for_probe_advertisement(
|
|
6521
|
+
pub_container, pub_setup, topic, timeout_s=_PROBE_ADVERTISE_TIMEOUT_S, log_line=log_line
|
|
6522
|
+
)
|
|
6523
|
+
if outcome == "publisher-gone":
|
|
6524
|
+
return [
|
|
6525
|
+
f"isolation check inconclusive: probe publisher for {topic} exited or never started in {pub_container}"
|
|
6526
|
+
]
|
|
6527
|
+
if outcome == "timeout":
|
|
6528
|
+
return [
|
|
6529
|
+
f"isolation check inconclusive: probe publisher for {topic} is running in {pub_container} "
|
|
6530
|
+
f"but the graph did not report it within {_PROBE_ADVERTISE_TIMEOUT_S:.0f}s"
|
|
6531
|
+
]
|
|
6338
6532
|
log_line(f"Checking that isolation probe {topic} is absent in {check_container}")
|
|
6339
6533
|
if _topic_present(check_container, check_setup, topic):
|
|
6340
6534
|
return [f"isolation breach: {topic} from {pub_container} leaked to {check_container}"]
|
|
@@ -6466,12 +6660,32 @@ def probe_publish_command(args: argparse.Namespace) -> int:
|
|
|
6466
6660
|
# Block until the topic is actually advertised so a caller's subsequent
|
|
6467
6661
|
# absence check on the other peer is meaningful (not a false pass on a
|
|
6468
6662
|
# publisher that never came up).
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6663
|
+
started = time.monotonic()
|
|
6664
|
+
outcome = _wait_for_probe_advertisement(container, ros_setup, args.topic, timeout_s=args.advertise_timeout)
|
|
6665
|
+
if outcome == "advertised":
|
|
6666
|
+
print(f"Publishing {args.topic} in {container} (identity {args.identity}); advertised.")
|
|
6667
|
+
return 0
|
|
6668
|
+
if outcome == "publisher-gone":
|
|
6669
|
+
if time.monotonic() - started >= args.duration:
|
|
6670
|
+
print(
|
|
6671
|
+
f"ERROR: probe publisher for {args.topic} in {container} (identity {args.identity}) ran its "
|
|
6672
|
+
f"{args.duration:.0f}s --duration without the graph reporting the topic; keep --duration "
|
|
6673
|
+
f"above --advertise-timeout",
|
|
6674
|
+
file=sys.stderr,
|
|
6675
|
+
)
|
|
6676
|
+
else:
|
|
6677
|
+
print(
|
|
6678
|
+
f"ERROR: probe publisher for {args.topic} exited or never started in {container} "
|
|
6679
|
+
f"(identity {args.identity})",
|
|
6680
|
+
file=sys.stderr,
|
|
6681
|
+
)
|
|
6682
|
+
else:
|
|
6683
|
+
print(
|
|
6684
|
+
f"ERROR: probe publisher for {args.topic} is running in {container} (identity {args.identity}) "
|
|
6685
|
+
f"but the graph did not report it within {args.advertise_timeout:.0f}s; a loaded graph reports "
|
|
6686
|
+
f"late, retry with a larger --advertise-timeout",
|
|
6687
|
+
file=sys.stderr,
|
|
6688
|
+
)
|
|
6475
6689
|
return 1
|
|
6476
6690
|
|
|
6477
6691
|
|
|
@@ -8445,6 +8659,18 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
8445
8659
|
"Required for every peer in that mode; the same repository is at a different path on each machine."
|
|
8446
8660
|
),
|
|
8447
8661
|
)
|
|
8662
|
+
ota_smoke_parser.add_argument(
|
|
8663
|
+
"--peer-exec",
|
|
8664
|
+
action="append",
|
|
8665
|
+
default=[],
|
|
8666
|
+
metavar="PEER=COMMAND",
|
|
8667
|
+
help=(
|
|
8668
|
+
"Run this peer's commands through COMMAND instead of ssh; the script is appended as the final "
|
|
8669
|
+
"argument, the same contract ssh has. For --install-mode checkout only, and mutually exclusive "
|
|
8670
|
+
"with --peer-ssh for the same peer. Use it to put a peer behind a transport narrower than a "
|
|
8671
|
+
"shell, such as a forced command that accepts only this project's own commands."
|
|
8672
|
+
),
|
|
8673
|
+
)
|
|
8448
8674
|
ota_smoke_parser.add_argument("--target-type", choices=["auto", "session", "scenario"], default="auto")
|
|
8449
8675
|
ota_smoke_parser.add_argument("--interactive", action="store_true", help="Open a local control tmux UI.")
|
|
8450
8676
|
ota_smoke_parser.add_argument("--stop", action="store_true", help="Stop an OTA smoke run.")
|
|
@@ -8907,7 +9133,13 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
8907
9133
|
probe_publish_parser.add_argument("--instance-id")
|
|
8908
9134
|
probe_publish_parser.add_argument("--topic", default=ISOLATION_PROBE_TOPIC)
|
|
8909
9135
|
probe_publish_parser.add_argument("--rate", type=float, default=5.0)
|
|
8910
|
-
probe_publish_parser.add_argument("--duration", type=float, default=
|
|
9136
|
+
probe_publish_parser.add_argument("--duration", type=float, default=_PROBE_DURATION_S)
|
|
9137
|
+
probe_publish_parser.add_argument(
|
|
9138
|
+
"--advertise-timeout",
|
|
9139
|
+
type=float,
|
|
9140
|
+
default=_PROBE_ADVERTISE_TIMEOUT_S,
|
|
9141
|
+
help="Seconds to wait for the local graph to report the probe topic before failing.",
|
|
9142
|
+
)
|
|
8911
9143
|
probe_publish_parser.add_argument(
|
|
8912
9144
|
"--stop", action="store_true", help="Stop a running probe publisher instead of starting one."
|
|
8913
9145
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rosotacom-dev
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.dev10
|
|
4
4
|
Summary: Host CLI for ROS OTA communication sessions.
|
|
5
5
|
Author: develNor
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -494,6 +494,34 @@ in this mode — there is no staging to undo, and the workdir is your repository
|
|
|
494
494
|
The run manifest records which mode and which version the peers ran, so a result
|
|
495
495
|
can be attributed to an artefact rather than to a working copy.
|
|
496
496
|
|
|
497
|
+
#### How the peers are reached: `--peer-exec`
|
|
498
|
+
|
|
499
|
+
`--peer-ssh` gives the orchestrator a shell on the peer, which is more than a
|
|
500
|
+
run needs and more than some machines should hand out. `--peer-exec` names the
|
|
501
|
+
transport instead:
|
|
502
|
+
|
|
503
|
+
```bash
|
|
504
|
+
rosotacom ota-smoke 2_native_chatter --peer a=workstation --peer b=robot \
|
|
505
|
+
--install-mode checkout \
|
|
506
|
+
--peer-checkout a=/home/me/fleet_mgmt --peer-checkout b=/home/robot/fleet_mgmt \
|
|
507
|
+
--peer-exec b='remote-rosotacom robot'
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
The command is run with the script as its final argument — the contract
|
|
511
|
+
`ssh host <script>` already has — so anything of that shape can carry a peer: a
|
|
512
|
+
wrapper that logs what a run asks for, a container exec, or a forced command
|
|
513
|
+
that accepts some scripts and refuses the rest. rosotacom does not know or care
|
|
514
|
+
which; it only stops assuming that reaching a peer means having a shell on it.
|
|
515
|
+
|
|
516
|
+
Two restrictions, both load-bearing. It applies to `--install-mode checkout`
|
|
517
|
+
only, because the staging modes push a tar stream and a file write by taking
|
|
518
|
+
the ssh client's own argv apart, and a transport that promises no more than
|
|
519
|
+
"run this script" cannot carry them. And a peer takes either `--peer-ssh` or
|
|
520
|
+
`--peer-exec`, never both: leaving it ambiguous hides which one carried the run.
|
|
521
|
+
|
|
522
|
+
`-t` and `-o BatchMode=yes` are dropped rather than forwarded. They are options
|
|
523
|
+
of one client, and a transport that is not ssh never agreed to understand them.
|
|
524
|
+
|
|
497
525
|
### Live status / debugging overview
|
|
498
526
|
|
|
499
527
|
Enable a continuously-updated, per-topic pipeline overview by setting
|