# Fedora host provisioning

This directory configures already-installed Fedora 44 hosts. Infrastructure can
be created manually or by the hand-maintained Terraform configuration; both
paths produce the same input: two reachable hosts in `inventory.yml`.

Node 1 runs the k3s server. Node 2 runs a k3s agent. The playbook is idempotent
and may be rerun to converge package, firewall, k3s, and service state.

## Automated path

Copy `inventory.example.yml` to `inventory.yml`, replace the addresses and node
IP values, set `k3s_node_cidr` to the network containing only cluster nodes,
set `k3s_operator_cidrs` to the authorized administration networks, and set the
SSH user and connection options required by those hosts.
The managed machines may be physical servers, VMs from any provider, or
manually installed systems; the playbook does not depend on libvirt or the
local lab subnet. Then provide the existing cluster token only in the process
environment:

```bash
K3S_TOKEN="$(openssl rand -hex 32)" ./bootstrap.sh inventory.yml
```

The bootstrap checks for `ansible-playbook` and installs the declared Ansible
collections. It does not install system packages on the operator machine.

Do not save the token in the inventory or repository. Preserve it in the
operator's secret manager so a replacement agent can join the same cluster.

## Manual path

Use `manual-checklist.md` when configuration must be performed interactively.
It describes the same end state as the playbook, so a manually prepared host
can later be managed by Ansible without rebuilding it.

## Terraform path

Terraform is responsible only for creating machines, networks, and addresses.
After `terraform apply`, put its resulting addresses into `inventory.yml` and
run this playbook. Keeping configuration out of provisioner hooks makes the
same Ansible workflow usable for physical hardware, VMs, and manually created
hosts.

## One-command local QEMU lab

`lab.sh` is only a disposable integration harness for this workstation. Its
`virbr0` interface, fixed test addresses, UFW forwarding rules, cloud image,
and NetworkManager profiles are deliberately kept out of the reusable Ansible
roles. Do not run it on the two production machines; put their real addresses
in an inventory and run `bootstrap.sh` instead.

On an x86_64 Fedora or Arch-family workstation with hardware virtualization enabled:

```bash
./lab.sh
```

To reuse an existing Fedora 44 Cloud Base Generic QCOW2 image instead of
downloading another copy:

```bash
FEDORA_IMAGE=/path/to/Fedora-Cloud-Base-Generic-44.x86_64.qcow2 ./lab.sh up
```

The lab intentionally supports x86_64 only. Both target Fedora hosts and the
workstation used for the final project run x86_64, so maintaining a separate
aarch64 image, firmware, and verification path would add an untested platform
without helping the deployment demonstration.

The Fedora Server Guest Generic image is not suitable for this workflow because
it starts the interactive initial-setup program instead of accepting cloud-init
configuration.

The command installs missing host packages, enables libvirt, uses the selected
local image or downloads the Fedora 44 cloud image, creates two reusable VMs,
waits for ping and SSH, runs the Ansible configuration, and verifies
applications, services, directories, ports, and Kubernetes node readiness. Its
VM metadata and SSH key live under
`${XDG_STATE_HOME:-$HOME/.local/state}/nereus-lab`, outside the repository.

Subsequent operations are `./lab.sh check`, `./lab.sh stop`, and the explicitly
destructive `./lab.sh destroy`.

Deleting a VM also deletes any k3s local-path volumes stored on that machine.
The lab recreates the host and its Kubernetes identity, but stateful demo data
on the deleted disk must be recreated separately. This is acceptable for the
disposable harness and is not a backup strategy.

### Tested lab capacity

The complete two-node stack passed provisioning, reboot, node-disconnect
recovery, workload readiness, and public API checks on 2026-08-24 with 2 vCPUs,
3 GiB RAM, and a 30 GiB virtual disk per node. These are the lowest settings
tested for this project, not a production sizing recommendation. The thin
QCOW2 files used approximately 2.0 GiB for node 1 and 3.3 GiB for node 2 during
that verification.
