Skip to content

setup: migrate Azure VMSS bootstrap scripts to Python #612

Description

Goal

Follow-up to #522 and Pedro's controller-language comment.

Make the Azure VMSS bootstrap added by that PR Python-first on Linux and Windows, minimizing newly introduced Bash and PowerShell. Move configuration, validation, orchestration, HTTP/identity/token handling, recovery decisions, and status reporting into directly testable Python. Do not replace large shell programs with wrappers containing embedded Python programs.

Files to migrate

All paths below are under scripts/setup/azure/. Consolidating related responsibilities into a smaller number of Python modules is fine; these are migration boundaries, not a requirement for nine separate Python programs.

Current file Python-first replacement / boundary
linux/bootstrap-runner.sh Direct Python controller for configuration, VMSS identity/name, credential acquisition, prerequisite invocation, reboot coordination, runner registration, and service finalization. Remove all three embedded Python blocks and shell-to-Python text marshalling.
linux/block-runner-metadata.sh Python locking, rule inspection/replacement decisions, and error handling; invoke iptables directly with explicit argument arrays. Preserve make-before-break protection and fail-closed behavior.
linux/setup-data-disk.sh Python disk/LUN discovery, blankness/ownership decisions, recovery, mount identity, fstab management, and validation. External storage utilities remain checked subprocesses, not another Bash controller.
linux/setup-mshv.sh Python preflight, package/retry orchestration, active GRUB Dom0 selection, state markers, and reboot decisions. Keep only the required boot-component requests.
linux/verify-mshv.sh Python kernel, device, root-partition, and package diagnostics with explicit exit status. Do not restore cloud-hypervisor/Kata dependencies.
windows/bootstrap-runner.ps1 Python VMSS identity, token requests, runner orchestration, reboot state, and logging/status. Isolate firewall/profile, feature, and other Windows cmdlet calls behind small PowerShell adapters.
windows/install-package.ps1 Python package/hash verification, archive validation/extraction, and staging policy once Python is available. Retain only the minimal trusted interpreter bootstrap and Windows ACL/scheduled-task operations that genuinely require PowerShell.
windows/setup-data-disk.ps1 Python discovery interpretation, safety checks, bounded-memory blankness scanning, ownership/recovery/pagefile decisions, and continuation state. Keep thin CIM/Storage/registry/task adapters where necessary. No per-byte interpreted scan.
windows/vmss-bootstrap.ps1 Python configuration/key decoding, idempotent bootstrap flow, and logging. Keep a minimal entry shim plus Windows-specific OpenSSH/capability, shell registry, ACL, firewall, and service operations.

Aim to remove Linux shell application logic entirely. Any remaining PowerShell should be a small, checked OS-operation adapter or unavoidable pre-Python entry point, not a second orchestration layer. Give each retained shell responsibility a concrete reason to exist; use structured input/output rather than embedded scripts and fragile text parsing.

Interpreter availability must be explicit

  • Linux already installs python3 through cloud-init and starts the controller after cloud-final.service. All guest files are embedded in the same payload, so splitting Python modules does not require separate downloads.
  • Windows currently reaches package staging and disk preparation before the shared runner toolchain installs Python. Do not assume that later installation makes Python available to the initial entry point. Define and document an early, verified interpreter path: an explicit image prerequisite or a minimal trusted PowerShell installer/launcher. Specify the supported Python version, installation/provenance checks, and the executable available to SYSTEM.
  • Prefer standard-library guest code. The workstation packager's PyYAML dependency must not accidentally become an undeclared guest bootstrap dependency.

Dependent files and scope boundary

Update scripts/setup/azure/build_package.py, scripts/test_setup_azure.py, scripts/setup/azure/README.md, and any affected example configuration/service/task payloads. Replace packaged entry points, hashes, service commands, scheduled-task actions, and installer references consistently; preserve Azure's decoded custom-data size limit and deterministic outputs.

The pre-existing scripts/setup/setup-linux-runner.sh and scripts/setup/setup-windows-whp.ps1 remain shared installer interfaces. Adapt their call sites or small PR-introduced glue if needed, but do not expand this follow-up into a wholesale rewrite of those shared installers or of the Rust runtime/CLI.

Contracts to preserve

  • Fail-closed disk selection and full-device blankness checks, owned interrupted-initialization recovery, preservation of unowned data, bounded memory, and pre/post-mount identity checks.
  • Trusted source ownership, package verification, validated paths, reserved administrator rejection, required/extra runner labels, scratch overlap rules, and service-account isolation.
  • Effective metadata protection before credential acquisition/registration; serialized Linux make-before-break updates and Windows effective service/profile/ActiveStore enforcement checks.
  • Tokens passed over stdin, never command arguments or logs, and explicit subprocess/error handling without silent success fallbacks.
  • Windows staging returns after an independent SYSTEM-task handoff, outside the Custom Script Extension's 90-minute limit. Preserve the four-hour task budget, startup/retry/reboot behavior, stale completion-marker invalidation, and distinct STAGED/FAILED/REBOOT/COMPLETE reporting.
  • Idempotence across retries/reboots, Linux successful-provisioning shutdown without restarting an already registered runner, and minimal MSHV boot requirements.

Acceptance criteria

  • Migrate the controllers and the listed helper decision logic to Python; remove obsolete shell files/embedded Python blocks where replaced.
  • Document the small residual PowerShell boundary and prove interpreter availability before every Python entry point, including the initial Windows staging path.
  • Update all packaging/service/task references and cross-host reproducibility/line-ending/hash/size coverage.
  • Port the existing inline-Python/PowerShell-AST fixture coverage to direct Python function/subprocess tests while retaining every existing safety regression and platform-specific adapter test.
  • Pass existing Linux/native Windows unit, lint, format, and type checks. Privileged local operations must remain mocked; require separately approved isolated-instance validation for actual fresh provisioning and reboot/registration behavior before rollout.
  • Request a fresh Copilot review after implementation and link its submitted result; do not equate green CI or resolved conversations with a clean review.

Metadata

Metadata

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions