Helper scripts for testing, debugging, and development workflows on range42 cyber ranges. Interacts with Proxmox API, Ansible vault, and VM management from the command line.
Before using devkit scripts, the infrastructure must be initialized once
(SSH keys, passwords, vault, Proxmox access, deployer-cli workspace).
Run python3 range42-init.py or see the range42
README for full setup instructions.
Activate your workspace, then use tab completion to discover and run scripts:
range42-context use <codename> <scenario>
proxmox_vm.<Tab><Tab> # list all VM commands
proxmox_firewall.<Tab><Tab> # list all firewall commands
devkit_ansible.<Tab><Tab> # list all ansible helpers
devkit_transform.<Tab><Tab> # list all JSON transformersAll environment variables (RANGE42_VAULT_PASSWORD_FILE, inventory paths, etc.)
are set automatically — scripts just work.
These are already installed on the deployer-cli by the range42 bootstrap:
- Ansible
jq,curl- Proxmox API access (configured via
range42-context use)
Scripts output JSON lines (jsons) by default — one JSON object per line,
pipeable to jq or other scripts.
Add --text to see raw Ansible output instead:
# JSON output (default) — one JSON object per line
proxmox_vm.list.to.jsons.sh
{"vmid": 100, "name": "r42.mon-wazuh-01", "status": "running", ...}
{"vmid": 101, "name": "r42.builder-api-01", "status": "stopped", ...}
# Raw Ansible output
proxmox_vm.list.to.jsons.sh --text# List all VMs, show names only
proxmox_vm.list.to.jsons.sh | jq '.name'
# Get CPU config for VM 100
proxmox_vm.vm_id.get_config_cpu.to.jsons.sh 100
# Stop a specific VM
proxmox_vm.vm_id.stop.to.jsons.sh 100
# Delete a specific VM
proxmox_vm.vm_id.delete.to.jsons.sh 100
# Chain: list all VMs → force stop → delete (full cleanup)
proxmox_vm.list.to.jsons.sh | jq -c | proxmox_vm.vm_id.stop_force.to.jsons.sh
proxmox_vm.list.to.jsons.sh | jq -c | proxmox_vm.vm_id.delete.to.jsons.sh
# Filter: stop only admin VMs (skip templates and groups)
proxmox_vm.list.to.jsons.sh \
| grep -vi template | grep -vi group \
| grep -iE "(admin-)|(testing-)" \
| jq -c | proxmox_vm.vm_id.stop_force.to.jsons.shScripts accept JSON lines on STDIN via | jq -c |. The JSON must contain
a vmid field — each line triggers the action on that VM.
This is what makes chaining possible: list → filter → act.
Use jq -c to ensure one compact JSON object per line before piping.
Use grep between pipes to filter by VM name, type, or status.
Each filename follows the structure:
<CONNECTOR>.<DATA_INPUT>.<VERB>.to.<DATA_OUTPUT>.sh
| Segment | Description | Example |
|---|---|---|
| CONNECTOR | Top-level namespace | proxmox_vm, devkit_ansible |
| DATA_INPUT | Required parameter (optional) | vm_id, node_name, storage_name |
| VERB | Operation to perform | get_config, list_interfaces |
| DATA_OUTPUT | Output format | to.jsons, to.text, to.stderr |
- Use dots to separate segments
- Use snake_case within segments
- Chain multiple
.to.<format>segments when needed (e.g..to.text.to.stderr) jsons= JSON lines (one JSON object per line, not a JSON array)
| Script | What it does |
|---|---|
proxmox_vm.vm_id.get_config.to.jsons.sh |
Get VM config as JSON |
proxmox_vm.list.to.jsons.sh |
List all VMs |
proxmox_vm.vm_id.start.to.jsons.sh |
Start a VM |
proxmox_network.node_name.list_interfaces_node.to.jsons.sh |
List node network interfaces |
proxmox_firewall.vm_id.enable_firewall.to.jsons.sh |
Enable firewall on a VM |
devkit_ansible.get_proxmox_node.to.jsons.sh |
Get Proxmox node info via Ansible |
devkit_utils.text.echo_error.to.text.to.stderr.sh |
Print error message to stderr |
├── proxmox_vm.* # VM lifecycle (create, clone, start, stop, delete, pause, resume)
├── proxmox_lxc.* # LXC container lifecycle
├── proxmox_network.* # Network interfaces and SDN
├── proxmox_firewall.* # Firewall rules, aliases, enable/disable
├── proxmox_storage.* # Storage, ISOs, cloud-init images
├── proxmox_template.* # Template conversion, cloud-init variables
├── proxmox_snapshot_vm.* # VM snapshots (create, delete, list, revert)
├── proxmox_snapshot_lxc.* # LXC snapshots
├── proxmox_cluster.* # Cluster-level operations (tags)
├── devkit_ansible.* # Ansible helpers (inventory, proxmox node)
├── devkit_transform.* # JSON transformers (filter, append, remove keys)
├── devkit_utils.* # Text utilities (echo_error, echo_warning, etc.) and the json-lines table renderer
├── devkit_manifest.* # Scenario manifest readers : vm id or ip by name, vms and ips by network or by role
├── devkit_proxmox.* # STDIN normalizers for json-lines pipelines
├── proxmox__inc.* # Internal shared includes (sourced by other scripts, not called directly)
├── _activate.sh # Sourced to activate the devkits : a venv with ansible, paramiko and cryptography (Ubuntu 24.04 paramiko issue)
│
├── examples/ # JSON examples for VM/LXC creation and firewall rules
├── callback_plugins/ # Ansible callback plugins (no_skipped output)
├── _tests/ # Test scripts
├── ansible.cfg # Devkit-specific ansible config
└── secrets/ # Symlink → workspace secrets (gitignored)
Full lifecycle: list, create, clone, start, stop, pause, resume, delete. Plus: get config (CPU, RAM, CDROM), usage stats, bulk operations (start/stop/pause all).
Per-VM, per-node, and datacenter-level firewall management. Rules, aliases, enable/disable at each level.
The views and the gestures range42-context uses are composites of this family, API-first :
proxmox_firewall.{scenario,datacenter,proxmox_node,vm_ids}.show_firewall.to.jsons.sh: the switches (datacenter, node, guest, card flag) and the effective filtering state per guest ;show_firewall_rules: the rules of the three chains with what is in force. The enginesproxmox_firewall.show_firewall[_rules].to.jsons.shread the ids on stdin ; their_with_apitwins answer from the Proxmox API, the ansible path stays the fallback.proxmox_firewall.vm_ids.{arm,disarm}.to.jsons.shandproxmox_firewall.proxmox_node.{arm,disarm}.to.jsons.sh: the arming sequences (anti-lockout accepts first, then the switches and the card flags), each unit action having a_with_apitwin that waits for the Proxmox config task before reading a card back.devkit_utils.jsons.render.to.table.shrenders any json-lines stream as the tablerange42-contextprints ;proxmox__inc.firewall_chain.shholds the chain predicate the role shares (fw_chain_verdict).
Interfaces of a VM or a node (vm_id.*_interfaces_vm, node_name.*_interfaces_node) and the SDN objects at the datacenter level : add_sdn_zone, add_sdn_vnet, sdn_vnet.add_sdn_subnet, list_sdn_{zones,vnets,subnets}, sdn_vnet.update_sdn_subnet, delete_sdn_*, apply_sdn (waits for the task), plus the live SNAT rules of the node read over ssh (datacenter.list_snat_rules, sdn_subnet_cidr.delete_extra_snat_rules, mirrored on the role's shell blocks through proxmox__inc.snat_rules.node.sh).
Composites, API-first, behind the range42-context networks-* commands :
proxmox_network.{scenario,datacenter,sdn_vnet,sdn_vnets}.show_sdn.to.jsons.sh: zone, vnet, subnet, SNAT count, isolation, per network (proxmox__inc.sdn_network.to.jsons.sh).proxmox_network.sdn_subnet_id.{enable,disable,toggle}_outgoing_nat.to.jsons.sh: update the subnet, apply once, reconcile the live SNAT rules of every declared subnet (proxmox__inc.sdn_outgoing_nat.to.jsons.sh) - an apply replays thepost-upof every active subnet, so the reconciliation is not optional.proxmox_network.datacenter.{create,delete}_sdn_network.to.jsons.sh: a whole zone up or down, in the only order Proxmox accepts (subnet, vnet, zone, apply).
List storage, ISOs, templates. Download ISOs, import cloud-init images, convert to template.
get_proxmox_node.to.jsons.sh— Query Proxmox node info via Ansibleshow_ansible_inventory.to.text.sh— Display current inventoryopen_vault.to.file.sh— Decrypt the vault of the active workspace to a file
Create, delete, list, and revert snapshots for both VMs and LXC containers. Useful for lab reset workflows (snapshot before exercise, revert after).
Pipeline-friendly tools to filter, append, remove, or select fields in JSON streams.
Designed to chain with | between devkit commands.
GPL-3.0 license