Add deploy_linux_vm role with LVM and SSH hardening

Features:
- Multi-distribution support (Debian, Ubuntu, RHEL, AlmaLinux, Rocky, SUSE)
- LVM configuration with meaningful volume groups and logical volumes
- 8 LVs: lv_opt, lv_tmp, lv_home, lv_var, lv_var_log, lv_var_tmp, lv_var_audit, lv_swap
- Security mount options on sensitive directories

SSH Hardening:
- GSSAPI authentication disabled
- GSSAPI cleanup credentials disabled
- Root login disabled via SSH
- Password authentication disabled
- Key-based authentication only
- MaxAuthTries: 3, ClientAliveInterval: 300s

Security Features:
- SELinux enforcing (RHEL family)
- AppArmor enabled (Debian family)
- Firewall configuration (UFW/firewalld)
- Automatic security updates
- Audit daemon (auditd) enabled
- Time synchronization (chrony)
- Essential security packages (aide, auditd)

Role Structure:
- Modular task organization (validate, install, download, storage, deploy, lvm)
- Tag-based execution for selective deployment
- OS-family specific cloud-init templates
- Comprehensive variable defaults (100+ configurable options)
- Post-deployment validation tasks
This commit is contained in:
Infrastructure Team
2025-11-10 22:51:51 +01:00
parent 47df4035c3
commit eec15a1cc2
18 changed files with 1869 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
---
# =============================================================================
# Cleanup Tasks - Remove Temporary Files
# =============================================================================
- name: Remove temporary cloud-init directory
file:
path: /tmp/cloud-init-{{ deploy_linux_vm_name }}
state: absent
tags: [cleanup]
- name: Remove downloaded checksums
file:
path: /tmp/{{ deploy_linux_vm_os_distribution }}-CHECKSUM
state: absent
tags: [cleanup]
- name: Remove cloud-init ISO (if requested)
file:
path: "{{ deploy_linux_vm_cloud_init_iso_path }}"
state: absent
when: deploy_linux_vm_remove_cloud_init_iso_after_boot | bool
tags: [cleanup]
- name: Display cleanup summary
debug:
msg:
- "=== Cleanup Complete ==="
- "Temporary files removed"
- "VM is ready for use"
tags: [cleanup]

View File

@@ -0,0 +1,70 @@
---
# =============================================================================
# Cloud-Init Tasks - Generate Cloud-Init Configuration
# =============================================================================
- name: Create cloud-init directory
file:
path: /tmp/cloud-init-{{ deploy_linux_vm_name }}
state: directory
mode: '0755'
tags: [cloud-init]
- name: Create cloud-init meta-data
template:
src: meta-data.j2
dest: /tmp/cloud-init-{{ deploy_linux_vm_name }}/meta-data
mode: '0644'
tags: [cloud-init]
- name: Create cloud-init user-data for Debian/Ubuntu
template:
src: user-data-debian.j2
dest: /tmp/cloud-init-{{ deploy_linux_vm_name }}/user-data
mode: '0644'
when: deploy_linux_vm_distro_config.family == "debian"
tags: [cloud-init]
- name: Create cloud-init user-data for RHEL/CentOS/Rocky/Alma
template:
src: user-data-rhel.j2
dest: /tmp/cloud-init-{{ deploy_linux_vm_name }}/user-data
mode: '0644'
when: deploy_linux_vm_distro_config.family == "rhel"
tags: [cloud-init]
- name: Create cloud-init user-data for SUSE/openSUSE
template:
src: user-data-suse.j2
dest: /tmp/cloud-init-{{ deploy_linux_vm_name }}/user-data
mode: '0644'
when: deploy_linux_vm_distro_config.family == "suse"
tags: [cloud-init]
- name: Create cloud-init ISO
command: >
genisoimage -output {{ deploy_linux_vm_cloud_init_iso_path }}
-volid cidata -joliet -rock
/tmp/cloud-init-{{ deploy_linux_vm_name }}/user-data
/tmp/cloud-init-{{ deploy_linux_vm_name }}/meta-data
args:
creates: "{{ deploy_linux_vm_cloud_init_iso_path }}"
tags: [cloud-init]
- name: Set proper permissions on cloud-init ISO (Debian/Ubuntu)
file:
path: "{{ deploy_linux_vm_cloud_init_iso_path }}"
owner: libvirt-qemu
group: kvm
mode: '0644'
when: ansible_os_family == "Debian"
tags: [cloud-init]
- name: Set proper permissions on cloud-init ISO (RHEL)
file:
path: "{{ deploy_linux_vm_cloud_init_iso_path }}"
owner: qemu
group: qemu
mode: '0644'
when: ansible_os_family == "RedHat"
tags: [cloud-init]

