Engineering case
A fleet of disposable virtual environments
A panel that raises a dozen independent environments from one image: each with its own disk, its own network credentials and settings delivered into the guest. Two interfaces over one core.
- methods in the backend contract
- 9
- environments in one click
- 10
- config delivery deadline
- 180 s
An orchestrator for isolated virtual machines on Windows: a dozen independent environments are raised from a single golden image, each with its own disk, its own network credentials and automatic delivery of settings into the guest. Two interfaces run over one core — a desktop window and a web panel — and both see the same environments.
Every environment is a differencing disk from an untouchable parent
Creating a machine starts not with a copy of the image but with a disk that stores only the differences from the parent. After it is built, the parent becomes read-only — permanently.
Copying the image per machine is obvious and unaffordable: a full copy of the system is tens of gigabytes, so ten environments turn into half a terabyte and a night of waiting instead of seconds. A differencing disk is created instantly and grows only by what changes. The price is accepted and written down: the parent becomes a single point of failure, and updating the image means working on a copy and recreating the children.
Disposable and persistent differ by disk model, not by a checkbox
Automatic state snapshots are disabled for every machine at creation. A disposable environment additionally gets one clean snapshot, and its “reset” is a rollback to it. A persistent one gets no snapshot at all, and its reset button is not merely hidden — the request is refused in the core.
The hypervisor’s automatic snapshots are a trap precisely for long-lived environments: the system takes them on its own, and state can roll back unexpectedly, taking days of work with it. The refusal lives in the core rather than the interface because there is more than one interface: the web panel is open, and a single request past the button would wipe accumulated state irrecoverably.
The mock backend is not a stub but the default mode
Under the panel sits a contract of nine methods, and the implementation is chosen by one settings field. The mock keeps state in memory and — crucially — reproduces the real one’s refusals: it declines to deliver a config into a stopped machine with the very same message.
Developing straight on the hypervisor means a cycle of “edit → launch as administrator → create a machine over minutes → check”, that is minutes instead of seconds for every interface detail, and no way to work at all on a machine without a hypervisor. And reproducing the refusals matters more than reproducing success: otherwise the mock only exercises the happy path, and every error message is first seen in production.
Credentials are handed out by the orchestrator, not the backend
Generating network credentials, choosing an address and handing out from a pool live in a layer above the backend. The backend receives a finished description of the environment and only applies it.
Put the generation inside and the two backends start producing different environments: simplified ones from the mock, real ones from the live backend. Everything debugged on the mock is then verified against the wrong data, and the whole point of the mode is gone.
Addresses are handed out as “first free”, not by a counter
Taken numbers are collected from existing environments, and the first unused one is chosen. Pool addresses are handed out the same way.
A counter, or “count plus one”, breaks on the first deletion: remove the third of ten environments and its address is free, but the counter does not know. Worse, a counter restored from the number of records will, after a deletion, hand out an address already in use — two environments on one address, and both stop working.
Delivering settings into the guest is a loop with a deadline, not one command
The file is placed inside the machine over the hypervisor channel: attempt, a few seconds’ pause, next attempt — up to three minutes, after which an honest error carrying the last failure’s text.
The service inside the guest comes up after the hypervisor has reported “machine running”, and the spread is wide: it depends on the clone’s first-run setup, host load, how many windows start at once. A single attempt right after start would fail almost always, while a fixed pause would either fall short on a loaded host or waste time on a fast one.
The main activation path needs no guest password
A task is placed into the image once, and it picks the file up from a known path by itself. The panel merely drops the file. The second path — running a command inside the guest — switches on only if a password is set in the settings.
The obvious option, “just run a command inside”, requires keeping the image’s administrator password in plain text — and for a dozen clones that is one password to all of them at once. The in-image task needs no credentials at all: delivery becomes one-way and the guest decides when to apply it. Separately valuable: the channel does not run over the network, so the panel can drive the guest exactly while its networking is being reconfigured and may be unreachable.
Two interfaces are two projections of one object, not two processes
The “Web” button in the desktop panel starts a web server in a background thread and hands it the same instance of the orchestrator. Both interfaces poll it every three seconds.
The obvious way to reconcile them is a separate process and a shared database. That creates two independent states over one file, and a race becomes a matter of time; in the mock mode, where state lives in memory, the processes diverge completely: running in one, never created in the other. Passing one object removes the problem entirely.
Everything going to the shell passes through one escaping function
Names and paths come from the interface and settings — that is, from outside the code — and go through escaping. Commands are invoked with no user profile and no interactive prompts.
The hypervisor’s interface is only available through a shell, so commands are assembled as text. A single quote in a name terminates the literal and turns the rest into executable code — that is command execution on a machine with administrator rights. Disabling the profile removes any dependence on what the user has added to their shell settings, and disabling interactivity keeps a command from hanging on a confirmation nobody will ever see.
The pre-flight check is one call, not seven
A separate screen shows the state of the environment: hypervisor, rights, virtual switch, image, disk directory. All checks are collected in a single request, and the list itself is supplied by the backend.
Without such a check the conditions are discovered one at a time, as an opaque error in the middle of creating a machine — and the most common cause, running without administrator rights, reads as a denial of access to something unrelated. One call instead of seven was chosen because starting a shell costs hundreds of milliseconds: seven launches would turn opening the window into a visible pause.
Publishing the sources is guarded by deny-by-default
The ignore rules start with the usual exclusions and end with a ban on everything in the root, with point permissions. Disk images, the local database, real settings and keys are excluded separately.
Ordinary rules work on the principle of “ban what we remembered”. The working directory held images of tens of gigabytes, real settings with credentials and private keys — one careless “add everything” is enough to put all of it into history for good, from where it does not simply come out. Inverting the rule changes the cost of a mistake: a forgotten file is not published by default.
Python · FastAPI · Tkinter · Hyper-V · PowerShell · SQLite