rosotacom-dev 2.5.dev52__tar.gz → 2.5.dev53__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.dev52 → rosotacom_dev-2.5.dev53}/PKG-INFO +19 -1
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/README.md +18 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/deployment-configuration.md +23 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/cli.py +93 -2
- rosotacom_dev-2.5.dev53/src/rosotacom/network_preflight.py +134 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/PKG-INFO +19 -1
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/SOURCES.txt +2 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/scm_file_list.json +2 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_cli.py +19 -2
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_concurrency.py +25 -1
- rosotacom_dev-2.5.dev53/tests/unit/test_network_preflight.py +173 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/actions/setup-just/action.yml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/ffmpeg-keyframes.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/README.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/fastdds-datagram-cap-drops-large-samples.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/graph-derived-types-block-a-non-graph-transport.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/keyframe-loss-kills-the-next-deltas.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/oversubscription-queues-not-losses.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/reorder-becomes-reader-loss.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/repro/decode_chain_repro.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/repro/reorder_drop_repro.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/sender-rows-make-a-dead-link-look-loss-free.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/forensics-report.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/link-bandwidth.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/link-trace.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0003-metric-backbone.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0004-network-profiles.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/testing.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/install.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/justfile +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/session-configuration.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/forensics.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/image_cache.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/dist/field-20260817.dist +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/profiles.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/fastdds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/status_eval.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_session_configuration_doc.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_session_template_substitution.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_fastdds-default/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_catmux_pane_logging.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_container_shaping.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_field_profiles.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_forensics.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_image_cache.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_link_trace.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ota_link_configs.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_pub_sub_pair_types.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_qos_fallback_logging.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_relay_optional_parameters.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_session_pipeline.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_status_eval.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_status_overview.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_status_overview_observer.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/tests/unit/test_transit.py +0 -0
- {rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/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.dev53
|
|
4
4
|
Summary: Host CLI for ROS OTA communication sessions.
|
|
5
5
|
Author: develNor
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -309,6 +309,24 @@ rosotacom start 1_heartbeat --identity b \
|
|
|
309
309
|
--peer-address a=10.0.0.10 --peer-address b=10.0.0.11
|
|
310
310
|
```
|
|
311
311
|
|
|
312
|
+
Before `start` stops a conflicting container, writes an instance, or builds an
|
|
313
|
+
image, it verifies that the selected identity's address belongs to this host and
|
|
314
|
+
that the route to the other peer selects that address as its source. A missing
|
|
315
|
+
VPN/data-plane interface or a route through the wrong network therefore fails
|
|
316
|
+
without disturbing a working session. Run the same check on its own with
|
|
317
|
+
`preflight`; deployments that require the other host to be online already can
|
|
318
|
+
also make three bounded ICMP probes mandatory:
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
rosotacom preflight 1_heartbeat --identity a \
|
|
322
|
+
--peer-address a=10.0.0.10 --peer-address b=10.0.0.11 \
|
|
323
|
+
--require-peer-reachable
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Peer reachability is opt-in because some valid networks block ICMP and peers may
|
|
327
|
+
be started in either order. `rosotacom start` accepts the same
|
|
328
|
+
`--require-peer-reachable` policy when a deployment does require it.
|
|
329
|
+
|
|
312
330
|
`rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
|
|
313
331
|
|
|
314
332
|
What else a run leaves under `logs/<peer>/`, and which file to open first when a
|
|
@@ -264,6 +264,24 @@ rosotacom start 1_heartbeat --identity b \
|
|
|
264
264
|
--peer-address a=10.0.0.10 --peer-address b=10.0.0.11
|
|
265
265
|
```
|
|
266
266
|
|
|
267
|
+
Before `start` stops a conflicting container, writes an instance, or builds an
|
|
268
|
+
image, it verifies that the selected identity's address belongs to this host and
|
|
269
|
+
that the route to the other peer selects that address as its source. A missing
|
|
270
|
+
VPN/data-plane interface or a route through the wrong network therefore fails
|
|
271
|
+
without disturbing a working session. Run the same check on its own with
|
|
272
|
+
`preflight`; deployments that require the other host to be online already can
|
|
273
|
+
also make three bounded ICMP probes mandatory:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
rosotacom preflight 1_heartbeat --identity a \
|
|
277
|
+
--peer-address a=10.0.0.10 --peer-address b=10.0.0.11 \
|
|
278
|
+
--require-peer-reachable
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Peer reachability is opt-in because some valid networks block ICMP and peers may
|
|
282
|
+
be started in either order. `rosotacom start` accepts the same
|
|
283
|
+
`--require-peer-reachable` policy when a deployment does require it.
|
|
284
|
+
|
|
267
285
|
`rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
|
|
268
286
|
|
|
269
287
|
What else a run leaves under `logs/<peer>/`, and which file to open first when a
|
|
@@ -85,6 +85,29 @@ Precedence is explicit:
|
|
|
85
85
|
All logical peers must resolve to addresses before a session starts. Session
|
|
86
86
|
definitions do not accept physical addresses or SSH targets.
|
|
87
87
|
|
|
88
|
+
## Data-plane preflight
|
|
89
|
+
|
|
90
|
+
`rosotacom start` checks the resolved bindings against the host before it stops
|
|
91
|
+
or creates containers:
|
|
92
|
+
|
|
93
|
+
1. The selected identity's IPv4 address must be assigned locally.
|
|
94
|
+
2. `ip route get` for the other peer must select that same address as its
|
|
95
|
+
source.
|
|
96
|
+
|
|
97
|
+
This makes an absent VPN/interface, a wrong identity, and a route escaping over
|
|
98
|
+
another network startup errors instead of silent communication failures. Inspect
|
|
99
|
+
the result without starting anything:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
rosotacom preflight SESSION --identity PEER
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Add `--require-peer-reachable` to `preflight` or `start` when this deployment
|
|
106
|
+
also requires three bounded ICMP probes to succeed. Reachability is not the
|
|
107
|
+
global default: ICMP can be intentionally filtered, and valid peers can be
|
|
108
|
+
started in either order. Docker-isolated local smoke networks use their own
|
|
109
|
+
network lifecycle and bypass this host data-plane check.
|
|
110
|
+
|
|
88
111
|
## Project selection and completion
|
|
89
112
|
|
|
90
113
|
The nearest `rosotacom.yaml` is discovered upward from the current directory.
|
|
@@ -64,6 +64,7 @@ from .image_cache import (
|
|
|
64
64
|
image_fingerprint,
|
|
65
65
|
reference_tag,
|
|
66
66
|
)
|
|
67
|
+
from .network_preflight import NetworkPreflightResult, run_network_preflight
|
|
67
68
|
|
|
68
69
|
anonymize_lib = importlib.import_module("rosotacom.anonymize")
|
|
69
70
|
|
|
@@ -1125,7 +1126,7 @@ def _get_local_ipv4s() -> list[str]:
|
|
|
1125
1126
|
out = subprocess.check_output(["ip", "-o", "-4", "addr", "show"], text=True)
|
|
1126
1127
|
except Exception:
|
|
1127
1128
|
return []
|
|
1128
|
-
return
|
|
1129
|
+
return re.findall(r"\binet\s+(\d+\.\d+\.\d+\.\d+)/", out)
|
|
1129
1130
|
|
|
1130
1131
|
|
|
1131
1132
|
def _default_local_ip() -> str:
|
|
@@ -1234,6 +1235,29 @@ def _auto_identity(bindings: dict[str, PeerBinding]) -> str:
|
|
|
1234
1235
|
raise RuntimeError(f"Auto identity ambiguous: matched peers={matches} for local IPv4s={sorted(local_ips)}.")
|
|
1235
1236
|
|
|
1236
1237
|
|
|
1238
|
+
def _network_preflight(
|
|
1239
|
+
bindings: dict[str, PeerBinding],
|
|
1240
|
+
identity: str,
|
|
1241
|
+
*,
|
|
1242
|
+
require_peer_reachable: bool = False,
|
|
1243
|
+
) -> NetworkPreflightResult:
|
|
1244
|
+
return run_network_preflight(
|
|
1245
|
+
bindings,
|
|
1246
|
+
identity,
|
|
1247
|
+
local_addresses=_get_local_ipv4s(),
|
|
1248
|
+
require_peer_reachable=require_peer_reachable,
|
|
1249
|
+
)
|
|
1250
|
+
|
|
1251
|
+
|
|
1252
|
+
def _print_network_preflight(result: NetworkPreflightResult) -> None:
|
|
1253
|
+
reachability = "peer reachable" if result.peer_reachable else "route verified"
|
|
1254
|
+
print(
|
|
1255
|
+
f"Network preflight OK: {result.identity} ({result.local_address}) -> "
|
|
1256
|
+
f"{result.remote_identity} ({result.remote_address}) via {result.interface} "
|
|
1257
|
+
f"src {result.source_address}; {reachability}."
|
|
1258
|
+
)
|
|
1259
|
+
|
|
1260
|
+
|
|
1237
1261
|
def _peer_com_name(peers: dict[str, Any], peer_key: str) -> str:
|
|
1238
1262
|
value = (peers.get(peer_key) or {}).get("com-name")
|
|
1239
1263
|
if value is None:
|
|
@@ -5123,10 +5147,18 @@ def start_session(args: argparse.Namespace) -> str:
|
|
|
5123
5147
|
identity = args.identity or _auto_identity(bindings)
|
|
5124
5148
|
if not args.identity:
|
|
5125
5149
|
print(f"Auto-selected identity: {identity}")
|
|
5150
|
+
network_isolated = bool(getattr(args, "network_name", None))
|
|
5151
|
+
if not network_isolated:
|
|
5152
|
+
_print_network_preflight(
|
|
5153
|
+
_network_preflight(
|
|
5154
|
+
bindings,
|
|
5155
|
+
identity,
|
|
5156
|
+
require_peer_reachable=getattr(args, "require_peer_reachable", False),
|
|
5157
|
+
)
|
|
5158
|
+
)
|
|
5126
5159
|
remote_name = _remote_peer_name(cfg, identity)
|
|
5127
5160
|
instance = _resolve_session_instance(runtime, session, getattr(args, "instance_id", None))
|
|
5128
5161
|
container_name = _container_name(remote_name, runtime, instance.instance_id)
|
|
5129
|
-
network_isolated = bool(getattr(args, "network_name", None))
|
|
5130
5162
|
if not network_isolated and not getattr(args, "skip_conflict_check", False):
|
|
5131
5163
|
matching = _matching_com_containers(runtime, remote_name)
|
|
5132
5164
|
if _fixed_com_container_name(runtime, remote_name) is not None:
|
|
@@ -5235,6 +5267,30 @@ def start_session(args: argparse.Namespace) -> str:
|
|
|
5235
5267
|
return container_name
|
|
5236
5268
|
|
|
5237
5269
|
|
|
5270
|
+
def preflight_session(args: argparse.Namespace) -> NetworkPreflightResult:
|
|
5271
|
+
runtime = _load_runtime_config(args)
|
|
5272
|
+
session = _resolve_session(args.session_dir, runtime)
|
|
5273
|
+
cfg = _effective_session_config(session.host_dir, runtime)
|
|
5274
|
+
bindings = _resolve_bindings(
|
|
5275
|
+
cfg,
|
|
5276
|
+
runtime,
|
|
5277
|
+
peer=getattr(args, "peer", None),
|
|
5278
|
+
peer_address=getattr(args, "peer_address", None),
|
|
5279
|
+
)
|
|
5280
|
+
if not args.identity and not getattr(args, "auto_identity", True):
|
|
5281
|
+
raise RuntimeError("Missing --identity. Provide --identity <peer> or allow auto identity.")
|
|
5282
|
+
identity = args.identity or _auto_identity(bindings)
|
|
5283
|
+
if not args.identity:
|
|
5284
|
+
print(f"Auto-selected identity: {identity}")
|
|
5285
|
+
result = _network_preflight(
|
|
5286
|
+
bindings,
|
|
5287
|
+
identity,
|
|
5288
|
+
require_peer_reachable=getattr(args, "require_peer_reachable", False),
|
|
5289
|
+
)
|
|
5290
|
+
_print_network_preflight(result)
|
|
5291
|
+
return result
|
|
5292
|
+
|
|
5293
|
+
|
|
5238
5294
|
def stop_session(args: argparse.Namespace) -> None:
|
|
5239
5295
|
runtime = _load_runtime_config(args)
|
|
5240
5296
|
session = _resolve_session(args.session_dir, runtime)
|
|
@@ -8668,6 +8724,11 @@ def _add_start_args(parser: argparse.ArgumentParser) -> None:
|
|
|
8668
8724
|
parser.add_argument("--rewrite-formatting", action="store_true")
|
|
8669
8725
|
_add_peer_arg(parser)
|
|
8670
8726
|
_add_peer_address_arg(parser)
|
|
8727
|
+
parser.add_argument(
|
|
8728
|
+
"--require-peer-reachable",
|
|
8729
|
+
action="store_true",
|
|
8730
|
+
help="Require three bounded ICMP probes to the peer to succeed before starting.",
|
|
8731
|
+
)
|
|
8671
8732
|
parser.add_argument("--instance-id", help="Join or create a named runtime session instance.")
|
|
8672
8733
|
parser.add_argument(
|
|
8673
8734
|
"--skip-conflict-check",
|
|
@@ -8681,6 +8742,22 @@ def _add_start_args(parser: argparse.ArgumentParser) -> None:
|
|
|
8681
8742
|
parser.set_defaults(force=True, auto_identity=True)
|
|
8682
8743
|
|
|
8683
8744
|
|
|
8745
|
+
def _add_preflight_args(parser: argparse.ArgumentParser) -> None:
|
|
8746
|
+
_add_common_config_args(parser)
|
|
8747
|
+
_add_session_arg(parser, "session_dir_positional", nargs="?")
|
|
8748
|
+
_add_session_arg(parser, "-s", "--session-dir", dest="session_dir")
|
|
8749
|
+
_add_identity_arg(parser)
|
|
8750
|
+
parser.add_argument("--no-auto-identity", dest="auto_identity", action="store_false")
|
|
8751
|
+
_add_peer_arg(parser)
|
|
8752
|
+
_add_peer_address_arg(parser)
|
|
8753
|
+
parser.add_argument(
|
|
8754
|
+
"--require-peer-reachable",
|
|
8755
|
+
action="store_true",
|
|
8756
|
+
help="Require three bounded ICMP probes to the peer to succeed.",
|
|
8757
|
+
)
|
|
8758
|
+
parser.set_defaults(auto_identity=True)
|
|
8759
|
+
|
|
8760
|
+
|
|
8684
8761
|
def _normalize_session_arg(args: argparse.Namespace) -> None:
|
|
8685
8762
|
positional = getattr(args, "session_dir_positional", None)
|
|
8686
8763
|
explicit = getattr(args, "session_dir", None)
|
|
@@ -8697,6 +8774,12 @@ def start_command(args: argparse.Namespace) -> int:
|
|
|
8697
8774
|
return 0
|
|
8698
8775
|
|
|
8699
8776
|
|
|
8777
|
+
def preflight_command(args: argparse.Namespace) -> int:
|
|
8778
|
+
_normalize_session_arg(args)
|
|
8779
|
+
preflight_session(args)
|
|
8780
|
+
return 0
|
|
8781
|
+
|
|
8782
|
+
|
|
8700
8783
|
def stop_command(args: argparse.Namespace) -> int:
|
|
8701
8784
|
_normalize_session_arg(args)
|
|
8702
8785
|
stop_session(args)
|
|
@@ -9052,6 +9135,7 @@ def videoquality_command(args: argparse.Namespace) -> int:
|
|
|
9052
9135
|
# turn into `rosotacom start foo` — so a contract test keeps the two in sync.
|
|
9053
9136
|
TOP_LEVEL_COMMANDS = {
|
|
9054
9137
|
"start",
|
|
9138
|
+
"preflight",
|
|
9055
9139
|
"stop",
|
|
9056
9140
|
"doctor",
|
|
9057
9141
|
"ps",
|
|
@@ -9127,6 +9211,13 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
9127
9211
|
_add_start_args(start_parser)
|
|
9128
9212
|
start_parser.set_defaults(func=start_command)
|
|
9129
9213
|
|
|
9214
|
+
preflight_parser = subparsers.add_parser(
|
|
9215
|
+
"preflight",
|
|
9216
|
+
help="Validate the resolved local address, peer route, and optional peer reachability.",
|
|
9217
|
+
)
|
|
9218
|
+
_add_preflight_args(preflight_parser)
|
|
9219
|
+
preflight_parser.set_defaults(func=preflight_command)
|
|
9220
|
+
|
|
9130
9221
|
stop_parser = subparsers.add_parser("stop", help="Stop rosotacom containers for a session.")
|
|
9131
9222
|
_add_common_config_args(stop_parser)
|
|
9132
9223
|
_add_session_arg(stop_parser, "session_dir_positional", nargs="?")
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Host data-plane validation for resolved communication peers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import ipaddress
|
|
6
|
+
import re
|
|
7
|
+
import subprocess
|
|
8
|
+
from collections.abc import Iterable
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
from .deployment import PeerBinding
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class NetworkPreflightResult:
|
|
16
|
+
identity: str
|
|
17
|
+
local_address: str
|
|
18
|
+
remote_identity: str
|
|
19
|
+
remote_address: str
|
|
20
|
+
interface: str
|
|
21
|
+
source_address: str
|
|
22
|
+
peer_reachable: bool | None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _binding_ipv4(binding: PeerBinding, *, role: str) -> str:
|
|
26
|
+
try:
|
|
27
|
+
return str(ipaddress.IPv4Address(binding.address))
|
|
28
|
+
except ipaddress.AddressValueError as exc:
|
|
29
|
+
raise RuntimeError(
|
|
30
|
+
f"Network preflight failed: {role} peer {binding.peer!r} has non-IPv4 address "
|
|
31
|
+
f"{binding.address!r}. Communication peer addresses must be concrete IPv4 addresses."
|
|
32
|
+
) from exc
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def run_network_preflight(
|
|
36
|
+
bindings: dict[str, PeerBinding],
|
|
37
|
+
identity: str,
|
|
38
|
+
*,
|
|
39
|
+
local_addresses: Iterable[str],
|
|
40
|
+
require_peer_reachable: bool = False,
|
|
41
|
+
) -> NetworkPreflightResult:
|
|
42
|
+
"""Validate the selected local binding and kernel path to its peer."""
|
|
43
|
+
if identity not in bindings:
|
|
44
|
+
raise RuntimeError(f"Network preflight failed: identity {identity!r} is not one of peers={sorted(bindings)}.")
|
|
45
|
+
if len(bindings) != 2:
|
|
46
|
+
raise RuntimeError(f"Network preflight failed: expected exactly 2 peers, got peers={sorted(bindings)}.")
|
|
47
|
+
|
|
48
|
+
local = bindings[identity]
|
|
49
|
+
remote_identity = next(peer for peer in bindings if peer != identity)
|
|
50
|
+
remote = bindings[remote_identity]
|
|
51
|
+
local_address = _binding_ipv4(local, role="local")
|
|
52
|
+
remote_address = _binding_ipv4(remote, role="remote")
|
|
53
|
+
|
|
54
|
+
known_local_addresses = sorted(set(local_addresses))
|
|
55
|
+
if not known_local_addresses:
|
|
56
|
+
raise RuntimeError(
|
|
57
|
+
"Network preflight failed: could not determine any local IPv4 addresses. "
|
|
58
|
+
"Verify that the `ip` command is installed and the required data-plane interface is up."
|
|
59
|
+
)
|
|
60
|
+
if local_address not in known_local_addresses:
|
|
61
|
+
raise RuntimeError(
|
|
62
|
+
f"Network preflight failed for identity {identity!r}: configured local address {local_address} "
|
|
63
|
+
f"is not assigned to this host (local IPv4s: {known_local_addresses}). "
|
|
64
|
+
"Verify --identity and the peer bindings; if the address belongs to a VPN or other data-plane "
|
|
65
|
+
"interface, bring that interface up before starting communication."
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
route = subprocess.run(
|
|
70
|
+
["ip", "-4", "route", "get", remote_address],
|
|
71
|
+
text=True,
|
|
72
|
+
capture_output=True,
|
|
73
|
+
check=False,
|
|
74
|
+
)
|
|
75
|
+
except FileNotFoundError as exc:
|
|
76
|
+
raise RuntimeError("Network preflight failed: required command `ip` was not found.") from exc
|
|
77
|
+
route_output = (route.stdout or "").strip()
|
|
78
|
+
if route.returncode != 0 or not route_output:
|
|
79
|
+
detail = (route.stderr or route.stdout or "no route returned").strip()
|
|
80
|
+
raise RuntimeError(
|
|
81
|
+
f"Network preflight failed: no usable IPv4 route from {identity!r} ({local_address}) "
|
|
82
|
+
f"to {remote_identity!r} ({remote_address}): {detail}"
|
|
83
|
+
)
|
|
84
|
+
route_line = route_output.splitlines()[0]
|
|
85
|
+
source_match = re.search(r"\bsrc\s+(\d+\.\d+\.\d+\.\d+)\b", route_line)
|
|
86
|
+
interface_match = re.search(r"\bdev\s+(\S+)", route_line)
|
|
87
|
+
if source_match is None or interface_match is None:
|
|
88
|
+
raise RuntimeError(
|
|
89
|
+
f"Network preflight failed: could not determine source address and interface from route: {route_line}"
|
|
90
|
+
)
|
|
91
|
+
source_address = source_match.group(1)
|
|
92
|
+
interface = interface_match.group(1)
|
|
93
|
+
if source_address != local_address:
|
|
94
|
+
raise RuntimeError(
|
|
95
|
+
f"Network preflight failed: route to {remote_identity!r} ({remote_address}) uses source "
|
|
96
|
+
f"{source_address} on {interface}, but identity {identity!r} is bound to {local_address}. "
|
|
97
|
+
"Fix the route or peer binding before starting communication."
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
peer_reachable: bool | None = None
|
|
101
|
+
if require_peer_reachable:
|
|
102
|
+
try:
|
|
103
|
+
ping = subprocess.run(
|
|
104
|
+
["ping", "-4", "-n", "-c", "3", "-W", "2", "-I", local_address, remote_address],
|
|
105
|
+
text=True,
|
|
106
|
+
capture_output=True,
|
|
107
|
+
check=False,
|
|
108
|
+
timeout=10,
|
|
109
|
+
)
|
|
110
|
+
except FileNotFoundError as exc:
|
|
111
|
+
raise RuntimeError(
|
|
112
|
+
"Network preflight failed: strict peer reachability was requested, but `ping` was not found."
|
|
113
|
+
) from exc
|
|
114
|
+
except subprocess.TimeoutExpired as exc:
|
|
115
|
+
raise RuntimeError(
|
|
116
|
+
f"Network preflight failed: ICMP check from {local_address} to {remote_address} exceeded 10 seconds."
|
|
117
|
+
) from exc
|
|
118
|
+
if ping.returncode != 0:
|
|
119
|
+
raise RuntimeError(
|
|
120
|
+
f"Network preflight failed: peer {remote_identity!r} ({remote_address}) did not answer "
|
|
121
|
+
f"3 ICMP echo requests sent from {local_address} via {interface}. This start requires an "
|
|
122
|
+
"already-reachable peer; verify the data plane, VPN, and firewall."
|
|
123
|
+
)
|
|
124
|
+
peer_reachable = True
|
|
125
|
+
|
|
126
|
+
return NetworkPreflightResult(
|
|
127
|
+
identity=identity,
|
|
128
|
+
local_address=local_address,
|
|
129
|
+
remote_identity=remote_identity,
|
|
130
|
+
remote_address=remote_address,
|
|
131
|
+
interface=interface,
|
|
132
|
+
source_address=source_address,
|
|
133
|
+
peer_reachable=peer_reachable,
|
|
134
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rosotacom-dev
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.dev53
|
|
4
4
|
Summary: Host CLI for ROS OTA communication sessions.
|
|
5
5
|
Author: develNor
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -309,6 +309,24 @@ rosotacom start 1_heartbeat --identity b \
|
|
|
309
309
|
--peer-address a=10.0.0.10 --peer-address b=10.0.0.11
|
|
310
310
|
```
|
|
311
311
|
|
|
312
|
+
Before `start` stops a conflicting container, writes an instance, or builds an
|
|
313
|
+
image, it verifies that the selected identity's address belongs to this host and
|
|
314
|
+
that the route to the other peer selects that address as its source. A missing
|
|
315
|
+
VPN/data-plane interface or a route through the wrong network therefore fails
|
|
316
|
+
without disturbing a working session. Run the same check on its own with
|
|
317
|
+
`preflight`; deployments that require the other host to be online already can
|
|
318
|
+
also make three bounded ICMP probes mandatory:
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
rosotacom preflight 1_heartbeat --identity a \
|
|
322
|
+
--peer-address a=10.0.0.10 --peer-address b=10.0.0.11 \
|
|
323
|
+
--require-peer-reachable
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Peer reachability is opt-in because some valid networks block ICMP and peers may
|
|
327
|
+
be started in either order. `rosotacom start` accepts the same
|
|
328
|
+
`--require-peer-reachable` policy when a deployment does require it.
|
|
329
|
+
|
|
312
330
|
`rosotacom` reads the static session input and creates generated files under `session-instances/<date>/<session>_<timestamp>_<id>/config/`, including per-peer plugin/session specs, topic lists, optional QoS, and optional `domain_bridge.yaml`. Catmux pane output is logged under the same instance in `logs/<peer>/catmux/`.
|
|
313
331
|
|
|
314
332
|
What else a run leaves under `logs/<peer>/`, and which file to open first when a
|
|
@@ -110,6 +110,7 @@ src/rosotacom/forensics.py
|
|
|
110
110
|
src/rosotacom/geomap.py
|
|
111
111
|
src/rosotacom/image_cache.py
|
|
112
112
|
src/rosotacom/netem_dist.py
|
|
113
|
+
src/rosotacom/network_preflight.py
|
|
113
114
|
src/rosotacom/network_profiles.py
|
|
114
115
|
src/rosotacom/network_shaper.py
|
|
115
116
|
src/rosotacom/plots.py
|
|
@@ -351,6 +352,7 @@ tests/unit/test_image_cache.py
|
|
|
351
352
|
tests/unit/test_link_bytes.py
|
|
352
353
|
tests/unit/test_link_trace.py
|
|
353
354
|
tests/unit/test_netem_dist.py
|
|
355
|
+
tests/unit/test_network_preflight.py
|
|
354
356
|
tests/unit/test_network_profiles.py
|
|
355
357
|
tests/unit/test_network_shaper.py
|
|
356
358
|
tests/unit/test_ota_link_configs.py
|
{rosotacom_dev-2.5.dev52 → rosotacom_dev-2.5.dev53}/src/rosotacom_dev.egg-info/scm_file_list.json
RENAMED
|
@@ -112,6 +112,7 @@
|
|
|
112
112
|
"src/rosotacom/geomap.py",
|
|
113
113
|
"src/rosotacom/image_cache.py",
|
|
114
114
|
"src/rosotacom/netem_dist.py",
|
|
115
|
+
"src/rosotacom/network_preflight.py",
|
|
115
116
|
"src/rosotacom/network_profiles.py",
|
|
116
117
|
"src/rosotacom/network_shaper.py",
|
|
117
118
|
"src/rosotacom/plots.py",
|
|
@@ -346,6 +347,7 @@
|
|
|
346
347
|
"tests/unit/test_link_bytes.py",
|
|
347
348
|
"tests/unit/test_link_trace.py",
|
|
348
349
|
"tests/unit/test_netem_dist.py",
|
|
350
|
+
"tests/unit/test_network_preflight.py",
|
|
349
351
|
"tests/unit/test_network_profiles.py",
|
|
350
352
|
"tests/unit/test_network_shaper.py",
|
|
351
353
|
"tests/unit/test_ota_link_configs.py",
|
|
@@ -1743,12 +1743,13 @@ def test_positional_session_defaults_to_start(monkeypatch: pytest.MonkeyPatch) -
|
|
|
1743
1743
|
|
|
1744
1744
|
monkeypatch.setattr(rosotacom, "start_session", fake_start_session)
|
|
1745
1745
|
|
|
1746
|
-
result = rosotacom.main(["1_heartbeat", "--identity", "a"])
|
|
1746
|
+
result = rosotacom.main(["1_heartbeat", "--identity", "a", "--require-peer-reachable"])
|
|
1747
1747
|
|
|
1748
1748
|
assert result == 0
|
|
1749
1749
|
assert calls
|
|
1750
1750
|
assert calls[0].session_dir == "1_heartbeat"
|
|
1751
1751
|
assert calls[0].identity == "a"
|
|
1752
|
+
assert calls[0].require_peer_reachable is True
|
|
1752
1753
|
|
|
1753
1754
|
|
|
1754
1755
|
def test_probe_verbs_dispatch_not_wrapped_in_start(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
@@ -2017,7 +2018,7 @@ def test_path_yaml_and_network_helpers(tmp_path: Path, monkeypatch: pytest.Monke
|
|
|
2017
2018
|
|
|
2018
2019
|
def fake_check_output(command: list[str], *, text: bool) -> str:
|
|
2019
2020
|
if command[:4] == ["ip", "-o", "-4", "addr"]:
|
|
2020
|
-
return "1: lo inet 127.0.0.1/8\n2: eth0 inet 10.0.0.5/24\n"
|
|
2021
|
+
return "1: lo inet 127.0.0.1/8\n2: eth0 inet 10.0.0.5/24 brd 10.0.0.255 scope global eth0\n"
|
|
2021
2022
|
return "1.1.1.1 via 10.0.0.1 dev eth0 src 10.0.0.5 uid 1000"
|
|
2022
2023
|
|
|
2023
2024
|
monkeypatch.setattr(rosotacom.subprocess, "check_output", fake_check_output)
|
|
@@ -2287,6 +2288,14 @@ def test_start_session_detached_dispatches_ros2docker(monkeypatch: pytest.Monkey
|
|
|
2287
2288
|
monkeypatch.setattr(rosotacom, "_load_runtime_config", lambda args: runtime)
|
|
2288
2289
|
monkeypatch.setattr(rosotacom, "_resolve_session", lambda session_dir, runtime: session)
|
|
2289
2290
|
monkeypatch.setattr(rosotacom, "_effective_session_config", lambda *args, **kwargs: cfg)
|
|
2291
|
+
monkeypatch.setattr(
|
|
2292
|
+
rosotacom,
|
|
2293
|
+
"_network_preflight",
|
|
2294
|
+
lambda *args, **kwargs: rosotacom.NetworkPreflightResult(
|
|
2295
|
+
"a", "127.0.0.1", "b", "127.0.0.2", "lo", "127.0.0.1", None
|
|
2296
|
+
),
|
|
2297
|
+
)
|
|
2298
|
+
monkeypatch.setattr(rosotacom, "_print_network_preflight", lambda result: None)
|
|
2290
2299
|
monkeypatch.setattr(rosotacom, "_scoped_image_name", lambda runtime: "image:id")
|
|
2291
2300
|
monkeypatch.setattr(
|
|
2292
2301
|
rosotacom,
|
|
@@ -2334,6 +2343,14 @@ def test_start_session_attach_dispatches_command_run(monkeypatch: pytest.MonkeyP
|
|
|
2334
2343
|
monkeypatch.setattr(rosotacom, "_resolve_session", lambda session_dir, runtime: session)
|
|
2335
2344
|
monkeypatch.setattr(rosotacom, "_effective_session_config", lambda *args, **kwargs: cfg)
|
|
2336
2345
|
monkeypatch.setattr(rosotacom, "_auto_identity", lambda *args: "a")
|
|
2346
|
+
monkeypatch.setattr(
|
|
2347
|
+
rosotacom,
|
|
2348
|
+
"_network_preflight",
|
|
2349
|
+
lambda *args, **kwargs: rosotacom.NetworkPreflightResult(
|
|
2350
|
+
"a", "127.0.0.1", "b", "127.0.0.2", "lo", "127.0.0.1", None
|
|
2351
|
+
),
|
|
2352
|
+
)
|
|
2353
|
+
monkeypatch.setattr(rosotacom, "_print_network_preflight", lambda result: None)
|
|
2337
2354
|
monkeypatch.setattr(rosotacom, "_scoped_image_name", lambda runtime: "image:id")
|
|
2338
2355
|
monkeypatch.setattr(rosotacom, "_base_extra_run_args", lambda runtime, session, cfg, instance, **kwargs: [])
|
|
2339
2356
|
monkeypatch.setattr(rosotacom, "_resolve_mode", lambda mode: "attach")
|
|
@@ -190,6 +190,14 @@ def _patch_start_session_collaborators(
|
|
|
190
190
|
monkeypatch.setattr(rosotacom, "_load_runtime_config", lambda args: runtime)
|
|
191
191
|
monkeypatch.setattr(rosotacom, "_resolve_session", lambda session_dir, runtime: session)
|
|
192
192
|
monkeypatch.setattr(rosotacom, "_effective_session_config", lambda *args, **kwargs: cfg)
|
|
193
|
+
monkeypatch.setattr(
|
|
194
|
+
rosotacom,
|
|
195
|
+
"_network_preflight",
|
|
196
|
+
lambda *args, **kwargs: rosotacom.NetworkPreflightResult(
|
|
197
|
+
"a", "127.0.0.1", "b", "127.0.0.2", "lo", "127.0.0.1", None
|
|
198
|
+
),
|
|
199
|
+
)
|
|
200
|
+
monkeypatch.setattr(rosotacom, "_print_network_preflight", lambda result: None)
|
|
193
201
|
monkeypatch.setattr(rosotacom, "_scoped_image_name", lambda runtime: "image:id")
|
|
194
202
|
monkeypatch.setattr(rosotacom, "_base_extra_run_args", lambda runtime, session, cfg, instance, **kwargs: [])
|
|
195
203
|
monkeypatch.setattr(rosotacom, "_resolve_mode", lambda mode: "detached")
|
|
@@ -236,16 +244,31 @@ def test_start_session_force_replaces_conflicting_identity_container(
|
|
|
236
244
|
cfg = {"peers": {"a": {}, "b": {"com-name": "remote"}}}
|
|
237
245
|
calls: list[tuple[str, dict[str, object]]] = []
|
|
238
246
|
stopped: list[str] = []
|
|
247
|
+
events: list[str] = []
|
|
239
248
|
_patch_start_session_collaborators(monkeypatch, runtime, session, cfg, calls)
|
|
249
|
+
monkeypatch.setattr(
|
|
250
|
+
rosotacom,
|
|
251
|
+
"_network_preflight",
|
|
252
|
+
lambda *args, **kwargs: (
|
|
253
|
+
events.append("preflight")
|
|
254
|
+
or rosotacom.NetworkPreflightResult("a", "127.0.0.1", "b", "127.0.0.2", "lo", "127.0.0.1", None)
|
|
255
|
+
),
|
|
256
|
+
)
|
|
240
257
|
monkeypatch.setattr(
|
|
241
258
|
rosotacom,
|
|
242
259
|
"_list_docker_containers",
|
|
243
260
|
lambda all_states=False: [("rosotacom_id_other_com_to_remote", ["bridge"])],
|
|
244
261
|
)
|
|
262
|
+
|
|
263
|
+
def record_stop(name: str, runtime: rosotacom.RuntimeConfig, **kwargs: object) -> bool:
|
|
264
|
+
events.append("stop")
|
|
265
|
+
stopped.append(name)
|
|
266
|
+
return True
|
|
267
|
+
|
|
245
268
|
monkeypatch.setattr(
|
|
246
269
|
rosotacom,
|
|
247
270
|
"_stop_container_name",
|
|
248
|
-
|
|
271
|
+
record_stop,
|
|
249
272
|
)
|
|
250
273
|
|
|
251
274
|
container = rosotacom.start_session(_start_session_args(force=True))
|
|
@@ -254,6 +277,7 @@ def test_start_session_force_replaces_conflicting_identity_container(
|
|
|
254
277
|
# The conflicting other-instance container is stopped first; force also
|
|
255
278
|
# keeps its pre-existing own-name replace for --instance-id rejoins.
|
|
256
279
|
assert stopped == ["rosotacom_id_other_com_to_remote", "rosotacom_id_unit_com_to_remote"]
|
|
280
|
+
assert events == ["preflight", "stop", "stop"]
|
|
257
281
|
assert [name for name, _ in calls] == ["build", "run", "exec"]
|
|
258
282
|
|
|
259
283
|
|