View File

@@ -0,0 +1,84 @@
---
# =============================================================================
# Deployment Tasks - Create and Start VM
# =============================================================================
- name: Build virt-install disk parameters
set_fact:
deploy_linux_vm_disk_params: >-
--disk path={{ deploy_linux_vm_disk_path }},format=qcow2,bus=virtio
{% if deploy_linux_vm_use_lvm | bool %}
--disk path={{ deploy_linux_vm_images_dir }}/{{ deploy_linux_vm_name }}-lvm.qcow2,format=qcow2,bus=virtio
{% endif %}
--disk path={{ deploy_linux_vm_cloud_init_iso_path }},device=cdrom
tags: [deploy]
- name: Create VM using virt-install
command: >
virt-install
--name {{ deploy_linux_vm_name }}
--memory {{ deploy_linux_vm_memory_mb }}
--vcpus {{ deploy_linux_vm_vcpus }}
{{ deploy_linux_vm_disk_params }}
--network network={{ deploy_linux_vm_network }},model=virtio
--os-variant {{ deploy_linux_vm_distro_config.os_variant }}
--graphics none
--console pty,target_type=serial
--import
--noautoconsole
register: deploy_linux_vm_create
tags: [deploy]
- name: Display VM creation result
debug:
msg:
- "=== VM Created ==="
- "VM Name: {{ deploy_linux_vm_name }}"
- "Distribution: {{ deploy_linux_vm_os_distribution }}"
- "Waiting for boot and cloud-init..."
tags: [deploy]
- name: Wait for VM to boot and cloud-init to complete
pause:
seconds: "{{ deploy_linux_vm_wait_for_boot_seconds }}"
prompt: "Waiting for VM to boot and cloud-init to complete configuration..."
tags: [deploy]
- name: Get VM IP address
shell: |
virsh domifaddr {{ deploy_linux_vm_name }} | grep -oP '(\d{1,3}\.){3}\d{1,3}' | head -1
register: deploy_linux_vm_ip_result
retries: 15
delay: 10
until: deploy_linux_vm_ip_result.stdout != ""
changed_when: false
tags: [deploy]
- name: Set VM IP fact
set_fact:
deploy_linux_vm_ip: "{{ deploy_linux_vm_ip_result.stdout }}"
tags: [deploy]
- name: Display VM information
debug:
msg:
- "=== VM Deployment Successful ==="
- "VM Name: {{ deploy_linux_vm_name }}"
- "Distribution: {{ deploy_linux_vm_os_distribution }}"
- "IP Address: {{ deploy_linux_vm_ip }}"
- "vCPUs: {{ deploy_linux_vm_vcpus }}"
- "Memory: {{ deploy_linux_vm_memory_mb }} MB"
- "Disk: {{ deploy_linux_vm_disk_size_gb }} GB"
- "OS Variant: {{ deploy_linux_vm_distro_config.os_variant }}"
- "Package Manager: {{ deploy_linux_vm_distro_config.package_manager }}"
- "LVM Enabled: {{ deploy_linux_vm_use_lvm }}"
- "Access: ssh {{ deploy_linux_vm_ansible_user }}@{{ deploy_linux_vm_ip }}"
tags: [deploy]
- name: Test SSH connectivity to new VM
wait_for:
host: "{{ deploy_linux_vm_ip }}"
port: 22
timeout: "{{ deploy_linux_vm_ssh_wait_timeout }}"
state: started
tags: [deploy]

View File

