Establish clean homelab infrastructure baseline
Reorganize the brownfield repository, remove retired and generated artifacts, harden ignore rules, and record the GitOps/IaC redesign.
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
---
|
||||
# PVE SDN — VLAN zone on vmbr0.
|
||||
#
|
||||
# WHY VLAN AND NOT VXLAN: the unmanaged switch forwards 802.1Q-tagged frames
|
||||
# untouched (dumb switches forward on MAC; the tag is opaque payload). VERIFIED
|
||||
# on this LAN 2026-07-25 — a VLAN-100 ping between nodes passed at both 1472B and
|
||||
# 8972B. So VLAN gives cross-node L2 with NO encapsulation, no overhead, and no
|
||||
# MTU arithmetic. VXLAN would work too (jumbo leaves room for its ~50 bytes) but
|
||||
# buys nothing here and costs CPU.
|
||||
#
|
||||
# ⚠️ A dumb switch enforces nothing, so these VLANs are SEGMENTATION, not
|
||||
# security: anything on the LAN could inject tagged frames. Do not treat a VNet
|
||||
# here as an isolation boundary for anything that matters.
|
||||
#
|
||||
# NOTE: a VLAN zone is pure L2 — no gateway, no SNAT, no internet. That is the
|
||||
# point for lab/retro-OS networks. If a VNet later needs routing or internet
|
||||
# egress, that is an EVPN zone (frr is already installed) or a router VM.
|
||||
pve_sdn_zone: lab
|
||||
pve_sdn_bridge: vmbr0
|
||||
# Guests keep a standard 1500 MTU; the 9000 underlay carries it comfortably.
|
||||
pve_sdn_mtu: 1500
|
||||
|
||||
pve_sdn_vnets:
|
||||
- name: labnet # general isolated lab L2
|
||||
tag: 100
|
||||
alias: "Isolated lab network (no gateway)"
|
||||
- name: retronet # retro OSes: keep ancient stacks off the real LAN
|
||||
tag: 110
|
||||
alias: "Retro OS network (no gateway, no internet)"
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
# SDN config is cluster-wide (/etc/pve/sdn/), so everything runs once.
|
||||
|
||||
- name: Read existing zones
|
||||
ansible.builtin.command:
|
||||
cmd: "pvesh get /cluster/sdn/zones --output-format json"
|
||||
register: _zones
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
run_once: true
|
||||
|
||||
- name: Create the VLAN zone
|
||||
ansible.builtin.command:
|
||||
cmd: >-
|
||||
pvesh create /cluster/sdn/zones --zone {{ pve_sdn_zone }} --type vlan
|
||||
--bridge {{ pve_sdn_bridge }} --mtu {{ pve_sdn_mtu }}
|
||||
--nodes {{ groups['pve'] | join(',') }}
|
||||
when: pve_sdn_zone not in (_zones.stdout | from_json | map(attribute='zone') | list)
|
||||
run_once: true
|
||||
|
||||
- name: Read existing vnets
|
||||
ansible.builtin.command:
|
||||
cmd: "pvesh get /cluster/sdn/vnets --output-format json"
|
||||
register: _vnets
|
||||
changed_when: false
|
||||
check_mode: false
|
||||
run_once: true
|
||||
|
||||
- name: Create the VNets
|
||||
ansible.builtin.command:
|
||||
cmd: >-
|
||||
pvesh create /cluster/sdn/vnets --vnet {{ item.name }}
|
||||
--zone {{ pve_sdn_zone }} --tag {{ item.tag }}
|
||||
--alias '{{ item.alias }}'
|
||||
loop: "{{ pve_sdn_vnets }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }} (vlan {{ item.tag }})"
|
||||
when: item.name not in (_vnets.stdout | from_json | map(attribute='vnet') | list)
|
||||
run_once: true
|
||||
|
||||
- name: Apply the SDN configuration
|
||||
# SDN changes stay PENDING until applied; without this the VNet bridges are
|
||||
# never actually created on the nodes.
|
||||
ansible.builtin.command:
|
||||
cmd: "pvesh set /cluster/sdn"
|
||||
register: _apply
|
||||
changed_when: true
|
||||
run_once: true
|
||||
|
||||
- name: Report
|
||||
ansible.builtin.shell:
|
||||
cmd: "pvesh get /cluster/sdn/vnets --output-format json | python3 -c \"import json,sys;[print(' ',v['vnet'],'vlan',v.get('tag'),'zone',v.get('zone')) for v in json.load(sys.stdin)]\""
|
||||
register: _rep
|
||||
changed_when: false
|
||||
run_once: true
|
||||
|
||||
- name: Show it
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ _rep.stdout_lines }}"
|
||||
run_once: true
|
||||
Reference in New Issue
Block a user