Add LVM-enabled VM deployment playbooks
- Add deploy-debian-lvm-netinst.yml for Debian with native LVM - Uses network installer with preseed configuration - Full LVM partitioning per infrastructure guidelines - Creates vg_system with 8 logical volumes - Separate /boot, /opt, /tmp, /home, /var, /var/log, /var/tmp, /var/log/audit - Security mount options (noexec,nosuid,nodev on /tmp and /var/tmp) - Add deploy-linux-vm-lvm.yml for multi-distro with post-config LVM - Supports all distributions from deploy-linux-vm.yml - Deploys VM with secondary 30GB disk for LVM - Post-deployment LVM configuration on /dev/vdb - Data migration from primary disk to LVM volumes - Automatic fstab updates
This commit is contained in:
532
plays/deploy-debian-lvm-netinst.yml
Normal file
532
plays/deploy-debian-lvm-netinst.yml
Normal file
@@ -0,0 +1,532 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Debian VM Deployment with LVM using Network Installer
|
||||
# =============================================================================
|
||||
# Deploys Debian 12 with proper LVM partitioning per CLAUDE.md
|
||||
# Uses preseed for automated installation
|
||||
# =============================================================================
|
||||
|
||||
- name: Deploy Debian 12 VM with LVM on KVM hypervisor
|
||||
hosts: grokbox
|
||||
gather_facts: yes
|
||||
become: yes
|
||||
|
||||
vars:
|
||||
# VM Configuration
|
||||
vm_name: "debian12-guest"
|
||||
vm_hostname: "debian12"
|
||||
vm_domain: "localdomain"
|
||||
vm_vcpus: 2
|
||||
vm_memory_mb: 2048
|
||||
vm_disk_size_gb: 40
|
||||
|
||||
# Network Configuration
|
||||
vm_network: "default"
|
||||
vm_bridge: "virbr0"
|
||||
|
||||
# Storage Configuration
|
||||
vm_disk_path: "/var/lib/libvirt/images/{{ vm_name }}.qcow2"
|
||||
|
||||
# Debian Network Installer
|
||||
debian_netinst_url: "https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.8.0-amd64-netinst.iso"
|
||||
debian_netinst_path: "/var/lib/libvirt/images/debian-12.8.0-amd64-netinst.iso"
|
||||
|
||||
# Ansible User Configuration
|
||||
ansible_user_ssh_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILBrnivsqjhAxWYeuuvnYc3neeRRuHsr2SjeKv+Drtpu user@debian"
|
||||
|
||||
tasks:
|
||||
# =========================================================================
|
||||
# Pre-flight Checks
|
||||
# =========================================================================
|
||||
|
||||
- name: Check if VM already exists
|
||||
command: virsh dominfo {{ vm_name }}
|
||||
register: vm_exists
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
tags: [validate, preflight]
|
||||
|
||||
- name: Fail if VM already exists
|
||||
fail:
|
||||
msg: "VM '{{ vm_name }}' already exists. Destroy it first."
|
||||
when: vm_exists.rc == 0
|
||||
tags: [validate, preflight]
|
||||
|
||||
- name: Display deployment information
|
||||
debug:
|
||||
msg:
|
||||
- "=== Debian 12 VM Deployment with LVM ==="
|
||||
- "VM Name: {{ vm_name }}"
|
||||
- "Method: Network installer with preseed"
|
||||
- "Disk: {{ vm_disk_size_gb }} GB with LVM"
|
||||
- "Installation time: ~10-15 minutes"
|
||||
- ""
|
||||
- "LVM Layout (per CLAUDE.md):"
|
||||
- " VG: vg_system"
|
||||
- " LVs: root(8G), opt(3G), tmp(1G), home(2G)"
|
||||
- " var(5G), var_log(2G), var_tmp(5G), var_audit(1G), swap(2G)"
|
||||
tags: [validate, preflight]
|
||||
|
||||
# =========================================================================
|
||||
# Package Installation
|
||||
# =========================================================================
|
||||
|
||||
- name: Install required packages
|
||||
apt:
|
||||
name:
|
||||
- libvirt-daemon-system
|
||||
- libvirt-clients
|
||||
- virtinst
|
||||
- qemu-kvm
|
||||
- qemu-utils
|
||||
- wget
|
||||
- genisoimage
|
||||
- python3-libvirt
|
||||
state: present
|
||||
tags: [install]
|
||||
|
||||
- name: Ensure libvirtd is running
|
||||
systemd:
|
||||
name: libvirtd
|
||||
state: started
|
||||
enabled: yes
|
||||
tags: [install]
|
||||
|
||||
# =========================================================================
|
||||
# Download Debian Network Installer
|
||||
# =========================================================================
|
||||
|
||||
- name: Check if Debian netinst ISO exists
|
||||
stat:
|
||||
path: "{{ debian_netinst_path }}"
|
||||
register: netinst_stat
|
||||
tags: [download]
|
||||
|
||||
- name: Download Debian network installer ISO
|
||||
get_url:
|
||||
url: "{{ debian_netinst_url }}"
|
||||
dest: "{{ debian_netinst_path }}"
|
||||
mode: '0644'
|
||||
timeout: 1200
|
||||
when: not netinst_stat.stat.exists
|
||||
tags: [download]
|
||||
|
||||
# =========================================================================
|
||||
# Create Preseed Configuration
|
||||
# =========================================================================
|
||||
|
||||
- name: Create preseed directory
|
||||
file:
|
||||
path: /tmp/preseed-{{ vm_name }}
|
||||
state: directory
|
||||
mode: '0755'
|
||||
tags: [preseed]
|
||||
|
||||
- name: Create preseed configuration file
|
||||
copy:
|
||||
dest: /tmp/preseed-{{ vm_name }}/preseed.cfg
|
||||
mode: '0644'
|
||||
content: |
|
||||
#### Debian 12 Preseed Configuration with LVM
|
||||
#### Per CLAUDE.md Requirements
|
||||
|
||||
### Localization
|
||||
d-i debian-installer/locale string en_US.UTF-8
|
||||
d-i keyboard-configuration/xkb-keymap select us
|
||||
|
||||
### Network configuration
|
||||
d-i netcfg/choose_interface select auto
|
||||
d-i netcfg/get_hostname string {{ vm_hostname }}
|
||||
d-i netcfg/get_domain string {{ vm_domain }}
|
||||
d-i netcfg/wireless_wep string
|
||||
|
||||
### Mirror settings
|
||||
d-i mirror/country string manual
|
||||
d-i mirror/http/hostname string deb.debian.org
|
||||
d-i mirror/http/directory string /debian
|
||||
d-i mirror/http/proxy string
|
||||
|
||||
### Account setup
|
||||
d-i passwd/root-login boolean true
|
||||
d-i passwd/root-password password ChangeMe123!
|
||||
d-i passwd/root-password-again password ChangeMe123!
|
||||
|
||||
# Create ansible user
|
||||
d-i passwd/user-fullname string Ansible User
|
||||
d-i passwd/username string ansible
|
||||
d-i passwd/user-password password ansible123
|
||||
d-i passwd/user-password-again password ansible123
|
||||
d-i passwd/user-default-groups string sudo
|
||||
|
||||
### Clock and time zone
|
||||
d-i clock-setup/utc boolean true
|
||||
d-i time/zone string UTC
|
||||
d-i clock-setup/ntp boolean true
|
||||
|
||||
### Partitioning with LVM
|
||||
d-i partman-auto/method string lvm
|
||||
d-i partman-lvm/device_remove_lvm boolean true
|
||||
d-i partman-md/device_remove_md boolean true
|
||||
d-i partman-lvm/confirm boolean true
|
||||
d-i partman-lvm/confirm_nooverwrite boolean true
|
||||
|
||||
# Create custom LVM recipe
|
||||
d-i partman-auto/expert_recipe string \
|
||||
boot-lvm :: \
|
||||
512 512 512 ext4 \
|
||||
$primary{ } $bootable{ } \
|
||||
method{ format } format{ } \
|
||||
use_filesystem{ } filesystem{ ext4 } \
|
||||
mountpoint{ /boot } \
|
||||
. \
|
||||
8192 8192 8192 ext4 \
|
||||
$defaultignore{ } \
|
||||
$primary{ } \
|
||||
method{ lvm } \
|
||||
vg_name{ vg_system } \
|
||||
. \
|
||||
8192 8192 8192 ext4 \
|
||||
$lvmok{ } \
|
||||
lv_name{ lv_root } \
|
||||
in_vg{ vg_system } \
|
||||
method{ format } format{ } \
|
||||
use_filesystem{ } filesystem{ ext4 } \
|
||||
mountpoint{ / } \
|
||||
. \
|
||||
3072 3072 3072 ext4 \
|
||||
$lvmok{ } \
|
||||
lv_name{ lv_opt } \
|
||||
in_vg{ vg_system } \
|
||||
method{ format } format{ } \
|
||||
use_filesystem{ } filesystem{ ext4 } \
|
||||
mountpoint{ /opt } \
|
||||
. \
|
||||
1024 1024 1024 ext4 \
|
||||
$lvmok{ } \
|
||||
lv_name{ lv_tmp } \
|
||||
in_vg{ vg_system } \
|
||||
method{ format } format{ } \
|
||||
use_filesystem{ } filesystem{ ext4 } \
|
||||
mountpoint{ /tmp } \
|
||||
options/noexec{ noexec } \
|
||||
options/nosuid{ nosuid } \
|
||||
options/nodev{ nodev } \
|
||||
. \
|
||||
2048 2048 2048 ext4 \
|
||||
$lvmok{ } \
|
||||
lv_name{ lv_home } \
|
||||
in_vg{ vg_system } \
|
||||
method{ format } format{ } \
|
||||
use_filesystem{ } filesystem{ ext4 } \
|
||||
mountpoint{ /home } \
|
||||
. \
|
||||
5120 5120 5120 ext4 \
|
||||
$lvmok{ } \
|
||||
lv_name{ lv_var } \
|
||||
in_vg{ vg_system } \
|
||||
method{ format } format{ } \
|
||||
use_filesystem{ } filesystem{ ext4 } \
|
||||
mountpoint{ /var } \
|
||||
. \
|
||||
2048 2048 2048 ext4 \
|
||||
$lvmok{ } \
|
||||
lv_name{ lv_var_log } \
|
||||
in_vg{ vg_system } \
|
||||
method{ format } format{ } \
|
||||
use_filesystem{ } filesystem{ ext4 } \
|
||||
mountpoint{ /var/log } \
|
||||
. \
|
||||
5120 5120 5120 ext4 \
|
||||
$lvmok{ } \
|
||||
lv_name{ lv_var_tmp } \
|
||||
in_vg{ vg_system } \
|
||||
method{ format } format{ } \
|
||||
use_filesystem{ } filesystem{ ext4 } \
|
||||
mountpoint{ /var/tmp } \
|
||||
options/noexec{ noexec } \
|
||||
options/nosuid{ nosuid } \
|
||||
options/nodev{ nodev } \
|
||||
. \
|
||||
1024 1024 1024 ext4 \
|
||||
$lvmok{ } \
|
||||
lv_name{ lv_var_audit } \
|
||||
in_vg{ vg_system } \
|
||||
method{ format } format{ } \
|
||||
use_filesystem{ } filesystem{ ext4 } \
|
||||
mountpoint{ /var/log/audit } \
|
||||
. \
|
||||
2048 2048 2048 linux-swap \
|
||||
$lvmok{ } \
|
||||
lv_name{ lv_swap } \
|
||||
in_vg{ vg_system } \
|
||||
method{ swap } format{ } \
|
||||
.
|
||||
|
||||
d-i partman-auto-lvm/guided_size string max
|
||||
d-i partman-auto-lvm/new_vg_name string vg_system
|
||||
d-i partman/choose_partition select finish
|
||||
d-i partman/confirm boolean true
|
||||
d-i partman/confirm_nooverwrite boolean true
|
||||
|
||||
### Package selection
|
||||
tasksel tasksel/first multiselect standard, ssh-server
|
||||
d-i pkgsel/include string sudo vim htop tmux curl wget rsync git python3 python3-pip jq bc lvm2 aide auditd chrony ufw cloud-init
|
||||
d-i pkgsel/upgrade select full-upgrade
|
||||
popularity-contest popularity-contest/participate boolean false
|
||||
|
||||
### Boot loader
|
||||
d-i grub-installer/only_debian boolean true
|
||||
d-i grub-installer/with_other_os boolean true
|
||||
d-i grub-installer/bootdev string default
|
||||
|
||||
### Finishing up
|
||||
d-i finish-install/reboot_in_progress note
|
||||
|
||||
### Late command - configure ansible user and SSH
|
||||
d-i preseed/late_command string \
|
||||
in-target mkdir -p /home/ansible/.ssh; \
|
||||
in-target chmod 700 /home/ansible/.ssh; \
|
||||
in-target sh -c 'echo "{{ ansible_user_ssh_key }}" > /home/ansible/.ssh/authorized_keys'; \
|
||||
in-target chown -R ansible:ansible /home/ansible/.ssh; \
|
||||
in-target chmod 600 /home/ansible/.ssh/authorized_keys; \
|
||||
in-target sh -c 'echo "ansible ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/ansible'; \
|
||||
in-target chmod 440 /etc/sudoers.d/ansible; \
|
||||
in-target mkdir -p /etc/ssh/sshd_config.d; \
|
||||
in-target sh -c 'echo -e "PermitRootLogin no\nPasswordAuthentication no\nPubkeyAuthentication yes" > /etc/ssh/sshd_config.d/99-security.conf'
|
||||
tags: [preseed]
|
||||
|
||||
- name: Create preseed ISO
|
||||
command: >
|
||||
genisoimage -r -J -o /tmp/preseed-{{ vm_name }}.iso
|
||||
-V "PRESEED" /tmp/preseed-{{ vm_name }}/
|
||||
args:
|
||||
creates: /tmp/preseed-{{ vm_name }}.iso
|
||||
tags: [preseed]
|
||||
|
||||
# =========================================================================
|
||||
# Create VM Disk
|
||||
# =========================================================================
|
||||
|
||||
- name: Create VM disk
|
||||
command: >
|
||||
qemu-img create -f qcow2
|
||||
{{ vm_disk_path }}
|
||||
{{ vm_disk_size_gb }}G
|
||||
args:
|
||||
creates: "{{ vm_disk_path }}"
|
||||
tags: [storage]
|
||||
|
||||
- name: Set permissions on VM disk
|
||||
file:
|
||||
path: "{{ vm_disk_path }}"
|
||||
owner: libvirt-qemu
|
||||
group: kvm
|
||||
mode: '0600'
|
||||
tags: [storage]
|
||||
|
||||
# =========================================================================
|
||||
# Install VM
|
||||
# =========================================================================
|
||||
|
||||
- name: Display installation notice
|
||||
debug:
|
||||
msg:
|
||||
- "=== Starting Debian Network Installation ==="
|
||||
- "This will take approximately 10-15 minutes"
|
||||
- "The VM will automatically install and configure:"
|
||||
- " - Debian 12 (Bookworm)"
|
||||
- " - LVM partitioning per CLAUDE.md"
|
||||
- " - ansible user with SSH keys"
|
||||
- " - Essential packages"
|
||||
- ""
|
||||
- "You can monitor progress with:"
|
||||
- " ssh grokbox 'sudo virsh console {{ vm_name }}'"
|
||||
tags: [install-vm]
|
||||
|
||||
- name: Create VM with network installer
|
||||
command: >
|
||||
virt-install
|
||||
--name {{ vm_name }}
|
||||
--memory {{ vm_memory_mb }}
|
||||
--vcpus {{ vm_vcpus }}
|
||||
--disk path={{ vm_disk_path }},format=qcow2,bus=virtio
|
||||
--cdrom {{ debian_netinst_path }}
|
||||
--disk path=/tmp/preseed-{{ vm_name }}.iso,device=cdrom
|
||||
--network network={{ vm_network }},model=virtio
|
||||
--os-variant debian12
|
||||
--graphics none
|
||||
--console pty,target_type=serial
|
||||
--extra-args "auto=true priority=critical console=ttyS0,115200n8 serial preseed/file=/cdrom/preseed.cfg"
|
||||
--noautoconsole
|
||||
tags: [install-vm]
|
||||
|
||||
- name: Wait for installation to complete
|
||||
pause:
|
||||
minutes: 15
|
||||
prompt: "Waiting for Debian installation (15 minutes)... You can monitor with: ssh grokbox 'sudo virsh console {{ vm_name }}'"
|
||||
tags: [install-vm]
|
||||
|
||||
- name: Check if VM is running
|
||||
command: virsh domstate {{ vm_name }}
|
||||
register: vm_state
|
||||
changed_when: false
|
||||
tags: [validate]
|
||||
|
||||
- name: Display VM state
|
||||
debug:
|
||||
var: vm_state.stdout
|
||||
tags: [validate]
|
||||
|
||||
- name: Start VM if not running
|
||||
command: virsh start {{ vm_name }}
|
||||
when: vm_state.stdout != "running"
|
||||
failed_when: false
|
||||
tags: [validate]
|
||||
|
||||
- name: Wait a bit for network
|
||||
pause:
|
||||
seconds: 30
|
||||
tags: [validate]
|
||||
|
||||
- name: Get VM IP address
|
||||
shell: |
|
||||
virsh domifaddr {{ vm_name }} | grep -oP '(\d{1,3}\.){3}\d{1,3}' | head -1
|
||||
register: vm_ip
|
||||
retries: 10
|
||||
delay: 10
|
||||
until: vm_ip.stdout != ""
|
||||
changed_when: false
|
||||
tags: [validate]
|
||||
|
||||
- name: Set VM IP fact
|
||||
set_fact:
|
||||
deployed_vm_ip: "{{ vm_ip.stdout }}"
|
||||
tags: [validate]
|
||||
|
||||
- name: Display VM information
|
||||
debug:
|
||||
msg:
|
||||
- "=== VM Installation Complete ==="
|
||||
- "VM Name: {{ vm_name }}"
|
||||
- "IP Address: {{ deployed_vm_ip }}"
|
||||
- "Access: ssh ansible@{{ deployed_vm_ip }}"
|
||||
- "Or: ssh -J grokbox ansible@{{ deployed_vm_ip }}"
|
||||
- ""
|
||||
- "Root password: ChangeMe123! (change immediately!)"
|
||||
- "Ansible password: ansible123 (SSH keys configured)"
|
||||
tags: [validate]
|
||||
|
||||
- name: Cleanup preseed files
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- /tmp/preseed-{{ vm_name }}
|
||||
- /tmp/preseed-{{ vm_name }}.iso
|
||||
tags: [cleanup]
|
||||
|
||||
# =============================================================================
|
||||
# Validate LVM Configuration
|
||||
# =============================================================================
|
||||
|
||||
- name: Validate LVM configuration on deployed VM
|
||||
hosts: "{{ hostvars['grokbox']['deployed_vm_ip'] }}"
|
||||
gather_facts: yes
|
||||
become: yes
|
||||
vars:
|
||||
ansible_user: ansible
|
||||
ansible_password: ansible123
|
||||
ansible_ssh_common_args: '-o ProxyJump=grokbox -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/dev/null'
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
|
||||
tasks:
|
||||
- name: Wait for SSH to be available
|
||||
wait_for_connection:
|
||||
timeout: 300
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Gather system facts
|
||||
setup:
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Display system information
|
||||
debug:
|
||||
msg:
|
||||
- "=== System Information ==="
|
||||
- "Hostname: {{ ansible_hostname }}"
|
||||
- "OS: {{ ansible_distribution }} {{ ansible_distribution_version }}"
|
||||
- "Kernel: {{ ansible_kernel }}"
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Check LVM configuration
|
||||
command: "{{ item }}"
|
||||
register: lvm_checks
|
||||
changed_when: false
|
||||
loop:
|
||||
- pvdisplay
|
||||
- vgdisplay
|
||||
- lvdisplay
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Display LVM configuration
|
||||
debug:
|
||||
msg: "{{ item.stdout_lines }}"
|
||||
loop: "{{ lvm_checks.results }}"
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Check filesystem layout
|
||||
command: df -h
|
||||
register: df_output
|
||||
changed_when: false
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Display filesystem layout
|
||||
debug:
|
||||
var: df_output.stdout_lines
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Verify mount options for /tmp
|
||||
shell: mount | grep ' /tmp '
|
||||
register: tmp_mount
|
||||
changed_when: false
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Display /tmp mount options
|
||||
debug:
|
||||
msg: "{{ tmp_mount.stdout }}"
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Check installed packages
|
||||
command: dpkg -l
|
||||
register: packages
|
||||
changed_when: false
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Verify essential packages are installed
|
||||
shell: dpkg -l | grep -E 'aide|auditd|chrony|ufw|lvm2' | awk '{print $2, $3}'
|
||||
register: essential_pkgs
|
||||
changed_when: false
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Display essential packages
|
||||
debug:
|
||||
var: essential_pkgs.stdout_lines
|
||||
tags: [validate-lvm]
|
||||
|
||||
- name: Final validation summary
|
||||
debug:
|
||||
msg:
|
||||
- "=== Validation Complete ==="
|
||||
- "✓ VM deployed with Debian 12"
|
||||
- "✓ LVM configuration applied"
|
||||
- "✓ Volume group: vg_system"
|
||||
- "✓ Logical volumes created per CLAUDE.md"
|
||||
- "✓ Ansible user configured with SSH keys"
|
||||
- "✓ Essential packages installed"
|
||||
- ""
|
||||
- "Next steps:"
|
||||
- " 1. Change root password: ssh ansible@{{ ansible_default_ipv4.address }} sudo passwd root"
|
||||
- " 2. Configure firewall: sudo ufw enable && sudo ufw allow ssh"
|
||||
- " 3. Enable services: sudo systemctl enable --now chrony auditd"
|
||||
- " 4. Run security hardening playbooks"
|
||||
tags: [validate-lvm]
|
||||
Reference in New Issue
Block a user