@@ -0,0 +1,79 @@
---
# =============================================================================
# Download Tasks - Download and Verify Cloud Images
# =============================================================================
- name: Check if cloud image already exists
stat:
path: "{{ deploy_linux_vm_image_cache_path }}"
register: deploy_linux_vm_cloud_image_stat
tags: [download]
- name: Display image cache status
debug:
msg: "Cloud image {{ 'exists' if deploy_linux_vm_cloud_image_stat.stat.exists else 'not found' }}: {{ deploy_linux_vm_image_cache_path }}"
tags: [download]
- name: Check for manual download requirement
debug:
msg:
- "WARNING: {{ deploy_linux_vm_os_distribution }} requires manual download"
- "{{ deploy_linux_vm_distro_config.note | default('') }}"
- "Please download the image and place it at: {{ deploy_linux_vm_image_cache_path }}"
when:
- not deploy_linux_vm_cloud_image_stat.stat.exists
- deploy_linux_vm_distro_config.note is defined
tags: [download]
- name: Download cloud image
get_url:
url: "{{ deploy_linux_vm_distro_config.url }}"
dest: "{{ deploy_linux_vm_image_cache_path }}"
mode: '0644'
timeout: 1200
when:
- not deploy_linux_vm_cloud_image_stat.stat.exists
- deploy_linux_vm_distro_config.note is not defined
register: deploy_linux_vm_download_result
tags: [download]
- name: Download checksum file
get_url:
url: "{{ deploy_linux_vm_distro_config.checksum_url }}"
dest: "/tmp/{{ deploy_linux_vm_os_distribution }}-CHECKSUM"
mode: '0644'
when:
- deploy_linux_vm_distro_config.checksum_url is defined
- deploy_linux_vm_download_result is changed or deploy_linux_vm_cloud_image_stat.stat.exists
tags: [download, verify]
- name: Verify cloud image checksum (SHA512)
shell: |
cd {{ deploy_linux_vm_images_dir }}
grep "{{ deploy_linux_vm_distro_config.cache_name }}" /tmp/{{ deploy_linux_vm_os_distribution }}-CHECKSUM | sha512sum -c -
register: deploy_linux_vm_checksum_result
changed_when: false
when:
- deploy_linux_vm_distro_config.checksum_type is defined
- deploy_linux_vm_distro_config.checksum_type == "sha512"
- deploy_linux_vm_distro_config.checksum_url is defined
tags: [verify]
- name: Verify cloud image checksum (SHA256)
shell: |
cd {{ deploy_linux_vm_images_dir }}
grep "{{ deploy_linux_vm_distro_config.cache_name }}" /tmp/{{ deploy_linux_vm_os_distribution }}-CHECKSUM | sha256sum -c -
register: deploy_linux_vm_checksum_result
changed_when: false
when:
- deploy_linux_vm_distro_config.checksum_type is defined
- deploy_linux_vm_distro_config.checksum_type == "sha256"
- deploy_linux_vm_distro_config.checksum_url is defined
tags: [verify]
- name: Ensure image file exists before proceeding
stat:
path: "{{ deploy_linux_vm_image_cache_path }}"
register: deploy_linux_vm_final_image_check
failed_when: not deploy_linux_vm_final_image_check.stat.exists
tags: [verify]

View File

@@ -0,0 +1,64 @@
---
# =============================================================================
# Installation Tasks - Install Required Packages on Hypervisor
# =============================================================================
- name: Install required packages for VM deployment (Debian/Ubuntu)
apt:
name:
- libvirt-daemon-system
- libvirt-clients
- virtinst
- qemu-kvm
- qemu-utils
- cloud-image-utils
- genisoimage
- wget
- curl
- python3-libvirt
- lvm2
- parted
state: present
update_cache: yes
when: ansible_os_family == "Debian"
tags: [install]
- name: Install required packages for VM deployment (RHEL/CentOS)
dnf:
name:
- libvirt
- libvirt-client
- virt-install
- qemu-kvm
- qemu-img
- cloud-utils
- genisoimage
- wget
- curl
- python3-libvirt
- lvm2
- parted
state: present
when: ansible_os_family == "RedHat"
tags: [install]
- name: Ensure libvirtd service is running
systemd:
name: libvirtd
state: started
enabled: yes
tags: [install]
- name: Ensure default libvirt network is active
command: virsh net-start default
register: deploy_linux_vm_net_start
failed_when: false
changed_when: deploy_linux_vm_net_start.rc == 0
tags: [install]
- name: Ensure default libvirt network is autostarted
command: virsh net-autostart default
register: deploy_linux_vm_net_autostart
failed_when: false
changed_when: false
tags: [install]

