Define the managed service machine architecture #45

Open
opened 2026-09-04 01:26:21 +01:00 by vnprc-agent · 2 comments
Contributor

Managed service machines need one composition model whether they run under a local hypervisor or on externally provided hardware.

Primary goals

  • Separate reusable service behavior from machine profiles and placement details.
  • Give inventory a common machine schema with explicit placement-specific data instead of assuming every managed machine is a VM.
  • Keep archetypes focused on profile composition while allowing service profiles to consume arbitrary application modules.
  • Administer initial provisioning, routine deployment, verification, and operator-invoked generation rollback from Nexus.
  • Prove the design with a synthetic stateless service machine without adding a generic stateful-service framework.

Direction

Create allod/services as the public library for reusable NixOS service modules and operational policy. It must not contain concrete machines, application-specific deployment flakes, identities, secrets, or deploy state. Generic public-host and static-site behavior can move there; site generators and content builds remain with their consumers.

Keep the service builder in allod/archetypes: archetypes compose profiles, and a service profile is defined by the application module it consumes rather than by whether it is stateful. Inventory will describe common machine facts plus a discriminated placement. Existing libvirt and microVM consumers must remain compatible while external KVM placement is added without fake runtime, hypervisor, MAC, or volume facts.

Nexus remains the operator surface for every managed machine. A fresh install and a routine deployment are distinct operations. Recovery favors rebuilding from declared configuration, restoring explicitly declared durable state, and reconnecting clients. Cheap operator-selected NixOS generation rollback remains useful for configuration failures, but does not imply application-data rollback.

Scope

This issue tracks the cross-repository framework work in allod/strategy, allod/services, allod/inventory, allod/archetypes, allod/profiles, allod/vm, and allod/nexus. It includes compatibility migrations and a synthetic end-to-end example.

Plan: allod/strategy/dev-plans/managed-service-machines.md on master.

Concrete deployments, provider accounts, DNS, private addressing, identities, secrets, application data, backup schedules, and live rollout are downstream concerns. Stateful-service continuity machinery is deferred until measured requirements and a second real consumer justify a shared abstraction.

Related: allod/nexus#39, allod/memory#47, and the superseded experiment recorded in allod/archetypes#60.

Managed service machines need one composition model whether they run under a local hypervisor or on externally provided hardware. ## Primary goals - Separate reusable service behavior from machine profiles and placement details. - Give inventory a common machine schema with explicit placement-specific data instead of assuming every managed machine is a VM. - Keep archetypes focused on profile composition while allowing service profiles to consume arbitrary application modules. - Administer initial provisioning, routine deployment, verification, and operator-invoked generation rollback from Nexus. - Prove the design with a synthetic stateless service machine without adding a generic stateful-service framework. ## Direction Create `allod/services` as the public library for reusable NixOS service modules and operational policy. It must not contain concrete machines, application-specific deployment flakes, identities, secrets, or deploy state. Generic public-host and static-site behavior can move there; site generators and content builds remain with their consumers. Keep the service builder in `allod/archetypes`: archetypes compose profiles, and a service profile is defined by the application module it consumes rather than by whether it is stateful. Inventory will describe common machine facts plus a discriminated placement. Existing libvirt and microVM consumers must remain compatible while external KVM placement is added without fake runtime, hypervisor, MAC, or volume facts. Nexus remains the operator surface for every managed machine. A fresh install and a routine deployment are distinct operations. Recovery favors rebuilding from declared configuration, restoring explicitly declared durable state, and reconnecting clients. Cheap operator-selected NixOS generation rollback remains useful for configuration failures, but does not imply application-data rollback. ## Scope This issue tracks the cross-repository framework work in `allod/strategy`, `allod/services`, `allod/inventory`, `allod/archetypes`, `allod/profiles`, `allod/vm`, and `allod/nexus`. It includes compatibility migrations and a synthetic end-to-end example. Plan: `allod/strategy/dev-plans/managed-service-machines.md` on master. Concrete deployments, provider accounts, DNS, private addressing, identities, secrets, application data, backup schedules, and live rollout are downstream concerns. Stateful-service continuity machinery is deferred until measured requirements and a second real consumer justify a shared abstraction. Related: `allod/nexus#39`, `allod/memory#47`, and the superseded experiment recorded in `allod/archetypes#60`.
Author
Contributor

The third milestone is being taken first, for hypervisor placement only, because allod/strategy#65 needs a stateful guest now: a service machine type that is a guest with a required data disk mounted at /var/lib, root as its only account over the hypervisor's keys, and a LAN-only firewall a profile may widen. Issues: allod/inventory#24 (the type and its diagnostics), allod/secrets#41 (serviceVMs identities with username = "root"), allod/archetypes#137 (mkServiceVm, its checks, and a VM test). The allod/services repo, placement-generalized inventory and external KVM hosts are untouched by this and remain this issue's scope; the type is shaped so a later placement discriminator can sit beside runtime without renaming anything. Unlike the withdrawn allod/archetypes#60, this machine is a guest and composes the shared guest modules.

