├── .html ├── packages ├── jumpstarter-testing │ ├── README.md │ ├── jumpstarter_testing │ │ ├── py.typed │ │ ├── __init__.py │ │ └── pytest_test.py │ ├── conftest.py │ └── pyproject.toml ├── hatch-pin-jumpstarter │ ├── README.md │ ├── src │ │ └── hatch_pin_jumpstarter │ │ │ └── py.typed │ └── pyproject.toml ├── jumpstarter-imagehash │ ├── README.md │ ├── jumpstarter_imagehash │ │ ├── py.typed │ │ ├── __init__.py │ │ ├── test_image_a.jpeg │ │ └── test_image_b.jpeg │ └── pyproject.toml ├── jumpstarter-protocol │ ├── README.md │ ├── jumpstarter_protocol │ │ ├── py.typed │ │ ├── jumpstarter │ │ │ ├── __init__.py │ │ │ ├── v1 │ │ │ │ ├── __init__.py │ │ │ │ ├── common_pb2_grpc.py │ │ │ │ └── kubernetes_pb2_grpc.py │ │ │ └── client │ │ │ │ ├── __init__.py │ │ │ │ └── v1 │ │ │ │ └── __init__.py │ │ └── __init__.py │ ├── protocol_test.py │ └── pyproject.toml ├── jumpstarter │ ├── jumpstarter │ │ ├── py.typed │ │ ├── config │ │ │ ├── __init__.py │ │ │ ├── shell.py │ │ │ ├── tls.py │ │ │ ├── env.py │ │ │ ├── common.py │ │ │ └── grpc.py │ │ ├── streams │ │ │ ├── __init__.py │ │ │ ├── blocking.py │ │ │ ├── aiohttp.py │ │ │ ├── encoding_test.py │ │ │ └── metadata.py │ │ ├── utils │ │ │ └── __init__.py │ │ ├── exporter │ │ │ ├── __init__.py │ │ │ └── logging.py │ │ ├── driver │ │ │ ├── __init__.py │ │ │ ├── decorators_test.py │ │ │ └── decorators.py │ │ ├── client │ │ │ ├── exceptions.py │ │ │ ├── __init__.py │ │ │ └── adapters.py │ │ ├── common │ │ │ ├── __init__.py │ │ │ ├── metadata.py │ │ │ ├── serde.py │ │ │ ├── importlib_test.py │ │ │ ├── utils_test.py │ │ │ ├── resources.py │ │ │ └── condition.py │ │ └── __init__.py │ └── README.md ├── jumpstarter-cli │ ├── jumpstarter_cli │ │ ├── py.typed │ │ ├── __main__.py │ │ ├── config.py │ │ ├── __init__.py │ │ ├── cli_test.py │ │ ├── jmp.py │ │ └── update.py │ ├── README.md │ └── pyproject.toml ├── jumpstarter-cli-admin │ ├── README.md │ ├── jumpstarter_cli_admin │ │ ├── py.typed │ │ ├── __main__.py │ │ ├── test_utils.py │ │ ├── k8s.py │ │ └── __init__.py │ └── pyproject.toml ├── jumpstarter-cli-common │ ├── jumpstarter_cli_common │ │ ├── py.typed │ │ ├── __init__.py │ │ ├── blocking.py │ │ └── signal.py │ ├── README.md │ └── pyproject.toml ├── jumpstarter-driver-can │ ├── jumpstarter_driver_can │ │ ├── py.typed │ │ └── __init__.py │ └── pyproject.toml ├── jumpstarter-kubernetes │ ├── jumpstarter_kubernetes │ │ ├── py.typed │ │ ├── util │ │ │ └── __init__.py │ │ ├── list.py │ │ ├── json.py │ │ └── serialize.py │ ├── README.md │ └── pyproject.toml ├── jumpstarter-driver-ble │ ├── jumpstarter_driver_ble │ │ ├── __init__.py │ │ └── driver_test.py │ ├── examples │ │ └── exporter.yaml │ └── pyproject.toml ├── jumpstarter-driver-flashers │ ├── oci_bundles │ │ ├── rcar_s4 │ │ │ ├── data │ │ │ │ └── .keep │ │ │ ├── overlay │ │ │ │ └── etc │ │ │ │ │ ├── udev │ │ │ │ │ └── rules.d │ │ │ │ │ │ └── 10-rename-tsn0.rules │ │ │ │ │ └── network │ │ │ │ │ └── if-pre-up.d │ │ │ │ │ └── wait-carrier.sh │ │ │ ├── build_flasher.sh │ │ │ ├── rootfs_only_defconfig │ │ │ └── manifest.yaml │ │ ├── aarch64-itb │ │ │ ├── data │ │ │ │ └── .gitkeep │ │ │ ├── manifest.yaml │ │ │ ├── overlay │ │ │ │ └── etc │ │ │ │ │ ├── udev │ │ │ │ │ └── rules.d │ │ │ │ │ │ └── 10-rename-tsn0.rules │ │ │ │ │ └── network │ │ │ │ │ └── if-pre-up.d │ │ │ │ │ └── wait-carrier.sh │ │ │ ├── manifest-renesas.yaml │ │ │ ├── buildroot_defconfig │ │ │ └── build_fits.sh │ │ ├── ti_j784s4xevm │ │ │ ├── data │ │ │ │ └── .gitkeep │ │ │ └── manifest.yaml │ │ ├── build_bundle.sh │ │ └── test │ │ │ ├── data │ │ │ └── kernel │ │ │ └── manifest.yaml │ ├── jumpstarter_driver_flashers │ │ └── __init__.py │ ├── .gitignore │ └── examples │ │ └── exporter.yaml ├── jumpstarter-driver-gpiod │ ├── jumpstarter_driver_gpiod │ │ ├── py.typed │ │ ├── __init__.py │ │ └── conftest.py │ ├── example │ │ └── exporter.yaml │ └── pyproject.toml ├── jumpstarter-driver-http │ ├── jumpstarter_driver_http │ │ ├── __init__.py │ │ └── py.typed │ └── pyproject.toml ├── jumpstarter-driver-iscsi │ ├── jumpstarter_driver_iscsi │ │ ├── py.typed │ │ └── __init__.py │ ├── examples │ │ └── exporter.yaml │ └── pyproject.toml ├── jumpstarter-driver-power │ ├── jumpstarter_driver_power │ │ ├── py.typed │ │ ├── __init__.py │ │ ├── common.py │ │ └── client_test.py │ ├── README.md │ └── pyproject.toml ├── jumpstarter-driver-qemu │ ├── jumpstarter_driver_qemu │ │ ├── __init__.py │ │ ├── py.typed │ │ └── client.py │ ├── images │ │ └── .gitignore │ └── README.md ├── jumpstarter-driver-snmp │ ├── jumpstarter_driver_snmp │ │ ├── __init__.py │ │ └── client.py │ ├── examples │ │ └── exporter.yaml │ └── pyproject.toml ├── jumpstarter-driver-ssh │ ├── jumpstarter_driver_ssh │ │ └── __init__.py │ ├── examples │ │ └── exporter.yaml │ └── pyproject.toml ├── jumpstarter-driver-tftp │ ├── jumpstarter_driver_tftp │ │ ├── py.typed │ │ ├── __init__.py │ │ └── driver_test.py │ ├── test.txt │ ├── examples │ │ ├── exporter.yaml │ │ └── tftp_test.py │ └── pyproject.toml ├── jumpstarter-driver-tmt │ ├── jumpstarter_driver_tmt │ │ ├── __init__.py │ │ └── driver.py │ ├── .gitignore │ ├── examples │ │ └── exporter.yaml │ └── pyproject.toml ├── jumpstarter-driver-uboot │ ├── jumpstarter_driver_uboot │ │ ├── py.typed │ │ ├── __init__.py │ │ ├── common.py │ │ └── driver.py │ ├── README.md │ └── pyproject.toml ├── jumpstarter-cli-driver │ ├── README.md │ ├── jumpstarter_cli_driver │ │ ├── __main__.py │ │ ├── driver_test.py │ │ ├── __init__.py │ │ └── driver.py │ └── pyproject.toml ├── jumpstarter-driver-dutlink │ ├── jumpstarter_driver_dutlink │ │ ├── py.typed │ │ ├── __init__.py │ │ └── conftest.py │ ├── examples │ │ └── exporter.yaml │ └── README.md ├── jumpstarter-driver-network │ └── jumpstarter_driver_network │ │ ├── py.typed │ │ ├── __init__.py │ │ ├── streams │ │ └── __init__.py │ │ ├── adapters │ │ ├── __init__.py │ │ ├── pexpect.py │ │ ├── dbus.py │ │ ├── fabric.py │ │ ├── novnc_test.py │ │ └── portforward.py │ │ └── conftest.py ├── jumpstarter-driver-opendal │ ├── jumpstarter_driver_opendal │ │ ├── py.typed │ │ ├── __init__.py │ │ └── conftest.py │ └── pyproject.toml ├── jumpstarter-driver-pyserial │ ├── jumpstarter_driver_pyserial │ │ ├── py.typed │ │ └── __init__.py │ └── pyproject.toml ├── jumpstarter-driver-ridesx │ ├── jumpstarter_driver_ridesx │ │ └── __init__.py │ ├── examples │ │ └── exporter.yaml │ └── pyproject.toml ├── jumpstarter-driver-sdwire │ ├── jumpstarter_driver_sdwire │ │ ├── __init__.py │ │ ├── py.typed │ │ └── driver_test.py │ ├── pyproject.toml │ └── README.md ├── jumpstarter-driver-shell │ ├── jumpstarter_driver_shell │ │ └── __init__.py │ ├── examples │ │ └── exporter.yaml │ └── pyproject.toml ├── jumpstarter-driver-tasmota │ ├── jumpstarter_driver_tasmota │ │ ├── py.typed │ │ ├── __init__.py │ │ └── driver_test.py │ └── pyproject.toml ├── jumpstarter-driver-yepkit │ ├── jumpstarter_driver_yepkit │ │ ├── __init__.py │ │ ├── py.typed │ │ ├── driver_test.py │ │ └── conftest.py │ ├── examples │ │ └── exporter.yaml │ └── pyproject.toml ├── jumpstarter-driver-composite │ ├── jumpstarter_driver_composite │ │ ├── __init__.py │ │ └── py.typed │ ├── README.md │ └── pyproject.toml ├── jumpstarter-driver-corellium │ ├── jumpstarter_driver_corellium │ │ ├── __init__.py │ │ ├── corellium │ │ │ ├── __init__.py │ │ │ ├── exceptions.py │ │ │ └── types.py │ │ └── client.py │ ├── fixtures │ │ └── http │ │ │ ├── get-instance-state-200.txt │ │ │ ├── json-error.json │ │ │ ├── create-instance-200.json │ │ │ ├── get-instance-console-url-200.json │ │ │ ├── login-200.json │ │ │ ├── get-instance-console-url-400.json │ │ │ ├── create-instance-400.json │ │ │ ├── get-projects-404.json │ │ │ ├── get-instance-404.json │ │ │ ├── 403.json │ │ │ ├── delete-instance-404.json │ │ │ ├── get-models-200.json │ │ │ └── get-projects-200.json │ ├── examples │ │ └── exporter.yml │ └── pyproject.toml ├── jumpstarter-driver-energenie │ ├── jumpstarter_driver_energenie │ │ └── __init__.py │ ├── .gitignore │ ├── examples │ │ └── exporter.yaml │ └── pyproject.toml ├── jumpstarter-driver-probe-rs │ ├── jumpstarter_driver_probe_rs │ │ ├── __init__.py │ │ └── driver_test.py │ ├── examples │ │ └── exporter.yaml │ └── pyproject.toml ├── jumpstarter-driver-ssh-mitm │ ├── jumpstarter_driver_ssh_mitm │ │ └── __init__.py │ └── examples │ │ └── exporter.yaml ├── jumpstarter-driver-ustreamer │ ├── jumpstarter_driver_ustreamer │ │ ├── __init__.py │ │ ├── py.typed │ │ ├── driver_test.py │ │ ├── client.py │ │ └── common.py │ ├── pyproject.toml │ └── README.md ├── jumpstarter-all │ ├── jumpstarter_all │ │ └── noop_test.py │ └── README.md ├── jumpstarter-driver-http-power │ ├── .gitignore │ ├── jumpstarter_driver_http_power │ │ └── __init__.py │ ├── examples │ │ └── exporter.yaml │ └── pyproject.toml └── jumpstarter-driver-vnc │ ├── jumpstarter_driver_vnc │ ├── __init__.py │ └── driver.py │ ├── examples │ └── exporter.yaml │ └── pyproject.toml ├── docs ├── source │ ├── _static │ │ ├── js │ │ │ └── .gitignore │ │ ├── img │ │ │ ├── avatar.png │ │ │ └── favicon.png │ │ └── css │ │ │ └── custom.css │ ├── reference │ │ ├── package-apis │ │ │ ├── drivers │ │ │ │ ├── ble.md │ │ │ │ ├── can.md │ │ │ │ ├── http.md │ │ │ │ ├── qemu.md │ │ │ │ ├── snmp.md │ │ │ │ ├── ssh.md │ │ │ │ ├── tftp.md │ │ │ │ ├── tmt.md │ │ │ │ ├── vnc.md │ │ │ │ ├── dutlink.md │ │ │ │ ├── gpiod.md │ │ │ │ ├── network.md │ │ │ │ ├── opendal.md │ │ │ │ ├── power.md │ │ │ │ ├── sdwire.md │ │ │ │ ├── shell.md │ │ │ │ ├── tasmota.md │ │ │ │ ├── uboot.md │ │ │ │ ├── yepkit.md │ │ │ │ ├── corellium.md │ │ │ │ ├── energenie.md │ │ │ │ ├── flashers.md │ │ │ │ ├── probe-rs.md │ │ │ │ ├── pyserial.md │ │ │ │ ├── ustreamer.md │ │ │ │ ├── http-power.md │ │ │ │ ├── dbus.yaml │ │ │ │ ├── proxy.yaml │ │ │ │ ├── sdwire.yaml │ │ │ │ ├── ustreamer.yaml │ │ │ │ ├── opendal.yaml │ │ │ │ └── uboot.yaml │ │ │ ├── exceptions.md │ │ │ └── index.md │ │ ├── man-pages │ │ │ ├── jmp.md │ │ │ ├── index.md │ │ │ └── j.md │ │ └── index.md │ ├── contributing │ │ └── images │ │ │ ├── rpc.png │ │ │ ├── router.png │ │ │ └── architecture.png │ ├── _templates │ │ ├── warning.html │ │ ├── head.html │ │ └── page.html │ ├── getting-started │ │ ├── installation │ │ │ ├── index.md │ │ │ └── service │ │ │ │ └── index.md │ │ ├── index.md │ │ ├── configuration │ │ │ └── index.md │ │ └── guides │ │ │ └── index.md │ └── introduction │ │ └── clients.md ├── multiversion.sh └── Makefile ├── __templates__ └── driver │ ├── jumpstarter_driver │ ├── __init__.py.tmpl │ ├── driver_test.py.tmpl │ ├── client.py.tmpl │ └── driver.py.tmpl │ ├── .gitignore.tmpl │ ├── examples │ └── exporter.yaml.tmpl │ └── pyproject.toml.tmpl ├── examples ├── automotive │ ├── jumpstarter_example_automotive │ │ ├── __init__.py │ │ ├── hello_test.py │ │ └── hello.py │ ├── README.md │ └── pyproject.toml └── soc-pytest │ ├── jumpstarter_example_soc_pytest │ ├── test_booted_ok.jpeg │ ├── test_booting_empty_ok.jpeg │ ├── test_booting_rainbow_ok.jpeg │ ├── test_booting_raspberries_ok.jpeg │ ├── image │ │ └── scripts │ │ │ ├── prepare-latest-raw │ │ │ └── download-latest-raspbian │ └── exporter.yaml │ └── pyproject.toml ├── .gitattributes ├── Dockerfile.utils ├── CONTRIBUTING.md ├── .devcontainer └── Dockerfile ├── buf.gen.yaml ├── .pre-commit-config.yaml ├── .github ├── workflows │ ├── typos.yaml │ ├── ruff.yaml │ ├── e2e.yaml │ ├── trigger-packages-index.yaml │ ├── build_oci_bundle.yaml │ └── pr_analytics.yaml └── dependabot.yml ├── .vscode ├── settings.json └── extensions.json ├── .devfile └── Containerfile ├── Dockerfile ├── kind_config.yaml ├── .devfile.yaml ├── conftest.py └── assets └── bolt.svg /.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-testing/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/hatch-pin-jumpstarter/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-imagehash/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-protocol/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter/README.md: -------------------------------------------------------------------------------- 1 | # Jumpstarter Core -------------------------------------------------------------------------------- /docs/source/_static/js/.gitignore: -------------------------------------------------------------------------------- 1 | version_array.js -------------------------------------------------------------------------------- /packages/jumpstarter-cli/jumpstarter_cli/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/config/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/streams/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /__templates__/driver/jumpstarter_driver/__init__.py.tmpl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli/README.md: -------------------------------------------------------------------------------- 1 | # The Jumpstarter CLI -------------------------------------------------------------------------------- /packages/jumpstarter-testing/jumpstarter_testing/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/automotive/jumpstarter_example_automotive/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-admin/README.md: -------------------------------------------------------------------------------- 1 | # Jumpstarter Admin CLI -------------------------------------------------------------------------------- /packages/jumpstarter-cli-admin/jumpstarter_cli_admin/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-common/jumpstarter_cli_common/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-can/jumpstarter_driver_can/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-imagehash/jumpstarter_imagehash/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-kubernetes/jumpstarter_kubernetes/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-protocol/jumpstarter_protocol/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/hatch-pin-jumpstarter/src/hatch_pin_jumpstarter/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-common/jumpstarter_cli_common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ble/jumpstarter_driver_ble/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-can/jumpstarter_driver_can/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/rcar_s4/data/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-gpiod/jumpstarter_driver_gpiod/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-http/jumpstarter_driver_http/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-http/jumpstarter_driver_http/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-iscsi/jumpstarter_driver_iscsi/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-power/jumpstarter_driver_power/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-snmp/jumpstarter_driver_snmp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ssh/jumpstarter_driver_ssh/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tmt/jumpstarter_driver_tmt/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-uboot/jumpstarter_driver_uboot/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-common/README.md: -------------------------------------------------------------------------------- 1 | # Jumpstarter CLI Common Utils -------------------------------------------------------------------------------- /packages/jumpstarter-cli-driver/README.md: -------------------------------------------------------------------------------- 1 | # Jumpstarter Driver CLI 2 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-gpiod/jumpstarter_driver_gpiod/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-iscsi/jumpstarter_driver_iscsi/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-network/jumpstarter_driver_network/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-power/jumpstarter_driver_power/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-qemu/images/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ridesx/jumpstarter_driver_ridesx/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-sdwire/jumpstarter_driver_sdwire/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-sdwire/jumpstarter_driver_sdwire/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-shell/jumpstarter_driver_shell/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tasmota/jumpstarter_driver_tasmota/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tftp/test.txt: -------------------------------------------------------------------------------- 1 | Hello from TFTP streaming test! -------------------------------------------------------------------------------- /packages/jumpstarter-driver-uboot/jumpstarter_driver_uboot/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-yepkit/jumpstarter_driver_yepkit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-yepkit/jumpstarter_driver_yepkit/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-kubernetes/README.md: -------------------------------------------------------------------------------- 1 | # Jumpstarter Kubernetes Library -------------------------------------------------------------------------------- /packages/jumpstarter-driver-composite/jumpstarter_driver_composite/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-composite/jumpstarter_driver_composite/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-energenie/jumpstarter_driver_energenie/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/jumpstarter_driver_flashers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/ti_j784s4xevm/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-network/jumpstarter_driver_network/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-probe-rs/jumpstarter_driver_probe_rs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-pyserial/jumpstarter_driver_pyserial/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ssh-mitm/jumpstarter_driver_ssh_mitm/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tasmota/jumpstarter_driver_tasmota/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/client/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /__templates__/driver/.gitignore.tmpl: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .coverage 3 | coverage.xml 4 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/get-instance-state-200.txt: -------------------------------------------------------------------------------- 1 | on 2 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/json-error.json: -------------------------------------------------------------------------------- 1 | {"token": "a} 2 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/client/v1/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-protocol/protocol_test.py: -------------------------------------------------------------------------------- 1 | def test_protocol(): 2 | pass 3 | -------------------------------------------------------------------------------- /packages/jumpstarter-all/jumpstarter_all/noop_test.py: -------------------------------------------------------------------------------- 1 | def test_nothing(): 2 | pass 3 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/manifest.yaml: -------------------------------------------------------------------------------- 1 | manifest-ti.yaml -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tmt/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .coverage 3 | coverage.xml 4 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-energenie/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .coverage 3 | coverage.xml 4 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .coverage 3 | coverage.xml 4 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-http-power/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .coverage 3 | coverage.xml 4 | -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/ble.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-ble/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/can.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-can/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/http.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-http/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/qemu.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-qemu/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/snmp.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-snmp/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/ssh.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-ssh/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/tftp.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-tftp/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/tmt.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-tmt/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/vnc.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-vnc/README.md -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ble/jumpstarter_driver_ble/driver_test.py: -------------------------------------------------------------------------------- 1 | # TODO: add some test if possible 2 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/__init__.py: -------------------------------------------------------------------------------- 1 | CHUNK_SIZE = 1024 * 1024 * 4 # 4MB 2 | -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/dutlink.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-dutlink/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/gpiod.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-gpiod/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/network.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-network/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/opendal.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-opendal/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/power.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-power/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/sdwire.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-sdwire/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/shell.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-shell/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/tasmota.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-tasmota/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/uboot.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-uboot/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/yepkit.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-yepkit/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/corellium.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-corellium/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/energenie.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-energenie/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/flashers.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-flashers/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/probe-rs.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-probe-rs/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/pyserial.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-pyserial/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/ustreamer.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-ustreamer/README.md -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/http-power.md: -------------------------------------------------------------------------------- 1 | ../../../../../packages/jumpstarter-driver-http-power/README.md -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | packages/jumpstarter-driver-flashers/oci_bundles/rcar_s4/data/flasher.itb filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-vnc/jumpstarter_driver_vnc/__init__.py: -------------------------------------------------------------------------------- 1 | from .client import VNClient 2 | 3 | VNClient = VNClient 4 | -------------------------------------------------------------------------------- /docs/source/_static/img/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumpstarter-dev/jumpstarter/HEAD/docs/source/_static/img/avatar.png -------------------------------------------------------------------------------- /docs/source/_static/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumpstarter-dev/jumpstarter/HEAD/docs/source/_static/img/favicon.png -------------------------------------------------------------------------------- /packages/jumpstarter-imagehash/jumpstarter_imagehash/__init__.py: -------------------------------------------------------------------------------- 1 | from .imagehash import ImageHash 2 | 3 | ImageHash = ImageHash 4 | -------------------------------------------------------------------------------- /docs/source/reference/man-pages/jmp.md: -------------------------------------------------------------------------------- 1 | ```{eval-rst} 2 | .. click:: jumpstarter_cli.jmp:jmp 3 | :prog: jmp 4 | :nested: full 5 | ``` -------------------------------------------------------------------------------- /docs/source/contributing/images/rpc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumpstarter-dev/jumpstarter/HEAD/docs/source/contributing/images/rpc.png -------------------------------------------------------------------------------- /examples/automotive/jumpstarter_example_automotive/hello_test.py: -------------------------------------------------------------------------------- 1 | from .hello import main 2 | 3 | 4 | def test_hello(): 5 | main() 6 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/create-instance-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "7f4f241c-821f-4219-905f-c3b50b0db5dd" 3 | } 4 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/get-instance-console-url-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "wss://api-host/port-cons-1" 3 | } 4 | -------------------------------------------------------------------------------- /packages/jumpstarter-testing/jumpstarter_testing/__init__.py: -------------------------------------------------------------------------------- 1 | from .pytest import JumpstarterTest 2 | 3 | __all__ = ["JumpstarterTest"] 4 | -------------------------------------------------------------------------------- /docs/source/contributing/images/router.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumpstarter-dev/jumpstarter/HEAD/docs/source/contributing/images/router.png -------------------------------------------------------------------------------- /Dockerfile.utils: -------------------------------------------------------------------------------- 1 | FROM fedora:42 2 | RUN dnf install -y kubernetes-client easy-rsa trurl && \ 3 | dnf clean all && \ 4 | rm -rf /var/cache/dnf 5 | -------------------------------------------------------------------------------- /docs/source/contributing/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumpstarter-dev/jumpstarter/HEAD/docs/source/contributing/images/architecture.png -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/login-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "session-token", 3 | "expiration": "2022-03-20T01:50:10.000Z" 4 | } 5 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-http-power/jumpstarter_driver_http_power/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Jumpstarter developers 2 | # SPDX-License-Identifier: Apache-2.0 3 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/exporter/__init__.py: -------------------------------------------------------------------------------- 1 | from .exporter import Exporter 2 | from .session import Session 3 | 4 | __all__ = ["Session", "Exporter"] 5 | -------------------------------------------------------------------------------- /examples/automotive/jumpstarter_example_automotive/hello.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | print("Hello from automotive!") 3 | 4 | 5 | if __name__ == "__main__": 6 | main() 7 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/config/shell.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class ShellConfigV1Alpha1(BaseModel): 5 | use_profiles: bool = False 6 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-network/jumpstarter_driver_network/streams/__init__.py: -------------------------------------------------------------------------------- 1 | from .websocket import WebsocketServerStream 2 | 3 | __all__ = ["WebsocketServerStream"] 4 | -------------------------------------------------------------------------------- /packages/jumpstarter-testing/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | pytest_plugins = ["pytester"] 4 | 5 | 6 | @pytest.fixture 7 | def anyio_backend(): 8 | return "asyncio" 9 | -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/dbus.yaml: -------------------------------------------------------------------------------- 1 | type: "jumpstarter_driver_network.driver.DbusNetwork" 2 | config: 3 | kind: "system" # which bus to connect to, system or session 4 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/get-instance-console-url-400.json: -------------------------------------------------------------------------------- 1 | { 2 | "error":"not a valid type", 3 | "errorID":"UserError", 4 | "field":"type" 5 | } 6 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/driver/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import Driver 2 | from .decorators import export, exportstream 3 | 4 | __all__ = ["Driver", "export", "exportstream"] 5 | -------------------------------------------------------------------------------- /docs/source/reference/package-apis/exceptions.md: -------------------------------------------------------------------------------- 1 | # Exceptions 2 | 3 | ## API Reference 4 | 5 | ```{eval-rst} 6 | .. automodule:: jumpstarter.common.exceptions 7 | :members: 8 | ``` 9 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/create-instance-400.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": "Unsupported device model", 3 | "errorID": "UserError", 4 | "field": "flavor" 5 | } 6 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/get-projects-404.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": "Found no matching Projects", 3 | "errorID": "UserError", 4 | "field": "Project" 5 | } 6 | -------------------------------------------------------------------------------- /packages/jumpstarter-kubernetes/jumpstarter_kubernetes/util/__init__.py: -------------------------------------------------------------------------------- 1 | from .async_custom_object_api import AbstractAsyncCustomObjectApi 2 | 3 | __all__ = ["AbstractAsyncCustomObjectApi"] 4 | -------------------------------------------------------------------------------- /examples/soc-pytest/jumpstarter_example_soc_pytest/test_booted_ok.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumpstarter-dev/jumpstarter/HEAD/examples/soc-pytest/jumpstarter_example_soc_pytest/test_booted_ok.jpeg -------------------------------------------------------------------------------- /packages/jumpstarter-imagehash/jumpstarter_imagehash/test_image_a.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumpstarter-dev/jumpstarter/HEAD/packages/jumpstarter-imagehash/jumpstarter_imagehash/test_image_a.jpeg -------------------------------------------------------------------------------- /packages/jumpstarter-imagehash/jumpstarter_imagehash/test_image_b.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumpstarter-dev/jumpstarter/HEAD/packages/jumpstarter-imagehash/jumpstarter_imagehash/test_image_b.jpeg -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/get-instance-404.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": "No instance associated with this value", 3 | "errorID": "UserError", 4 | "field": "InstanceId" 5 | } 6 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/client.py: -------------------------------------------------------------------------------- 1 | from jumpstarter_driver_composite.client import CompositeClient 2 | 3 | 4 | class CorelliumClient(CompositeClient): 5 | pass 6 | -------------------------------------------------------------------------------- /examples/soc-pytest/jumpstarter_example_soc_pytest/test_booting_empty_ok.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumpstarter-dev/jumpstarter/HEAD/examples/soc-pytest/jumpstarter_example_soc_pytest/test_booting_empty_ok.jpeg -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/client/exceptions.py: -------------------------------------------------------------------------------- 1 | from jumpstarter.common import exceptions 2 | 3 | 4 | class LeaseError(exceptions.JumpstarterException): 5 | """Raised when a lease operation fails.""" 6 | -------------------------------------------------------------------------------- /examples/soc-pytest/jumpstarter_example_soc_pytest/test_booting_rainbow_ok.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumpstarter-dev/jumpstarter/HEAD/examples/soc-pytest/jumpstarter_example_soc_pytest/test_booting_rainbow_ok.jpeg -------------------------------------------------------------------------------- /packages/jumpstarter-cli/jumpstarter_cli/__main__.py: -------------------------------------------------------------------------------- 1 | """Allow running Jumpstarter through `python -m jumpstarter_cli`.""" 2 | 3 | from .jmp import jmp 4 | 5 | if __name__ == "__main__": 6 | jmp(prog_name="jmp") 7 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/client/__init__.py: -------------------------------------------------------------------------------- 1 | from .base import DriverClient 2 | from .client import client_from_path 3 | from .lease import Lease 4 | 5 | __all__ = ["DriverClient", "client_from_path", "Lease"] 6 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/config/tls.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | 3 | 4 | class TLSConfigV1Alpha1(BaseModel): 5 | ca: str = Field(default="") 6 | insecure: bool = Field(default=False) 7 | -------------------------------------------------------------------------------- /examples/soc-pytest/jumpstarter_example_soc_pytest/test_booting_raspberries_ok.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jumpstarter-dev/jumpstarter/HEAD/examples/soc-pytest/jumpstarter_example_soc_pytest/test_booting_raspberries_ok.jpeg -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/403.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": "Invalid or missing authorization token", 3 | "errorID": "PermissionDenied", 4 | "originalError": "Invalid or missing authorization token" 5 | } 6 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/overlay/etc/udev/rules.d/10-rename-tsn0.rules: -------------------------------------------------------------------------------- 1 | # rename Renesas S4 main interface tsn0 to eth0 to unify setup 2 | SUBSYSTEM=="net", ACTION=="add", KERNEL=="tsn0", NAME="eth0" 3 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/rcar_s4/overlay/etc/udev/rules.d/10-rename-tsn0.rules: -------------------------------------------------------------------------------- 1 | # rename Renesas S4 main interface tsn0 to eth0 to unify setup 2 | SUBSYSTEM=="net", ACTION=="add", KERNEL=="tsn0", NAME="eth0" 3 | -------------------------------------------------------------------------------- /docs/source/_templates/warning.html: -------------------------------------------------------------------------------- 1 |
2 |