View File

@@ -0,0 +1,185 @@
---
# =============================================================================
# LVM Configuration Tasks - Configure LVM on Deployed VM
# =============================================================================
# This task file configures LVM on the deployed VM per CLAUDE.md requirements
- name: Wait for cloud-init to complete on VM
delegate_to: "{{ deploy_linux_vm_ip }}"
command: cloud-init status --wait
changed_when: false
failed_when: false
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Install LVM packages on VM (Debian/Ubuntu)
delegate_to: "{{ deploy_linux_vm_ip }}"
apt:
name:
- lvm2
- parted
state: present
update_cache: yes
when: deploy_linux_vm_distro_config.family == "debian"
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Install LVM packages on VM (RHEL)
delegate_to: "{{ deploy_linux_vm_ip }}"
dnf:
name:
- lvm2
- parted
state: present
when: deploy_linux_vm_distro_config.family == "rhel"
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Create Physical Volume on {{ deploy_linux_vm_lvm_pv_device }}
delegate_to: "{{ deploy_linux_vm_ip }}"
command: pvcreate {{ deploy_linux_vm_lvm_pv_device }}
register: deploy_linux_vm_pvcreate_result
failed_when: false
changed_when: deploy_linux_vm_pvcreate_result.rc == 0
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Create Volume Group {{ deploy_linux_vm_lvm_vg_name }}
delegate_to: "{{ deploy_linux_vm_ip }}"
lvg:
vg: "{{ deploy_linux_vm_lvm_vg_name }}"
pvs: "{{ deploy_linux_vm_lvm_pv_device }}"
state: present
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Create Logical Volumes
delegate_to: "{{ deploy_linux_vm_ip }}"
lvol:
vg: "{{ deploy_linux_vm_lvm_vg_name }}"
lv: "{{ item.name }}"
size: "{{ item.size }}"
state: present
loop: "{{ deploy_linux_vm_lvm_volumes }}"
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Create filesystems on logical volumes (non-swap)
delegate_to: "{{ deploy_linux_vm_ip }}"
filesystem:
fstype: "{{ item.fstype }}"
dev: "/dev/{{ deploy_linux_vm_lvm_vg_name }}/{{ item.name }}"
loop: "{{ deploy_linux_vm_lvm_volumes }}"
when: item.fstype != "swap"
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Create swap filesystem
delegate_to: "{{ deploy_linux_vm_ip }}"
command: mkswap /dev/{{ deploy_linux_vm_lvm_vg_name }}/{{ item.name }}
loop: "{{ deploy_linux_vm_lvm_volumes }}"
when: item.fstype == "swap"
register: deploy_linux_vm_mkswap_result
failed_when: false
changed_when: deploy_linux_vm_mkswap_result.rc == 0
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Create temporary mount points
delegate_to: "{{ deploy_linux_vm_ip }}"
file:
path: "/mnt/{{ item.name | regex_replace('^lv_', '') | regex_replace('_', '-') }}"
state: directory
mode: '0755'
loop: "{{ deploy_linux_vm_lvm_volumes }}"
when: item.fstype != "swap"
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Mount logical volumes temporarily for data copy
delegate_to: "{{ deploy_linux_vm_ip }}"
mount:
path: "/mnt/{{ item.name | regex_replace('^lv_', '') | regex_replace('_', '-') }}"
src: "/dev/{{ deploy_linux_vm_lvm_vg_name }}/{{ item.name }}"
fstype: "{{ item.fstype }}"
state: mounted
loop: "{{ deploy_linux_vm_lvm_volumes }}"
when: item.fstype != "swap"
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Copy existing data to LVM volumes
delegate_to: "{{ deploy_linux_vm_ip }}"
shell: |
if [ -d "{{ item.mount }}" ] && [ "$(ls -A {{ item.mount }})" ]; then
rsync -av {{ item.mount }}/ /mnt/{{ item.name | regex_replace('^lv_', '') | regex_replace('_', '-') }}/
fi
loop: "{{ deploy_linux_vm_lvm_volumes }}"
when:
- item.fstype != "swap"
- item.mount != "none"
register: deploy_linux_vm_rsync_result
failed_when: false
changed_when: deploy_linux_vm_rsync_result.rc == 0
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Unmount temporary mount points
delegate_to: "{{ deploy_linux_vm_ip }}"
mount:
path: "/mnt/{{ item.name | regex_replace('^lv_', '') | regex_replace('_', '-') }}"
state: unmounted
loop: "{{ deploy_linux_vm_lvm_volumes }}"
when: item.fstype != "swap"
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Update /etc/fstab with LVM mounts
delegate_to: "{{ deploy_linux_vm_ip }}"
lineinfile:
path: /etc/fstab
line: "/dev/{{ deploy_linux_vm_lvm_vg_name }}/{{ item.name }} {{ item.mount }} {{ item.fstype }} {{ item.mount_options }} 0 {{ '0' if item.fstype == 'swap' else '2' }}"
state: present
loop: "{{ deploy_linux_vm_lvm_volumes }}"
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
tags: [lvm, post-deploy]
- name: Display LVM configuration summary
debug:
msg:
- "=== LVM Configuration Complete ==="
- "Volume Group: {{ deploy_linux_vm_lvm_vg_name }}"
- "Physical Volume: {{ deploy_linux_vm_lvm_pv_device }} (30GB)"
- "Logical Volumes: {{ deploy_linux_vm_lvm_volumes | length }}"
- ""
- "⚠️ IMPORTANT: VM needs reboot to use new mounts"
- "After reboot, LVM volumes will be mounted automatically"
- ""
- "To reboot: ssh {{ deploy_linux_vm_ansible_user }}@{{ deploy_linux_vm_ip }} 'sudo reboot'"
tags: [lvm, post-deploy]

