feat: add new VM
All checks were successful
build / image (push) Successful in 49s

This commit is contained in:
Antoine Pelletier 2026-09-23 10:21:51 +02:00
parent fb47979787
commit 1f0a037723
3 changed files with 20 additions and 7 deletions

View file

@ -4,7 +4,7 @@ A page to start and stop the VMs of the server, one at a time. **Rust** backend
(axum + sqlx + aide) driving **libvirt**, serving a **Vue 3** frontend (TypeScript +
vue-query + shadcn-vue), on **PostgreSQL** with **dbmate** migrations.
The two VMs (`win11` and `arch-hyprland`) share the same hardware and may never run
The VMs (`win11`, `arch-hyprland` and `cs-477`) share the same hardware and may never run
together: starting one while the other is up asks first, shuts that one down, waits
for it to be really off, and only then boots the wanted one. The state is read from
libvirt on every request, so a VM shut down from inside the guest shows up as
@ -21,7 +21,7 @@ is the only thing that changes between the two.
# 1. Start the development database
cd dev-db && docker compose up -d && cd ..
psql -h localhost -U postgres -c 'CREATE DATABASE app_template'
dbmate up # creates the schema and inserts the two VMs
dbmate up # creates the schema and inserts the VMs
# 2. Configure the app
cp config.example.yml config.yml # then set vm.uri, see below
@ -70,7 +70,7 @@ build dependency, and the uri alone decides local or remote. It needs `virsh` on
│ │ └── hypervisor/ libvirt (virsh) and mock implementations
│ └── utils/ configuration
├── db/
│ ├── migrations/ dbmate migrations (the two VMs are inserted by one)
│ ├── migrations/ dbmate migrations (the VMs are inserted by them)
│ └── schema.sql dump regenerated by dbmate, do not edit by hand
├── dev-db/ postgres + adminer for development
└── frontend/
@ -103,8 +103,9 @@ documentation sits right next to them (`fn *_docs`).
### The `vms` table
It only holds what libvirt does not know: how to present a domain in the UI
(`display_name`, `icon`, `position`). The live state is never stored. Adding a third
VM is one insert, no redeploy — but the one-at-a-time rule then applies to all three.
(`display_name`, `icon`, `position`). The live state is never stored. Adding a VM is
one insert (see the migrations), no redeploy — but the one-at-a-time rule then
applies to it as well.
### Routes

View file

@ -0,0 +1,11 @@
-- migrate:up
-- Third VM: an Ubuntu server guest. Like the others it is configuration, not
-- demo data, so a fresh deployment shows it without manual seeding.
--
-- `domain` must match the libvirt domain name exactly (`virsh list --all`).
INSERT INTO vms ("domain", "display_name", "icon", "position") VALUES
('cs-477', 'CS-477 Advanced OS', 'server', 3)
ON CONFLICT ("domain") DO NOTHING;
-- migrate:down
DELETE FROM vms WHERE "domain" = 'cs-477';

View file

@ -3,14 +3,14 @@
* The page: one card per VM, its live state, and the buttons to act on it.
*
* The state is polled, so a VM shut down from inside the guest shows up as
* stopped here on its own. The two VMs share the same hardware and may never run
* stopped here on its own. The VMs share the same hardware and may never run
* together: starting one while the other is up asks the user first, then runs
* the sequence "stop the other, wait for it to be really off, start the wanted
* one". The backend refuses the start anyway (409), this is only the nice path.
*/
import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { AppWindow, Monitor, Play, Power, Terminal, TriangleAlert, Zap } from '@lucide/vue'
import { AppWindow, Monitor, Play, Power, Server, Terminal, TriangleAlert, Zap } from '@lucide/vue'
import { HttpStatus } from 'http-status-ts'
import { toast } from 'vue-sonner'
@ -82,6 +82,7 @@ const STATE_DOT: Record<VmState, string> = {
const ICONS: Record<string, typeof Monitor> = {
windows: AppWindow,
linux: Terminal,
server: Server,
}
function iconFor(vm: VmStatus) {