On this page

Cloud hosts

Providers

A cloud host is a fleet host Stado rents from a cloud to build on. It is an ordinary registry target, reached over SSH with its own fleet key, so stado host kompilator <host> … builds there like on any other host. It carries one more declaration, targets[].cloud, and it is returned once it stands idle. Azure is the provider this release implements.

stado cloud host create NAME --provider azure --location LOCATION --size SIZE --disk-gb GIB --idle-minutes MINUTES [--json]
stado cloud host list --provider azure [--json]
stado cloud host delete NAME --provider azure [--json]
stado cloud host reap --provider azure [--apply] [--json]

What it needs

  • Azure enabled in the profile (providers, not providers_disabled; the environment's WC_PROVIDERS and WC_DISABLED_PROVIDERS select it for one invocation) and the compute bindings azure.subscription_id, azure.resource_group, azure.vnet, azure.subnet, azure.image_urn and azure.vm_username. A missing one is refused naming every missing key: a cloud host on Azure is addressed with bindings this deployment does not declare: <keys>; stado config set declares each.
  • The location's subnet, <azure.vnet>-<location>/<azure.subnet>; Stado creates no virtual network.
  • cloud_hosts.admit_from in the registry: the fleet hosts that reach cloud hosts, for example stado registry set --path cloud_hosts --value '{"admit_from":["build-host","always-on-mac"]}'. Without it: the registry names no host whose address a cloud host admits (cloud_hosts.admit_from is absent); ….
  • The operator's Azure credit floor ruling, read by the Azure credit gate.
  • No Azure Policy denying the resources a host is made of (application security groups, public addresses, interfaces, VMs, disks). A deny answers at the first of them, the application security group stado-cloud-hosts-<location> was not made: … HTTP 403: RequestDisallowedByPolicy … naming the assignment, and nothing is created.

Create

create does these in order and stops at the first that fails:

  1. Refuses a name already registered (target '<name>' is already registered) and a name that is not a target identifier.
  2. Prices the size at the highest on-demand hour any configured location quotes and prints the projected hourly burn, that hour plus the recorded hour of every cloud host already declared: projected hourly burn: <total> USD (<name> <size> at <hour> USD, <where priced>; <n> cloud host(s) already running at <hours> USD). The credit gate then takes one hour of all of them from the balance and refuses unless what remains is above the floor: creating cloud host <name> (<size>) in <location> is refused: the Azure credit balance <balance> USD less one hour of <size> (…) and one hour of the machines already running (<hours> USD) is not above the floor <amount> <currency> (the operator's ruling <id>: "<his words>"); …. Otherwise it prints credit: balance <balance> USD, <after> USD after one hour of all of them, above the floor ….
  3. Asks each admit_from host for its public address over its host channel (curl of <api.url>/api/egress, which the product site answers with the address the request came from) and records the answers in cloud_hosts.egress with the time they were read.
  4. Admits exactly those addresses on SSH (port 22): the location gets the application security group stado-cloud-hosts-<location>, and when the subnet carries a security group of its own, that group gets the rule stado-cloud-hosts admitting the addresses to the application group only, at the first priority from 100 no other rule holds. Every other interface in the subnet is left as it was. Every cloud host already declared is readmitted with the same addresses.
  5. Mints the host's fleet key as stado fleet key generate does.
  6. Creates the host's public address (static, Standard), its security group admitting the addresses on SSH, its interface in the subnet and the application group, and the VM holding the key's public half. cloud-init installs the build toolchain (build-essential, pkg-config, OpenSSL headers, clang, cmake, protoc, git, rsync, Node.js and npm from the image, rustup in the account's home) and an sshd drop-in refusing passwords. Each revision's rust-toolchain.toml chooses its Rust toolchain. A failure removes what was created and names what could not be removed.
  7. Enrolls the host through the verified fleet enroll path. A host that cannot be enrolled is deleted again, since nothing would return it.
  8. Records targets[].cloud: provider, location, size, disk, the priced hour and where it was priced, the idle minutes, the address, the VM id and when it was created.
  9. Waits for cloud-init to finish (cloud-init status --wait) and asks for $HOME/.cargo/bin/rustc --version (rustup's prefix; kompilator is compiled with that rustc), node --version and npm --version. A first boot that did not finish cleanly is refused naming /var/log/cloud-init-output.log on the host.

Reap

A cloud host is busy while a managed run stands in ~/.stado/work/runs (every stado host kompilator run lives there until it ends) or a cargo or rustc process runs. Otherwise it has stood idle since its run area last changed, or since it was created if no run ever came. reap first measures and readmits the fleet's addresses as create does, then lists each host as busy, idle, reapable (idle past its minutes) or unread with the cause; a host that cannot be read is never judged idle. With --apply, each reapable host is deleted as delete deletes it (reaped, or reap_failed with the cause, which exits non-zero).

The coordinator runs the applied pass on every tick when Azure is enabled in its profile and a cloud host is declared, and logs cloud-host reaper: … for each host it reaped, failed to reap or could not read.

Delete

delete refuses a name the registry declares no cloud host for (the registry declares no Azure cloud host <name> (it declares …)), then deletes the VM with its OS disk, the interface, the security group and the public address, each followed to the end of Azure's operation and confirmed gone. Only then does it remove the registry entry and the fleet key. A resource Azure still holds keeps the entry: <name> is still registered because Azure did not release everything: …; deleting it again retries.

List

list prints each declared host with Azure's power state of its VM (running, deallocated, absent, or unread: <cause>), location, size, address, priced hour, idle minutes and creation time, and the hourly burn of the running ones. --json carries the same rows and cloud_hosts.egress.

Source: this website