View File

@@ -0,0 +1,42 @@
---
# =============================================================================
# Deploy Linux VM Role - Main Tasks
# =============================================================================
- name: Include validation tasks
include_tasks: validate.yml
tags: [validate, preflight, always]
- name: Include installation tasks
include_tasks: install.yml
tags: [install]
- name: Include download tasks
include_tasks: download.yml
tags: [download]
- name: Include storage tasks
include_tasks: storage.yml
tags: [storage]
- name: Include cloud-init tasks
include_tasks: cloud-init.yml
tags: [cloud-init]
- name: Include deployment tasks
include_tasks: deploy.yml
tags: [deploy]
- name: Include LVM configuration tasks
include_tasks: lvm.yml
when: deploy_linux_vm_use_lvm | bool
tags: [lvm, post-deploy]
- name: Include validation tasks (post-deployment)
include_tasks: post-validate.yml
tags: [validate, post-deploy]
- name: Include cleanup tasks
include_tasks: cleanup.yml
when: deploy_linux_vm_cleanup_temp_files | bool
tags: [cleanup]

View File

@@ -0,0 +1,82 @@
---
# =============================================================================
# Post-Validation Tasks - Validate Deployed VM
# =============================================================================
- name: Get VM details
command: virsh dominfo {{ deploy_linux_vm_name }}
register: deploy_linux_vm_details
changed_when: false
tags: [validate, post-deploy]
- name: Display VM details
debug:
var: deploy_linux_vm_details.stdout_lines
tags: [validate, post-deploy]
- name: Check VM is running
command: virsh list --name
register: deploy_linux_vm_running_vms
changed_when: false
failed_when: deploy_linux_vm_name not in deploy_linux_vm_running_vms.stdout_lines
tags: [validate, post-deploy]
- name: Validate SSH connectivity
wait_for:
host: "{{ deploy_linux_vm_ip }}"
port: 22
timeout: 60
state: started
when: not deploy_linux_vm_skip_validation
tags: [validate, post-deploy]
- name: Gather system information from VM
delegate_to: "{{ deploy_linux_vm_ip }}"
setup:
register: deploy_linux_vm_facts
vars:
ansible_user: "{{ deploy_linux_vm_ansible_user }}"
ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'
when: not deploy_linux_vm_skip_validation
tags: [validate, post-deploy]
- name: Display VM system information
debug:
msg:
- "=== System Information ==="
- "OS: {{ deploy_linux_vm_facts.ansible_facts.ansible_distribution }} {{ deploy_linux_vm_facts.ansible_facts.ansible_distribution_version }}"
- "Kernel: {{ deploy_linux_vm_facts.ansible_facts.ansible_kernel }}"
- "Architecture: {{ deploy_linux_vm_facts.ansible_facts.ansible_architecture }}"
- "Hostname: {{ deploy_linux_vm_facts.ansible_facts.ansible_hostname }}"
- "FQDN: {{ deploy_linux_vm_facts.ansible_facts.ansible_fqdn }}"
- "Python: {{ deploy_linux_vm_facts.ansible_facts.ansible_python_version }}"
when: not deploy_linux_vm_skip_validation
tags: [validate, post-deploy]
- name: Display deployment summary
debug:
msg:
- "╔════════════════════════════════════════════════════════════════╗"
- "║ VM Deployment Successfully Completed ║"
- "╚════════════════════════════════════════════════════════════════╝"
- ""
- "VM Details:"
- " Name: {{ deploy_linux_vm_name }}"
- " Distribution: {{ deploy_linux_vm_os_distribution }}"
- " IP Address: {{ deploy_linux_vm_ip }}"
- " Resources: {{ deploy_linux_vm_vcpus }} vCPUs, {{ deploy_linux_vm_memory_mb }}MB RAM, {{ deploy_linux_vm_disk_size_gb }}GB Disk"
- " LVM: {{ 'Enabled' if deploy_linux_vm_use_lvm else 'Disabled' }}"
- ""
- "Access:"
- " ssh {{ deploy_linux_vm_ansible_user }}@{{ deploy_linux_vm_ip }}"
- " ssh -J {{ inventory_hostname }} {{ deploy_linux_vm_ansible_user }}@{{ deploy_linux_vm_ip }}"
- ""
- "Add to Ansible inventory:"
- " {{ deploy_linux_vm_name }}:"
- " ansible_host: {{ deploy_linux_vm_ip }}"
- " ansible_user: {{ deploy_linux_vm_ansible_user }}"
- " ansible_ssh_common_args: '-o ProxyJump={{ inventory_hostname }} -o StrictHostKeyChecking=accept-new'"
- " os_distribution: {{ deploy_linux_vm_os_distribution }}"
- " os_family: {{ deploy_linux_vm_distro_config.family }}"
- ""
tags: [validate, post-deploy]