Warning

3 |

This documentation is actively being updated as the project evolves and may not be complete in all areas.

4 |
-------------------------------------------------------------------------------- /packages/jumpstarter-cli-admin/jumpstarter_cli_admin/__main__.py: -------------------------------------------------------------------------------- 1 | """Allow running Jumpstarter through `python -m jumpstarter_cli_admin`.""" 2 | 3 | from . import admin 4 | 5 | if __name__ == "__main__": 6 | admin(prog_name="jmp-admin") 7 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-driver/jumpstarter_cli_driver/__main__.py: -------------------------------------------------------------------------------- 1 | """Allow running Jumpstarter through `python -m jumpstarter_cli_driver`.""" 2 | 3 | from . import driver 4 | 5 | if __name__ == "__main__": 6 | driver(prog_name="jmp-driver") 7 | -------------------------------------------------------------------------------- /packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/common_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /packages/jumpstarter-protocol/jumpstarter_protocol/jumpstarter/v1/kubernetes_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/proxy.yaml: -------------------------------------------------------------------------------- 1 | children: 2 | proxy: 3 | ref: "foo.bar.power" 4 | foo: 5 | children: 6 | bar: 7 | children: 8 | power: 9 | type: "jumpstarter_driver_power.driver.MockPower" 10 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/common/__init__.py: -------------------------------------------------------------------------------- 1 | from .metadata import Metadata 2 | from .tempfile import TemporarySocket, TemporaryTcpListener, TemporaryUnixListener 3 | 4 | __all__ = ["Metadata", "TemporarySocket", "TemporaryUnixListener", "TemporaryTcpListener"] 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for your interest in contributing to Jumpstarter, we are an open 4 | community and we welcome contributions. 5 | 6 | For a complete contribution guide, please refer to our 7 | [documentation](https://jumpstarter.dev/main/contributing.html). 8 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-common/jumpstarter_cli_common/blocking.py: -------------------------------------------------------------------------------- 1 | from asyncio import run 2 | from functools import wraps 3 | 4 | 5 | def blocking(f): 6 | @wraps(f) 7 | def wrapper(*args, **kwargs): 8 | return run(f(*args, **kwargs)) 9 | 10 | return wrapper 11 | -------------------------------------------------------------------------------- /packages/jumpstarter-all/README.md: -------------------------------------------------------------------------------- 1 | # jumpstarter-all 2 | 3 | The Jumpstarter project is a collection of tools and services to help automate 4 | the testing of/on hardware devices. 5 | 6 | This is a meta-package that pulls installation of all the Python modules 7 | produced in the Jumpstarter project. 8 | 9 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-power/jumpstarter_driver_power/common.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class PowerReading(BaseModel): 5 | voltage: float 6 | current: float 7 | 8 | @property 9 | def apparent_power(self): 10 | return self.voltage * self.current 11 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-yepkit/jumpstarter_driver_yepkit/driver_test.py: -------------------------------------------------------------------------------- 1 | from .driver import Ykush 2 | from jumpstarter.common.utils import serve 3 | 4 | 5 | def test_drivers_yepkit(): 6 | instance = Ykush() 7 | 8 | with serve(instance) as client: 9 | client.on() 10 | client.off() 11 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/delete-instance-404.json: -------------------------------------------------------------------------------- 1 | { 2 | "error": "Instance with instanceId=7f4f241c-821f-4219-905f-c3b50b0db5dd not found", 3 | "errorID": "InstanceNotFound", 4 | "name": "Instance", 5 | "params": { 6 | "instanceId": "7f4f241c-821f-4219-905f-c3b50b0db5dd" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-driver/jumpstarter_cli_driver/driver_test.py: -------------------------------------------------------------------------------- 1 | from click.testing import CliRunner 2 | 3 | from . import driver 4 | 5 | 6 | def test_list_drivers(): 7 | runner = CliRunner() 8 | 9 | result = runner.invoke( 10 | driver, 11 | ["list"], 12 | ) 13 | assert result.exit_code == 0 14 | -------------------------------------------------------------------------------- /examples/automotive/README.md: -------------------------------------------------------------------------------- 1 | # Jumpstarter Automotive Example 2 | 3 | This example aims to demonstrate Jumpstarter in an automotive context. 4 | 5 | The following drivers will be utilized: 6 | - SSH 7 | - CAN/ISO-TP (UDS) 8 | 9 | This example requires the following hardware: 10 | - 2x Raspberry Pi 4 11 | - 2x Waveshare CAN FD Hat 12 | -------------------------------------------------------------------------------- /__templates__/driver/examples/exporter.yaml.tmpl: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: demo 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | example: 10 | type: jumpstarter_driver_${DRIVER_NAME}.driver.${DRIVER_CLASS} 11 | 12 | -------------------------------------------------------------------------------- /__templates__/driver/jumpstarter_driver/driver_test.py.tmpl: -------------------------------------------------------------------------------- 1 | from jumpstarter.common.utils import serve 2 | 3 | from .driver import ${DRIVER_CLASS} 4 | 5 | 6 | def test_drivers_${DRIVER_NAME}(): 7 | instance = ${DRIVER_CLASS}() 8 | 9 | with serve(instance) as client: 10 | assert client.state().ok 11 | _ = client.snapshot() 12 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli/jumpstarter_cli/config.py: -------------------------------------------------------------------------------- 1 | import click 2 | 3 | from .config_client import config_client 4 | from .config_exporter import config_exporter 5 | 6 | 7 | @click.group 8 | def config(): 9 | """ 10 | Manage local configurations 11 | """ 12 | pass 13 | 14 | 15 | config.add_command(config_client) 16 | config.add_command(config_exporter) 17 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Corellium API client exceptions module 3 | """ 4 | from jumpstarter.common.exceptions import JumpstarterException 5 | 6 | 7 | class CorelliumApiException(JumpstarterException): 8 | """ 9 | Exception raised when something goes wrong with Corellium's API. 10 | """ 11 | -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/sdwire.yaml: -------------------------------------------------------------------------------- 1 | type: "jumpstarter_driver_sdwire.driver.SDWire" 2 | config: 3 | # optional serial number of the sd-wire device 4 | # the first one found would be used if unset 5 | serial: "sdw-00001" 6 | # optional path to the block device exposed by sd-wire 7 | # automatically detected if unset 8 | storage_device: "/dev/disk/by-diskseq/1" 9 | -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/ustreamer.yaml: -------------------------------------------------------------------------------- 1 | type: "jumpstarter_driver_ustreamer.driver.UStreamer" 2 | config: 3 | # name or path of the ustreamer executable 4 | # defaults to finding ustreamer from path 5 | executable: "ustreamer" 6 | args: # extra arguments to pass to ustreamer 7 | brightness: auto # --brightness=auto 8 | contrast: default # --contract=default 9 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/client/adapters.py: -------------------------------------------------------------------------------- 1 | from contextlib import contextmanager 2 | from functools import wraps 3 | 4 | 5 | def blocking(f): 6 | @wraps(f) 7 | @contextmanager 8 | def wrapper(*args, **kwargs): 9 | with kwargs["client"].portal.wrap_async_context_manager(f(*args, **kwargs)) as res: 10 | yield res 11 | 12 | return wrapper 13 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/get-models-200.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "iot", 4 | "name": "rpi4b", 5 | "flavor": "rpi4b", 6 | "description": "Raspberry Pi 4", 7 | "model": "rpi4b", 8 | "peripherals": false, 9 | "quotas": { 10 | "cores": 4, 11 | "cpus": 4 12 | } 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/vscode/devcontainers/base:bookworm 2 | 3 | ENV PYTHONUNBUFFERED=True 4 | ENV UV_LINK_MODE=copy 5 | 6 | WORKDIR /opt 7 | 8 | COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv 9 | COPY --from=ghcr.io/astral-sh/uv:latest /uvx /bin/uvx 10 | COPY ./.python-version ./ 11 | 12 | # Install required tools for development 13 | RUN apt-get update && apt-get install -y iperf3 libusb-dev -------------------------------------------------------------------------------- /docs/source/_templates/head.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /buf.gen.yaml: -------------------------------------------------------------------------------- 1 | version: v2 2 | managed: 3 | enabled: true 4 | plugins: 5 | - remote: buf.build/protocolbuffers/python:v30.1 6 | out: ./packages/jumpstarter-protocol/jumpstarter_protocol 7 | - remote: buf.build/grpc/python 8 | out: ./packages/jumpstarter-protocol/jumpstarter_protocol 9 | inputs: 10 | - git_repo: https://github.com/jumpstarter-dev/jumpstarter-protocol.git 11 | branch: main 12 | subdir: proto 13 | -------------------------------------------------------------------------------- /docs/source/getting-started/installation/index.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | This section provides guidance on installing Jumpstarter components in your 4 | environment. The guides cover: 5 | 6 | - [Packages](packages.md): Installing Jumpstarter software packages 7 | - [Service](service/index.md): Setting up Jumpstarter as a Kubernetes service 8 | 9 | ```{toctree} 10 | :maxdepth: 1 11 | :hidden: 12 | packages.md 13 | service/index.md 14 | ``` -------------------------------------------------------------------------------- /packages/jumpstarter-driver-dutlink/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | # /etc/jumpstarter/exporters/dutlink.yaml 2 | apiVersion: jumpstarter.dev/v1alpha1 3 | kind: ExporterConfig 4 | metadata: 5 | namespace: default 6 | name: demo 7 | endpoint: "" 8 | token: "" 9 | export: 10 | dutlink: 11 | type: jumpstarter_driver_dutlink.driver.Dutlink 12 | config: 13 | storage_device: "/dev/null" # TODO: replace with real storage device 14 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-energenie/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: demo 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | power: 10 | type: jumpstarter_driver_energenie.driver.EnerGenie 11 | config: 12 | host: "192.168.1.51" 13 | password: "1" 14 | slot: 1 15 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_stages: [pre-commit] 2 | repos: 3 | - repo: https://github.com/astral-sh/ruff-pre-commit 4 | rev: v0.9.2 5 | hooks: 6 | - id: ruff 7 | name: Ruff Check 8 | description: "Run 'ruff check' for extremely fast Python linting" 9 | args: [ --fix ] 10 | 11 | - id: ruff-format 12 | name: Ruff Format 13 | description: "Run 'ruff format' for extremely fast Python formatting" -------------------------------------------------------------------------------- /examples/automotive/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-example-automotive" 3 | version = "0.1.0" 4 | description = "" 5 | authors = [ 6 | { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, 7 | { name = "Nick Cao", email = "ncao@redhat.com" }, 8 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 9 | ] 10 | readme = "README.md" 11 | license = "Apache-2.0" 12 | requires-python = ">=3.11" 13 | dependencies = ["jumpstarter"] 14 | -------------------------------------------------------------------------------- /.github/workflows/typos.yaml: -------------------------------------------------------------------------------- 1 | name: Spell Check 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | - release-* 9 | pull_request: 10 | merge_group: 11 | 12 | permissions: 13 | contents: read 14 | 15 | jobs: 16 | typos: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Run typos 21 | uses: crate-ci/typos@0f0ccba9ed1df83948f0c15026e4f5ccfce46109 # v1.32.0 22 | -------------------------------------------------------------------------------- /__templates__/driver/jumpstarter_driver/client.py.tmpl: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from jumpstarter.client import DriverClient 4 | 5 | 6 | @dataclass(kw_only=True) 7 | class ${DRIVER_CLASS}Client(DriverClient): 8 | """ 9 | Client interface for ... 10 | 11 | This client provides methods to 12 | """ 13 | 14 | def method1(self): 15 | self.call("method1") 16 | 17 | def method2(self): 18 | self.call("method2") 19 | 20 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-probe-rs/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: demo 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | probe: 10 | type: jumpstarter_driver_probe_rs.driver.ProbeRs 11 | config: 12 | probe_rs_path: /home/majopela/.cargo/bin/probe-rs 13 | protocol: "swd" 14 | speed: 4000 15 | 16 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/common/metadata.py: -------------------------------------------------------------------------------- 1 | from dataclasses import field 2 | from uuid import UUID, uuid4 3 | 4 | from pydantic.dataclasses import dataclass 5 | 6 | 7 | @dataclass(kw_only=True, slots=True) 8 | class Metadata: 9 | uuid: UUID = field(default_factory=uuid4) 10 | labels: dict[str, str] = field(default_factory=dict) 11 | 12 | @property 13 | def name(self): 14 | return self.labels.get("jumpstarter.dev/name", "unknown") 15 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/common/serde.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from google.protobuf import json_format, struct_pb2 4 | from pydantic import TypeAdapter 5 | 6 | adapter = TypeAdapter(Any) 7 | 8 | 9 | def encode_value(v: Any): 10 | return json_format.ParseDict(adapter.dump_python(v, mode="json"), struct_pb2.Value()) 11 | 12 | 13 | def decode_value(v: struct_pb2.Value) -> Any: 14 | return adapter.validate_python(json_format.MessageToDict(v)) 15 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli/jumpstarter_cli/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import truststore 4 | 5 | # if we are running in MacOS avoid injecting system certificates to avoid 6 | # https://github.com/jumpstarter-dev/jumpstarter/issues/362 7 | # also allow to force the system certificates injection with 8 | # JUMPSTARTER_FORCE_SYSTEM_CERTS=1 9 | if os.uname().sysname != "Darwin" or os.environ.get("JUMPSTARTER_FORCE_SYSTEM_CERTS") == "1": 10 | truststore.inject_into_ssl() 11 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/__init__.py: -------------------------------------------------------------------------------- 1 | from .dbus import DbusAdapter 2 | from .fabric import FabricAdapter 3 | from .novnc import NovncAdapter 4 | from .pexpect import PexpectAdapter 5 | from .portforward import TcpPortforwardAdapter, UnixPortforwardAdapter 6 | 7 | __all__ = [ 8 | "DbusAdapter", 9 | "FabricAdapter", 10 | "NovncAdapter", 11 | "PexpectAdapter", 12 | "TcpPortforwardAdapter", 13 | "UnixPortforwardAdapter", 14 | ] 15 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/config/env.py: -------------------------------------------------------------------------------- 1 | # Common environment variables for client/exporter config 2 | JMP_CLIENT_CONFIG_HOME = "JMP_CLIENT_CONFIG_HOME" 3 | JMP_CLIENT_CONFIG = "JMP_CLIENT_CONFIG" 4 | JMP_NAMESPACE = "JMP_NAMESPACE" 5 | JMP_NAME = "JMP_NAME" 6 | JMP_ENDPOINT = "JMP_ENDPOINT" 7 | JMP_TOKEN = "JMP_TOKEN" 8 | JMP_DRIVERS_ALLOW = "JMP_DRIVERS_ALLOW" 9 | JUMPSTARTER_HOST = "JUMPSTARTER_HOST" 10 | JMP_LEASE = "JMP_LEASE" 11 | 12 | JMP_DISABLE_COMPRESSION = "JMP_DISABLE_COMPRESSION" 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.testing.pytestArgs": [ 3 | "tests", 4 | "jumpstarter", 5 | "--cov", 6 | "--cov-report=html", 7 | "--cov-report=xml" 8 | ], 9 | "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", 10 | "python.testing.unittestEnabled": false, 11 | "python.testing.pytestEnabled": true, 12 | "python.analysis.extraPaths": [ 13 | "./contrib/*" 14 | ], 15 | "makefile.configureOnOpen": false 16 | } -------------------------------------------------------------------------------- /docs/source/reference/man-pages/index.md: -------------------------------------------------------------------------------- 1 | # MAN Pages 2 | 3 | This section provides reference documentation for Jumpstarter's command-line 4 | interfaces. The documentation covers: 5 | 6 | - [`jmp`](jmp.md): Main command-line interface for Jumpstarter 7 | - [`j`](j.md): Shorthand utility for quick interactions with Jumpstarter 8 | 9 | These references support both local and distributed deployment modes of 10 | Jumpstarter. 11 | 12 | ```{toctree} 13 | :maxdepth: 1 14 | :hidden: 15 | jmp.md 16 | j.md 17 | ``` -------------------------------------------------------------------------------- /packages/jumpstarter-cli-admin/jumpstarter_cli_admin/test_utils.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | def json_equal(a: str, b: str) -> bool: 5 | def _parse(s: str): 6 | try: 7 | data = json.loads(s) 8 | except ValueError: 9 | return object() 10 | if isinstance(data, str): 11 | try: 12 | data = json.loads(data) 13 | except ValueError: 14 | pass 15 | return data 16 | 17 | return _parse(a) == _parse(b) 18 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-iscsi/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: iscsi-exporter 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | iscsi: 10 | type: jumpstarter_driver_iscsi.driver.ISCSI 11 | config: 12 | root_dir: "/var/lib/iscsi" 13 | iqn_prefix: "iqn.2024-06.dev.jumpstarter" 14 | target_name: "my-target" 15 | host: "" 16 | port: 3260 -------------------------------------------------------------------------------- /packages/jumpstarter-kubernetes/jumpstarter_kubernetes/list.py: -------------------------------------------------------------------------------- 1 | from typing import Generic, Literal, TypeVar 2 | 3 | from pydantic import Field 4 | 5 | from .json import JsonBaseModel 6 | 7 | T = TypeVar("T") 8 | 9 | 10 | class V1Alpha1List(JsonBaseModel, Generic[T]): 11 | """A generic list result type.""" 12 | 13 | api_version: Literal["jumpstarter.dev/v1alpha1"] = Field(alias="apiVersion", default="jumpstarter.dev/v1alpha1") 14 | items: list[T] 15 | kind: Literal["List"] = Field(default="List") 16 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/streams/blocking.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from anyio.abc import AnyByteStream 4 | from anyio.from_thread import BlockingPortal 5 | 6 | 7 | @dataclass(kw_only=True) 8 | class BlockingStream: 9 | stream: AnyByteStream 10 | portal: BlockingPortal 11 | 12 | def send(self, data: bytes) -> None: 13 | return self.portal.call(self.stream.send, data) 14 | 15 | def receive(self) -> bytes: 16 | return self.portal.call(self.stream.receive) 17 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli/jumpstarter_cli/cli_test.py: -------------------------------------------------------------------------------- 1 | from click.testing import CliRunner 2 | 3 | from .jmp import jmp 4 | 5 | 6 | def test_cli(): 7 | runner = CliRunner() 8 | result = runner.invoke(jmp, []) 9 | for subcommand in [ 10 | "config", 11 | "create", 12 | "delete", 13 | "driver", 14 | "get", 15 | "login", 16 | "run", 17 | "shell", 18 | "update", 19 | "version", 20 | ]: 21 | assert subcommand in result.output 22 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-snmp/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 4 | metadata: 5 | namespace: default 6 | name: demo 7 | tls: 8 | ca: '' 9 | insecure: true 10 | token: 11 | export: 12 | power: 13 | type: "jumpstarter_driver_snmp.driver.SNMPServer" 14 | config: 15 | host: "pdu.mgmt.com" 16 | user: "labuser" 17 | plug: 32 18 | oid: "1.3.6.1.4.1.13742.6.4.1.2.1.2.1" 19 | -------------------------------------------------------------------------------- /.github/workflows/ruff.yaml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | - release-* 9 | pull_request: 10 | merge_group: 11 | 12 | permissions: 13 | contents: read 14 | 15 | jobs: 16 | ruff: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Run ruff 21 | uses: astral-sh/ruff-action@84f83ecf9e1e15d26b7984c7ec9cf73d39ffc946 # v3.3.1 22 | with: 23 | version-file: pyproject.toml 24 | -------------------------------------------------------------------------------- /docs/source/_static/css/custom.css: -------------------------------------------------------------------------------- 1 | .admonition.warning { 2 | margin-bottom: 2rem; 3 | } 4 | 5 | /* Hide the Furo attribution text */ 6 | .made-with-furo { 7 | display: none !important; 8 | } 9 | 10 | /* Fix version name overflow in sidebar */ 11 | .sidebar-brand .sidebar-brand-text { 12 | white-space: normal; 13 | word-break: break-word; 14 | } 15 | 16 | .sidebar-brand .sidebar-brand-text a { 17 | display: inline-block; 18 | max-width: 100%; 19 | overflow: hidden; 20 | text-overflow: ellipsis; 21 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for more information: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | # https://containers.dev/guide/dependabot 6 | 7 | version: 2 8 | updates: 9 | - package-ecosystem: "devcontainers" 10 | directory: "/" 11 | schedule: 12 | interval: weekly 13 | -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/opendal.yaml: -------------------------------------------------------------------------------- 1 | type: "jumpstarter_driver_opendal.driver.Opendal" 2 | config: 3 | # See https://docs.rs/opendal/latest/opendal/services/index.html 4 | # for list of supported services and their configuration parameters 5 | scheme: "fs" 6 | kwargs: 7 | root: "/tmp/jumpstarter" 8 | # Optional: automatically remove created files/directories when driver closes 9 | # Note: all tracked paths are normalized by stripping leading/trailing slashes 10 | remove_created_on_close: false 11 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-dutlink/jumpstarter_driver_dutlink/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import usb 3 | 4 | 5 | def pytest_runtest_call(item): 6 | try: 7 | item.runtest() 8 | except FileNotFoundError: 9 | pytest.skip("dutlink not available") # ty: ignore[call-non-callable] 10 | except usb.core.USBError: 11 | pytest.skip("USB not available") # ty: ignore[call-non-callable] 12 | except usb.core.NoBackendError: 13 | pytest.skip("No USB backend") # ty: ignore[call-non-callable] 14 | -------------------------------------------------------------------------------- /docs/source/reference/index.md: -------------------------------------------------------------------------------- 1 | # Reference 2 | 3 | This section provides reference documentation for Jumpstarter. The documentation 4 | covers: 5 | 6 | - [API Pages](man-pages/index.md): Command-line tools and utilities 7 | documentation 8 | - [Packages](package-apis/index.md): API documentation for Jumpstarter packages 9 | and components 10 | 11 | These references are useful for developers working with Jumpstarter. 12 | 13 | ```{toctree} 14 | :maxdepth: 1 15 | :hidden: 16 | 17 | man-pages/index.md 18 | package-apis/index.md 19 | ``` -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/rcar_s4/overlay/etc/network/if-pre-up.d/wait-carrier.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | IF_WAIT_DELAY=30 4 | 5 | if [ "${IFACE}" != "lo" ]; then 6 | ip link set ${IFACE} up 7 | printf "Waiting for interface %s carrier" "${IFACE}" 8 | while [ ${IF_WAIT_DELAY} -gt 0 ]; do 9 | if [ "$(cat /sys/class/net/${IFACE}/carrier)" = "1" ]; then 10 | printf "\n" 11 | exit 0 12 | fi 13 | sleep 1 14 | printf "." 15 | : $((IF_WAIT_DELAY -= 1)) 16 | done 17 | printf " timeout!\n" 18 | exit 1 19 | fi 20 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-opendal/jumpstarter_driver_opendal/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from .driver import Opendal 4 | from jumpstarter.common.utils import serve 5 | 6 | 7 | @pytest.fixture 8 | def opendal(tmp_path): 9 | with serve(Opendal(scheme="fs", kwargs={"root": str(tmp_path)})) as client: 10 | yield client 11 | 12 | 13 | @pytest.fixture(autouse=True) 14 | def opendal_namespace(doctest_namespace, opendal, tmp_path): 15 | doctest_namespace["opendal"] = opendal 16 | doctest_namespace["tmp"] = tmp_path 17 | -------------------------------------------------------------------------------- /docs/source/_templates/page.html: -------------------------------------------------------------------------------- 1 | {% extends "!page.html" %} 2 | {% block extrahead %} 3 | {% include "head.html" %} 4 | {% endblock %} 5 | 6 | {% block content %} 7 | {% if pagename != 'index' %} 8 |
9 |

Warning

10 |

This documentation is actively being updated as the project evolves and may not be complete in all areas.

11 |
12 | {% endif %} 13 | 14 | {{ super() }} 15 | {% endblock %} 16 | 17 | {% block footer %} 18 | {% include "footer.html" %} 19 | {% endblock %} -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/overlay/etc/network/if-pre-up.d/wait-carrier.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | IF_WAIT_DELAY=30 4 | 5 | if [ "${IFACE}" != "lo" ]; then 6 | ip link set ${IFACE} up 7 | printf "Waiting for interface %s carrier" "${IFACE}" 8 | while [ ${IF_WAIT_DELAY} -gt 0 ]; do 9 | if [ "$(cat /sys/class/net/${IFACE}/carrier)" = "1" ]; then 10 | printf "\n" 11 | exit 0 12 | fi 13 | sleep 1 14 | printf "." 15 | : $((IF_WAIT_DELAY -= 1)) 16 | done 17 | printf " timeout!\n" 18 | exit 1 19 | fi 20 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-uboot/jumpstarter_driver_uboot/common.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | ESC = "\x1b" 4 | 5 | 6 | class DhcpInfo(BaseModel): 7 | ip_address: str 8 | gateway: str 9 | netmask: str 10 | 11 | @property 12 | def cidr(self) -> str: 13 | try: 14 | octets = [int(x) for x in self.netmask.split(".")] 15 | binary = "".join([bin(x)[2:].zfill(8) for x in octets]) 16 | return str(binary.count("1")) 17 | except Exception: 18 | return "24" 19 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/driver_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from jumpstarter_driver_ustreamer.driver import UStreamer 4 | 5 | from jumpstarter.common.utils import serve 6 | 7 | 8 | def test_drivers_video_ustreamer(): 9 | try: 10 | instance = UStreamer() 11 | except FileNotFoundError: 12 | pytest.skip("ustreamer not available") # ty: ignore[call-non-callable] 13 | 14 | with serve(instance) as client: 15 | assert client.state().ok 16 | _ = client.snapshot() 17 | -------------------------------------------------------------------------------- /docs/source/reference/package-apis/index.md: -------------------------------------------------------------------------------- 1 | # Package APIs 2 | 3 | This section provides reference documentation for Jumpstarter's package APIs and 4 | components. The documentation covers: 5 | 6 | - [Drivers](drivers/index.md): APIs for various driver categories 7 | - [Exceptions](exceptions.md): Exceptions raised by driver clients 8 | 9 | These references are useful for developers extending Jumpstarter or integrating 10 | with custom hardware. 11 | 12 | ```{toctree} 13 | :maxdepth: 1 14 | :hidden: 15 | drivers/index.md 16 | exceptions.md 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-driver/jumpstarter_cli_driver/__init__.py: -------------------------------------------------------------------------------- 1 | import click 2 | from jumpstarter_cli_common.alias import AliasedGroup 3 | from jumpstarter_cli_common.opt import opt_log_level 4 | from jumpstarter_cli_common.version import version 5 | 6 | from .driver import list_drivers 7 | 8 | 9 | @click.group(cls=AliasedGroup) 10 | @opt_log_level 11 | def driver(): 12 | """Jumpstarter driver CLI tool""" 13 | 14 | 15 | driver.add_command(list_drivers) 16 | driver.add_command(version) 17 | 18 | if __name__ == "__main__": 19 | driver() 20 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-yepkit/jumpstarter_driver_yepkit/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import usb 3 | 4 | 5 | def pytest_runtest_call(item): 6 | try: 7 | item.runtest() 8 | except FileNotFoundError: 9 | pytest.skip("yepkit not available") # ty: ignore[call-non-callable] 10 | except usb.core.USBError: 11 | pytest.skip("USB not available, could need root permissions") # ty: ignore[call-non-callable] 12 | except usb.core.NoBackendError: 13 | pytest.skip("No USB backend") # ty: ignore[call-non-callable] 14 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-gpiod/example/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | name: shell-exporter 5 | namespace: default 6 | export: 7 | gpio: 8 | type: jumpstarter_driver_gpiod.driver.DigitalOutput 9 | config: 10 | line: 23 11 | drive: open_drain 12 | bias: pull_up 13 | initial_value: "off" 14 | 15 | gpioin: 16 | type: jumpstarter_driver_gpiod.driver.DigitalInput 17 | config: 18 | line: 24 19 | bias: pull_up 20 | active_low: True 21 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ssh/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: demo 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | ssh: 10 | type: jumpstarter_driver_ssh.driver.SSHWrapper 11 | config: 12 | default_username: "core" 13 | children: 14 | tcp: 15 | type: jumpstarter_driver_network.driver.TcpNetwork 16 | config: 17 | host: "192.168.1.3" 18 | port: 22 19 | 20 | -------------------------------------------------------------------------------- /packages/jumpstarter-kubernetes/jumpstarter_kubernetes/json.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | from pydantic import BaseModel, ConfigDict 3 | 4 | 5 | class JsonBaseModel(BaseModel): 6 | """A Pydantic BaseModel with additional Jumpstarter JSON options applied.""" 7 | 8 | def dump_json(self): 9 | return self.model_dump_json(indent=4, by_alias=True) 10 | 11 | def dump_yaml(self): 12 | return yaml.safe_dump(self.model_dump(mode="json", by_alias=True), indent=2) 13 | 14 | model_config = ConfigDict(arbitrary_types_allowed=True, populate_by_name=True) 15 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/config/common.py: -------------------------------------------------------------------------------- 1 | from os import getenv 2 | from pathlib import Path 3 | 4 | from pydantic_settings import BaseSettings, SettingsConfigDict 5 | from xdg_base_dirs import xdg_config_home 6 | 7 | from .env import JMP_CLIENT_CONFIG_HOME 8 | 9 | CONFIG_API_VERSION = "jumpstarter.dev/v1alpha1" 10 | CONFIG_PATH = Path(getenv(JMP_CLIENT_CONFIG_HOME, xdg_config_home() / "jumpstarter")) 11 | 12 | 13 | class ObjectMeta(BaseSettings): 14 | model_config = SettingsConfigDict(env_prefix="JMP_") 15 | 16 | namespace: str | None 17 | name: str 18 | -------------------------------------------------------------------------------- /.github/workflows/e2e.yaml: -------------------------------------------------------------------------------- 1 | name: "Run E2E Tests" 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: 6 | - main 7 | - release-* 8 | pull_request: 9 | merge_group: 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | e2e: 16 | if: github.repository_owner == 'jumpstarter-dev' 17 | runs-on: ubuntu-latest 18 | timeout-minutes: 60 19 | continue-on-error: false 20 | steps: 21 | - uses: jumpstarter-dev/jumpstarter-e2e@main 22 | with: 23 | controller-ref: main 24 | jumpstarter-ref: ${{ github.ref }} 25 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/rcar_s4/build_flasher.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dnf install --setopt=install_weak_deps=false -y git make gcc gcc-c++ which file diffutils wget cpio rsync bc lzop zip patch perl tar qemu-system-aarch64 qemu-img unzboot uboot-tools kmod awk 4 | 5 | git clone --depth 1 --branch 2025.05 https://github.com/buildroot/buildroot /buildroot 6 | 7 | ./replace_kernel.sh 8 | cp -R overlay /buildroot 9 | cp rootfs_only_defconfig /buildroot/configs/ 10 | ( cd /buildroot; make rootfs_only_defconfig && make ) 11 | mkimage -f flasher.its data/flasher.itb 12 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-http-power/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: demo 6 | endpoint: "" 7 | token: "" 8 | export: 9 | power: 10 | type: jumpstarter_driver_http_power.driver.HttpPower 11 | config: 12 | name: "splug" 13 | power_on: 14 | url: "http://192.168.1.65/relay/0?turn=on" 15 | power_off: 16 | url: "http://192.168.1.65/relay/0?turn=off" 17 | auth: 18 | basic: 19 | user: admin 20 | password: something 21 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tftp/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: demo 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | serial: 10 | type: "jumpstarter_driver_pyserial.driver.PySerial" 11 | config: 12 | url: "/dev/ttyUSB0" 13 | baudrate: 1843200 14 | tftp: 15 | type: jumpstarter_driver_tftp.driver.TftpServer 16 | config: 17 | root_dir: "/var/lib/tftpboot/" 18 | host: "192.168.1.111" 19 | port: 6969 20 | -------------------------------------------------------------------------------- /packages/jumpstarter-protocol/jumpstarter_protocol/__init__.py: -------------------------------------------------------------------------------- 1 | from .jumpstarter.client.v1 import ( 2 | client_pb2, 3 | client_pb2_grpc, 4 | ) 5 | 6 | from .jumpstarter.v1 import ( 7 | jumpstarter_pb2, 8 | jumpstarter_pb2_grpc, 9 | kubernetes_pb2, 10 | kubernetes_pb2_grpc, 11 | router_pb2, 12 | router_pb2_grpc, 13 | ) 14 | 15 | __all__ = [ 16 | "client_pb2", 17 | "client_pb2_grpc", 18 | "jumpstarter_pb2", 19 | "jumpstarter_pb2_grpc", 20 | "kubernetes_pb2", 21 | "kubernetes_pb2_grpc", 22 | "router_pb2", 23 | "router_pb2_grpc" 24 | ] 25 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ble/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: demo 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | ble: 10 | type: "jumpstarter_driver_ble.driver.BleWriteNotifyStream" 11 | config: 12 | address: "00:11:22:33:44:55" 13 | service_uuid: "0000180a-0000-1000-8000-000000000000" 14 | write_char_uuid: "0000fe41-8e22-4541-9d4c-000000000000" 15 | notify_char_uuid: "0000fe42-8e22-4541-9d4c-000000000000" 16 | 17 | 18 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-shell/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | name: shell-exporter 5 | namespace: default 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | example: 10 | type: jumpstarter_driver_shell.driver.Shell 11 | config: 12 | methods: 13 | ls: "ls" 14 | method2: "echo 'Hello World 2'" 15 | #multi line method 16 | method3: | 17 | echo 'Hello World $1' 18 | echo 'Hello World $2' 19 | env_var: "echo $ENV_VAR" 20 | 21 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-composite/README.md: -------------------------------------------------------------------------------- 1 | # Composite Driver 2 | 3 | `jumpstarter-driver-composite` provides functionality for interacting with composite devices. 4 | 5 | ## Installation 6 | 7 | ```bash 8 | pip3 install --extra-index-url https://pkg.jumpstarter.dev/simple/ jumpstarter-driver-composite 9 | ``` 10 | 11 | ## Configuration 12 | 13 | Example configuration: 14 | 15 | ```yaml 16 | export: 17 | composite: 18 | type: jumpstarter_driver_composite.driver.Composite 19 | config: 20 | # Add required config parameters here 21 | ``` 22 | 23 | ## API Reference 24 | 25 | Add API documentation here. 26 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-qemu/README.md: -------------------------------------------------------------------------------- 1 | # QEMU driver 2 | 3 | `jumpstarter-driver-qemu` provides functionality for interacting with QEMU 4 | virtualization platform. 5 | 6 | ## Installation 7 | 8 | ```{code-block} console 9 | :substitutions: 10 | $ pip3 install --extra-index-url {{index_url}} jumpstarter-driver-qemu 11 | ``` 12 | 13 | ## Configuration 14 | 15 | Example configuration: 16 | 17 | ```yaml 18 | export: 19 | qemu: 20 | type: jumpstarter_driver_qemu.driver.Qemu 21 | config: 22 | # Add required config parameters here 23 | ``` 24 | 25 | ## API Reference 26 | 27 | Add API documentation here. 28 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/common/importlib_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from .importlib import import_class 4 | 5 | 6 | def test_import_class(): 7 | import_class("os.open", [], True) 8 | 9 | with pytest.raises(ImportError): 10 | import_class("os.invalid", [], True) 11 | 12 | with pytest.raises(ImportError): 13 | import_class("os.open", [], False) 14 | 15 | import_class("os.open", ["os.*"], False) 16 | 17 | with pytest.raises(ImportError): 18 | import_class("os.open", ["sys.*"], False) 19 | 20 | with pytest.raises(ImportError): 21 | import_class("os", [], True) 22 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-dutlink/README.md: -------------------------------------------------------------------------------- 1 | # DUT Link driver 2 | 3 | `jumpstarter-driver-dutlink` provides functionality for interacting with DUT 4 | Link devices. 5 | 6 | ## Installation 7 | 8 | ```{code-block} console 9 | :substitutions: 10 | $ pip3 install --extra-index-url {{index_url}} jumpstarter-driver-dutlink 11 | ``` 12 | 13 | ## Configuration 14 | 15 | Example configuration: 16 | 17 | ```yaml 18 | export: 19 | dutlink: 20 | type: jumpstarter_driver_dutlink.driver.Dutlink 21 | config: 22 | # Add required config parameters here 23 | ``` 24 | 25 | ## API Reference 26 | 27 | Add API documentation here. 28 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/examples/exporter.yml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | # endpoint and token are intentionally left empty 4 | metadata: 5 | namespace: default 6 | name: corellium-demo 7 | endpoint: "" 8 | token: "" 9 | export: 10 | rd1ae: 11 | type: jumpstarter_driver_corellium.driver.Corellium 12 | config: 13 | project_id: "778f00af-5e9b-40e6-8e7f-c4f14b632e9c" 14 | device_name: "jmp-rd1ae" 15 | device_flavor: "kronos" 16 | # optional 17 | device_os: "1.1.1" 18 | device_build: "Critical Application Monitor (Baremetal)" 19 | console_name: "Primary Compute Non-Secure" 20 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/pexpect.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from contextlib import contextmanager 3 | 4 | from pexpect.fdpexpect import fdspawn 5 | 6 | from .portforward import TcpPortforwardAdapter 7 | from jumpstarter.client import DriverClient 8 | 9 | 10 | @contextmanager 11 | def PexpectAdapter(*, client: DriverClient, method: str = "connect"): 12 | with TcpPortforwardAdapter(client=client, method=method) as addr: 13 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 14 | sock.connect(addr) 15 | 16 | try: 17 | yield fdspawn(sock) 18 | finally: 19 | sock.close() 20 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/rcar_s4/rootfs_only_defconfig: -------------------------------------------------------------------------------- 1 | BR2_aarch64=y 2 | BR2_TOOLCHAIN_EXTERNAL=y 3 | BR2_TARGET_GENERIC_HOSTNAME="flasher" 4 | BR2_TARGET_GENERIC_ISSUE="flasher" 5 | BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y 6 | BR2_TARGET_GENERIC_ROOT_PASSWD="" 7 | BR2_SYSTEM_DHCP="eth0" 8 | BR2_ROOTFS_OVERLAY="$(CONFIG_DIR)/overlay" 9 | BR2_PACKAGE_CA_CERTIFICATES=y 10 | BR2_PACKAGE_OPENSSL=y 11 | BR2_PACKAGE_LIBCURL=y 12 | BR2_PACKAGE_LIBCURL_CURL=y 13 | BR2_PACKAGE_NTP=y 14 | BR2_PACKAGE_NTP_SNTP=y 15 | BR2_PACKAGE_NTP_NTPDATE=y 16 | BR2_TARGET_ROOTFS_CPIO=y 17 | BR2_TARGET_ROOTFS_CPIO_LZO=y 18 | BR2_PACKAGE_DROPBEAR=n 19 | # BR2_TARGET_ROOTFS_TAR is not set 20 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-network/jumpstarter_driver_network/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from anyio.from_thread import start_blocking_portal 3 | 4 | from jumpstarter.common import TemporaryTcpListener 5 | 6 | 7 | async def echo_handler(stream): 8 | async with stream: 9 | while True: 10 | try: 11 | await stream.send(await stream.receive()) 12 | except Exception: 13 | pass 14 | 15 | 16 | @pytest.fixture 17 | def tcp_echo_server(): 18 | with start_blocking_portal() as portal: 19 | with portal.wrap_async_context_manager(TemporaryTcpListener(echo_handler, local_host="127.0.0.1")) as addr: 20 | yield addr 21 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-vnc/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: demo 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | vnc: 10 | type: jumpstarter_driver_vnc.driver.Vnc 11 | # You can set the default encryption behavior for the `j vnc session` command. 12 | # If not set, it defaults to False (unencrypted). 13 | default_encrypt: false 14 | children: 15 | tcp: 16 | type: jumpstarter_driver_network.driver.TcpNetwork 17 | config: 18 | host: "127.0.0.1" 19 | port: 5901 # Default VNC port for display :1 20 | -------------------------------------------------------------------------------- /packages/jumpstarter-kubernetes/jumpstarter_kubernetes/serialize.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated, Any, Dict 2 | 3 | from kubernetes_asyncio.client.models import V1Condition, V1ObjectMeta, V1ObjectReference 4 | from pydantic import WrapSerializer 5 | 6 | 7 | def k8s_obj_to_dict(value: Any, handler, info) -> Dict[str, Any]: 8 | result = value.to_dict(serialize=True) 9 | return {k: v for k, v in result.items() if v is not None} 10 | 11 | 12 | SerializeV1Condition = Annotated[V1Condition, WrapSerializer(k8s_obj_to_dict)] 13 | SerializeV1ObjectMeta = Annotated[V1ObjectMeta, WrapSerializer(k8s_obj_to_dict)] 14 | SerializeV1ObjectReference = Annotated[V1ObjectReference, WrapSerializer(k8s_obj_to_dict)] 15 | -------------------------------------------------------------------------------- /docs/source/reference/man-pages/j.md: -------------------------------------------------------------------------------- 1 | # j 2 | 3 | The `j` command is available within the Jumpstarter shell environment (launched 4 | via `jmp shell`). It provides access to driver CLI interfaces configured in your 5 | exporter. 6 | 7 | Usage: 8 | 9 | ```console 10 | $ j [OPTIONS] COMMAND [ARGS]... 11 | ``` 12 | 13 | The available commands depend on which drivers are loaded in your current 14 | session. When you run the `j` command in the shell: 15 | 16 | - Use `j` alone to see all available driver interfaces 17 | - Access specific drivers with `j ` 18 | - Each driver exposes different commands through this interface 19 | 20 | Available commands vary depending on your configured drivers. 21 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | def configure_grpc_env(): 5 | # disable informative logs by default, i.e.: 6 | # WARNING: All log messages before absl::InitializeLog() is called are written to STDERR 7 | # I0000 00:00:1739970744.889307 61962 ssl_transport_security.cc:1665] Handshake failed ... 8 | if os.environ.get("GRPC_VERBOSITY") is None: 9 | os.environ["GRPC_VERBOSITY"] = "ERROR" 10 | if os.environ.get("GLOG_minloglevel") is None: 11 | os.environ["GLOG_minloglevel"] = "2" 12 | 13 | 14 | # make sure that the grpc environment is always configured 15 | # before any grpc calls are made to avoid unnecessary logs 16 | configure_grpc_env() 17 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-power/README.md: -------------------------------------------------------------------------------- 1 | # Power driver 2 | 3 | `jumpstarter-driver-power` provides functionality for interacting with power 4 | control devices. 5 | 6 | ## Installation 7 | 8 | ```{code-block} console 9 | :substitutions: 10 | $ pip3 install --extra-index-url {{index_url}} jumpstarter-driver-power 11 | ``` 12 | 13 | ## Configuration 14 | 15 | Example configuration: 16 | 17 | ```yaml 18 | export: 19 | power: 20 | type: jumpstarter_driver_power.driver.MockPower 21 | config: 22 | # Add required config parameters here 23 | ``` 24 | 25 | ## API Reference 26 | 27 | ```{eval-rst} 28 | .. autoclass:: jumpstarter_driver_power.client.PowerClient() 29 | :members: on, off, read, cycle 30 | ``` -------------------------------------------------------------------------------- /packages/jumpstarter-driver-yepkit/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | name: exporter 5 | namespace: default 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | power: 10 | type: jumpstarter_driver_yepkit.driver.Ykush 11 | config: 12 | port: "1" 13 | 14 | power2: 15 | type: jumpstarter_driver_yepkit.driver.Ykush 16 | config: 17 | serial: "YK25838" 18 | port: "2" 19 | 20 | power3: 21 | type: jumpstarter_driver_yepkit.driver.Ykush 22 | config: 23 | port: "3" 24 | 25 | all: 26 | type: jumpstarter_driver_yepkit.driver.Ykush 27 | config: 28 | port: "all" 29 | 30 | -------------------------------------------------------------------------------- /docs/source/reference/package-apis/drivers/uboot.yaml: -------------------------------------------------------------------------------- 1 | type: "jumpstarter_driver_uboot.driver.UbootConsole" 2 | children: 3 | power: 4 | type: "jumpstarter_driver_power.driver.MockPower" 5 | config: {} # omitted, power driver configuration 6 | serial: 7 | type: "jumpstarter_driver_pyserial.driver.PySerial" 8 | config: # omitted, serial driver configuration 9 | url: "loop://" 10 | # instead of configuring the power and serial driver inline 11 | # other drivers configured on the exporter can also be referenced 12 | # power: 13 | # ref: "dutlink.power" 14 | # serial: 15 | # ref: "dutlink.console" 16 | config: 17 | prompt: "=>" # the u-boot command prompt to expect, defaults to "=>" 18 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-power/jumpstarter_driver_power/client_test.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import time 3 | from unittest.mock import MagicMock 4 | 5 | from .driver import MockPower 6 | from jumpstarter.common.utils import serve 7 | 8 | 9 | def test_log_stream(monkeypatch): 10 | with serve(MockPower()) as client: 11 | log = MagicMock() 12 | monkeypatch.setattr(client, "_AsyncDriverClient__log", log) 13 | with client.log_stream(): 14 | client.on() 15 | time.sleep(1) # to ensure log is flushed 16 | log.assert_called_with(logging.INFO, "power on") 17 | 18 | client.off() 19 | time.sleep(1) 20 | log.assert_called_with(logging.INFO, "power off") 21 | -------------------------------------------------------------------------------- /packages/hatch-pin-jumpstarter/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "hatch-pin-jumpstarter" 3 | version = "0.1.0" 4 | description = "Hatch plugin that pins jumpstarter packages in the monorepo" 5 | readme = "README.md" 6 | authors = [ 7 | { name = "Nick Cao", email = "nickcao@nichi.co" } 8 | ] 9 | requires-python = ">=3.11" 10 | dependencies = [ 11 | "hatchling>=1.27.0", 12 | "packaging>=24.2", 13 | "tomli>=2.2.1", 14 | "tomli-w>=1.2.0", 15 | ] 16 | 17 | [build-system] 18 | requires = ["hatchling"] 19 | build-backend = "hatchling.build" 20 | 21 | [dependency-groups] 22 | dev = [ 23 | "pytest>=8.3.5", 24 | "pytest-cov>=6.1.1", 25 | ] 26 | 27 | [project.entry-points.hatch] 28 | pin_jumpstarter = "hatch_pin_jumpstarter" 29 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/common/utils_test.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | 3 | from .utils import launch_shell 4 | 5 | 6 | def test_launch_shell(tmp_path, monkeypatch): 7 | monkeypatch.setenv("SHELL", shutil.which("true")) 8 | exit_code = launch_shell( 9 | host=str(tmp_path / "test.sock"), 10 | context="remote", 11 | allow=["*"], 12 | unsafe=False, 13 | use_profiles=False 14 | ) 15 | assert exit_code == 0 16 | 17 | monkeypatch.setenv("SHELL", shutil.which("false")) 18 | exit_code = launch_shell( 19 | host=str(tmp_path / "test.sock"), 20 | context="remote", allow=["*"], 21 | unsafe=False, 22 | use_profiles=False 23 | ) 24 | assert exit_code == 1 25 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tmt/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: demo 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | tmt: 10 | type: jumpstarter_driver_tmt.driver.TMT 11 | config: 12 | reboot_cmd: "j power cycle" 13 | default_username: "root" 14 | default_password: "somePass" 15 | children: 16 | ssh: 17 | ref: ssh 18 | ssh: 19 | type: jumpstarter_driver_network.driver.TcpNetwork 20 | config: 21 | host: 127.0.0.1 22 | port: 2222 23 | enable_address: true 24 | power: 25 | type: jumpstarter_driver_power.driver.MockPower 26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/config/grpc.py: -------------------------------------------------------------------------------- 1 | import grpc 2 | 3 | from .common import ObjectMeta 4 | 5 | 6 | def call_credentials(kind: str, metadata: ObjectMeta, token: str): 7 | def metadata_call_credentials(context: grpc.AuthMetadataContext, callback: grpc.AuthMetadataPluginCallback): 8 | callback( 9 | [ 10 | ("jumpstarter-kind", kind), 11 | ("jumpstarter-namespace", metadata.namespace), 12 | ("jumpstarter-name", metadata.name), 13 | ], 14 | None, 15 | ) 16 | 17 | return grpc.composite_call_credentials( 18 | grpc.metadata_call_credentials(metadata_call_credentials), 19 | grpc.access_token_call_credentials(token), 20 | ) 21 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/rcar_s4/manifest.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: FlashBundleManifest 3 | metadata: 4 | name: rcar-s4 5 | spec: 6 | manufacturer: Renesas 7 | link: "https://www.renesas.com/en/products/automotive-products/automotive-system-chips-socs/r-car-s4-automotive-system-chip-soc-car-servercommunication-gateway" 8 | # boot default configuration R-Car S4 Spider, for S4SK use "bootm 0x58000000#s4sk" 9 | bootcmd: "bootm 0x58000000" 10 | shelltype: "busybox" 11 | login: 12 | login_prompt: "login:" 13 | username: "root" 14 | prompt: "#" 15 | default_target: "emmc" 16 | targets: 17 | emmc: "/dev/mmcblk0" 18 | kernel: 19 | file: data/flasher.itb 20 | address: "0x58000000" 21 | -------------------------------------------------------------------------------- /docs/source/getting-started/index.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | This section provides hands-on guides to start using Jumpstarter in your own 4 | environment. The guides cover: 5 | 6 | - [Installation](installation/index.md): Setting up Jumpstarter packages and 7 | services 8 | - [Configuration](configuration/index.md): Configuring clients, exporters, and 9 | authentication 10 | - [Guides](guides/index.md): Running your first tests and integrating with your 11 | development workflow 12 | 13 | These guides support both local-mode for individual development and 14 | distributed-mode for team environments with shared hardware resources. 15 | 16 | ```{toctree} 17 | :maxdepth: 1 18 | :hidden: 19 | installation/index.md 20 | configuration/index.md 21 | guides/index.md 22 | ``` -------------------------------------------------------------------------------- /examples/soc-pytest/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-example-soc-pytest" 3 | version = "0.1.0" 4 | description = "" 5 | authors = [ 6 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 7 | { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, 8 | { name = "Nick Cao", email = "ncao@redhat.com" }, 9 | ] 10 | readme = "README.md" 11 | license = "Apache-2.0" 12 | requires-python = ">=3.11" 13 | dependencies = [ 14 | "pytest>=8.3.2", 15 | "jumpstarter", 16 | "jumpstarter-testing", 17 | "jumpstarter-imagehash", 18 | "jumpstarter-driver-network", 19 | "jumpstarter-driver-dutlink", 20 | ] 21 | 22 | [tool.pytest.ini_options] 23 | addopts = "-s --ignore examples/pytest/test_on_rpi4.py" 24 | log_cli = 1 25 | log_cli_level = "INFO" 26 | -------------------------------------------------------------------------------- /.devfile/Containerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/devfile/base-developer-image:ubi9-latest 2 | LABEL maintainer="Jumpstarter.dev" 3 | 4 | LABEL name="devfile/udi9/jumpstarter" 5 | 6 | #labels for container catalog 7 | LABEL summary="devfile jumpstarter developer image" 8 | LABEL description="Image with developers tools." 9 | LABEL io.k8s.display-name="jumpstarter-developer-universal" 10 | 11 | COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv 12 | COPY --from=ghcr.io/astral-sh/uv:latest /uvx /bin/uvx 13 | 14 | USER root 15 | 16 | RUN dnf -y install make git python3.12 libusbx python3-pyusb golang podman && dnf clean all 17 | 18 | USER 10001 19 | 20 | # This will make sure that we always run python from our venv instead 21 | RUN echo "alias python='uv run python'" >> /home/user/.bashrc 22 | -------------------------------------------------------------------------------- /docs/source/getting-started/configuration/index.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | This section explains how to configure Jumpstarter for your environment. 4 | 5 | - [Files](files.md): Understanding the structure and content of configuration 6 | files 7 | - [Loading Order](loading-order.md): Understanding how configuration files are 8 | prioritized from different sources (environment variables, command line, 9 | system and user config files) 10 | - [Authentication](authentication.md): Setting up OIDC and managing tokens 11 | 12 | For a list of supported configuration options including an explanation please 13 | refer to the [MAN pages](../../reference/man-pages/index.md). 14 | 15 | ```{toctree} 16 | :maxdepth: 1 17 | :hidden: 18 | files.md 19 | loading-order.md 20 | authentication.md 21 | ``` -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/build_bundle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # oras login quay.io -u mangelajo 4 | 5 | set -e 6 | 7 | FLASHER_OCI_CONTAINER="${1:-quay.io/jumpstarter-dev/jumpstarter-flasher-test:latest}" 8 | BUNDLE_FILES=${2:-"./test/"} 9 | 10 | echo "Building and pushing ${FLASHER_OCI_CONTAINER}" 11 | 12 | set -x 13 | 14 | cd "${BUNDLE_FILES}" 15 | MANIFESTS= 16 | for file in $(ls -1 *.yaml); do 17 | MANIFESTS="${MANIFESTS} ${file}:application/yaml " 18 | done 19 | DATA_FILES= 20 | for file in $(find ./data -type f -prune -a -not -name .gitkeep); do 21 | DATA_FILES="${DATA_FILES} ${file}:application/octet-stream " 22 | done 23 | 24 | oras push $FLASHER_OCI_CONTAINER \ 25 | --artifact-type application/vnd.oci.bundle.v1 \ 26 | $MANIFESTS \ 27 | $DATA_FILES 28 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=$BUILDPLATFORM ghcr.io/astral-sh/uv:latest AS uv 2 | 3 | FROM --platform=$BUILDPLATFORM fedora:42 AS builder 4 | RUN dnf install -y make git && \ 5 | dnf clean all && \ 6 | rm -rf /var/cache/dnf 7 | COPY --from=uv /uv /uvx /bin/ 8 | 9 | FROM fedora:42 AS product 10 | RUN dnf install -y python3 ustreamer libusb1 android-tools python3-libgpiod && \ 11 | dnf clean all && \ 12 | rm -rf /var/cache/dnf 13 | COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ 14 | 15 | FROM builder AS wheels 16 | ADD . /src 17 | RUN make -C /src build 18 | 19 | FROM product 20 | RUN --mount=from=wheels,source=/src/dist,target=/dist \ 21 | uv venv /jumpstarter && \ 22 | VIRTUAL_ENV=/jumpstarter uv pip install /dist/*.whl 23 | ENV PATH="/jumpstarter/bin:$PATH" 24 | -------------------------------------------------------------------------------- /kind_config.yaml: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | kubeadmConfigPatches: 4 | - | 5 | kind: ClusterConfiguration 6 | apiServer: 7 | extraArgs: 8 | "service-node-port-range": "3000-32767" 9 | - | 10 | kind: InitConfiguration 11 | nodeRegistration: 12 | kubeletExtraArgs: 13 | node-labels: "ingress-ready=true" 14 | nodes: 15 | - role: control-plane 16 | extraPortMappings: 17 | - containerPort: 80 # ingress controller 18 | hostPort: 5080 19 | protocol: TCP 20 | - containerPort: 30010 # grpc nodeport 21 | hostPort: 8082 22 | protocol: TCP 23 | - containerPort: 30011 # grpc router nodeport 24 | hostPort: 8083 25 | protocol: TCP 26 | - containerPort: 443 # minimalistic UI 27 | hostPort: 5443 28 | protocol: TCP 29 | -------------------------------------------------------------------------------- /examples/soc-pytest/jumpstarter_example_soc_pytest/image/scripts/prepare-latest-raw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -x 3 | # all output to serial port 4 | sudo sed -i 's/console=serial0,115200 console=tty1/console=serial0,115200/g' mnt/boot/firmware/cmdline.txt 5 | cat mnt/boot/firmware/cmdline.txt 6 | 7 | cat << EOF | sudo tee mnt/boot/firmware/custom.toml 8 | # Raspberry Pi First Boot Setup 9 | [system] 10 | hostname = "rpitest" 11 | 12 | [user] 13 | name = "root" 14 | password = "changeme" 15 | password_encrypted = false 16 | 17 | [ssh] 18 | enabled = false 19 | 20 | [wlan] 21 | country = "es" 22 | 23 | [locale] 24 | keymap = "es" 25 | timezone = "Europe/Madrid" 26 | EOF 27 | 28 | cat << EOF | sudo tee -a mnt/boot/firmware/config.txt 29 | dtparam=spi=on 30 | dtoverlay=tpm-slb9670 31 | enable_uart=1 32 | EOF -------------------------------------------------------------------------------- /packages/jumpstarter-driver-uboot/jumpstarter_driver_uboot/driver.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from jumpstarter.driver import Driver, export 4 | 5 | 6 | @dataclass(kw_only=True) 7 | class UbootConsole(Driver): 8 | prompt: str = "\n=>" 9 | 10 | @classmethod 11 | def client(cls) -> str: 12 | return "jumpstarter_driver_uboot.client.UbootConsoleClient" 13 | 14 | def __post_init__(self): 15 | if hasattr(super(), "__post_init__"): 16 | super().__post_init__() 17 | 18 | for child in ("power", "serial"): 19 | if child not in self.children: 20 | raise ValueError("UbootConsole: {} driver not configured as a child".format(child)) 21 | 22 | @export 23 | def get_prompt(self) -> str: 24 | return self.prompt 25 | -------------------------------------------------------------------------------- /docs/source/getting-started/guides/index.md: -------------------------------------------------------------------------------- 1 | # Guides 2 | 3 | This section provides guidance on how to use Jumpstarter effectively in your 4 | development workflow. The guides cover: 5 | 6 | - [Setup Local Mode](setup-local-mode.md): Running Jumpstarter in local mode for 7 | individual development 8 | - [Setup Distributed Mode](setup-distributed-mode.md): Configuring Jumpstarter 9 | for team environments with shared resources 10 | - [Examples](examples.md): Practical examples of Jumpstarter usage in common 11 | scenarios 12 | - [Integration Patterns](integration-patterns.md): Integrate Jumpstarter into 13 | your existing workflows and systems 14 | 15 | 16 | ```{toctree} 17 | :maxdepth: 1 18 | :hidden: 19 | setup-local-mode.md 20 | setup-distributed-mode.md 21 | examples.md 22 | integration-patterns.md 23 | ``` -------------------------------------------------------------------------------- /packages/jumpstarter-cli-common/jumpstarter_cli_common/signal.py: -------------------------------------------------------------------------------- 1 | import signal 2 | 3 | import click 4 | from anyio import open_signal_receiver 5 | from anyio.abc import CancelScope 6 | 7 | 8 | # Reference: https://github.com/agronholm/anyio/blob/4.9.0/docs/signals.rst 9 | async def signal_handler(scope: CancelScope): 10 | with open_signal_receiver(signal.SIGINT, signal.SIGTERM) as signals: 11 | async for signum in signals: 12 | match signum: 13 | case signal.SIGINT: 14 | click.echo("SIGINT pressed, terminating", err=True) 15 | case signal.SIGTERM: 16 | click.echo("SIGTERM received, terminating", err=True) 17 | case _: 18 | pass 19 | 20 | scope.cancel() 21 | 22 | break 23 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-sdwire/jumpstarter_driver_sdwire/driver_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import usb 3 | 4 | from jumpstarter_driver_sdwire.driver import SDWire 5 | 6 | from jumpstarter.common.utils import serve 7 | 8 | 9 | def test_drivers_sdwire(): 10 | try: 11 | instance = SDWire() 12 | except FileNotFoundError: 13 | pytest.skip("sd-wire not available") # ty: ignore[call-non-callable] 14 | except usb.core.USBError: 15 | pytest.skip("USB not available") # ty: ignore[call-non-callable] 16 | except usb.core.NoBackendError: 17 | pytest.skip("No USB backend") # ty: ignore[call-non-callable] 18 | 19 | with serve(instance) as client: 20 | client.host() 21 | assert instance.query() == "host" 22 | client.dut() 23 | assert instance.query() == "dut" 24 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/exporter/logging.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from collections import deque 3 | 4 | from jumpstarter_protocol import jumpstarter_pb2 5 | 6 | 7 | class LogHandler(logging.Handler): 8 | def __init__(self, queue: deque): 9 | logging.Handler.__init__(self) 10 | self.queue = queue 11 | self.listener = None 12 | 13 | def enqueue(self, record): 14 | self.queue.append(record) 15 | 16 | def prepare(self, record): 17 | return jumpstarter_pb2.LogStreamResponse( 18 | uuid="", 19 | severity=record.levelname, 20 | message=self.format(record), 21 | ) 22 | 23 | def emit(self, record): 24 | try: 25 | self.enqueue(self.prepare(record)) 26 | except Exception: 27 | self.handleError(record) 28 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-snmp/jumpstarter_driver_snmp/client.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from jumpstarter_driver_power.client import PowerClient 4 | 5 | from jumpstarter.client.decorators import driver_click_group 6 | 7 | 8 | @dataclass(kw_only=True) 9 | class SNMPServerClient(PowerClient): 10 | """Client interface for SNMP Power Control""" 11 | 12 | def on(self): 13 | """Turn power on""" 14 | self.call("on") 15 | 16 | def off(self): 17 | """Turn power off""" 18 | self.call("off") 19 | 20 | def cli(self): 21 | @driver_click_group(self) 22 | def snmp(): 23 | """SNMP power control commands""" 24 | pass 25 | 26 | for cmd in super().cli().commands.values(): 27 | snmp.add_command(cmd) 28 | 29 | return snmp 30 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/common/resources.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated, Literal, Union 2 | from uuid import UUID 3 | 4 | from pydantic import BaseModel, Field, Json 5 | 6 | 7 | class ClientStreamResource(BaseModel): 8 | kind: Literal["client_stream"] = "client_stream" 9 | uuid: UUID 10 | x_jmp_content_encoding: str | None = None 11 | 12 | 13 | class PresignedRequestResource(BaseModel): 14 | kind: Literal["presigned_request"] = "presigned_request" 15 | headers: dict[str, str] 16 | url: str 17 | method: Literal["GET", "PUT"] 18 | 19 | 20 | Resource = Annotated[ 21 | Union[ClientStreamResource, PresignedRequestResource], 22 | Field(discriminator="kind"), 23 | ] 24 | 25 | 26 | class ResourceMetadata(BaseModel): 27 | resource: Json[Resource] 28 | x_jmp_accept_encoding: str | None = None 29 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-driver/jumpstarter_cli_driver/driver.py: -------------------------------------------------------------------------------- 1 | from importlib.metadata import entry_points 2 | 3 | import click 4 | from rich.console import Console 5 | from rich.table import Table 6 | 7 | 8 | @click.command("list") 9 | def list_drivers(): 10 | drivers = list(entry_points(group="jumpstarter.drivers")) 11 | if not drivers: 12 | click.echo("No drivers found.") 13 | else: 14 | table = Table( 15 | box=None, 16 | header_style=None, 17 | pad_edge=None, 18 | ) 19 | 20 | table.add_column("NAME", no_wrap=True) 21 | table.add_column("TYPE") 22 | 23 | for driver in drivers: 24 | table.add_row( 25 | driver.name, 26 | driver.value.replace(":", "."), 27 | ) 28 | 29 | Console().print(table) 30 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/jumpstarter_driver_corellium/corellium/types.py: -------------------------------------------------------------------------------- 1 | """ 2 | Corellium API types. 3 | """ 4 | from dataclasses import dataclass, field 5 | from typing import Optional 6 | 7 | 8 | @dataclass 9 | class Project: 10 | """ 11 | Dataclass that represents a Corellium project. 12 | """ 13 | id: str 14 | name: str 15 | 16 | 17 | @dataclass 18 | class Device: 19 | """ 20 | Dataclass to represent a Corellium Device. 21 | 22 | A device object is used to create virtual instances. 23 | """ 24 | name: str 25 | type: str 26 | flavor: str 27 | description: str 28 | model: str 29 | peripherals: bool 30 | quotas: dict 31 | 32 | 33 | @dataclass 34 | class Instance: 35 | """ 36 | Virtual instance dataclass. 37 | """ 38 | id: str 39 | state: Optional[str] = field(default=None) 40 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/streams/aiohttp.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from aiohttp import ClientError, StreamReader 4 | from anyio import BrokenResourceError, EndOfStream 5 | from anyio.abc import ObjectStream 6 | 7 | 8 | @dataclass(frozen=True, kw_only=True, slots=True) 9 | class AiohttpStreamReaderStream(ObjectStream[bytes]): 10 | reader: StreamReader 11 | 12 | async def send(self, item: bytes): 13 | raise BrokenResourceError 14 | 15 | async def receive(self) -> bytes: 16 | try: 17 | item = await self.reader.readany() 18 | except ClientError as e: 19 | raise BrokenResourceError from e 20 | if len(item) == 0: 21 | raise EndOfStream 22 | return item 23 | 24 | async def send_eof(self): 25 | pass 26 | 27 | async def aclose(self): 28 | pass 29 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-admin/jumpstarter_cli_admin/k8s.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import click 4 | from kubernetes_asyncio.client.exceptions import ApiException 5 | from kubernetes_asyncio.config.config_exception import ConfigException 6 | 7 | 8 | def handle_k8s_api_exception(e: ApiException): 9 | """Handle a Kubernetes API exception""" 10 | # Try to parse the JSON response 11 | try: 12 | json_body = json.loads(e.body) 13 | raise click.ClickException(f"Error from server ({json_body['reason']}): {json_body['message']}") from e 14 | except json.decoder.JSONDecodeError: 15 | raise click.ClickException(f"Server error: {e.body}") from e 16 | 17 | 18 | def handle_k8s_config_exception(e: ConfigException): 19 | """Handle a Kubernetes config exception""" 20 | # Try to parse the JSON response 21 | raise click.ClickException(e.args[0]) from e 22 | -------------------------------------------------------------------------------- /docs/source/getting-started/installation/service/index.md: -------------------------------------------------------------------------------- 1 | # Service 2 | 3 | This section explains how to install and configure the Jumpstarter service in your Kubernetes cluster. The service enables centralized management of your Jumpstarter environment. 4 | 5 | ## Getting Started 6 | 7 | For most users, we recommend starting with a **local installation** to get familiar with Jumpstarter before moving to production deployments. 8 | 9 | ```{toctree} 10 | :maxdepth: 2 11 | 12 | service-local.md 13 | service-production.md 14 | ``` 15 | 16 | ## Quick Start 17 | 18 | **New to Jumpstarter?** Start with the [Local Installation](service-local.md) guide to get up and running quickly on your development machine. 19 | 20 | **Ready for production?** See the [Production Deployment](service-production.md) guide for Kubernetes and OpenShift clusters with proper security, monitoring, and ingress configurations. 21 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-admin/jumpstarter_cli_admin/__init__.py: -------------------------------------------------------------------------------- 1 | import click 2 | from jumpstarter_cli_common.alias import AliasedGroup 3 | from jumpstarter_cli_common.opt import opt_log_level 4 | from jumpstarter_cli_common.version import version 5 | 6 | from .create import create 7 | from .delete import delete 8 | from .get import get 9 | from .import_res import import_res 10 | from .install import install, ip, uninstall 11 | 12 | 13 | @click.group(cls=AliasedGroup) 14 | @opt_log_level 15 | def admin(): 16 | """Jumpstarter Kubernetes cluster admin CLI tool""" 17 | 18 | 19 | admin.add_command(get) 20 | admin.add_command(create) 21 | admin.add_command(delete) 22 | admin.add_command(install) 23 | admin.add_command(uninstall) 24 | admin.add_command(ip) 25 | admin.add_command(import_res) 26 | admin.add_command(version) 27 | admin.add_command(ip) 28 | 29 | if __name__ == "__main__": 30 | admin() 31 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/client.py: -------------------------------------------------------------------------------- 1 | import io 2 | from base64 import b64decode 3 | 4 | from PIL import Image 5 | 6 | from .common import UStreamerState 7 | from jumpstarter.client import DriverClient 8 | 9 | 10 | class UStreamerClient(DriverClient): 11 | """UStreamer client class 12 | 13 | Client methods for the UStreamer driver. 14 | """ 15 | 16 | def state(self): 17 | """ 18 | Get state of ustreamer service 19 | """ 20 | 21 | return UStreamerState.model_validate(self.call("state")) 22 | 23 | def snapshot(self): 24 | """ 25 | Get a snapshot image from the video input 26 | 27 | :return: PIL Image object of the snapshot image 28 | :rtype: PIL.Image 29 | """ 30 | input_jpg_data = b64decode(self.call("snapshot")) 31 | return Image.open(io.BytesIO(input_jpg_data)) 32 | -------------------------------------------------------------------------------- /__templates__/driver/jumpstarter_driver/driver.py.tmpl: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from jumpstarter.driver import Driver, export 4 | 5 | @dataclass(kw_only=True) 6 | class ${DRIVER_CLASS}(Driver): 7 | """${DRIVE_NAME} driver for Jumpstarter""" 8 | 9 | some_config: str = "default" 10 | some_other_config: int = 69 11 | 12 | def __post_init__(self): 13 | if hasattr(super(), "__post_init__"): 14 | super().__post_init__() 15 | # some initialization here. 16 | 17 | @classmethod 18 | def client(cls) -> str: 19 | return "jumpstarter_driver_${DRIVER_NAME}.client.${DRIVER_CLASS}Client" 20 | 21 | @export 22 | def method1(self): 23 | self.logger.info("Method1 called") 24 | return "method1 response" 25 | 26 | @export 27 | def method2(self): 28 | self.logger.info("Method2 called") 29 | return "method2 response" 30 | -------------------------------------------------------------------------------- /packages/jumpstarter-testing/jumpstarter_testing/pytest_test.py: -------------------------------------------------------------------------------- 1 | from jumpstarter_driver_power.driver import MockPower 2 | from pytest import Pytester 3 | 4 | from jumpstarter.config.env import JMP_DRIVERS_ALLOW, JUMPSTARTER_HOST 5 | from jumpstarter.exporter import Session 6 | 7 | 8 | def test_env(pytester: Pytester, monkeypatch): 9 | pytester.makepyfile( 10 | """ 11 | from jumpstarter_testing import JumpstarterTest 12 | 13 | class TestSample(JumpstarterTest): 14 | def test_simple(self, client): 15 | client.on() 16 | """ 17 | ) 18 | 19 | with Session(root_device=MockPower()) as session: 20 | with session.serve_unix() as path: 21 | monkeypatch.setenv(JUMPSTARTER_HOST, str(path)) 22 | monkeypatch.setenv(JMP_DRIVERS_ALLOW, "UNSAFE") 23 | result = pytester.runpytest() 24 | result.assert_outcomes(passed=1) 25 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/fixtures/http/get-projects-200.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "d59db33d-27bd-4b22-878d-49e4758a648e", 4 | "name": "Default Project", 5 | "settings": { 6 | "internet-access": true, 7 | "dhcp": true 8 | }, 9 | "quotas": { 10 | "cores": 30, 11 | "instances": 75, 12 | "ram": 184320 13 | }, 14 | "quotasUsed": { 15 | "cores": 2, 16 | "instances": 7, 17 | "ram": 2048, 18 | "gpu": 0 19 | } 20 | }, 21 | { 22 | "id": "e2fdb33c-37ae-4b22-878d-49e4758a51f0", 23 | "name": "OtherProject", 24 | "settings": { 25 | "internet-access": true, 26 | "dhcp": true 27 | }, 28 | "quotas": { 29 | "cores": 30, 30 | "instances": 75, 31 | "ram": 184320 32 | }, 33 | "quotasUsed": { 34 | "cores": 2, 35 | "instances": 7, 36 | "ram": 2048, 37 | "gpu": 0 38 | } 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /docs/multiversion.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euox pipefail 3 | 4 | declare -a BRANCHES=("main" "release-0.5" "release-0.6" "release-0.7") 5 | 6 | # https://stackoverflow.com/a/246128 7 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 8 | OUTPUT_DIR="${SCRIPT_DIR}/build" 9 | 10 | rm -rf "${OUTPUT_DIR}" 11 | mkdir -p "${OUTPUT_DIR}" 12 | 13 | for BRANCH in "${BRANCHES[@]}"; do 14 | WORKTREE="${OUTPUT_DIR}/.worktree/tmp-docs-${BRANCH}" 15 | 16 | git worktree add --force "${WORKTREE}" "${BRANCH}" 17 | 18 | uv run --project "${WORKTREE}" --isolated --all-packages --group docs \ 19 | make -C "${WORKTREE}/docs" html SPHINXOPTS="-D version=${BRANCH}" 20 | 21 | cp -r "${WORKTREE}/docs/build/html" "${OUTPUT_DIR}/${BRANCH}" 22 | 23 | git worktree remove --force "${WORKTREE}" 24 | done 25 | 26 | pushd "${OUTPUT_DIR}" 27 | uvx --from git+https://github.com/steinwurf/versjon --with jinja2 versjon 28 | popd 29 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/streams/encoding_test.py: -------------------------------------------------------------------------------- 1 | from io import BytesIO 2 | 3 | import pytest 4 | from anyio import EndOfStream, create_memory_object_stream 5 | from anyio.streams.stapled import StapledObjectStream 6 | 7 | from .encoding import compress_stream 8 | 9 | pytestmark = pytest.mark.anyio 10 | 11 | 12 | def create_buffer(size): 13 | tx, rx = create_memory_object_stream[bytes](size) 14 | return StapledObjectStream(tx, rx) 15 | 16 | 17 | @pytest.mark.parametrize("compression", [None, "gzip", "xz", "bz2", "zstd"]) 18 | async def test_compress_stream(compression): 19 | stream = compress_stream(create_buffer(128), compression) 20 | 21 | await stream.send(b"hello") 22 | await stream.send_eof() 23 | 24 | result = BytesIO() 25 | while True: 26 | try: 27 | result.write(await stream.receive()) 28 | except EndOfStream: 29 | break 30 | assert result.getvalue() == b"hello" 31 | -------------------------------------------------------------------------------- /.devfile.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: 2.3.0 2 | metadata: 3 | name: jumpstarter-dev 4 | icon: https://jumpstarter.dev/jumpstarter.svg 5 | tags: 6 | - Python 7 | - UV 8 | - Jumpstarter 9 | language: Python 10 | projects: 11 | - name: jumpstarter 12 | git: 13 | remotes: 14 | origin: https://github.com/jumpstarter-dev/jumpstarter.git 15 | components: 16 | - name: runtime 17 | container: 18 | image: quay.io/jumpstarter-dev/jumpstarter-dev:latest 19 | mountSources: true 20 | 21 | commands: 22 | - id: serve-docs 23 | exec: 24 | component: runtime 25 | commandLine: make docs-serve DOC_LISTEN="--host 0.0.0.0" 26 | - id: sync 27 | exec: 28 | component: runtime 29 | commandLine: make sync 30 | - id: clean 31 | exec: 32 | component: runtime 33 | commandLine: make clean 34 | - id: test 35 | exec: 36 | component: runtime 37 | commandLine: make test 38 | 39 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ustreamer/jumpstarter_driver_ustreamer/common.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class UStreamerState(BaseModel): 5 | class Result(BaseModel): 6 | class Encoder(BaseModel): 7 | type: str 8 | """type of encoder in use, e.g. CPU/GPU""" 9 | quality: int 10 | """encoding quality""" 11 | 12 | class Source(BaseModel): 13 | class Resolution(BaseModel): 14 | width: int 15 | """resolution width""" 16 | height: int 17 | """resolution height""" 18 | 19 | online: bool 20 | """client active""" 21 | desired_fps: int 22 | """desired fps""" 23 | captured_fps: int 24 | """actual fps""" 25 | 26 | resolution: Resolution 27 | 28 | encoder: Encoder 29 | source: Source 30 | 31 | ok: bool 32 | 33 | result: Result 34 | -------------------------------------------------------------------------------- /examples/soc-pytest/jumpstarter_example_soc_pytest/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: demo 6 | endpoint: grpc.jumpstarter.example.com:443 7 | token: xxxxx 8 | export: 9 | # a DUTLink interface to the DUT 10 | dutlink: 11 | type: jumpstarter_driver_dutlink.driver.Dutlink 12 | config: 13 | storage_device: "/dev/disk/by-id/usb-SanDisk_3.2_Gen_1_5B4C0AB025C0-0:0" 14 | # an HDMI to USB capture card 15 | video: 16 | type: jumpstarter_driver_ustreamer.driver.UStreamer 17 | config: 18 | args: 19 | device: '/dev/v4l/by-path/pci-0000:00:14.0-usbv2-0:3:1.0-video-index0' 20 | resolution: 1920x1080 21 | # a USB camera pointing to the DUT 22 | camera: 23 | type: jumpstarter_driver_ustreamer.driver.UStreamer 24 | config: 25 | args: 26 | device: '/dev/v4l/by-path/pci-0000:00:14.0-usbv2-0:4:1.0-video-index0' 27 | resolution: 1280x720 28 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: demo 6 | endpoint: grpc.jumpstarter.192.168.0.203.nip.io:8082 7 | token: "" 8 | export: 9 | storage: 10 | type: "jumpstarter_driver_flashers.driver.TIJ784S4Flasher" 11 | children: 12 | serial: 13 | ref: "serial" 14 | power: 15 | ref: "power" 16 | # tftp and http driver are automatically created when not specified, cannot be specified via ref 17 | # tftp: 18 | # type: "jumpstarter_driver_tftp.driver.TftpServer" 19 | # http 20 | serial: 21 | type: "jumpstarter_driver_pyserial.driver.PySerial" 22 | config: 23 | url: "/dev/serial/by-id/usb-FTDI_USB__-__Serial_Converter_112214101760A-if00-port0" 24 | baudrate: 115200 25 | power: 26 | type: jumpstarter_driver_yepkit.driver.Ykush 27 | config: 28 | serial: "YK112233" 29 | port: "1" -------------------------------------------------------------------------------- /packages/jumpstarter-testing/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-testing" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [{ name = "Kirk Brauer", email = "kbrauer@hatci.com" }] 6 | readme = "README.md" 7 | license = "Apache-2.0" 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "jumpstarter", 11 | "pytest>=8.3.2", 12 | "pytest-anyio>=0.0.0", 13 | "pytest-asyncio>=0.0.0", 14 | "pytest-cov>=5.0.0", 15 | ] 16 | 17 | [dependency-groups] 18 | dev = ["jumpstarter-driver-power"] 19 | 20 | [tool.hatch.metadata.hooks.vcs.urls] 21 | Homepage = "https://jumpstarter.dev" 22 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 23 | 24 | [tool.hatch.version] 25 | source = "vcs" 26 | raw-options = { 'root' = '../../' } 27 | 28 | [build-system] 29 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 30 | build-backend = "hatchling.build" 31 | 32 | [tool.hatch.build.hooks.pin_jumpstarter] 33 | name = "pin_jumpstarter" 34 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-uboot/README.md: -------------------------------------------------------------------------------- 1 | # U-Boot driver 2 | 3 | `jumpstarter-driver-uboot` provides functionality for interacting with the 4 | U-Boot bootloader. This driver does not interact with the DUT directly, instead 5 | it should be configured with backing power and serial drivers. 6 | 7 | ## Installation 8 | 9 | ```{code-block} console 10 | :substitutions: 11 | $ pip3 install --extra-index-url {{index_url}} jumpstarter-driver-uboot 12 | ``` 13 | 14 | ## Configuration 15 | 16 | Example configuration: 17 | 18 | ```{literalinclude} uboot.yaml 19 | :language: yaml 20 | ``` 21 | 22 | ```{doctest} 23 | :hide: 24 | >>> from jumpstarter.config.exporter import ExporterConfigV1Alpha1DriverInstance 25 | >>> ExporterConfigV1Alpha1DriverInstance.from_path("source/reference/package-apis/drivers/uboot.yaml").instantiate() 26 | UbootConsole(...) 27 | ``` 28 | 29 | ## API Reference 30 | 31 | ```{eval-rst} 32 | .. autoclass:: jumpstarter_driver_uboot.client.UbootConsoleClient() 33 | :members: 34 | ``` 35 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-qemu/jumpstarter_driver_qemu/client.py: -------------------------------------------------------------------------------- 1 | from contextlib import contextmanager 2 | 3 | from jumpstarter_driver_composite.client import CompositeClient 4 | from jumpstarter_driver_network.adapters import FabricAdapter, NovncAdapter 5 | 6 | 7 | class QemuClient(CompositeClient): 8 | @property 9 | def hostname(self) -> str: 10 | return self.call("get_hostname") 11 | 12 | @property 13 | def username(self) -> str: 14 | return self.call("get_username") 15 | 16 | @property 17 | def password(self) -> str: 18 | return self.call("get_password") 19 | 20 | @contextmanager 21 | def novnc(self): 22 | with NovncAdapter(client=self.vnc) as url: 23 | yield url 24 | 25 | @contextmanager 26 | def shell(self): 27 | with FabricAdapter( 28 | client=self.ssh, 29 | user=self.username, 30 | connect_kwargs={"password": self.password}, 31 | ) as conn: 32 | yield conn 33 | -------------------------------------------------------------------------------- /.github/workflows/trigger-packages-index.yaml: -------------------------------------------------------------------------------- 1 | name: Trigger Packages Index Generation 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - release-* 8 | tags: 9 | - "*" 10 | 11 | jobs: 12 | trigger-packages-index: 13 | runs-on: ubuntu-latest 14 | if: ${{ github.repository_owner == 'jumpstarter-dev' }} 15 | steps: 16 | - uses: actions/create-github-app-token@3ff1caaa28b64c9cc276ce0a02e2ff584f3900c5 # v2.0.2 17 | id: app-token 18 | with: 19 | app-id: ${{ secrets.JUMPSTARTER_BACKPORT_BOT_APP_ID }} 20 | private-key: ${{ secrets.JUMPSTARTER_BACKPORT_BOT_PRIVATE_KEY }} 21 | owner: ${{ github.repository_owner }} 22 | repositories: | 23 | packages 24 | 25 | - name: Trigger packages repository index generation 26 | uses: peter-evans/repository-dispatch@v3 27 | with: 28 | token: ${{ steps.app-token.outputs.token }} 29 | repository: jumpstarter-dev/packages 30 | event-type: generate-index 31 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli/jumpstarter_cli/jmp.py: -------------------------------------------------------------------------------- 1 | import click 2 | from jumpstarter_cli_admin import admin 3 | from jumpstarter_cli_common.alias import AliasedGroup 4 | from jumpstarter_cli_common.opt import opt_log_level 5 | from jumpstarter_cli_common.version import version 6 | from jumpstarter_cli_driver import driver 7 | 8 | from .config import config 9 | from .create import create 10 | from .delete import delete 11 | from .get import get 12 | from .login import login 13 | from .run import run 14 | from .shell import shell 15 | from .update import update 16 | 17 | 18 | @click.group(cls=AliasedGroup) 19 | @opt_log_level 20 | def jmp(): 21 | """The Jumpstarter CLI""" 22 | 23 | 24 | jmp.add_command(create) 25 | jmp.add_command(delete) 26 | jmp.add_command(update) 27 | jmp.add_command(get) 28 | jmp.add_command(shell) 29 | jmp.add_command(run) 30 | jmp.add_command(login) 31 | jmp.add_command(config) 32 | 33 | jmp.add_command(driver) 34 | jmp.add_command(admin) 35 | jmp.add_command(version) 36 | 37 | if __name__ == "__main__": 38 | jmp() 39 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/driver/decorators_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from . import export 4 | from .decorators import ( 5 | MARKER_DRIVERCALL, 6 | MARKER_MAGIC, 7 | MARKER_STREAMING_DRIVERCALL, 8 | ) 9 | 10 | 11 | class Functions: 12 | @export 13 | def function(self): 14 | pass 15 | 16 | @export 17 | async def asyncfunction(self): 18 | pass 19 | 20 | @export 21 | def generator(self): 22 | yield 23 | 24 | @export 25 | async def asyncgenerator(self): 26 | yield 27 | 28 | 29 | def test_driver_decorators(): 30 | functions = Functions() 31 | 32 | assert getattr(functions.function, MARKER_DRIVERCALL) == MARKER_MAGIC 33 | assert getattr(functions.asyncfunction, MARKER_DRIVERCALL) == MARKER_MAGIC 34 | assert getattr(functions.generator, MARKER_STREAMING_DRIVERCALL) == MARKER_MAGIC 35 | assert getattr(functions.asyncgenerator, MARKER_STREAMING_DRIVERCALL) == MARKER_MAGIC 36 | 37 | with pytest.raises(ValueError): 38 | export(None) 39 | -------------------------------------------------------------------------------- /packages/jumpstarter-imagehash/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-imagehash" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [ 6 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 7 | { name = "Nick Cao", email = "ncao@redhat.com" }, 8 | { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, 9 | ] 10 | readme = "README.md" 11 | license = "Apache-2.0" 12 | requires-python = ">=3.11" 13 | dependencies = ["imagehash>=4.3.1", "jumpstarter"] 14 | 15 | [dependency-groups] 16 | dev = ["pytest>=8.3.2", "pytest-cov>=5.0.0"] 17 | 18 | [tool.hatch.metadata.hooks.vcs.urls] 19 | Homepage = "https://jumpstarter.dev" 20 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 21 | 22 | [tool.hatch.version] 23 | source = "vcs" 24 | raw-options = { 'root' = '../../' } 25 | 26 | [build-system] 27 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 28 | build-backend = "hatchling.build" 29 | 30 | [tool.hatch.build.hooks.pin_jumpstarter] 31 | name = "pin_jumpstarter" 32 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/test/data/kernel: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ustreamer/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-ustreamer" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [ 6 | { name = "Nick Cao", email = "ncao@redhat.com" }, 7 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 8 | { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, 9 | ] 10 | readme = "README.md" 11 | license = "Apache-2.0" 12 | requires-python = ">=3.11" 13 | dependencies = ["jumpstarter", "pillow>=10.4.0"] 14 | 15 | [dependency-groups] 16 | dev = ["pytest>=8.3.2", "pytest-cov>=5.0.0"] 17 | 18 | [tool.hatch.metadata.hooks.vcs.urls] 19 | Homepage = "https://jumpstarter.dev" 20 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 21 | 22 | [tool.hatch.version] 23 | source = "vcs" 24 | raw-options = { 'root' = '../../' } 25 | 26 | [build-system] 27 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 28 | build-backend = "hatchling.build" 29 | 30 | [tool.hatch.build.hooks.pin_jumpstarter] 31 | name = "pin_jumpstarter" 32 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/driver/decorators.py: -------------------------------------------------------------------------------- 1 | from inspect import isasyncgenfunction, iscoroutinefunction, isfunction, isgeneratorfunction 2 | from typing import Final 3 | 4 | MARKER_MAGIC: Final[str] = "07c9b9cc" 5 | MARKER_DRIVERCALL: Final[str] = "marker_drivercall" 6 | MARKER_STREAMCALL: Final[str] = "marker_streamcall" 7 | MARKER_STREAMING_DRIVERCALL: Final[str] = "marker_streamingdrivercall" 8 | 9 | 10 | def export(func): 11 | """ 12 | Decorator for exporting method as driver call 13 | """ 14 | if isasyncgenfunction(func) or isgeneratorfunction(func): 15 | setattr(func, MARKER_STREAMING_DRIVERCALL, MARKER_MAGIC) 16 | elif iscoroutinefunction(func) or isfunction(func): 17 | setattr(func, MARKER_DRIVERCALL, MARKER_MAGIC) 18 | else: 19 | raise ValueError(f"unsupported exported function {func}") 20 | return func 21 | 22 | 23 | def exportstream(func): 24 | """ 25 | Decorator for exporting method as stream 26 | """ 27 | setattr(func, MARKER_STREAMCALL, MARKER_MAGIC) 28 | return func 29 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tmt/jumpstarter_driver_tmt/driver.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from jumpstarter.common.exceptions import ConfigurationError 4 | from jumpstarter.driver import Driver, export 5 | 6 | 7 | @dataclass(kw_only=True) 8 | class TMT(Driver): 9 | """ driver for Jumpstarter""" 10 | 11 | reboot_cmd: str = "" 12 | default_username: str = "" 13 | default_password: str = "" 14 | 15 | def __post_init__(self): 16 | if hasattr(super(), "__post_init__"): 17 | super().__post_init__() 18 | 19 | if "ssh" not in self.children: 20 | raise ConfigurationError("'ssh' child is required via ref, or directly as a TcpNetwork driver instance") 21 | 22 | 23 | @classmethod 24 | def client(cls) -> str: 25 | return "jumpstarter_driver_tmt.client.TMTClient" 26 | 27 | @export 28 | def get_reboot_cmd(self): 29 | return self.reboot_cmd 30 | 31 | @export 32 | def get_default_user_pass(self): 33 | return self.default_username, self.default_password 34 | 35 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "tamasfe.even-better-toml", 4 | "tekumara.typos-vscode", 5 | "charliermarsh.ruff", 6 | "codezombiech.gitignore", 7 | "littlefoxteam.vscode-python-test-adapter", 8 | "hbenl.vscode-test-explorer", 9 | "ryanluker.vscode-coverage-gutters", 10 | "lextudio.restructuredtext", 11 | "trond-snekvik.simple-rst", 12 | "swyddfa.esbonio", 13 | "ExecutableBookProject.myst-highlight", 14 | "eamodio.gitlens", 15 | "kevinrose.vsc-python-indent", 16 | "mosapride.zenkaku", 17 | "ms-azuretools.vscode-docker", 18 | "ms-python.python", 19 | "njpwerner.autodocstring", 20 | "pkief.material-icon-theme", 21 | "shardulm94.trailing-spaces", 22 | "usernamehw.errorlens", 23 | "yzhang.markdown-all-in-one", 24 | "ms-vscode.makefile-tools", 25 | "cnshenj.vscode-task-manager" 26 | ], 27 | "unwantedRecommendations": [ 28 | "ms-python.autopep8" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/manifest-renesas.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: FlashBundleManifest 3 | metadata: 4 | name: rcar-s4 5 | spec: 6 | manufacturer: Renesas 7 | link: "https://www.renesas.com/en/products/automotive-products/automotive-system-chips-socs/r-car-s4-automotive-system-chip-soc-car-servercommunication-gateway" 8 | # boot default configuration R-Car S4 Spider, for S4SK use "bootm 0x58000000#s4sk" 9 | bootcmd: "bootm 0x58000000" 10 | shelltype: "busybox" 11 | login: 12 | login_prompt: "login:" 13 | username: "root" 14 | prompt: "#" 15 | default_target: "emmc" 16 | targets: 17 | emmc: "/dev/mmcblk0" 18 | kernel: 19 | file: data/flasher-automotive.itb 20 | address: "0x58000000" 21 | dtb: 22 | default: spider 23 | address: "0x48000000" 24 | variants: 25 | spider: 26 | bootcmd: "bootm 0x58000000#spider" 27 | s4sk: 28 | bootcmd: "bootm 0x58000000#s4sk" 29 | custom: 30 | bootcmd: "bootm 0x58000000:kernel 0x58000000:initrd 0x48000000" 31 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ustreamer/README.md: -------------------------------------------------------------------------------- 1 | # Ustreamer driver 2 | 3 | `jumpstarter-driver-ustreamer` provides functionality for using the ustreamer 4 | video streaming server driven by the jumpstarter exporter. This driver takes a 5 | video device and exposes both snapshot and streaming interfaces. 6 | 7 | ## Installation 8 | 9 | ```{code-block} console 10 | :substitutions: 11 | $ pip3 install --extra-index-url {{index_url}} jumpstarter-driver-ustreamer 12 | ``` 13 | 14 | ## Configuration 15 | 16 | Example configuration: 17 | 18 | ```{literalinclude} ustreamer.yaml 19 | :language: yaml 20 | ``` 21 | 22 | ```{doctest} 23 | :hide: 24 | >>> from jumpstarter.config.exporter import ExporterConfigV1Alpha1DriverInstance 25 | >>> ExporterConfigV1Alpha1DriverInstance.from_path("source/reference/package-apis/drivers/ustreamer.yaml").instantiate() 26 | Traceback (most recent call last): 27 | ... 28 | io.UnsupportedOperation: fileno 29 | ``` 30 | 31 | ## API Reference 32 | 33 | ```{eval-rst} 34 | .. autoclass:: jumpstarter_driver_ustreamer.client.UStreamerClient() 35 | :members: 36 | ``` 37 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-sdwire/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-sdwire" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [{ name = "Nick Cao", email = "ncao@redhat.com" }] 6 | readme = "README.md" 7 | license = "Apache-2.0" 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "jumpstarter", 11 | "jumpstarter-driver-opendal", 12 | "pyusb>=1.2.1", 13 | "pyudev>=0.24.3", 14 | ] 15 | 16 | [project.entry-points."jumpstarter.drivers"] 17 | SDWire = "jumpstarter_driver_sdwire.driver:SDWire" 18 | 19 | [dependency-groups] 20 | dev = ["pytest>=8.3.2", "pytest-cov>=5.0.0"] 21 | 22 | [tool.hatch.metadata.hooks.vcs.urls] 23 | Homepage = "https://jumpstarter.dev" 24 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 25 | 26 | [tool.hatch.version] 27 | source = "vcs" 28 | raw-options = { 'root' = '../../' } 29 | 30 | [build-system] 31 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 32 | build-backend = "hatchling.build" 33 | 34 | [tool.hatch.build.hooks.pin_jumpstarter] 35 | name = "pin_jumpstarter" 36 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tasmota/jumpstarter_driver_tasmota/driver_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pytest_mqtt.model import MqttMessage 3 | 4 | from .driver import TasmotaPower 5 | from jumpstarter.common.utils import serve 6 | 7 | 8 | @pytest.mark.skip("requires docker") 9 | def test_tasmota_power(mosquitto, capmqtt): 10 | cmnd_topic = "cmnd/tasmota_6990F2/POWER" 11 | stat_topic = "stat/tasmota_6990F2/POWER" 12 | 13 | with serve( 14 | TasmotaPower( 15 | host=mosquitto[0], 16 | port=int(mosquitto[1]), 17 | tls=False, 18 | transport="tcp", 19 | cmnd_topic=cmnd_topic, 20 | stat_topic=stat_topic, 21 | ) 22 | ) as client: 23 | capmqtt.publish(topic=stat_topic, payload="ON") 24 | client.on() 25 | assert MqttMessage(topic=cmnd_topic, payload=b"ON", userdata=None) in capmqtt.messages 26 | 27 | capmqtt.publish(topic=stat_topic, payload="OFF") 28 | client.off() 29 | assert MqttMessage(topic=cmnd_topic, payload=b"OFF", userdata=None) in capmqtt.messages 30 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/dbus.py: -------------------------------------------------------------------------------- 1 | from contextlib import contextmanager 2 | from os import environ, getenv 3 | from typing import TYPE_CHECKING 4 | 5 | from .portforward import TcpPortforwardAdapter 6 | 7 | if TYPE_CHECKING: 8 | from ..client import DbusNetworkClient 9 | 10 | 11 | @contextmanager 12 | def DbusAdapter(*, client: "DbusNetworkClient"): 13 | match client.kind: 14 | case "system": 15 | varname = "DBUS_SYSTEM_BUS_ADDRESS" 16 | pass 17 | case "session": 18 | varname = "DBUS_SESSION_BUS_ADDRESS" 19 | pass 20 | case _: 21 | raise ValueError(f"invalid bus type: {client.kind}") 22 | 23 | oldenv = getenv(varname) 24 | 25 | with TcpPortforwardAdapter(client=client) as addr: 26 | environ[varname] = f"tcp:host={addr[0]},port={addr[1]}" 27 | 28 | try: 29 | yield 30 | finally: 31 | if oldenv is None: 32 | del environ[varname] 33 | else: 34 | environ[varname] = oldenv 35 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-sdwire/README.md: -------------------------------------------------------------------------------- 1 | # SDWire driver 2 | 3 | `jumpstarter-driver-sdwire` provides functionality for using the SDWire storage 4 | multiplexer. This device multiplexes an SD card between the DUT and the exporter 5 | host. 6 | 7 | ## Installation 8 | 9 | ```{code-block} console 10 | :substitutions: 11 | $ pip3 install --extra-index-url {{index_url}} jumpstarter-driver-sdwire 12 | ``` 13 | 14 | ## Configuration 15 | 16 | Example configuration: 17 | 18 | ```{literalinclude} sdwire.yaml 19 | :language: yaml 20 | ``` 21 | 22 | ```{doctest} 23 | :hide: 24 | >>> from jumpstarter.config.exporter import ExporterConfigV1Alpha1DriverInstance 25 | >>> ExporterConfigV1Alpha1DriverInstance.from_path("source/api-reference/drivers/sdwire.yaml").instantiate() 26 | Traceback (most recent call last): 27 | ... 28 | FileNotFoundError: failed to find sd-wire device 29 | ``` 30 | 31 | ## API Reference 32 | 33 | The SDWire driver implements the `StorageMuxClient` class, which is a generic 34 | storage class. 35 | 36 | ```{eval-rst} 37 | .. autoclass:: jumpstarter_driver_opendal.client.StorageMuxClient() 38 | :members: 39 | ``` 40 | -------------------------------------------------------------------------------- /packages/jumpstarter-protocol/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-protocol" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [{ name = "Kirk Brauer", email = "kbrauer@hatci.com" }] 6 | readme = "README.md" 7 | license = "Apache-2.0" 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "googleapis-common-protos>=1.69.1", 11 | "grpcio>=1.66.1", 12 | "protobuf>=6.30.1", 13 | ] 14 | 15 | [dependency-groups] 16 | dev = [ 17 | "pytest>=8.3.2", 18 | "pytest-anyio>=0.0.0", 19 | "pytest-asyncio>=0.0.0", 20 | "pytest-cov>=5.0.0", 21 | ] 22 | 23 | [tool.hatch.build.targets.wheel] 24 | packages = ["jumpstarter_protocol"] 25 | 26 | [tool.hatch.metadata.hooks.vcs.urls] 27 | Homepage = "https://jumpstarter.dev" 28 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 29 | 30 | [tool.hatch.version] 31 | source = "vcs" 32 | raw-options = { 'root' = '../../' } 33 | 34 | [build-system] 35 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 36 | build-backend = "hatchling.build" 37 | 38 | [tool.hatch.build.hooks.pin_jumpstarter] 39 | name = "pin_jumpstarter" 40 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-opendal/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-opendal" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [ 6 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 7 | { name = "Nick Cao", email = "ncao@redhat.com" }, 8 | ] 9 | readme = "README.md" 10 | license = "Apache-2.0" 11 | requires-python = ">=3.11" 12 | dependencies = ["jumpstarter", "opendal>=0.45.8", "click>=8.1.7.2"] 13 | 14 | [project.entry-points."jumpstarter.adapters"] 15 | Opendal = "jumpstarter_driver_opendal.adapters:OpendalAdapter" 16 | 17 | [dependency-groups] 18 | dev = ["pytest>=8.3.2", "pytest-cov>=5.0.0"] 19 | 20 | [tool.hatch.metadata.hooks.vcs.urls] 21 | Homepage = "https://jumpstarter.dev" 22 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 23 | 24 | [tool.hatch.version] 25 | source = "vcs" 26 | raw-options = { 'root' = '../../' } 27 | 28 | [build-system] 29 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 30 | build-backend = "hatchling.build" 31 | 32 | [tool.hatch.build.hooks.pin_jumpstarter] 33 | name = "pin_jumpstarter" 34 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-power/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-power" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [ 6 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 7 | { name = "Nick Cao", email = "ncao@redhat.com" }, 8 | ] 9 | readme = "README.md" 10 | license = "Apache-2.0" 11 | requires-python = ">=3.11" 12 | dependencies = ["jumpstarter", "pyserial>=3.5", "click>=8.1.7.2"] 13 | 14 | [project.entry-points."jumpstarter.drivers"] 15 | MockPower = "jumpstarter_driver_power.driver:MockPower" 16 | 17 | [dependency-groups] 18 | dev = ["pytest>=8.3.2", "pytest-cov>=5.0.0", "trio>=0.28.0"] 19 | 20 | [tool.hatch.metadata.hooks.vcs.urls] 21 | Homepage = "https://jumpstarter.dev" 22 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 23 | 24 | [tool.hatch.version] 25 | source = "vcs" 26 | raw-options = { 'root' = '../../' } 27 | 28 | [build-system] 29 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 30 | build-backend = "hatchling.build" 31 | 32 | [tool.hatch.build.hooks.pin_jumpstarter] 33 | name = "pin_jumpstarter" 34 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ridesx/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: jumpstarter-lab 5 | name: qc 6 | endpoint: 7 | tls: 8 | ca: "" 9 | insecure: true 10 | token: 11 | export: 12 | storage: 13 | type: "jumpstarter_driver_ridesx.driver.RideSXDriver" 14 | config: 15 | log_level: "DEBUG" 16 | children: 17 | serial: 18 | type: "jumpstarter_driver_pyserial.driver.PySerial" 19 | config: 20 | log_level: "DEBUG" 21 | url: "/dev/ttyACM0" 22 | baudrate: 115200 23 | power: 24 | type: "jumpstarter_driver_ridesx.driver.RideSXPowerDriver" 25 | config: 26 | log_level: "DEBUG" 27 | children: 28 | serial: 29 | type: "jumpstarter_driver_pyserial.driver.PySerial" 30 | config: 31 | log_level: "DEBUG" 32 | url: "/dev/ttyACM0" 33 | baudrate: 115200 34 | serial: 35 | type: "jumpstarter_driver_pyserial.driver.PySerial" 36 | config: 37 | log_level: "DEBUG" 38 | url: "/dev/ttyUSB1" 39 | baudrate: 115200 40 | -------------------------------------------------------------------------------- /.github/workflows/build_oci_bundle.yaml: -------------------------------------------------------------------------------- 1 | name: Build and push buildroot-based flasher OCI bundle 2 | on: 3 | workflow_dispatch: 4 | 5 | jobs: 6 | build-fits: 7 | runs-on: ubuntu-24.04-arm 8 | container: fedora:42 9 | steps: 10 | - name: Checkout repository 11 | uses: actions/checkout@v4 12 | with: 13 | fetch-depth: 0 14 | 15 | - name: Run build_fits.sh 16 | run: | 17 | cd packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb 18 | ./build_fits.sh 19 | 20 | - name: Upload FIT artifacts 21 | uses: actions/upload-artifact@v4 22 | with: 23 | name: FIT-images 24 | path: packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/data/*.itb 25 | 26 | - name: Run build_bundle.sh for aarch64-itb 27 | run: | 28 | cd packages/jumpstarter-driver-flashers/oci_bundles && dnf install -y oras 29 | oras login quay.io -u jumpstarter-dev+jumpstarter_ci --password-stdin <<< "${{ secrets.QUAY_TOKEN }}" 30 | ./build_bundle.sh quay.io/jumpstarter-dev/jumpstarter-flasher-aarch64-itb:latest aarch64-itb 31 | -------------------------------------------------------------------------------- /packages/jumpstarter-kubernetes/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-kubernetes" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [{ name = "Kirk Brauer", email = "kbrauer@hatci.com" }] 6 | readme = "README.md" 7 | license = "Apache-2.0" 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "jumpstarter", 11 | "pydantic>=2.8.2", 12 | "kubernetes>=31.0.0", 13 | "kubernetes-asyncio>=31.1.0", 14 | "aiohttp>=3.11.18", 15 | "semver~=2.13", 16 | "packaging>=25.0", 17 | ] 18 | 19 | [dependency-groups] 20 | dev = [ 21 | "pytest>=8.3.2", 22 | "pytest-anyio>=0.0.0", 23 | "pytest-asyncio>=0.0.0", 24 | "pytest-cov>=5.0.0", 25 | ] 26 | 27 | [tool.hatch.metadata.hooks.vcs.urls] 28 | Homepage = "https://jumpstarter.dev" 29 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 30 | 31 | [tool.hatch.version] 32 | source = "vcs" 33 | raw-options = { 'root' = '../../' } 34 | 35 | [build-system] 36 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 37 | build-backend = "hatchling.build" 38 | 39 | [tool.hatch.build.hooks.pin_jumpstarter] 40 | name = "pin_jumpstarter" 41 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-energenie/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-energenie" 3 | dynamic = ["version", "urls"] 4 | description = "Energenie is an advanced surge protector with power management features" 5 | readme = "README.md" 6 | license = { text = "Apache-2.0" } 7 | authors = [ 8 | { name = "Enric Balletbo i Serra", email = "eballetbo@redhat.com" } 9 | ] 10 | requires-python = ">=3.11" 11 | dependencies = [ 12 | "anyio>=4.10.0", 13 | "jumpstarter", 14 | "jumpstarter-driver-power" 15 | ] 16 | 17 | [project.entry-points."jumpstarter.drivers"] 18 | EnerGenie = "jumpstarter_driver_energenie.driver:EnerGenie" 19 | 20 | [dependency-groups] 21 | dev = [ 22 | "pytest-cov>=6.0.0", 23 | "pytest>=8.3.3", 24 | "pytest-httpserver>=1.0.0", 25 | ] 26 | 27 | [tool.hatch.metadata.hooks.vcs.urls] 28 | Homepage = "https://jumpstarter.dev" 29 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 30 | 31 | [tool.hatch.version] 32 | source = "vcs" 33 | raw-options = { 'root' = '../../'} 34 | 35 | [build-system] 36 | requires = ["hatchling", "hatch-vcs"] 37 | build-backend = "hatchling.build" 38 | -------------------------------------------------------------------------------- /examples/soc-pytest/jumpstarter_example_soc_pytest/image/scripts/download-latest-raspbian: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | #LATEST_URL=$(wget -O /dev/null -o - --max-redirect=0 https://downloads.raspberrypi.org/raspios_lite_armhf_latest 2>/dev/null| sed -n "s/^Location: \(.*\) \[following\]$/\1/p") 4 | LATEST_URL=$(curl https://downloads.raspberrypi.org/raspios_lite_armhf_latest -v 2>&1 | sed -n "s/< location: \(.*\)\r$/\1/p") 5 | echo $LATEST_URL 6 | CACHE="./images" 7 | wget "${LATEST_URL}" -np -m -A '*img.xz' -c -P "${CACHE}" 8 | # use the latest compose image 9 | LATEST_IMG=$(ls -Art "${CACHE}/downloads.raspberrypi.org/raspios_lite_armhf/images"/*/*.img.xz | tail -n 1) 10 | 11 | echo "Latest image: ${LATEST_IMG}" 12 | 13 | # calculate full path to LATEST_IMG 14 | LATEST_IMG_FULLPATH=$(readlink -f ${LATEST_IMG}) 15 | EXISTING_LINK=$(readlink "${CACHE}/latest.raw.xz" || true ) 16 | # if the link has changed, update the link 17 | if [[ "${LATEST_IMG_FULLPATH}" != "${EXISTING_LINK}" ]]; then 18 | echo "Updating link from latest.raw.xz -> ${LATEST_IMG}" 19 | ln -fs "${LATEST_IMG_FULLPATH}" "${CACHE}/latest.raw.xz" 20 | else 21 | echo "We are up-to-date." 22 | fi 23 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ble/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-ble" 3 | dynamic = ["version", "urls"] 4 | description = "Bluetooth Low Energy (BLE) driver" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [{ name = "Andreas Karner", email = "andreas.karner@outlook.com" }] 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "anyio>=4.10.0", 11 | "jumpstarter", 12 | "bleak>=1.1.1", 13 | ] 14 | 15 | [tool.hatch.version] 16 | source = "vcs" 17 | raw-options = { 'root' = '../../' } 18 | 19 | [tool.hatch.metadata.hooks.vcs.urls] 20 | Homepage = "https://jumpstarter.dev" 21 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 22 | 23 | [tool.pytest.ini_options] 24 | addopts = "--cov --cov-report=html --cov-report=xml" 25 | log_cli = true 26 | log_cli_level = "INFO" 27 | testpaths = ["jumpstarter_driver_ble"] 28 | 29 | [build-system] 30 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 31 | build-backend = "hatchling.build" 32 | 33 | [dependency-groups] 34 | dev = ["pytest-cov>=6.0.0", "pytest>=8.3.3"] 35 | 36 | [tool.hatch.build.hooks.pin_jumpstarter] 37 | name = "pin_jumpstarter" 38 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-gpiod/jumpstarter_driver_gpiod/conftest.py: -------------------------------------------------------------------------------- 1 | import platform 2 | 3 | import pytest 4 | 5 | # Skip all tests on Darwin (macOS) due to missing gpiod module 6 | pytestmark = pytest.mark.skipif(platform.system() == "Darwin", reason="gpiod module not available on Darwin/macOS") 7 | 8 | 9 | # Add test utilities for GPIO testing 10 | @pytest.fixture 11 | def mock_gpiod_values(): 12 | """Provide mock gpiod value constants for testing""" 13 | return {"ACTIVE": 1, "INACTIVE": 0, "RISING_EDGE": "rising", "FALLING_EDGE": "falling"} 14 | 15 | 16 | @pytest.fixture 17 | def mock_gpiod_directions(): 18 | """Provide mock gpiod direction constants for testing""" 19 | return {"INPUT": "input", "OUTPUT": "output"} 20 | 21 | 22 | @pytest.fixture 23 | def mock_gpiod_drives(): 24 | """Provide mock gpiod drive constants for testing""" 25 | return {"PUSH_PULL": "push_pull", "OPEN_DRAIN": "open_drain", "OPEN_SOURCE": "open_source"} 26 | 27 | 28 | @pytest.fixture 29 | def mock_gpiod_biases(): 30 | """Provide mock gpiod bias constants for testing""" 31 | return {"AS_IS": "as_is", "PULL_UP": "pull_up", "PULL_DOWN": "pull_down", "DISABLED": "disabled"} 32 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-iscsi/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-iscsi" 3 | dynamic = ["version", "urls"] 4 | description = "Exporter ISCSI service driver" 5 | readme = "README.md" 6 | authors = [{ name = "Benny Zlotnik", email = "bzlotnik@redhat.com" }] 7 | requires-python = ">=3.11" 8 | dependencies = [ 9 | "anyio>=4.10.0", 10 | "jumpstarter", 11 | "jumpstarter-driver-composite", 12 | "jumpstarter-driver-opendal", 13 | "click>=8.1.8", 14 | "rtslib-fb", 15 | "requests>=2.32.5" 16 | ] 17 | 18 | [tool.hatch.version] 19 | source = "vcs" 20 | raw-options = { 'root' = '../../' } 21 | 22 | [tool.hatch.metadata.hooks.vcs.urls] 23 | Homepage = "https://jumpstarter.dev" 24 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 25 | 26 | [tool.pytest.ini_options] 27 | asyncio_mode = "strict" 28 | asyncio_default_fixture_loop_scope = "function" 29 | testpaths = ["src"] 30 | 31 | [build-system] 32 | requires = ["hatchling", "hatch-vcs"] 33 | build-backend = "hatchling.build" 34 | 35 | [dependency-groups] 36 | dev = [ 37 | "pytest-cov>=6.0.0", 38 | "pytest>=8.3.3", 39 | "pytest-asyncio>=0.24.0", 40 | ] 41 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-composite/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-composite" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [ 6 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 7 | { name = "Nick Cao", email = "ncao@redhat.com" }, 8 | ] 9 | readme = "README.md" 10 | license = "Apache-2.0" 11 | requires-python = ">=3.11" 12 | dependencies = ["jumpstarter", "click>=8.1.7.2"] 13 | 14 | [project.entry-points."jumpstarter.drivers"] 15 | Composite = "jumpstarter_driver_composite.driver:Composite" 16 | Proxy = "jumpstarter_driver_composite.driver:Proxy" 17 | 18 | [dependency-groups] 19 | dev = ["pytest>=8.3.2", "pytest-cov>=5.0.0", "jumpstarter-driver-power"] 20 | 21 | [tool.hatch.metadata.hooks.vcs.urls] 22 | Homepage = "https://jumpstarter.dev" 23 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 24 | 25 | [tool.hatch.version] 26 | source = "vcs" 27 | raw-options = { 'root' = '../../' } 28 | 29 | [build-system] 30 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 31 | build-backend = "hatchling.build" 32 | 33 | [tool.hatch.build.hooks.pin_jumpstarter] 34 | name = "pin_jumpstarter" 35 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-pyserial/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-pyserial" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [ 6 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 7 | { name = "Nick Cao", email = "ncao@redhat.com" }, 8 | ] 9 | readme = "README.md" 10 | license = "Apache-2.0" 11 | requires-python = ">=3.11" 12 | dependencies = [ 13 | "jumpstarter", 14 | "jumpstarter-driver-network", 15 | "pyserial>=3.5", 16 | "click>=8.1.7.2", 17 | "pyserial-asyncio>=0.6", 18 | ] 19 | 20 | [dependency-groups] 21 | dev = [ 22 | "pytest>=8.3.2", 23 | "pytest-cov>=5.0.0", 24 | "types-pexpect>=4.9.0.20241208", 25 | "types-pyserial>=3.5.0.20250130", 26 | ] 27 | 28 | [tool.hatch.metadata.hooks.vcs.urls] 29 | Homepage = "https://jumpstarter.dev" 30 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 31 | 32 | [tool.hatch.version] 33 | source = "vcs" 34 | raw-options = { 'root' = '../../' } 35 | 36 | [build-system] 37 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 38 | build-backend = "hatchling.build" 39 | 40 | [tool.hatch.build.hooks.pin_jumpstarter] 41 | name = "pin_jumpstarter" 42 | -------------------------------------------------------------------------------- /__templates__/driver/pyproject.toml.tmpl: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-${DRIVER_NAME}" 3 | dynamic = ["version", "urls"] 4 | description = "Add your description here" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [ 8 | { name = "${AUTHOR_NAME}", email = "${AUTHOR_EMAIL}" } 9 | ] 10 | requires-python = ">=3.11" 11 | dependencies = [ 12 | "anyio>=4.10.0", 13 | "jumpstarter", 14 | ] 15 | 16 | [tool.hatch.version] 17 | source = "vcs" 18 | raw-options = { 'root' = '../../'} 19 | 20 | [tool.hatch.metadata.hooks.vcs.urls] 21 | Homepage = "https://jumpstarter.dev" 22 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 23 | 24 | [tool.pytest.ini_options] 25 | addopts = "--cov --cov-report=html --cov-report=xml" 26 | log_cli = true 27 | log_cli_level = "INFO" 28 | testpaths = ["jumpstarter_driver_${DRIVER_NAME}"] 29 | asyncio_mode = "auto" 30 | 31 | [build-system] 32 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 33 | build-backend = "hatchling.build" 34 | 35 | [tool.hatch.build.hooks.pin_jumpstarter] 36 | name = "pin_jumpstarter" 37 | 38 | [dependency-groups] 39 | dev = [ 40 | "pytest-cov>=6.0.0", 41 | "pytest>=8.3.3", 42 | ] 43 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-admin/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-cli-admin" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [{ name = "Kirk Brauer", email = "kbrauer@hatci.com" }] 6 | readme = "README.md" 7 | license = "Apache-2.0" 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "grpcio-reflection>=1.60.0", 11 | "jumpstarter-cli-common", 12 | "jumpstarter-kubernetes", 13 | ] 14 | 15 | [dependency-groups] 16 | dev = [ 17 | "pytest>=8.3.2", 18 | "pytest-anyio>=0.0.0", 19 | "pytest-asyncio>=0.0.0", 20 | "pytest-cov>=5.0.0", 21 | ] 22 | 23 | [project.scripts] 24 | jmp-admin = "jumpstarter_cli_admin:admin" 25 | 26 | [tool.hatch.build.targets.wheel] 27 | packages = ["jumpstarter_cli_admin"] 28 | 29 | [tool.hatch.metadata.hooks.vcs.urls] 30 | Homepage = "https://jumpstarter.dev" 31 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 32 | 33 | [tool.hatch.version] 34 | source = "vcs" 35 | raw-options = { 'root' = '../../' } 36 | 37 | [build-system] 38 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 39 | build-backend = "hatchling.build" 40 | 41 | [tool.hatch.build.hooks.pin_jumpstarter] 42 | name = "pin_jumpstarter" 43 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-probe-rs/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-probe-rs" 3 | dynamic = ["version", "urls"] 4 | description = "rust probe-rs driver for jumpstarter" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [{ name = "Miguel Angel Ajo", email = "miguelangel@ajo.es" }] 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "anyio>=4.10.0", 11 | "click>=8.1.7.2", 12 | "jumpstarter", 13 | "jumpstarter-driver-opendal", 14 | ] 15 | 16 | [tool.hatch.version] 17 | source = "vcs" 18 | raw-options = { 'root' = '../../' } 19 | 20 | [tool.hatch.metadata.hooks.vcs.urls] 21 | Homepage = "https://jumpstarter.dev" 22 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 23 | 24 | [tool.pytest.ini_options] 25 | addopts = "--cov --cov-report=html --cov-report=xml" 26 | log_cli = true 27 | log_cli_level = "INFO" 28 | testpaths = ["jumpstarter_driver_probe_rs"] 29 | 30 | [build-system] 31 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 32 | build-backend = "hatchling.build" 33 | 34 | [dependency-groups] 35 | dev = ["pytest-cov>=6.0.0", "pytest>=8.3.3"] 36 | 37 | [tool.hatch.build.hooks.pin_jumpstarter] 38 | name = "pin_jumpstarter" 39 | -------------------------------------------------------------------------------- /conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | from contextlib import contextmanager 3 | 4 | import pytest 5 | 6 | os.environ["TERM"] = "dumb" 7 | 8 | try: 9 | from jumpstarter.common.utils import serve 10 | from jumpstarter.config.exporter import ExporterConfigV1Alpha1, ExporterConfigV1Alpha1DriverInstance 11 | except ImportError: 12 | # some packages in the workspace does not depend on jumpstarter 13 | pass 14 | else: 15 | 16 | @contextmanager 17 | def run(config): 18 | with serve(ExporterConfigV1Alpha1DriverInstance.from_str(config).instantiate()) as client: 19 | yield client 20 | 21 | @pytest.fixture(autouse=True) 22 | def jumpstarter_namespace(doctest_namespace): 23 | doctest_namespace["serve"] = serve 24 | doctest_namespace["run"] = run 25 | 26 | @pytest.fixture(autouse=True) 27 | def tmp_config_path(tmp_path, monkeypatch): 28 | monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / "client-config")) 29 | monkeypatch.setattr(ExporterConfigV1Alpha1, "BASE_PATH", tmp_path / "exporters") 30 | 31 | @pytest.fixture(autouse=True) 32 | def console_size(monkeypatch): 33 | monkeypatch.setenv("COLUMNS", "1024") 34 | monkeypatch.setenv("LINES", "1024") 35 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-common/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-cli-common" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [{ name = "Kirk Brauer", email = "kbrauer@hatci.com" }] 6 | readme = "README.md" 7 | license = "Apache-2.0" 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "jumpstarter", 11 | "pydantic>=2.8.2", 12 | "click>=8.1.7.2", 13 | "authlib>=1.4.1", 14 | "truststore>=0.10.1", 15 | "joserfc>=1.0.3", 16 | "yarl>=1.18.3", 17 | "rich>=14.0.0", 18 | ] 19 | 20 | [dependency-groups] 21 | dev = [ 22 | "pytest>=8.3.2", 23 | "pytest-anyio>=0.0.0", 24 | "pytest-asyncio>=0.0.0", 25 | "pytest-cov>=5.0.0", 26 | ] 27 | 28 | [tool.hatch.build.targets.wheel] 29 | packages = ["jumpstarter_cli_common"] 30 | 31 | [tool.hatch.metadata.hooks.vcs.urls] 32 | Homepage = "https://jumpstarter.dev" 33 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 34 | 35 | [tool.hatch.version] 36 | source = "vcs" 37 | raw-options = { 'root' = '../../' } 38 | 39 | [build-system] 40 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 41 | build-backend = "hatchling.build" 42 | 43 | [tool.hatch.build.hooks.pin_jumpstarter] 44 | name = "pin_jumpstarter" 45 | -------------------------------------------------------------------------------- /.github/workflows/pr_analytics.yaml: -------------------------------------------------------------------------------- 1 | name: "PR Analytics" 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | report_date_start: 6 | description: "Report date start(d/MM/yyyy)" 7 | report_date_end: 8 | description: "Report date end(d/MM/yyyy)" 9 | jobs: 10 | create-report: 11 | name: "Create report" 12 | runs-on: ubuntu-latest 13 | permissions: 14 | contents: read 15 | pull-requests: read 16 | issues: write 17 | steps: 18 | - name: "Run script for analytics" 19 | uses: AlexSim93/pull-request-analytics-action@cc57ceb92148c5d5879ca578a2b59f99c3cbe231 # v4.6.1 20 | with: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # In the case of a personal access token, it needs to be added to the repository's secrets and used in this field. 22 | GITHUB_REPO_FOR_ISSUE: jumpstarter 23 | GITHUB_OWNER_FOR_ISSUE: jumpstarter-dev 24 | GITHUB_OWNERS_REPOS: jumpstarter-dev/jumpstarter #TODO: check with more repos later, needs PAT: ,jumpstarter-dev/jumpstarter-controller 25 | USE_CHARTS: true 26 | TIMEZONE: "Etc/UTC" 27 | REPORT_DATE_START: ${{ inputs.report_date_start }} 28 | REPORT_DATE_END: ${{ inputs.report_date_end }} 29 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | HOST ?= 127.0.0.1 11 | PORT ?= 8000 12 | 13 | # Put it first so that "make" without argument is like "make help". 14 | help: 15 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 16 | 17 | # Define custom targets as PHONY to prevent them from being caught by the pattern rule 18 | .PHONY: help Makefile serve multiversion redirect serve-multiversion 19 | 20 | # Catch-all target: route all unknown targets to Sphinx using the new 21 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 22 | %: Makefile 23 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 24 | 25 | serve: 26 | sphinx-autobuild --host $(HOST) --port $(PORT) "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 27 | 28 | multiversion: 29 | ./multiversion.sh 30 | 31 | serve-multiversion: 32 | @echo "Serving multiversion documentation using the HOST variable" 33 | @cd "$(BUILDDIR)" && python -m http.server $(PORT) --bind $(HOST) 34 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tmt/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-tmt" 3 | dynamic = ["version", "urls"] 4 | description = "Add your description here" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [ 8 | { name = "Miguel Angel Ajo Pelayo", email = "miguelangel@ajo.es" } 9 | ] 10 | requires-python = ">=3.11" 11 | dependencies = [ 12 | "anyio>=4.10.0", 13 | "jumpstarter", 14 | "jumpstarter-driver-network", 15 | "jumpstarter-driver-composite", 16 | ] 17 | 18 | [tool.hatch.version] 19 | source = "vcs" 20 | raw-options = { 'root' = '../../'} 21 | 22 | [tool.hatch.metadata.hooks.vcs.urls] 23 | Homepage = "https://jumpstarter.dev" 24 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 25 | 26 | [tool.pytest.ini_options] 27 | addopts = "" 28 | log_cli = true 29 | log_cli_level = "INFO" 30 | testpaths = ["jumpstarter_driver_tmt"] 31 | asyncio_mode = "auto" 32 | 33 | [build-system] 34 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 35 | build-backend = "hatchling.build" 36 | 37 | [tool.hatch.build.hooks.pin_jumpstarter] 38 | name = "pin_jumpstarter" 39 | 40 | [dependency-groups] 41 | dev = [ 42 | "pytest-cov>=6.0.0", 43 | "pytest>=8.3.3", 44 | ] 45 | -------------------------------------------------------------------------------- /docs/source/introduction/clients.md: -------------------------------------------------------------------------------- 1 | # Clients 2 | 3 | To interact with your target device from a development machine or through a 4 | CI/CD pipeline, you must use a Jumpstarter client. The Python client can be used 5 | either as a library or as a [CLI tool](../reference/man-pages/index.md). 6 | 7 | ## Types of Clients 8 | 9 | Jumpstarter supports two types of client configurations: *local* and *remote*. 10 | 11 | ### Local Clients 12 | 13 | When using Jumpstarter in *local-only* mode, you can use the local client 14 | functionality to directly access your hardware. The local client will 15 | automatically use any drivers that are registered without the need for an 16 | exporter instance running in the background. 17 | 18 | ### Remote Clients 19 | 20 | When using Jumpstarter in *distributed* mode, the client must be configured to 21 | connect to an instance of the Service that can authenticate and route requests 22 | to the appropriate exporter instance. 23 | 24 | The following parameters are required to set up a remote client: 25 | 26 | - The URL of a Service endpoint to connect to 27 | - An authentication token generated by the Service 28 | 29 | ```{note} 30 | The endpoint must be accessible from your client machine to communicate 31 | with the Service. 32 | ``` -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/test/manifest.yaml: -------------------------------------------------------------------------------- 1 | # This is a test manifest for the flasher bundle 2 | # It is used to test the flasher bundle, not intended for any production use 3 | apiVersion: jumpstarter.dev/v1alpha1 4 | kind: FlashBundleManifest 5 | metadata: 6 | name: test-bundle 7 | spec: 8 | manufacturer: The Jumpstarter Authors 9 | link: "https://jumpstarter.dev" 10 | bootcmd: "booti 0x82000000 - 0x84000000" 11 | default_target: "usd" 12 | login: 13 | type: "busybox" 14 | login_prompt: "login:" 15 | username: "root" 16 | password: "password" 17 | prompt: "#" 18 | targets: 19 | usd: "/sys/class/block#4fb0000" 20 | emmc: "/sys/class/block#4f80000" 21 | preflash_commands: 22 | - "dd if=/dev/zero of=/dev/mmcblk0 bs=512 count=34" 23 | - "dd if=/dev/zero of=/dev/mmcblk1 bs=512 count=34" 24 | kernel: 25 | file: data/kernel 26 | address: "0x82000000" 27 | initram: 28 | file: data/initramfs 29 | address: "0x83000000" 30 | dtb: 31 | default: test-dtb 32 | address: "0x84000000" 33 | variants: 34 | test-dtb: 35 | file: data/dtbs/test-dtb.dtb 36 | alternate: 37 | file: data/dtbs/alternate.dtb 38 | othercmd: 39 | bootcmd: "bootm" 40 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-corellium/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter_driver_corellium" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [{ name = "Leonardo Rossetti", email = "lrossett@redhat.com" }] 6 | readme = "README.md" 7 | license = "Apache-2.0" 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "jumpstarter", 11 | "jumpstarter-driver-composite", 12 | "jumpstarter-driver-power", 13 | "jumpstarter-driver-network", 14 | "jumpstarter-driver-pyserial", 15 | "click>=8.1.7.2", 16 | ] 17 | 18 | [project.entry-points."jumpstarter.drivers"] 19 | Corellium = "jumpstarter_driver_corellium.driver:Corellium" 20 | 21 | [dependency-groups] 22 | dev = ["pytest>=8.3.2", "pytest-cov>=5.0.0", "trio>=0.28.0", "requests_mock", "pytest-asyncio>=0.25.3"] 23 | 24 | [tool.hatch.metadata.hooks.vcs.urls] 25 | Homepage = "https://jumpstarter.dev" 26 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 27 | 28 | [tool.hatch.version] 29 | source = "vcs" 30 | raw-options = { 'root' = '../../' } 31 | 32 | [build-system] 33 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 34 | build-backend = "hatchling.build" 35 | 36 | [tool.hatch.build.hooks.pin_jumpstarter] 37 | name = "pin_jumpstarter" 38 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tftp/examples/tftp_test.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | import pytest 4 | from jumpstarter_driver_tftp.driver import TftpError 5 | from jumpstarter_testing.pytest import JumpstarterTest 6 | 7 | log = logging.getLogger(__name__) 8 | 9 | 10 | class TestResource(JumpstarterTest): 11 | selector = "board=rpi4" 12 | 13 | @pytest.fixture() 14 | def setup_tftp(self, client): 15 | # Move the setup code to a fixture 16 | client.tftp.start() 17 | yield client 18 | client.tftp.stop() 19 | 20 | def test_tftp_operations(self, setup_tftp): 21 | client = setup_tftp 22 | test_file = "test.bin" 23 | 24 | # Create test file 25 | with open(test_file, "wb") as f: 26 | f.write(b"Hello from TFTP streaming test!") 27 | 28 | try: 29 | # Test upload 30 | client.tftp.put_local_file(test_file) 31 | assert test_file in client.tftp.list_files() 32 | 33 | # Test delete 34 | client.tftp.delete_file(test_file) 35 | assert test_file not in client.tftp.list_files() 36 | 37 | except (TftpError, FileNotFoundError) as e: 38 | pytest.fail(f"Test failed: {e}") # ty: ignore[call-non-callable] 39 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ssh-mitm/examples/exporter.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: ExporterConfig 3 | metadata: 4 | namespace: default 5 | name: ssh-mitm-example 6 | endpoint: "grpc.jumpstarter.example.com:443" 7 | token: "your-exporter-token" 8 | export: 9 | # "j ssh_mitm" command - secure SSH with key on server 10 | ssh_mitm: 11 | type: jumpstarter_driver_ssh.driver.SSHWrapper 12 | config: 13 | # Change to the user you will SSH as on the DUT 14 | default_username: root 15 | children: 16 | tcp: 17 | type: jumpstarter_driver_ssh_mitm.driver.SSHMITM 18 | config: 19 | # Must match the user on the DUT 20 | default_username: root 21 | # Option 1: Path to key file (on exporter machine) 22 | ssh_identity_file: /etc/jumpstarter/ssh_keys/dut_key 23 | # Option 2: Inline key (from secret management) 24 | # ssh_identity: | 25 | # -----BEGIN OPENSSH PRIVATE KEY----- 26 | # ...key content... 27 | # -----END OPENSSH PRIVATE KEY----- 28 | children: 29 | tcp: 30 | type: jumpstarter_driver_network.driver.TcpNetwork 31 | config: 32 | host: 192.168.1.100 33 | port: 22 34 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-can/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-can" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [ 6 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 7 | { name = "Nick Cao", email = "ncao@redhat.com" }, 8 | { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, 9 | ] 10 | readme = "README.md" 11 | license = "Apache-2.0" 12 | requires-python = ">=3.11" 13 | dependencies = ["jumpstarter", "python-can>=4.5.0", "can-isotp>=2.0.6"] 14 | 15 | [project.entry-points."jumpstarter.drivers"] 16 | Can = "jumpstarter_driver_can.driver:Can" 17 | IsoTpPython = "jumpstarter_driver_can.driver:IsoTpPython" 18 | IsoTpSocket = "jumpstarter_driver_can.driver:IsoTpSocket" 19 | 20 | [dependency-groups] 21 | dev = ["pytest>=8.3.2", "pytest-cov>=5.0.0"] 22 | 23 | [tool.hatch.metadata.hooks.vcs.urls] 24 | Homepage = "https://jumpstarter.dev" 25 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 26 | 27 | [tool.hatch.version] 28 | source = "vcs" 29 | raw-options = { 'root' = '../../' } 30 | 31 | [build-system] 32 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 33 | build-backend = "hatchling.build" 34 | 35 | [tool.hatch.build.hooks.pin_jumpstarter] 36 | name = "pin_jumpstarter" 37 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-http-power/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-http-power" 3 | dynamic = ["version", "urls"] 4 | description = "A power driver for HTTP enabled PDUs or smart sockets, like the Shelly splug" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [ 8 | { name = "Miguel Angel Ajo", email = "majopela@redhat.com" } 9 | ] 10 | requires-python = ">=3.11" 11 | dependencies = [ 12 | "anyio>=4.10.0", 13 | "jumpstarter", 14 | "jumpstarter-driver-power", 15 | ] 16 | 17 | 18 | [tool.hatch.version] 19 | source = "vcs" 20 | raw-options = { 'root' = '../../' } 21 | 22 | [tool.hatch.metadata.hooks.vcs.urls] 23 | Homepage = "https://jumpstarter.dev" 24 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 25 | 26 | [tool.pytest.ini_options] 27 | addopts = "--cov --cov-report=html --cov-report=xml" 28 | log_cli = true 29 | log_cli_level = "INFO" 30 | testpaths = ["jumpstarter_driver_http_power"] 31 | 32 | [build-system] 33 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 34 | build-backend = "hatchling.build" 35 | 36 | [tool.hatch.build.hooks.pin_jumpstarter] 37 | name = "pin_jumpstarter" 38 | 39 | [dependency-groups] 40 | dev = [ 41 | "pytest-cov>=6.0.0", 42 | "pytest>=8.3.3", 43 | ] 44 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-probe-rs/jumpstarter_driver_probe_rs/driver_test.py: -------------------------------------------------------------------------------- 1 | from .driver import ProbeRs 2 | from jumpstarter.common.utils import serve 3 | 4 | 5 | def test_drivers_probe_rs(monkeypatch): 6 | instance = ProbeRs() 7 | 8 | def mock_run_cmd(cmd): 9 | if cmd[0] == "info": 10 | return "Target: nRF52840_xxAA\nFlash size: 1MB" 11 | elif cmd[0] == "read": 12 | return "DEADBEEF CAFEBABE\nCAFE0000 DEAD0000" 13 | return "ok" 14 | 15 | monkeypatch.setattr(instance, "_run_cmd", mock_run_cmd) 16 | 17 | with serve(instance) as client: 18 | info = client.info() 19 | assert "Target:" in info 20 | assert "Flash size:" in info 21 | assert client.reset() == "ok" 22 | assert client.erase() == "ok" 23 | assert client.download_file("/dev/null") == "ok" 24 | assert client.read(32, 0xF000, 4) == [0xDEADBEEF, 0xCAFEBABE, 0xCAFE0000, 0xDEAD0000] 25 | 26 | 27 | def test_drivers_probe_rs_errors(monkeypatch): 28 | instance = ProbeRs() 29 | 30 | monkeypatch.setattr(instance, "_run_cmd", lambda cmd: "") # Simulate error response 31 | 32 | with serve(instance) as client: 33 | assert client.info() == "" # Error case 34 | assert client.reset() == "" # Error case 35 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-http/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-http" 3 | dynamic = ["version", "urls"] 4 | description = "Exporter HTTP service driver" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [{ name = "Benny Zlotnik", email = "bzlotnik@redhat.com" }] 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "anyio>=4.10.0", 11 | "jumpstarter", 12 | "jumpstarter-driver-composite", 13 | "jumpstarter-driver-opendal", 14 | "yarl>=1.18.3", 15 | ] 16 | 17 | [tool.hatch.version] 18 | source = "vcs" 19 | raw-options = { 'root' = '../../' } 20 | 21 | [tool.hatch.metadata.hooks.vcs.urls] 22 | Homepage = "https://jumpstarter.dev" 23 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 24 | 25 | [tool.pytest.ini_options] 26 | asyncio_mode = "strict" 27 | asyncio_default_fixture_loop_scope = "function" 28 | testpaths = ["src"] 29 | 30 | [build-system] 31 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 32 | build-backend = "hatchling.build" 33 | 34 | [dependency-groups] 35 | dev = [ 36 | "pytest-cov>=6.0.0", 37 | "pytest>=8.3.3", 38 | "pytest-asyncio>=0.0.0", 39 | "pytest-asyncio>=0.24.0", 40 | ] 41 | 42 | [tool.hatch.build.hooks.pin_jumpstarter] 43 | name = "pin_jumpstarter" 44 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli-driver/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-cli-driver" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [ 6 | { name = "Nick Cao", email = "ncao@redhat.com" }, 7 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 8 | { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, 9 | ] 10 | readme = "README.md" 11 | license = "Apache-2.0" 12 | requires-python = ">=3.11" 13 | dependencies = ["jumpstarter-cli-common", "click>=8.1.7.2"] 14 | 15 | [dependency-groups] 16 | dev = [ 17 | "pytest>=8.3.2", 18 | "pytest-anyio>=0.0.0", 19 | "pytest-asyncio>=0.0.0", 20 | "pytest-cov>=5.0.0", 21 | ] 22 | 23 | [project.scripts] 24 | jmp-driver = "jumpstarter_cli_driver:driver" 25 | 26 | [tool.hatch.build.targets.wheel] 27 | packages = ["jumpstarter_cli_driver"] 28 | 29 | [tool.hatch.metadata.hooks.vcs.urls] 30 | Homepage = "https://jumpstarter.dev" 31 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 32 | 33 | [tool.hatch.version] 34 | source = "vcs" 35 | raw-options = { 'root' = '../../' } 36 | 37 | [build-system] 38 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 39 | build-backend = "hatchling.build" 40 | 41 | [tool.hatch.build.hooks.pin_jumpstarter] 42 | name = "pin_jumpstarter" 43 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-shell/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-shell" 3 | dynamic = ["version", "urls"] 4 | description = "Jumpstarter shell driver, for running controlled shell commands on the exporter." 5 | readme = "README.md" 6 | authors = [{ name = "Miguel Angel Ajo", email = "miguelangel@ajo.es" }] 7 | requires-python = ">=3.11" 8 | license = "Apache-2.0" 9 | dependencies = ["anyio>=4.10.0", "jumpstarter", "click>=8.1.8"] 10 | 11 | [project.entry-points."jumpstarter.drivers"] 12 | Shell = "jumpstarter_driver_shell.driver:Shell" 13 | [tool.pytest.ini_options] 14 | addopts = "--cov --cov-report=html --cov-report=xml" 15 | log_cli = true 16 | log_cli_level = "INFO" 17 | testpaths = ["jumpstarter_driver_shell"] 18 | 19 | 20 | [dependency-groups] 21 | dev = ["pytest-cov>=6.0.0", "pytest>=8.3.3"] 22 | 23 | 24 | [tool.hatch.metadata.hooks.vcs.urls] 25 | Homepage = "https://jumpstarter.dev" 26 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 27 | 28 | [tool.hatch.version] 29 | source = "vcs" 30 | raw-options = { 'root' = '../../' } 31 | 32 | [build-system] 33 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 34 | build-backend = "hatchling.build" 35 | 36 | [tool.hatch.build.hooks.pin_jumpstarter] 37 | name = "pin_jumpstarter" 38 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/ti_j784s4xevm/manifest.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: jumpstarter.dev/v1alpha1 2 | kind: FlashBundleManifest 3 | metadata: 4 | name: ti-j784s4 5 | spec: 6 | manufacturer: Texas Instruments 7 | link: "https://www.ti.com/tool/PROCESSOR-SDK-J784S4" 8 | bootcmd: "booti 0x82000000 - 0x84000000" 9 | shelltype: "busybox" 10 | login: 11 | login_prompt: "login:" 12 | username: "root" 13 | prompt: "#" 14 | default_target: "usd" 15 | targets: 16 | usd: "/sys/class/block#4fb0000" 17 | emmc: "/sys/class/block#4f80000" 18 | # removed for now, even if it's our documented procedure, if 19 | # the board is configured to boot from sd or emmc (and not SPI), and 20 | # the flashing of the final image fails, it will result in an un-bootable 21 | # system -> lab admin going to the site and re-flashing SD, this can 22 | # only be avoided by using something like sdwire 23 | # 24 | # preflash_commands: 25 | # - "dd if=/dev/zero of=/dev/mmcblk0 bs=512 count=34" 26 | # - "dd if=/dev/zero of=/dev/mmcblk1 bs=512 count=34" 27 | kernel: 28 | file: data/J784S4XEVM.flasher.img 29 | address: "0x82000000" 30 | dtb: 31 | default: k3-j784s4-evm 32 | address: "0x84000000" 33 | variants: 34 | k3-j784s4-evm: 35 | file: data/dtbs/k3-j784s4-evm.dtb 36 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/fabric.py: -------------------------------------------------------------------------------- 1 | from contextlib import asynccontextmanager 2 | from functools import partial 3 | from typing import Any 4 | 5 | from fabric.config import Config 6 | from fabric.connection import Connection 7 | 8 | from .portforward import handler 9 | from jumpstarter.client import DriverClient 10 | from jumpstarter.client.adapters import blocking 11 | from jumpstarter.common import TemporaryTcpListener 12 | 13 | 14 | @blocking 15 | @asynccontextmanager 16 | async def FabricAdapter( 17 | *, 18 | client: DriverClient, 19 | method: str = "connect", 20 | user: str | None = None, 21 | config: Config | None = None, 22 | forward_agent: bool | None = None, 23 | connect_timeout: int | None = None, 24 | connect_kwargs: dict[str, Any] | None = None, 25 | inline_ssh_env: bool | None = None, 26 | ): 27 | async with TemporaryTcpListener(partial(handler, client, method)) as addr: 28 | yield Connection( 29 | addr[0], 30 | user=user, 31 | port=addr[1], 32 | config=config, 33 | forward_agent=forward_agent, 34 | connect_timeout=connect_timeout, 35 | connect_kwargs=connect_kwargs, 36 | inline_ssh_env=inline_ssh_env, 37 | ) 38 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tftp/jumpstarter_driver_tftp/driver_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from jumpstarter_driver_tftp.driver import Tftp 4 | 5 | from jumpstarter.common.utils import serve 6 | 7 | 8 | @pytest.fixture 9 | def anyio_backend(): 10 | return "asyncio" 11 | 12 | 13 | @pytest.fixture 14 | def tftp(tmp_path): 15 | with serve(Tftp(root_dir=str(tmp_path), host="127.0.0.1")) as client: 16 | try: 17 | yield client 18 | finally: 19 | client.close() 20 | 21 | 22 | @pytest.mark.anyio 23 | async def test_tftp_file_operations(tftp, tmp_path): 24 | filename = "test.txt" 25 | test_data = b"Hello" 26 | 27 | tftp.storage.write_bytes(filename, test_data) 28 | 29 | files = list(tftp.storage.list("/")) 30 | assert filename in files 31 | 32 | tftp.storage.delete(filename) 33 | assert filename not in list(tftp.storage.list("/")) 34 | 35 | 36 | def test_tftp_host_config(tmp_path): 37 | custom_host = "192.168.1.1" 38 | server = Tftp(root_dir=str(tmp_path), host=custom_host) 39 | assert server.get_host() == custom_host 40 | 41 | 42 | def test_tftp_root_directory_creation(tmp_path): 43 | new_dir = tmp_path / "new_tftp_root" 44 | server = Tftp(root_dir=str(new_dir)) 45 | assert new_dir.exists() 46 | server.close() 47 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tftp/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-tftp" 3 | dynamic = ["version", "urls"] 4 | description = "Add your description here" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [{ name = "Benny Zlotnik", email = "bzlotnik@redhat.com" }] 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "anyio>=4.10.0", 11 | "jumpstarter", 12 | "jumpstarter-driver-composite", 13 | "jumpstarter-driver-opendal", 14 | ] 15 | 16 | [dependency-groups] 17 | dev = [ 18 | "pytest>=8.3.2", 19 | "pytest-cov>=6.0.0", 20 | "pytest-anyio>=0.0.0", 21 | "pytest-asyncio>=0.0.0", 22 | "jumpstarter-testing", 23 | ] 24 | 25 | 26 | [tool.hatch.version] 27 | source = "vcs" 28 | raw-options = { 'root' = '../../' } 29 | 30 | [tool.hatch.metadata.hooks.vcs.urls] 31 | Homepage = "https://jumpstarter.dev" 32 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 33 | 34 | [tool.pytest.ini_options] 35 | log_cli = true 36 | log_cli_level = "INFO" 37 | testpaths = ["jumpstarter_driver_tftp"] 38 | asyncio_mode = "auto" 39 | 40 | [build-system] 41 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 42 | build-backend = "hatchling.build" 43 | 44 | [tool.hatch.build.hooks.pin_jumpstarter] 45 | name = "pin_jumpstarter" 46 | -------------------------------------------------------------------------------- /assets/bolt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/buildroot_defconfig: -------------------------------------------------------------------------------- 1 | # Initrd config 2 | BR2_aarch64=y 3 | BR2_TOOLCHAIN_EXTERNAL=y 4 | BR2_TARGET_GENERIC_HOSTNAME="flasher" 5 | BR2_TARGET_GENERIC_ISSUE="flasher" 6 | BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_EUDEV=y 7 | BR2_TARGET_GENERIC_ROOT_PASSWD="" 8 | BR2_SYSTEM_DHCP="eth0" 9 | BR2_ROOTFS_OVERLAY="$(CONFIG_DIR)/overlay" 10 | BR2_PACKAGE_CA_CERTIFICATES=y 11 | BR2_PACKAGE_OPENSSL=y 12 | BR2_PACKAGE_LIBCURL=y 13 | BR2_PACKAGE_LIBCURL_CURL=y 14 | BR2_PACKAGE_NTP=y 15 | BR2_PACKAGE_NTP_SNTP=y 16 | BR2_PACKAGE_NTP_NTPDATE=y 17 | BR2_TARGET_ROOTFS_CPIO=y 18 | BR2_TARGET_ROOTFS_CPIO_LZ4=y 19 | BR2_PACKAGE_DROPBEAR=n 20 | # use full-featured dd 21 | BR2_PACKAGE_BUSYBOX_SHOW_OTHERS=y 22 | BR2_PACKAGE_COREUTILS=y 23 | # BR2_TARGET_ROOTFS_TAR is not set 24 | # 25 | # 26 | # Buildroot Kernel config 27 | # include initramfs within the kernel Image 28 | # on J784S4 the size exceeds uboot's CONFIG_SYS_BOOTM_LEN 29 | # BR2_TARGET_ROOTFS_INITRAMFS=y 30 | # 31 | # Not building kernel anymore, keeping for reference in case Fedora kernel is not good enough 32 | BR2_LINUX_KERNEL=n 33 | #BR2_LINUX_KERNEL_USE_ARCH_DEFAULT_CONFIG=y 34 | #BR2_LINUX_KERNEL_LZO=y 35 | #BR2_LINUX_KERNEL_IMAGE=y 36 | #BR2_LINUX_KERNEL_DTS_SUPPORT=y 37 | #BR2_LINUX_KERNEL_INTREE_DTS_NAME="ti/k3-j784s4-evm ti/k3-am69-sk" 38 | 39 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-yepkit/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-yepkit" 3 | dynamic = ["version", "urls"] 4 | description = "Add your description here" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [{ name = "Miguel Angel Ajo", email = "miguelangel@ajo.es" }] 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "anyio>=4.10.0", 11 | "pyusb>=1.2.1", 12 | "jumpstarter_driver_power", 13 | "jumpstarter", 14 | ] 15 | 16 | [project.entry-points."jumpstarter.drivers"] 17 | Ykush = "jumpstarter_driver_yepkit.driver:Ykush" 18 | 19 | 20 | [tool.hatch.version] 21 | source = "vcs" 22 | raw-options = { 'root' = '../../' } 23 | 24 | [tool.hatch.metadata.hooks.vcs.urls] 25 | Homepage = "https://jumpstarter.dev" 26 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 27 | 28 | [tool.pytest.ini_options] 29 | addopts = "--cov --cov-report=html --cov-report=xml" 30 | log_cli = true 31 | log_cli_level = "INFO" 32 | testpaths = ["jumpstarter_driver_yepkit"] 33 | asyncio_mode = "auto" 34 | 35 | [build-system] 36 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 37 | build-backend = "hatchling.build" 38 | 39 | [dependency-groups] 40 | dev = ["pytest-cov>=6.0.0", "pytest>=8.3.3"] 41 | 42 | [tool.hatch.build.hooks.pin_jumpstarter] 43 | name = "pin_jumpstarter" 44 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/common/condition.py: -------------------------------------------------------------------------------- 1 | # Ported from https://github.com/kubernetes/apimachinery/blob/v0.31.1/pkg/api/meta/conditions.go 2 | 3 | from jumpstarter_protocol import kubernetes_pb2 4 | 5 | 6 | def condition_present_and_equal( 7 | conditions: list[kubernetes_pb2.Condition], condition_type: str, status: str, reason: str | None = None 8 | ) -> bool: 9 | for condition in conditions: 10 | if condition.type == condition_type: 11 | if reason is None or condition.reason == reason: 12 | return condition.status == status 13 | return False 14 | 15 | 16 | def condition_message( 17 | conditions: list[kubernetes_pb2.Condition], condition_type: str, reason: str | None = None 18 | ) -> str | None: 19 | for condition in conditions: 20 | if condition.type == condition_type: 21 | if reason is None or condition.reason == reason: 22 | return condition.message 23 | return None 24 | 25 | 26 | def condition_true(conditions: list[kubernetes_pb2.Condition], condition_type: str) -> bool: 27 | return condition_present_and_equal(conditions, condition_type, "True") 28 | 29 | 30 | def condition_false(conditions: list[kubernetes_pb2.Condition], condition_type: str) -> bool: 31 | return condition_present_and_equal(conditions, condition_type, "False") 32 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-uboot/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-uboot" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [ 6 | { name = "Nick Cao", email = "ncao@redhat.com" }, 7 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 8 | { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, 9 | ] 10 | readme = "README.md" 11 | license = "Apache-2.0" 12 | requires-python = ">=3.11" 13 | dependencies = ["jumpstarter", "jumpstarter-driver-composite", "pexpect>=4.9.0"] 14 | 15 | [dependency-groups] 16 | dev = [ 17 | "jumpstarter-driver-qemu", 18 | "pytest>=8.3.2", 19 | "pytest-cov>=5.0.0", 20 | "requests>=2.32.3", 21 | "rpmfile>=2.1.0", 22 | "zstandard>=0.23.0", 23 | ] 24 | 25 | [tool.hatch.metadata.hooks.vcs.urls] 26 | Homepage = "https://jumpstarter.dev" 27 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 28 | 29 | [tool.hatch.version] 30 | source = "vcs" 31 | raw-options = { 'root' = '../../' } 32 | 33 | [tool.uv.sources] 34 | jumpstarter-driver-composite = { workspace = true } 35 | jumpstarter-driver-qemu = { workspace = true } 36 | 37 | [build-system] 38 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 39 | build-backend = "hatchling.build" 40 | 41 | [tool.hatch.build.hooks.pin_jumpstarter] 42 | name = "pin_jumpstarter" 43 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-cli" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [ 6 | { name = "Nick Cao", email = "ncao@redhat.com" }, 7 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 8 | { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, 9 | ] 10 | readme = "README.md" 11 | license = "Apache-2.0" 12 | requires-python = ">=3.11" 13 | dependencies = [ 14 | "jumpstarter-cli-admin", 15 | "jumpstarter-cli-driver", 16 | "pytimeparse2>=1.7.1", 17 | ] 18 | 19 | [dependency-groups] 20 | dev = [ 21 | "pytest>=8.3.2", 22 | "pytest-anyio>=0.0.0", 23 | "pytest-asyncio>=0.0.0", 24 | "pytest-cov>=5.0.0", 25 | ] 26 | 27 | [project.scripts] 28 | jmp = "jumpstarter_cli.jmp:jmp" 29 | j = "jumpstarter_cli.j:j" 30 | 31 | [tool.hatch.build.targets.wheel] 32 | packages = ["jumpstarter_cli"] 33 | 34 | [tool.hatch.metadata.hooks.vcs.urls] 35 | Homepage = "https://jumpstarter.dev" 36 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 37 | 38 | [tool.hatch.version] 39 | source = "vcs" 40 | raw-options = { 'root' = '../../' } 41 | 42 | [build-system] 43 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 44 | build-backend = "hatchling.build" 45 | 46 | [tool.hatch.build.hooks.pin_jumpstarter] 47 | name = "pin_jumpstarter" 48 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/novnc_test.py: -------------------------------------------------------------------------------- 1 | from contextlib import closing 2 | from urllib.parse import parse_qsl, urlparse 3 | 4 | from anyio.from_thread import start_blocking_portal 5 | from websocket import create_connection 6 | 7 | from ..driver import TcpNetwork 8 | from .novnc import NovncAdapter 9 | from jumpstarter.common import TemporaryTcpListener 10 | from jumpstarter.common.utils import serve 11 | 12 | 13 | async def echo_handler(stream): 14 | async with stream: 15 | while True: 16 | try: 17 | await stream.send(await stream.receive()) 18 | except Exception: 19 | pass 20 | 21 | 22 | def test_client_adapter_novnc(): 23 | with start_blocking_portal() as portal: 24 | with portal.wrap_async_context_manager(TemporaryTcpListener(echo_handler, local_host="127.0.0.1")) as addr: 25 | with serve(TcpNetwork(host=addr[0], port=addr[1])) as client: 26 | with NovncAdapter(client=client) as url: 27 | parsed = dict(parse_qsl(urlparse(url).query)) 28 | with closing(create_connection(f"ws://{parsed['host']}:{parsed['port']}")) as ws: 29 | ws.ping() 30 | ws.send_bytes(b"hello") 31 | assert ws.recv() == b"hello" 32 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ssh/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-ssh" 3 | dynamic = ["version", "urls"] 4 | description = "SSH wrapper driver for Jumpstarter that provides SSH CLI functionality" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [ 8 | { name = "Miguel Angel Ajo Pelayo", email = "miguelangel@ajo.es" } 9 | ] 10 | requires-python = ">=3.11" 11 | dependencies = [ 12 | "anyio>=4.10.0", 13 | "click>=8.0.0", 14 | "jumpstarter", 15 | "jumpstarter-driver-composite", 16 | "jumpstarter-driver-network", 17 | ] 18 | 19 | [tool.hatch.version] 20 | source = "vcs" 21 | raw-options = { 'root' = '../../'} 22 | 23 | [tool.hatch.metadata.hooks.vcs.urls] 24 | Homepage = "https://jumpstarter.dev" 25 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 26 | 27 | [tool.pytest.ini_options] 28 | addopts = "--cov --cov-report=html --cov-report=xml" 29 | log_cli = true 30 | log_cli_level = "INFO" 31 | testpaths = ["jumpstarter_driver_ssh"] 32 | asyncio_mode = "auto" 33 | 34 | [build-system] 35 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 36 | build-backend = "hatchling.build" 37 | 38 | [tool.hatch.build.hooks.pin_jumpstarter] 39 | name = "pin_jumpstarter" 40 | 41 | [dependency-groups] 42 | dev = [ 43 | "pytest-cov>=6.0.0", 44 | "pytest>=8.3.3", 45 | ] 46 | -------------------------------------------------------------------------------- /packages/jumpstarter/jumpstarter/streams/metadata.py: -------------------------------------------------------------------------------- 1 | from contextlib import suppress 2 | from dataclasses import dataclass 3 | from typing import Any, Callable, Mapping 4 | 5 | from anyio import TypedAttributeLookupError, TypedAttributeSet, typed_attribute 6 | from anyio.abc import AnyByteStream, ObjectStream 7 | 8 | 9 | class MetadataStreamAttributes(TypedAttributeSet): 10 | # https://grpc.io/docs/guides/metadata/ 11 | metadata: dict[str, str] = typed_attribute() 12 | 13 | 14 | @dataclass(frozen=True, kw_only=True, slots=True) 15 | class MetadataStream(ObjectStream[bytes]): 16 | stream: AnyByteStream 17 | metadata: dict[str, str] 18 | 19 | async def send(self, item: bytes): 20 | await self.stream.send(item) 21 | 22 | async def receive(self) -> bytes: 23 | return await self.stream.receive() 24 | 25 | async def send_eof(self): 26 | await self.stream.send_eof() 27 | 28 | async def aclose(self): 29 | await self.stream.aclose() 30 | 31 | @property 32 | def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: 33 | metadata = {} 34 | with suppress(TypedAttributeLookupError): 35 | metadata = self.stream.extra(MetadataStreamAttributes.metadata) 36 | return self.stream.extra_attributes | {MetadataStreamAttributes.metadata: lambda: metadata | self.metadata} 37 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-gpiod/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-gpiod" 3 | dynamic = ["version", "urls"] 4 | description = "" 5 | authors = [ 6 | { name = "Miguel Angel Ajo Pelayo", email = "majopela@redhat.com" }, 7 | { name = "Nick Cao", email = "ncao@redhat.com" }, 8 | { name = "Kirk Brauer", email = "kbrauer@hatci.com" }, 9 | ] 10 | readme = "README.md" 11 | license = "Apache-2.0" 12 | requires-python = ">=3.11" 13 | dependencies = ["jumpstarter", "jumpstarter-driver-power", "click>=8.1.7.2", "gpiod; platform_system == 'Linux'"] 14 | 15 | [project.entry-points."jumpstarter.drivers"] 16 | DigitalInput = "jumpstarter_driver_gpiod.driver:DigitalInput" 17 | DigitalOutput = "jumpstarter_driver_gpiod.driver:DigitalOutput" 18 | PowerSwitch = "jumpstarter_driver_gpiod.driver:PowerSwitch" 19 | 20 | [dependency-groups] 21 | dev = ["pytest>=8.3.2", "pytest-cov>=5.0.0"] 22 | 23 | [tool.hatch.metadata.hooks.vcs.urls] 24 | Homepage = "https://jumpstarter.dev" 25 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 26 | 27 | [tool.hatch.version] 28 | source = "vcs" 29 | raw-options = { 'root' = '../../' } 30 | 31 | [build-system] 32 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 33 | build-backend = "hatchling.build" 34 | 35 | [tool.hatch.build.hooks.pin_jumpstarter] 36 | name = "pin_jumpstarter" 37 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-ridesx/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-ridesx" 3 | dynamic = ["version", "urls"] 4 | description = "Jumpstarter driver for Qualcomm RideSX" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [{ name = "Benny Zlotnik", email = "bzlotnik@redhat.com" }] 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "jumpstarter", 11 | "jumpstarter-driver-composite", 12 | "jumpstarter-driver-opendal", 13 | "jumpstarter-driver-power", 14 | "jumpstarter-driver-pyserial", 15 | ] 16 | 17 | [tool.hatch.version] 18 | source = "vcs" 19 | raw-options = { 'root' = '../../' } 20 | 21 | [tool.hatch.metadata.hooks.vcs.urls] 22 | Homepage = "https://jumpstarter.dev" 23 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 24 | 25 | [tool.pytest.ini_options] 26 | addopts = "--cov --cov-report=html --cov-report=xml" 27 | log_cli = true 28 | log_cli_level = "INFO" 29 | testpaths = ["jumpstarter_driver_ridesx"] 30 | asyncio_mode = "auto" 31 | 32 | 33 | [build-system] 34 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 35 | build-backend = "hatchling.build" 36 | 37 | [dependency-groups] 38 | dev = [ 39 | "pytest-cov>=6.0.0", 40 | "pytest>=8.3.3", 41 | "pytest-asyncio>=0.0.0", 42 | ] 43 | 44 | [tool.hatch.build.hooks.pin_jumpstarter] 45 | name = "pin_jumpstarter" 46 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-snmp/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-snmp" 3 | dynamic = ["version", "urls"] 4 | description = "SNMP driver" 5 | readme = "README.md" 6 | requires-python = ">=3.11" 7 | license = "Apache-2.0" 8 | authors = [{ name = "Benny Zlotnik", email = "bzlotnik@redhat.com" }] 9 | 10 | dependencies = [ 11 | "click>=8.1.8", 12 | "jumpstarter", 13 | "jumpstarter-driver-power", 14 | "pysnmp==7.1.16", 15 | ] 16 | 17 | 18 | [dependency-groups] 19 | dev = [ 20 | "pytest>=8.3.2", 21 | "pytest-cov>=6.0.0", 22 | "pytest-anyio>=0.0.0", 23 | "pytest-asyncio>=0.0.0", 24 | "jumpstarter-testing", 25 | ] 26 | 27 | 28 | [tool.pytest.ini_options] 29 | log_cli = true 30 | log_cli_level = "INFO" 31 | testpaths = ["jumpstarter_driver_snmp"] 32 | asyncio_mode = "auto" 33 | 34 | [tool.hatch.metadata.hooks.vcs.urls] 35 | Homepage = "https://jumpstarter.dev" 36 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 37 | 38 | [tool.hatch.version] 39 | source = "vcs" 40 | raw-options = { 'root' = '../../' } 41 | 42 | [build-system] 43 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 44 | build-backend = "hatchling.build" 45 | 46 | [tool.hatch.build.hooks.pin_jumpstarter] 47 | name = "pin_jumpstarter" 48 | 49 | [tool.uv.sources] 50 | jumpstarter-driver-power = { workspace = true } 51 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-vnc/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-vnc" 3 | dynamic = ["version", "urls"] 4 | description = "Jumpstarter driver for VNC" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [ 8 | { name = "Albert Esteve", email = "aesteve@redhat.com" } 9 | ] 10 | requires-python = ">=3.11" 11 | dependencies = [ 12 | "anyio>=4.10.0", 13 | "jumpstarter", 14 | "jumpstarter-driver-composite", 15 | "jumpstarter-driver-network", 16 | "click", 17 | ] 18 | 19 | [project.entry-points."jumpstarter.drivers"] 20 | vnc = "jumpstarter_driver_vnc.driver:Vnc" 21 | 22 | [tool.hatch.version] 23 | source = "vcs" 24 | raw-options = { 'root' = '../../'} 25 | 26 | [tool.hatch.metadata.hooks.vcs.urls] 27 | Homepage = "https://jumpstarter.dev" 28 | source_archive = "https://github.com/jumpstarter-dev/jumpstarter/archive/{commit_hash}.zip" 29 | 30 | [tool.pytest.ini_options] 31 | addopts = "--cov --cov-report=html --cov-report=xml" 32 | log_cli = true 33 | log_cli_level = "INFO" 34 | testpaths = ["jumpstarter_driver_vnc"] 35 | asyncio_mode = "auto" 36 | 37 | [build-system] 38 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 39 | build-backend = "hatchling.build" 40 | 41 | [tool.hatch.build.hooks.pin_jumpstarter] 42 | name = "pin_jumpstarter" 43 | 44 | [dependency-groups] 45 | dev = [ 46 | "pytest-cov>=6.0.0", 47 | "pytest>=8.3.3", 48 | ] 49 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-network/jumpstarter_driver_network/adapters/portforward.py: -------------------------------------------------------------------------------- 1 | from contextlib import asynccontextmanager 2 | from functools import partial 3 | from os import PathLike 4 | 5 | from jumpstarter.client import DriverClient 6 | from jumpstarter.client.adapters import blocking 7 | from jumpstarter.common import TemporaryTcpListener, TemporaryUnixListener 8 | from jumpstarter.streams.common import forward_stream 9 | 10 | 11 | async def handler(client, method, conn): 12 | async with conn: 13 | async with client.stream_async(method) as stream: 14 | async with forward_stream(conn, stream): 15 | pass 16 | 17 | 18 | @blocking 19 | @asynccontextmanager 20 | async def TcpPortforwardAdapter( 21 | *, 22 | client: DriverClient, 23 | method: str = "connect", 24 | local_host: str = "127.0.0.1", 25 | local_port: int = 0, 26 | ): 27 | async with TemporaryTcpListener( 28 | partial(handler, client, method), 29 | local_host=local_host, 30 | local_port=local_port, 31 | ) as addr: 32 | yield addr 33 | 34 | 35 | @blocking 36 | @asynccontextmanager 37 | async def UnixPortforwardAdapter( 38 | *, 39 | client: DriverClient, 40 | method: str = "connect", 41 | path: PathLike | None = None, 42 | ): 43 | async with TemporaryUnixListener(partial(handler, client, method), path=path) as addr: 44 | yield addr 45 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-flashers/oci_bundles/aarch64-itb/build_fits.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd "$(dirname "$0")" 4 | 5 | # run only in a container 6 | if [[ -z "$container" && ! -f /.dockerenv ]]; then 7 | exec podman run --rm -it -v $(pwd):/host:Z -w /host fedora:42 "$0" "$@" 8 | else 9 | set -euo pipefail 10 | BUILDROOT_DIR="/var/tmp/buildroot" 11 | 12 | dnf install --setopt=install_weak_deps=false -y git make gcc gcc-c++ which file diffutils \ 13 | wget cpio rsync bc lzop zip patch perl tar qemu-system-aarch64 qemu-img unzboot \ 14 | uboot-tools kmod awk zstd lz4 kernel dtc rpm-build 15 | 16 | git clone --depth 1 --branch 2025.08 https://github.com/buildroot/buildroot "${BUILDROOT_DIR}" 17 | 18 | # build buildroot (initramfs) 19 | cp buildroot_defconfig "${BUILDROOT_DIR}/configs/" 20 | cp -R overlay "${BUILDROOT_DIR}" 21 | ./kernel_fedora.sh "${BUILDROOT_DIR}/overlay" 22 | ( cd "${BUILDROOT_DIR}"; make buildroot_defconfig && make ) 23 | dtc s32g3.dts -o s32g3.dtb 24 | mkimage -f fedora.its data/flasher-fedora.itb 25 | rm -rf "${BUILDROOT_DIR}/overlay" 26 | 27 | # replace kernel with kernel-automotive and rebuild. Beware the $BUILDROOT_DIR/output/target is reused! 28 | cp -R overlay "${BUILDROOT_DIR}" 29 | ./kernel_automotive.sh "${BUILDROOT_DIR}/overlay" 30 | ( cd "${BUILDROOT_DIR}" && make ) 31 | mkimage -f automotive.its data/flasher-automotive.itb 32 | rm -rf "${BUILDROOT_DIR}/overlay" 33 | fi 34 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-tasmota/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "jumpstarter-driver-tasmota" 3 | dynamic = ["version", "urls"] 4 | description = "Jumpstarter driver for controlling Tasmota-compatible devices via MQTT" 5 | readme = "README.md" 6 | license = "Apache-2.0" 7 | authors = [{ name = "Nick Cao", email = "nickcao@nichi.co" }] 8 | requires-python = ">=3.11" 9 | dependencies = [ 10 | "anyio>=4.10.0", 11 | "jumpstarter_driver_power", 12 | "jumpstarter", 13 | "paho-mqtt>=2.1.0", 14 | ] 15 | 16 | [project.entry-points."jumpstarter.drivers"] 17 | TasmotaPower = "jumpstarter_driver_tasmota.driver:TasmotaPower" 18 | 19 | 20 | [tool.hatch.version] 21 | source = "vcs" 22 | raw-options = { 'root' = '../../' } 23 | 24 | [tool.hatch.metadata.hooks.vcs.urls] 25 | Homepage = "https://jumpstarter.dev" 26 | source_archive = "https://github.com/jumpstarter-dev/repo/archive/{commit_hash}.zip" 27 | 28 | [tool.pytest.ini_options] 29 | addopts = "--cov --cov-report=html --cov-report=xml" 30 | log_cli = true 31 | log_cli_level = "INFO" 32 | testpaths = ["jumpstarter_driver_tasmota"] 33 | 34 | [build-system] 35 | requires = ["hatchling", "hatch-vcs", "hatch-pin-jumpstarter"] 36 | build-backend = "hatchling.build" 37 | 38 | [tool.hatch.build.hooks.pin_jumpstarter] 39 | name = "pin_jumpstarter" 40 | 41 | [dependency-groups] 42 | dev = [ 43 | "pytest-cov>=6.0.0", 44 | "pytest>=8.3.3", 45 | "pytest-mqtt>=0.5.0", 46 | ] 47 | -------------------------------------------------------------------------------- /packages/jumpstarter-driver-vnc/jumpstarter_driver_vnc/driver.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from dataclasses import dataclass 4 | 5 | from jumpstarter_driver_composite.driver import Composite 6 | 7 | from jumpstarter.common.exceptions import ConfigurationError 8 | from jumpstarter.driver import export 9 | 10 | 11 | @dataclass 12 | class Vnc(Composite): 13 | """A VNC driver. 14 | 15 | Members: 16 | default_encrypt: Whether to default to an encrypted client connection. 17 | """ 18 | 19 | default_encrypt: bool = False 20 | 21 | def __post_init__(self): 22 | """ 23 | Validate the VNC driver's post-initialization configuration. 24 | Ensures the driver has a "tcp" child configured. 25 | 26 | Raises: 27 | ConfigurationError: If a "tcp" child is not present. 28 | """ 29 | super().__post_init__() 30 | if "tcp" not in self.children: 31 | raise ConfigurationError("A tcp child is required for Vnc") 32 | 33 | @export 34 | async def get_default_encrypt(self) -> bool: 35 | """Return the default encryption setting.""" 36 | return self.default_encrypt 37 | 38 | @classmethod 39 | def client(cls) -> str: 40 | """ 41 | Client class path for this driver. 42 | 43 | Returns: 44 | str: Dotted import path of the client class. 45 | """ 46 | return "jumpstarter_driver_vnc.client.VNClient" 47 | -------------------------------------------------------------------------------- /packages/jumpstarter-cli/jumpstarter_cli/update.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta 2 | 3 | import click 4 | from jumpstarter_cli_common.config import opt_config 5 | from jumpstarter_cli_common.exceptions import handle_exceptions_with_reauthentication 6 | from jumpstarter_cli_common.opt import OutputType, opt_output_all 7 | from jumpstarter_cli_common.print import model_print 8 | 9 | from .common import opt_begin_time, opt_duration_partial 10 | from .login import relogin_client 11 | 12 | 13 | @click.group() 14 | def update(): 15 | """ 16 | Update a resource 17 | """ 18 | 19 | 20 | @update.command(name="lease") 21 | @opt_config(exporter=False) 22 | @click.argument("name") 23 | @opt_duration_partial(required=False) 24 | @opt_begin_time 25 | @opt_output_all 26 | @handle_exceptions_with_reauthentication(relogin_client) 27 | def update_lease(config, name: str, duration: timedelta | None, begin_time: datetime | None, output: OutputType): 28 | """ 29 | Update a lease 30 | 31 | Update the duration and/or begin time of an existing lease. 32 | At least one of --duration or --begin-time must be specified. 33 | Updating the begin time of an already active lease is not allowed. 34 | """ 35 | 36 | if duration is None and begin_time is None: 37 | raise click.UsageError("At least one of --duration or --begin-time must be specified") 38 | 39 | lease = config.update_lease(name, duration=duration, begin_time=begin_time) 40 | 41 | model_print(lease, output) 42 | --------------------------------------------------------------------------------