The third milestone is being taken first, for hypervisor placement only, because allod/strategy#65 needs a stateful guest now: a `service` machine type that is a guest with a required data disk mounted at `/var/lib`, root as its only account over the hypervisor's keys, and a LAN-only firewall a profile may widen. Issues: allod/inventory#24 (the type and its diagnostics), allod/secrets#41 (`serviceVMs` identities with `username = "root"`), allod/archetypes#137 (`mkServiceVm`, its checks, and a VM test). The `allod/services` repo, placement-generalized inventory and external KVM hosts are untouched by this and remain this issue's scope; the type is shaped so a later placement discriminator can sit beside `runtime` without renaming anything. Unlike the withdrawn allod/archetypes#60, this machine is a guest and composes the shared guest modules.
Author
Contributor

Two things for M1 ("Establish the service-module boundary") that postdate this plan, both arising from allod/strategy#65's slice 3.

modules/forgejo is a third module that belongs in allod/services. M1 names the reusable public-host and static-site modules as the ones to move out of allod/archetypes. The Forgejo module did not exist when that was written; it landed in allod/archetypes as nixosModules.forgejo beside publicHost, and it is exactly what this plan's charter describes — reusable NixOS service behaviour with no concrete machine, identity or application content. It should move with the other two, under the same temporary re-export arrangement. It is also the largest of the three, around 670 lines, and it is the one with a live second copy outside the framework (vnprc-side, tracked privately), so moving it is worth more than moving either of the others.

M1 should delete a bridge, not inherit it. allod/archetypes#138 added a seam the framework did not previously have: nix/builders/service.nix hands profile modules the framework's exported module set through specialArgs, as allodModules, so a profile definition can compose nixosModules.forgejo by name. That exists only because allod/profiles declares one input, nixpkgs, and an archetypes input would be a dependency cycle, so a profile had no way to name a module the framework owns.

Once allod/services exists, that cycle is gone: allod/profiles can take allod/services as an ordinary input and select modules from it directly, which is what M2 already describes when it says "a profile selects it without the application depending on inventory, profiles, archetypes, Nexus, or deploy". At that point allodModules has no remaining consumer and should be removed rather than carried forward.

The seam was deliberately scoped to the service builder alone, and not wired into dev, privacy or hypervisor, to keep it a narrow bridge with one consumer and an obvious removal. Worth stating the risk plainly: a convenience that makes it easy to keep service modules in allod/archetypes works against this plan's boundary, so the longer M1 waits the more likely something else reaches for the same seam.

Nothing here changes this plan's milestones or contracts; it adds one module to M1's move list and one deletion to its exit.

Two things for M1 ("Establish the service-module boundary") that postdate this plan, both arising from allod/strategy#65's slice 3. **`modules/forgejo` is a third module that belongs in `allod/services`.** M1 names the reusable public-host and static-site modules as the ones to move out of `allod/archetypes`. The Forgejo module did not exist when that was written; it landed in `allod/archetypes` as `nixosModules.forgejo` beside `publicHost`, and it is exactly what this plan's charter describes — reusable NixOS service behaviour with no concrete machine, identity or application content. It should move with the other two, under the same temporary re-export arrangement. It is also the largest of the three, around 670 lines, and it is the one with a live second copy outside the framework (vnprc-side, tracked privately), so moving it is worth more than moving either of the others. **M1 should delete a bridge, not inherit it.** allod/archetypes#138 added a seam the framework did not previously have: `nix/builders/service.nix` hands profile modules the framework's exported module set through `specialArgs`, as `allodModules`, so a profile definition can compose `nixosModules.forgejo` by name. That exists only because `allod/profiles` declares one input, `nixpkgs`, and an `archetypes` input would be a dependency cycle, so a profile had no way to name a module the framework owns. Once `allod/services` exists, that cycle is gone: `allod/profiles` can take `allod/services` as an ordinary input and select modules from it directly, which is what M2 already describes when it says "a profile selects it without the application depending on inventory, profiles, archetypes, Nexus, or deploy". At that point `allodModules` has no remaining consumer and should be removed rather than carried forward. The seam was deliberately scoped to the `service` builder alone, and not wired into `dev`, `privacy` or `hypervisor`, to keep it a narrow bridge with one consumer and an obvious removal. Worth stating the risk plainly: a convenience that makes it easy to keep service modules in `allod/archetypes` works against this plan's boundary, so the longer M1 waits the more likely something else reaches for the same seam. Nothing here changes this plan's milestones or contracts; it adds one module to M1's move list and one deletion to its exit.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
allod/strategy#45
No description provided.