View File

@@ -0,0 +1,64 @@
---
# =============================================================================
# Storage Tasks - Create VM Disk Images
# =============================================================================
- name: Create primary VM disk from cloud image
command: >
qemu-img create -f qcow2 -F qcow2
-b {{ deploy_linux_vm_image_cache_path }}
{{ deploy_linux_vm_disk_path }}
{{ deploy_linux_vm_disk_size_gb }}G
args:
creates: "{{ deploy_linux_vm_disk_path }}"
tags: [storage]
- name: Set proper permissions on VM disk (Debian/Ubuntu)
file:
path: "{{ deploy_linux_vm_disk_path }}"
owner: libvirt-qemu
group: kvm
mode: '0600'
when: ansible_os_family == "Debian"
tags: [storage]
- name: Set proper permissions on VM disk (RHEL)
file:
path: "{{ deploy_linux_vm_disk_path }}"
owner: qemu
group: qemu
mode: '0600'
when: ansible_os_family == "RedHat"
tags: [storage]
- name: Create LVM data disk for VM
command: >
qemu-img create -f qcow2
{{ deploy_linux_vm_images_dir }}/{{ deploy_linux_vm_name }}-lvm.qcow2
30G
args:
creates: "{{ deploy_linux_vm_images_dir }}/{{ deploy_linux_vm_name }}-lvm.qcow2"
when: deploy_linux_vm_use_lvm | bool
tags: [storage, lvm]
- name: Set proper permissions on LVM disk (Debian/Ubuntu)
file:
path: "{{ deploy_linux_vm_images_dir }}/{{ deploy_linux_vm_name }}-lvm.qcow2"
owner: libvirt-qemu
group: kvm
mode: '0600'
when:
- deploy_linux_vm_use_lvm | bool
- ansible_os_family == "Debian"
tags: [storage, lvm]
- name: Set proper permissions on LVM disk (RHEL)
file:
path: "{{ deploy_linux_vm_images_dir }}/{{ deploy_linux_vm_name }}-lvm.qcow2"
owner: qemu
group: qemu
mode: '0600'
when:
- deploy_linux_vm_use_lvm | bool
- ansible_os_family == "RedHat"
tags: [storage, lvm]

