Establish clean homelab infrastructure baseline
lint / yaml (push) Has been cancelled
lint / ansible (push) Has been cancelled
lint / terraform (push) Has been cancelled

Reorganize the brownfield repository, remove retired and generated artifacts, harden ignore rules, and record the GitOps/IaC redesign.
This commit is contained in:
2026-09-09 16:47:20 +00:00
commit 88a02ababa
418 changed files with 50579 additions and 0 deletions
@@ -0,0 +1,37 @@
---
# bao_vm role — create the OpenBao host as a small Ubuntu VM via libvirt + cloud-init
# (NoCloud). Runs on the libvirt host (localhost). Configures nothing inside the OS
# beyond the cloud-init seed; the openbao role installs the daemon afterward.
bao_vm_name: "bao1"
bao_vm_domain: "ddupan.top"
# Tiny footprint — OpenBao idle is ~50-150 MB RAM, one Go process.
bao_vm_vcpus: 1
bao_vm_memory_mb: 1024
bao_vm_disk_gb: 10
# Latest Ubuntu LTS cloud image (24.04 Noble). "current" always points at the newest build.
bao_vm_image_url: "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
bao_vm_osinfo: "ubuntu24.04"
# libvirt placement (matches the dc_vm convention).
bao_vm_images_dir: "/var/lib/libvirt/images"
bao_vm_bridge: "br0" # LAN bridge → puts bao on 192.168.10.0/24
# ZFS zvol for the root disk. Thin-provisioned (sparse) — bao stores very little.
bao_vm_zvol_parent: "data/vm"
bao_vm_zvol: "{{ bao_vm_zvol_parent }}/{{ bao_vm_name }}"
bao_vm_zvol_dev: "/dev/zvol/{{ bao_vm_zvol }}"
bao_vm_zvol_volblocksize: "16K"
bao_vm_zvol_sparse: true
# Guest networking (static). IP comes from group_vars/all/vars.yml (openbao_lan_ip).
bao_vm_ip: "{{ openbao_lan_ip }}"
bao_vm_prefix: 24
bao_vm_gateway: "192.168.10.1"
bao_vm_boot_dns: "192.168.10.5" # internal resolver (the Samba DC); or the gateway
# Cloud-init login user + the public key Ansible will connect with.
bao_vm_user: "ansible"
bao_vm_ssh_pubkey_file: "~/.ssh/id_ed25519.pub"
@@ -0,0 +1,113 @@
---
# Create the OpenBao VM on the local libvirt host. Idempotent: if the domain already
# exists it does nothing. Run on localhost with qemu:///system (become: true).
- name: Resolve the SSH public key to inject
ansible.builtin.set_fact:
bao_vm_ssh_pubkey: "{{ lookup('file', bao_vm_ssh_pubkey_file | expanduser) }}"
- name: Fail early if no usable public key
ansible.builtin.assert:
that:
- bao_vm_ssh_pubkey is search('^ssh-')
fail_msg: >-
No SSH public key at {{ bao_vm_ssh_pubkey_file }}. Generate one
(ssh-keygen -t ed25519) or set bao_vm_ssh_pubkey_file.
- name: Check whether the libvirt domain already exists
ansible.builtin.command: "virsh dominfo {{ bao_vm_name }}"
register: bao_vm_dominfo
changed_when: false
failed_when: false
- name: Create the VM
when: bao_vm_dominfo.rc != 0
block:
- name: Ensure image directories exist
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: "0711"
loop:
- "{{ bao_vm_images_dir }}"
- "{{ bao_vm_images_dir }}/base"
- name: Download the Ubuntu cloud image (once)
ansible.builtin.get_url:
url: "{{ bao_vm_image_url }}"
dest: "{{ bao_vm_images_dir }}/base/{{ bao_vm_image_url | basename }}"
mode: "0644"
- name: Check whether the root-disk zvol already exists
ansible.builtin.command: "zfs list -H -o name {{ bao_vm_zvol }}"
register: bao_vm_zvol_check
changed_when: false
failed_when: false
- name: Create the root-disk zvol
ansible.builtin.command:
cmd: >-
zfs create {{ '-s ' if bao_vm_zvol_sparse else '' }}-V {{ bao_vm_disk_gb }}G
-o volblocksize={{ bao_vm_zvol_volblocksize }}
{{ bao_vm_zvol }}
when: bao_vm_zvol_check.rc != 0
- name: Wait for the zvol device node to appear
ansible.builtin.wait_for:
path: "{{ bao_vm_zvol_dev }}"
timeout: 30
when: bao_vm_zvol_check.rc != 0
- name: Write the cloud image into the zvol (raw)
ansible.builtin.command:
cmd: >-
qemu-img convert -O raw
{{ bao_vm_images_dir }}/base/{{ bao_vm_image_url | basename }}
{{ bao_vm_zvol_dev }}
when: bao_vm_zvol_check.rc != 0
# cloud-init growpart expands the rootfs to fill the zvol on first boot.
- name: Render the cloud-init seed files
ansible.builtin.template:
src: "{{ item }}.j2"
dest: "{{ bao_vm_images_dir }}/{{ bao_vm_name }}-seed-{{ item }}"
mode: "0644"
loop:
- user-data
- meta-data
- network-config
- name: Build the NoCloud seed ISO
ansible.builtin.command:
cmd: >-
genisoimage -output {{ bao_vm_images_dir }}/{{ bao_vm_name }}-seed.iso
-volid cidata -joliet -rock
-graft-points
user-data={{ bao_vm_images_dir }}/{{ bao_vm_name }}-seed-user-data
meta-data={{ bao_vm_images_dir }}/{{ bao_vm_name }}-seed-meta-data
network-config={{ bao_vm_images_dir }}/{{ bao_vm_name }}-seed-network-config
args:
creates: "{{ bao_vm_images_dir }}/{{ bao_vm_name }}-seed.iso"
- name: Define and start the domain (cloud-init imports the disk)
ansible.builtin.command:
cmd: >-
virt-install
--name {{ bao_vm_name }}
--memory {{ bao_vm_memory_mb }}
--vcpus {{ bao_vm_vcpus }}
--osinfo require=off,name={{ bao_vm_osinfo }}
--disk path={{ bao_vm_zvol_dev }},format=raw,bus=virtio
--disk path={{ bao_vm_images_dir }}/{{ bao_vm_name }}-seed.iso,device=cdrom
--network bridge={{ bao_vm_bridge }},model=virtio
--graphics none --noautoconsole --import
register: virt_install
changed_when: true
- name: Wait for SSH on the new bao host
ansible.builtin.wait_for:
host: "{{ bao_vm_ip }}"
port: 22
delay: 10
timeout: 300
when: bao_vm_dominfo.rc != 0
@@ -0,0 +1,2 @@
instance-id: {{ bao_vm_name }}-001
local-hostname: {{ bao_vm_name }}
@@ -0,0 +1,20 @@
version: 2
ethernets:
primary:
# Match the (single) ethernet NIC by kernel name and configure it in place.
# NOTE: do NOT add set-name here — netplan only supports set-name when matching
# on mac/driver, not on name, and a name-match + rename leaves the NIC unconfigured.
match:
name: "en*"
dhcp4: false
dhcp6: false
addresses:
- {{ bao_vm_ip }}/{{ bao_vm_prefix }}
routes:
- to: default
via: {{ bao_vm_gateway }}
nameservers:
addresses:
- {{ bao_vm_boot_dns }}
search:
- {{ bao_vm_domain }}
@@ -0,0 +1,18 @@
#cloud-config
# NoCloud user-data for the OpenBao host VM.
hostname: {{ bao_vm_name }}
fqdn: {{ bao_vm_name }}.{{ bao_vm_domain }}
preserve_hostname: false
users:
- name: {{ bao_vm_user }}
groups: [sudo]
shell: /bin/bash
sudo: "ALL=(ALL) NOPASSWD:ALL"
lock_passwd: true
ssh_authorized_keys:
- {{ bao_vm_ssh_pubkey }}
ssh_pwauth: false
package_update: true
package_upgrade: false