View File

@@ -0,0 +1,82 @@
---
# =============================================================================
# Validation Tasks - Pre-flight Checks
# =============================================================================
- name: Validate distribution selection
assert:
that:
- deploy_linux_vm_os_distribution is defined
- deploy_linux_vm_os_distribution in deploy_linux_vm_cloud_images.keys()
fail_msg: |
Invalid distribution '{{ deploy_linux_vm_os_distribution }}'.
Supported distributions: {{ deploy_linux_vm_cloud_images.keys() | list | join(', ') }}
success_msg: "Distribution '{{ deploy_linux_vm_os_distribution }}' is valid"
tags: [validate, preflight]
- name: Set distribution facts
set_fact:
deploy_linux_vm_distro_config: "{{ deploy_linux_vm_cloud_images[deploy_linux_vm_os_distribution] }}"
deploy_linux_vm_image_cache_path: "{{ deploy_linux_vm_images_dir }}/{{ deploy_linux_vm_cloud_images[deploy_linux_vm_os_distribution].cache_name }}"
tags: [always]
- name: Display deployment information
debug:
msg:
- "=== VM Deployment Configuration ==="
- "VM Name: {{ deploy_linux_vm_name }}"
- "Distribution: {{ deploy_linux_vm_os_distribution }}"
- "OS Family: {{ deploy_linux_vm_distro_config.family }}"
- "Package Manager: {{ deploy_linux_vm_distro_config.package_manager }}"
- "vCPUs: {{ deploy_linux_vm_vcpus }}"
- "Memory: {{ deploy_linux_vm_memory_mb }} MB"
- "Disk: {{ deploy_linux_vm_disk_size_gb }} GB"
- "LVM Enabled: {{ deploy_linux_vm_use_lvm }}"
tags: [validate, preflight]
- name: Validate VM name
assert:
that:
- deploy_linux_vm_name is defined
- deploy_linux_vm_name | length > 0
- deploy_linux_vm_name is match('^[a-zA-Z0-9_-]+$')
fail_msg: "VM name must be defined and contain only alphanumeric characters, hyphens, or underscores"
success_msg: "VM name '{{ deploy_linux_vm_name }}' is valid"
tags: [validate, preflight]
- name: Check if VM already exists
command: virsh dominfo {{ deploy_linux_vm_name }}
register: deploy_linux_vm_exists_check
failed_when: false
changed_when: false
tags: [validate, preflight]
- name: Fail if VM already exists
fail:
msg: "VM '{{ deploy_linux_vm_name }}' already exists on hypervisor. Please choose a different name or destroy the existing VM."
when: deploy_linux_vm_exists_check.rc == 0
tags: [validate, preflight]
- name: Verify virtualization support
command: virt-host-validate qemu
register: deploy_linux_vm_virt_validation
failed_when: false
changed_when: false
tags: [validate, preflight]
- name: Display virtualization validation results
debug:
var: deploy_linux_vm_virt_validation.stdout_lines
tags: [validate, preflight]
- name: Validate LVM configuration
assert:
that:
- deploy_linux_vm_lvm_vg_name is defined
- deploy_linux_vm_lvm_pv_device is defined
- deploy_linux_vm_lvm_volumes is defined
- deploy_linux_vm_lvm_volumes | length > 0
fail_msg: "LVM is enabled but configuration is incomplete"
success_msg: "LVM configuration is valid"
when: deploy_linux_vm_use_lvm | bool
tags: [validate, preflight, lvm]