Add multi-distribution VM deployment playbooks
- Add deploy-debian12-vm.yml for basic Debian 12 deployment - Add deploy-linux-vm.yml for multi-distribution support - Support for Debian, Ubuntu, RHEL, CentOS, Rocky, Alma, SUSE - Cloud-init based provisioning - Distribution-specific security hardening - Automatic security updates configuration - UFW/firewalld setup per OS family - SELinux enforcing for RHEL family
This commit is contained in:
479
plays/deploy-debian12-vm.yml
Normal file
479
plays/deploy-debian12-vm.yml
Normal file
@@ -0,0 +1,479 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Debian 12 VM Deployment Playbook
|
||||
# =============================================================================
|
||||
# Deploys a new Debian 12 guest VM on grokbox KVM hypervisor
|
||||
# Uses libvirt/KVM with cloud-init for unattended configuration
|
||||
# =============================================================================
|
||||
|
||||
- name: Deploy Debian 12 VM on grokbox 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: 20
|
||||
|
||||
# Network Configuration
|
||||
vm_network: "default"
|
||||
vm_bridge: "virbr0"
|
||||
|
||||
# Storage Configuration
|
||||
vm_disk_path: "/var/lib/libvirt/images/{{ vm_name }}.qcow2"
|
||||
cloud_init_iso_path: "/var/lib/libvirt/images/{{ vm_name }}-cloud-init.iso"
|
||||
|
||||
# Debian 12 Cloud Image
|
||||
debian_cloud_image_url: "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2"
|
||||
debian_cloud_image_checksum_url: "https://cloud.debian.org/images/cloud/bookworm/latest/SHA512SUMS"
|
||||
debian_image_cache: "/var/lib/libvirt/images/debian-12-generic-amd64.qcow2"
|
||||
|
||||
# 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 on hypervisor. Please choose a different name or destroy the existing VM."
|
||||
when: vm_exists.rc == 0
|
||||
tags: [validate, preflight]
|
||||
|
||||
- name: Verify virtualization support
|
||||
command: virt-host-validate qemu
|
||||
register: virt_validation
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
tags: [validate, preflight]
|
||||
|
||||
- name: Display virtualization validation results
|
||||
debug:
|
||||
var: virt_validation.stdout_lines
|
||||
tags: [validate, preflight]
|
||||
|
||||
# =========================================================================
|
||||
# Package Installation
|
||||
# =========================================================================
|
||||
|
||||
- name: Install required packages for VM deployment
|
||||
package:
|
||||
name:
|
||||
- libvirt-daemon-system
|
||||
- libvirt-clients
|
||||
- virtinst
|
||||
- qemu-kvm
|
||||
- qemu-utils
|
||||
- cloud-image-utils
|
||||
- genisoimage
|
||||
- wget
|
||||
- python3-libvirt
|
||||
state: present
|
||||
tags: [install]
|
||||
|
||||
- name: Ensure libvirtd service is running
|
||||
systemd:
|
||||
name: libvirtd
|
||||
state: started
|
||||
enabled: yes
|
||||
tags: [install]
|
||||
|
||||
# =========================================================================
|
||||
# Download Debian Cloud Image
|
||||
# =========================================================================
|
||||
|
||||
- name: Check if Debian cloud image already exists
|
||||
stat:
|
||||
path: "{{ debian_image_cache }}"
|
||||
register: debian_image_stat
|
||||
tags: [download]
|
||||
|
||||
- name: Download Debian 12 cloud image
|
||||
get_url:
|
||||
url: "{{ debian_cloud_image_url }}"
|
||||
dest: "{{ debian_image_cache }}"
|
||||
mode: '0644'
|
||||
timeout: 600
|
||||
when: not debian_image_stat.stat.exists
|
||||
tags: [download]
|
||||
|
||||
- name: Download Debian 12 checksums
|
||||
get_url:
|
||||
url: "{{ debian_cloud_image_checksum_url }}"
|
||||
dest: "/tmp/debian-12-SHA512SUMS"
|
||||
mode: '0644'
|
||||
tags: [download, verify]
|
||||
|
||||
- name: Verify cloud image checksum
|
||||
shell: |
|
||||
cd /var/lib/libvirt/images
|
||||
grep "debian-12-generic-amd64.qcow2" /tmp/debian-12-SHA512SUMS | sha512sum -c -
|
||||
register: checksum_result
|
||||
changed_when: false
|
||||
tags: [download, verify]
|
||||
|
||||
# =========================================================================
|
||||
# Create VM Disk
|
||||
# =========================================================================
|
||||
|
||||
- name: Create VM disk from cloud image
|
||||
command: >
|
||||
qemu-img create -f qcow2 -F qcow2
|
||||
-b {{ debian_image_cache }}
|
||||
{{ vm_disk_path }}
|
||||
{{ vm_disk_size_gb }}G
|
||||
args:
|
||||
creates: "{{ vm_disk_path }}"
|
||||
tags: [storage]
|
||||
|
||||
- name: Set proper permissions on VM disk
|
||||
file:
|
||||
path: "{{ vm_disk_path }}"
|
||||
owner: libvirt-qemu
|
||||
group: kvm
|
||||
mode: '0600'
|
||||
tags: [storage]
|
||||
|
||||
# =========================================================================
|
||||
# Create Cloud-Init Configuration
|
||||
# =========================================================================
|
||||
|
||||
- name: Create cloud-init directory
|
||||
file:
|
||||
path: /tmp/cloud-init-{{ vm_name }}
|
||||
state: directory
|
||||
mode: '0755'
|
||||
tags: [cloud-init]
|
||||
|
||||
- name: Create cloud-init meta-data
|
||||
copy:
|
||||
content: |
|
||||
instance-id: {{ vm_name }}
|
||||
local-hostname: {{ vm_hostname }}
|
||||
dest: /tmp/cloud-init-{{ vm_name }}/meta-data
|
||||
mode: '0644'
|
||||
tags: [cloud-init]
|
||||
|
||||
- name: Create cloud-init user-data
|
||||
copy:
|
||||
content: |
|
||||
#cloud-config
|
||||
hostname: {{ vm_hostname }}
|
||||
fqdn: {{ vm_hostname }}.{{ vm_domain }}
|
||||
manage_etc_hosts: true
|
||||
|
||||
# Create ansible user with sudo privileges
|
||||
users:
|
||||
- name: ansible
|
||||
groups: sudo
|
||||
shell: /bin/bash
|
||||
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
||||
ssh_authorized_keys:
|
||||
- {{ ansible_user_ssh_key }}
|
||||
- name: root
|
||||
lock_passwd: false
|
||||
|
||||
# Set root password (for emergency console access)
|
||||
chpasswd:
|
||||
list: |
|
||||
root:debian
|
||||
expire: false
|
||||
|
||||
# SSH configuration - secure by default
|
||||
ssh_pwauth: false
|
||||
disable_root: false
|
||||
|
||||
# Install essential packages per CLAUDE.md guidelines
|
||||
packages:
|
||||
- sudo
|
||||
- vim
|
||||
- htop
|
||||
- tmux
|
||||
- curl
|
||||
- wget
|
||||
- rsync
|
||||
- git
|
||||
- python3
|
||||
- python3-pip
|
||||
- jq
|
||||
- bc
|
||||
- aide
|
||||
- auditd
|
||||
- chrony
|
||||
- ufw
|
||||
- lvm2
|
||||
- cloud-guest-utils
|
||||
- parted
|
||||
- unattended-upgrades
|
||||
- apt-listchanges
|
||||
|
||||
# Security configuration files
|
||||
write_files:
|
||||
- path: /etc/ssh/sshd_config.d/99-security.conf
|
||||
content: |
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication no
|
||||
PubkeyAuthentication yes
|
||||
MaxAuthTries 3
|
||||
MaxSessions 10
|
||||
ClientAliveInterval 300
|
||||
ClientAliveCountMax 2
|
||||
permissions: '0644'
|
||||
|
||||
- path: /etc/sudoers.d/ansible
|
||||
content: |
|
||||
ansible ALL=(ALL) NOPASSWD:ALL
|
||||
permissions: '0440'
|
||||
|
||||
- path: /etc/apt/apt.conf.d/50unattended-upgrades
|
||||
content: |
|
||||
Unattended-Upgrade::Allowed-Origins {
|
||||
"${distro_id}:${distro_codename}-security";
|
||||
};
|
||||
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
|
||||
Unattended-Upgrade::MinimalSteps "true";
|
||||
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
||||
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
||||
Unattended-Upgrade::Automatic-Reboot "false";
|
||||
permissions: '0644'
|
||||
|
||||
- path: /etc/apt/apt.conf.d/20auto-upgrades
|
||||
content: |
|
||||
APT::Periodic::Update-Package-Lists "1";
|
||||
APT::Periodic::Unattended-Upgrade "1";
|
||||
APT::Periodic::AutocleanInterval "7";
|
||||
permissions: '0644'
|
||||
|
||||
# System configuration commands
|
||||
runcmd:
|
||||
# SSH service
|
||||
- systemctl enable ssh
|
||||
- systemctl restart ssh
|
||||
|
||||
# Time synchronization
|
||||
- systemctl enable chrony
|
||||
- systemctl start chrony
|
||||
|
||||
# Firewall - enable but allow SSH
|
||||
- ufw --force enable
|
||||
- ufw allow ssh
|
||||
|
||||
# Audit daemon
|
||||
- systemctl enable auditd
|
||||
- systemctl start auditd
|
||||
|
||||
# Grow root partition
|
||||
- growpart /dev/vda 1 || true
|
||||
- resize2fs /dev/vda1 || true
|
||||
|
||||
# Package updates
|
||||
package_update: true
|
||||
package_upgrade: true
|
||||
package_reboot_if_required: false
|
||||
|
||||
# Set timezone
|
||||
timezone: UTC
|
||||
|
||||
# Locale
|
||||
locale: en_US.UTF-8
|
||||
|
||||
# Enable cloud-init logging
|
||||
output:
|
||||
all: '| tee -a /var/log/cloud-init-output.log'
|
||||
|
||||
# Final message
|
||||
final_message: "Debian 12 VM deployment completed. System is ready after $UPTIME seconds."
|
||||
dest: /tmp/cloud-init-{{ vm_name }}/user-data
|
||||
mode: '0644'
|
||||
tags: [cloud-init]
|
||||
|
||||
- name: Create cloud-init ISO
|
||||
command: >
|
||||
genisoimage -output {{ cloud_init_iso_path }}
|
||||
-volid cidata -joliet -rock
|
||||
/tmp/cloud-init-{{ vm_name }}/user-data
|
||||
/tmp/cloud-init-{{ vm_name }}/meta-data
|
||||
args:
|
||||
creates: "{{ cloud_init_iso_path }}"
|
||||
tags: [cloud-init]
|
||||
|
||||
- name: Set proper permissions on cloud-init ISO
|
||||
file:
|
||||
path: "{{ cloud_init_iso_path }}"
|
||||
owner: libvirt-qemu
|
||||
group: kvm
|
||||
mode: '0644'
|
||||
tags: [cloud-init]
|
||||
|
||||
# =========================================================================
|
||||
# Create and Start VM
|
||||
# =========================================================================
|
||||
|
||||
- name: Create VM using virt-install
|
||||
command: >
|
||||
virt-install
|
||||
--name {{ vm_name }}
|
||||
--memory {{ vm_memory_mb }}
|
||||
--vcpus {{ vm_vcpus }}
|
||||
--disk path={{ vm_disk_path }},format=qcow2,bus=virtio
|
||||
--disk path={{ cloud_init_iso_path }},device=cdrom
|
||||
--network network={{ vm_network }},model=virtio
|
||||
--os-variant debian11
|
||||
--graphics none
|
||||
--console pty,target_type=serial
|
||||
--import
|
||||
--noautoconsole
|
||||
register: vm_create
|
||||
tags: [deploy]
|
||||
|
||||
- name: Wait for VM to boot and cloud-init to complete
|
||||
pause:
|
||||
seconds: 60
|
||||
prompt: "Waiting for VM to boot and cloud-init to complete configuration..."
|
||||
tags: [deploy]
|
||||
|
||||
- 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: [deploy, validate]
|
||||
|
||||
- name: Display VM information
|
||||
debug:
|
||||
msg:
|
||||
- "=== VM Deployment Successful ==="
|
||||
- "VM Name: {{ vm_name }}"
|
||||
- "IP Address: {{ vm_ip.stdout }}"
|
||||
- "vCPUs: {{ vm_vcpus }}"
|
||||
- "Memory: {{ vm_memory_mb }} MB"
|
||||
- "Disk: {{ vm_disk_size_gb }} GB"
|
||||
- "Access: ssh ansible@{{ vm_ip.stdout }}"
|
||||
- ""
|
||||
- "Note: Add this VM to your Ansible inventory:"
|
||||
- " {{ vm_name }}:"
|
||||
- " ansible_host: {{ vm_ip.stdout }}"
|
||||
- " ansible_user: ansible"
|
||||
- " ansible_ssh_common_args: '-o ProxyJump=grokbox -o StrictHostKeyChecking=accept-new'"
|
||||
tags: [deploy, validate]
|
||||
|
||||
# =========================================================================
|
||||
# Validation and Health Check
|
||||
# =========================================================================
|
||||
|
||||
- name: Test SSH connectivity to new VM
|
||||
wait_for:
|
||||
host: "{{ vm_ip.stdout }}"
|
||||
port: 22
|
||||
timeout: 300
|
||||
state: started
|
||||
tags: [validate]
|
||||
|
||||
- name: Display VM console log (for troubleshooting)
|
||||
command: virsh console {{ vm_name }} --force
|
||||
async: 5
|
||||
poll: 0
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
tags: [never, debug]
|
||||
|
||||
- name: Get VM details
|
||||
command: virsh dominfo {{ vm_name }}
|
||||
register: vm_details
|
||||
changed_when: false
|
||||
tags: [validate]
|
||||
|
||||
- name: Display VM details
|
||||
debug:
|
||||
var: vm_details.stdout_lines
|
||||
tags: [validate]
|
||||
|
||||
# =========================================================================
|
||||
# Cleanup
|
||||
# =========================================================================
|
||||
|
||||
- name: Remove temporary cloud-init directory
|
||||
file:
|
||||
path: /tmp/cloud-init-{{ vm_name }}
|
||||
state: absent
|
||||
tags: [cleanup]
|
||||
|
||||
- name: Remove downloaded checksums
|
||||
file:
|
||||
path: /tmp/debian-12-SHA512SUMS
|
||||
state: absent
|
||||
tags: [cleanup]
|
||||
|
||||
# =============================================================================
|
||||
# Post-Deployment Configuration
|
||||
# =============================================================================
|
||||
# After VM is deployed, run additional configuration playbooks
|
||||
|
||||
- name: Configure deployed VM
|
||||
hosts: "{{ vm_ip.stdout }}"
|
||||
gather_facts: yes
|
||||
become: yes
|
||||
vars:
|
||||
ansible_user: ansible
|
||||
ansible_ssh_common_args: '-o ProxyJump=grokbox -o StrictHostKeyChecking=accept-new'
|
||||
|
||||
tasks:
|
||||
- name: Wait for cloud-init to complete
|
||||
command: cloud-init status --wait
|
||||
changed_when: false
|
||||
tags: [validate]
|
||||
|
||||
- name: Gather system facts
|
||||
setup:
|
||||
tags: [validate]
|
||||
|
||||
- name: Display system information
|
||||
debug:
|
||||
msg:
|
||||
- "=== System Information ==="
|
||||
- "OS: {{ ansible_distribution }} {{ ansible_distribution_version }}"
|
||||
- "Kernel: {{ ansible_kernel }}"
|
||||
- "Architecture: {{ ansible_architecture }}"
|
||||
- "Hostname: {{ ansible_hostname }}"
|
||||
- "FQDN: {{ ansible_fqdn }}"
|
||||
- "Python: {{ ansible_python_version }}"
|
||||
tags: [validate]
|
||||
|
||||
- name: Gather disk usage
|
||||
command: df -h
|
||||
register: disk_usage
|
||||
changed_when: false
|
||||
tags: [validate]
|
||||
|
||||
- name: Display disk usage
|
||||
debug:
|
||||
var: disk_usage.stdout_lines
|
||||
tags: [validate]
|
||||
|
||||
- name: Gather memory usage
|
||||
command: free -h
|
||||
register: memory_usage
|
||||
changed_when: false
|
||||
tags: [validate]
|
||||
|
||||
- name: Display memory usage
|
||||
debug:
|
||||
var: memory_usage.stdout_lines
|
||||
tags: [validate]
|
||||
976
plays/deploy-linux-vm.yml
Normal file
976
plays/deploy-linux-vm.yml
Normal file
@@ -0,0 +1,976 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Multi-Distribution Linux VM Deployment Playbook
|
||||
# =============================================================================
|
||||
# Deploys Linux VMs on KVM hypervisor with support for:
|
||||
# - Debian (11, 12)
|
||||
# - Ubuntu (20.04 LTS, 22.04 LTS, 24.04 LTS)
|
||||
# - RHEL (8, 9)
|
||||
# - CentOS Stream (8, 9)
|
||||
# - Rocky Linux (8, 9)
|
||||
# - AlmaLinux (8, 9)
|
||||
# - SLES (15)
|
||||
# - openSUSE Leap (15)
|
||||
#
|
||||
# Uses libvirt/KVM with cloud-init for unattended configuration
|
||||
# =============================================================================
|
||||
|
||||
- name: Deploy Linux VM on KVM hypervisor
|
||||
hosts: grokbox
|
||||
gather_facts: yes
|
||||
become: yes
|
||||
|
||||
vars:
|
||||
# VM Configuration
|
||||
vm_name: "linux-guest"
|
||||
vm_hostname: "linux-vm"
|
||||
vm_domain: "localdomain"
|
||||
vm_vcpus: 2
|
||||
vm_memory_mb: 2048
|
||||
vm_disk_size_gb: 20
|
||||
|
||||
# Distribution Selection (REQUIRED - set via -e flag)
|
||||
# Format: "distro-version" or "distro-major.minor"
|
||||
# Examples: debian-12, ubuntu-22.04, rhel-9, centos-stream-9, sles-15
|
||||
os_distribution: "debian-12"
|
||||
|
||||
# Network Configuration
|
||||
vm_network: "default"
|
||||
vm_bridge: "virbr0"
|
||||
|
||||
# Storage Configuration
|
||||
vm_disk_path: "/var/lib/libvirt/images/{{ vm_name }}.qcow2"
|
||||
cloud_init_iso_path: "/var/lib/libvirt/images/{{ vm_name }}-cloud-init.iso"
|
||||
|
||||
# Ansible User Configuration
|
||||
ansible_user_ssh_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILBrnivsqjhAxWYeuuvnYc3neeRRuHsr2SjeKv+Drtpu user@debian"
|
||||
|
||||
# ==========================================================================
|
||||
# Cloud Image Repository Configuration
|
||||
# ==========================================================================
|
||||
cloud_images:
|
||||
# Debian
|
||||
debian-11:
|
||||
url: "https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.qcow2"
|
||||
checksum_url: "https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS"
|
||||
checksum_type: "sha512"
|
||||
os_variant: "debian11"
|
||||
cache_name: "debian-11-generic-amd64.qcow2"
|
||||
package_manager: "apt"
|
||||
family: "debian"
|
||||
|
||||
debian-12:
|
||||
url: "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2"
|
||||
checksum_url: "https://cloud.debian.org/images/cloud/bookworm/latest/SHA512SUMS"
|
||||
checksum_type: "sha512"
|
||||
os_variant: "debian12"
|
||||
cache_name: "debian-12-generic-amd64.qcow2"
|
||||
package_manager: "apt"
|
||||
family: "debian"
|
||||
|
||||
# Ubuntu
|
||||
ubuntu-20.04:
|
||||
url: "https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img"
|
||||
checksum_url: "https://cloud-images.ubuntu.com/focal/current/SHA256SUMS"
|
||||
checksum_type: "sha256"
|
||||
os_variant: "ubuntu20.04"
|
||||
cache_name: "ubuntu-20.04-server-cloudimg-amd64.img"
|
||||
package_manager: "apt"
|
||||
family: "debian"
|
||||
|
||||
ubuntu-22.04:
|
||||
url: "https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img"
|
||||
checksum_url: "https://cloud-images.ubuntu.com/jammy/current/SHA256SUMS"
|
||||
checksum_type: "sha256"
|
||||
os_variant: "ubuntu22.04"
|
||||
cache_name: "ubuntu-22.04-server-cloudimg-amd64.img"
|
||||
package_manager: "apt"
|
||||
family: "debian"
|
||||
|
||||
ubuntu-24.04:
|
||||
url: "https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
|
||||
checksum_url: "https://cloud-images.ubuntu.com/noble/current/SHA256SUMS"
|
||||
checksum_type: "sha256"
|
||||
os_variant: "ubuntu24.04"
|
||||
cache_name: "ubuntu-24.04-server-cloudimg-amd64.img"
|
||||
package_manager: "apt"
|
||||
family: "debian"
|
||||
|
||||
# RHEL (requires subscription)
|
||||
rhel-8:
|
||||
url: "https://access.redhat.com/downloads/content/rhel/8/x86_64/latest/rhel-8-x86_64-kvm.qcow2"
|
||||
os_variant: "rhel8.0"
|
||||
cache_name: "rhel-8-x86_64-kvm.qcow2"
|
||||
package_manager: "dnf"
|
||||
family: "rhel"
|
||||
note: "Requires Red Hat subscription and manual download"
|
||||
|
||||
rhel-9:
|
||||
url: "https://access.redhat.com/downloads/content/rhel/9/x86_64/latest/rhel-9-x86_64-kvm.qcow2"
|
||||
os_variant: "rhel9.0"
|
||||
cache_name: "rhel-9-x86_64-kvm.qcow2"
|
||||
package_manager: "dnf"
|
||||
family: "rhel"
|
||||
note: "Requires Red Hat subscription and manual download"
|
||||
|
||||
# CentOS Stream
|
||||
centos-stream-8:
|
||||
url: "https://cloud.centos.org/centos/8-stream/x86_64/images/CentOS-Stream-GenericCloud-8-latest.x86_64.qcow2"
|
||||
checksum_url: "https://cloud.centos.org/centos/8-stream/x86_64/images/CHECKSUM"
|
||||
checksum_type: "sha256"
|
||||
os_variant: "centos-stream8"
|
||||
cache_name: "centos-stream-8-genericcloud-amd64.qcow2"
|
||||
package_manager: "dnf"
|
||||
family: "rhel"
|
||||
|
||||
centos-stream-9:
|
||||
url: "https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2"
|
||||
checksum_url: "https://cloud.centos.org/centos/9-stream/x86_64/images/CHECKSUM"
|
||||
checksum_type: "sha256"
|
||||
os_variant: "centos-stream9"
|
||||
cache_name: "centos-stream-9-genericcloud-amd64.qcow2"
|
||||
package_manager: "dnf"
|
||||
family: "rhel"
|
||||
|
||||
# Rocky Linux
|
||||
rocky-8:
|
||||
url: "https://download.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-GenericCloud-Base.latest.x86_64.qcow2"
|
||||
checksum_url: "https://download.rockylinux.org/pub/rocky/8/images/x86_64/CHECKSUM"
|
||||
checksum_type: "sha256"
|
||||
os_variant: "rocky8"
|
||||
cache_name: "rocky-8-genericcloud-amd64.qcow2"
|
||||
package_manager: "dnf"
|
||||
family: "rhel"
|
||||
|
||||
rocky-9:
|
||||
url: "https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base.latest.x86_64.qcow2"
|
||||
checksum_url: "https://download.rockylinux.org/pub/rocky/9/images/x86_64/CHECKSUM"
|
||||
checksum_type: "sha256"
|
||||
os_variant: "rocky9"
|
||||
cache_name: "rocky-9-genericcloud-amd64.qcow2"
|
||||
package_manager: "dnf"
|
||||
family: "rhel"
|
||||
|
||||
# AlmaLinux
|
||||
almalinux-8:
|
||||
url: "https://repo.almalinux.org/almalinux/8/cloud/x86_64/images/AlmaLinux-8-GenericCloud-latest.x86_64.qcow2"
|
||||
checksum_url: "https://repo.almalinux.org/almalinux/8/cloud/x86_64/images/CHECKSUM"
|
||||
checksum_type: "sha256"
|
||||
os_variant: "almalinux8"
|
||||
cache_name: "almalinux-8-genericcloud-amd64.qcow2"
|
||||
package_manager: "dnf"
|
||||
family: "rhel"
|
||||
|
||||
almalinux-9:
|
||||
url: "https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2"
|
||||
checksum_url: "https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/CHECKSUM"
|
||||
checksum_type: "sha256"
|
||||
os_variant: "almalinux9"
|
||||
cache_name: "almalinux-9-genericcloud-amd64.qcow2"
|
||||
package_manager: "dnf"
|
||||
family: "rhel"
|
||||
|
||||
# SLES (requires registration)
|
||||
sles-15:
|
||||
url: "https://download.suse.com/Download?buildid=XXXXX"
|
||||
os_variant: "sles15"
|
||||
cache_name: "sles-15-genericcloud-amd64.qcow2"
|
||||
package_manager: "zypper"
|
||||
family: "suse"
|
||||
note: "Requires SUSE subscription and manual download"
|
||||
|
||||
# openSUSE Leap
|
||||
opensuse-leap-15.5:
|
||||
url: "https://download.opensuse.org/distribution/leap/15.5/appliances/openSUSE-Leap-15.5-Minimal-VM.x86_64-Cloud.qcow2"
|
||||
checksum_url: "https://download.opensuse.org/distribution/leap/15.5/appliances/openSUSE-Leap-15.5-Minimal-VM.x86_64-Cloud.qcow2.sha256"
|
||||
checksum_type: "sha256"
|
||||
os_variant: "opensuse15.5"
|
||||
cache_name: "opensuse-leap-15.5-minimal-vm-amd64.qcow2"
|
||||
package_manager: "zypper"
|
||||
family: "suse"
|
||||
|
||||
opensuse-leap-15.6:
|
||||
url: "https://download.opensuse.org/distribution/leap/15.6/appliances/openSUSE-Leap-15.6-Minimal-VM.x86_64-Cloud.qcow2"
|
||||
checksum_url: "https://download.opensuse.org/distribution/leap/15.6/appliances/openSUSE-Leap-15.6-Minimal-VM.x86_64-Cloud.qcow2.sha256"
|
||||
checksum_type: "sha256"
|
||||
os_variant: "opensuse15.6"
|
||||
cache_name: "opensuse-leap-15.6-minimal-vm-amd64.qcow2"
|
||||
package_manager: "zypper"
|
||||
family: "suse"
|
||||
|
||||
tasks:
|
||||
# =========================================================================
|
||||
# Validation and Setup
|
||||
# =========================================================================
|
||||
|
||||
- name: Validate distribution selection
|
||||
assert:
|
||||
that:
|
||||
- os_distribution is defined
|
||||
- os_distribution in cloud_images.keys()
|
||||
fail_msg: |
|
||||
Invalid distribution '{{ os_distribution }}'.
|
||||
Supported distributions: {{ cloud_images.keys() | list | join(', ') }}
|
||||
tags: [validate, preflight]
|
||||
|
||||
- name: Set distribution facts
|
||||
set_fact:
|
||||
distro_config: "{{ cloud_images[os_distribution] }}"
|
||||
image_cache_path: "/var/lib/libvirt/images/{{ cloud_images[os_distribution].cache_name }}"
|
||||
tags: [always]
|
||||
|
||||
- name: Display deployment information
|
||||
debug:
|
||||
msg:
|
||||
- "=== VM Deployment Configuration ==="
|
||||
- "VM Name: {{ vm_name }}"
|
||||
- "Distribution: {{ os_distribution }}"
|
||||
- "OS Family: {{ distro_config.family }}"
|
||||
- "Package Manager: {{ distro_config.package_manager }}"
|
||||
- "vCPUs: {{ vm_vcpus }}"
|
||||
- "Memory: {{ vm_memory_mb }} MB"
|
||||
- "Disk: {{ vm_disk_size_gb }} GB"
|
||||
tags: [validate, preflight]
|
||||
|
||||
- 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 on hypervisor. Please choose a different name or destroy the existing VM."
|
||||
when: vm_exists.rc == 0
|
||||
tags: [validate, preflight]
|
||||
|
||||
- name: Verify virtualization support
|
||||
command: virt-host-validate qemu
|
||||
register: virt_validation
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
tags: [validate, preflight]
|
||||
|
||||
- name: Display virtualization validation results
|
||||
debug:
|
||||
var: virt_validation.stdout_lines
|
||||
tags: [validate, preflight]
|
||||
|
||||
# =========================================================================
|
||||
# Package Installation
|
||||
# =========================================================================
|
||||
|
||||
- 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
|
||||
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
|
||||
state: present
|
||||
when: ansible_os_family == "RedHat"
|
||||
tags: [install]
|
||||
|
||||
- name: Ensure libvirtd service is running
|
||||
systemd:
|
||||
name: libvirtd
|
||||
state: started
|
||||
enabled: yes
|
||||
tags: [install]
|
||||
|
||||
# =========================================================================
|
||||
# Download Cloud Image
|
||||
# =========================================================================
|
||||
|
||||
- name: Check if cloud image already exists
|
||||
stat:
|
||||
path: "{{ image_cache_path }}"
|
||||
register: cloud_image_stat
|
||||
tags: [download]
|
||||
|
||||
- name: Display image cache status
|
||||
debug:
|
||||
msg: "Cloud image {{ 'exists' if cloud_image_stat.stat.exists else 'not found' }}: {{ image_cache_path }}"
|
||||
tags: [download]
|
||||
|
||||
- name: Check for manual download requirement
|
||||
debug:
|
||||
msg:
|
||||
- "WARNING: {{ os_distribution }} requires manual download"
|
||||
- "{{ distro_config.note | default('') }}"
|
||||
- "Please download the image and place it at: {{ image_cache_path }}"
|
||||
when:
|
||||
- not cloud_image_stat.stat.exists
|
||||
- distro_config.note is defined
|
||||
tags: [download]
|
||||
|
||||
- name: Download cloud image
|
||||
get_url:
|
||||
url: "{{ distro_config.url }}"
|
||||
dest: "{{ image_cache_path }}"
|
||||
mode: '0644'
|
||||
timeout: 1200
|
||||
when:
|
||||
- not cloud_image_stat.stat.exists
|
||||
- distro_config.note is not defined
|
||||
register: download_result
|
||||
tags: [download]
|
||||
|
||||
- name: Download checksum file
|
||||
get_url:
|
||||
url: "{{ distro_config.checksum_url }}"
|
||||
dest: "/tmp/{{ os_distribution }}-CHECKSUM"
|
||||
mode: '0644'
|
||||
when:
|
||||
- distro_config.checksum_url is defined
|
||||
- download_result is changed or cloud_image_stat.stat.exists
|
||||
tags: [download, verify]
|
||||
|
||||
- name: Verify cloud image checksum (SHA512)
|
||||
shell: |
|
||||
cd /var/lib/libvirt/images
|
||||
grep "{{ distro_config.cache_name }}" /tmp/{{ os_distribution }}-CHECKSUM | sha512sum -c -
|
||||
register: checksum_result
|
||||
changed_when: false
|
||||
when:
|
||||
- distro_config.checksum_type is defined
|
||||
- distro_config.checksum_type == "sha512"
|
||||
- distro_config.checksum_url is defined
|
||||
tags: [verify]
|
||||
|
||||
- name: Verify cloud image checksum (SHA256)
|
||||
shell: |
|
||||
cd /var/lib/libvirt/images
|
||||
grep "{{ distro_config.cache_name }}" /tmp/{{ os_distribution }}-CHECKSUM | sha256sum -c -
|
||||
register: checksum_result
|
||||
changed_when: false
|
||||
when:
|
||||
- distro_config.checksum_type is defined
|
||||
- distro_config.checksum_type == "sha256"
|
||||
- distro_config.checksum_url is defined
|
||||
tags: [verify]
|
||||
|
||||
- name: Ensure image file exists before proceeding
|
||||
stat:
|
||||
path: "{{ image_cache_path }}"
|
||||
register: final_image_check
|
||||
failed_when: not final_image_check.stat.exists
|
||||
tags: [verify]
|
||||
|
||||
# =========================================================================
|
||||
# Create VM Disk
|
||||
# =========================================================================
|
||||
|
||||
- name: Create VM disk from cloud image
|
||||
command: >
|
||||
qemu-img create -f qcow2 -F qcow2
|
||||
-b {{ image_cache_path }}
|
||||
{{ vm_disk_path }}
|
||||
{{ vm_disk_size_gb }}G
|
||||
args:
|
||||
creates: "{{ vm_disk_path }}"
|
||||
tags: [storage]
|
||||
|
||||
- name: Set proper permissions on VM disk
|
||||
file:
|
||||
path: "{{ 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: "{{ vm_disk_path }}"
|
||||
owner: qemu
|
||||
group: qemu
|
||||
mode: '0600'
|
||||
when: ansible_os_family == "RedHat"
|
||||
tags: [storage]
|
||||
|
||||
# =========================================================================
|
||||
# Create Cloud-Init Configuration
|
||||
# =========================================================================
|
||||
|
||||
- name: Create cloud-init directory
|
||||
file:
|
||||
path: /tmp/cloud-init-{{ vm_name }}
|
||||
state: directory
|
||||
mode: '0755'
|
||||
tags: [cloud-init]
|
||||
|
||||
- name: Create cloud-init meta-data
|
||||
copy:
|
||||
content: |
|
||||
instance-id: {{ vm_name }}
|
||||
local-hostname: {{ vm_hostname }}
|
||||
dest: /tmp/cloud-init-{{ vm_name }}/meta-data
|
||||
mode: '0644'
|
||||
tags: [cloud-init]
|
||||
|
||||
- name: Create cloud-init user-data for Debian/Ubuntu
|
||||
copy:
|
||||
content: |
|
||||
#cloud-config
|
||||
hostname: {{ vm_hostname }}
|
||||
fqdn: {{ vm_hostname }}.{{ vm_domain }}
|
||||
manage_etc_hosts: true
|
||||
|
||||
# Create ansible user with sudo privileges
|
||||
users:
|
||||
- name: ansible
|
||||
groups: sudo
|
||||
shell: /bin/bash
|
||||
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
||||
ssh_authorized_keys:
|
||||
- {{ ansible_user_ssh_key }}
|
||||
- name: root
|
||||
lock_passwd: false
|
||||
|
||||
# Set root password (for emergency console access)
|
||||
chpasswd:
|
||||
list: |
|
||||
root:ChangeMe123!
|
||||
expire: false
|
||||
|
||||
# SSH configuration
|
||||
ssh_pwauth: false
|
||||
disable_root: false
|
||||
|
||||
# Install essential packages per CLAUDE.md guidelines
|
||||
packages:
|
||||
- sudo
|
||||
- vim
|
||||
- htop
|
||||
- tmux
|
||||
- curl
|
||||
- wget
|
||||
- rsync
|
||||
- git
|
||||
- python3
|
||||
- python3-pip
|
||||
- jq
|
||||
- bc
|
||||
- aide
|
||||
- auditd
|
||||
- chrony
|
||||
- ufw
|
||||
- lvm2
|
||||
- cloud-guest-utils
|
||||
- parted
|
||||
- unattended-upgrades
|
||||
- apt-listchanges
|
||||
|
||||
# Security configuration files
|
||||
write_files:
|
||||
- path: /etc/ssh/sshd_config.d/99-security.conf
|
||||
content: |
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication no
|
||||
PubkeyAuthentication yes
|
||||
MaxAuthTries 3
|
||||
MaxSessions 10
|
||||
ClientAliveInterval 300
|
||||
ClientAliveCountMax 2
|
||||
permissions: '0644'
|
||||
|
||||
- path: /etc/sudoers.d/ansible
|
||||
content: |
|
||||
ansible ALL=(ALL) NOPASSWD:ALL
|
||||
permissions: '0440'
|
||||
|
||||
- path: /etc/apt/apt.conf.d/50unattended-upgrades
|
||||
content: |
|
||||
Unattended-Upgrade::Allowed-Origins {
|
||||
"${distro_id}:${distro_codename}-security";
|
||||
};
|
||||
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
|
||||
Unattended-Upgrade::MinimalSteps "true";
|
||||
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
||||
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
||||
Unattended-Upgrade::Automatic-Reboot "false";
|
||||
permissions: '0644'
|
||||
|
||||
- path: /etc/apt/apt.conf.d/20auto-upgrades
|
||||
content: |
|
||||
APT::Periodic::Update-Package-Lists "1";
|
||||
APT::Periodic::Unattended-Upgrade "1";
|
||||
APT::Periodic::AutocleanInterval "7";
|
||||
permissions: '0644'
|
||||
|
||||
# System configuration commands
|
||||
runcmd:
|
||||
- systemctl enable ssh
|
||||
- systemctl restart ssh
|
||||
- systemctl enable chrony
|
||||
- systemctl start chrony
|
||||
- ufw --force enable
|
||||
- ufw allow ssh
|
||||
- systemctl enable auditd
|
||||
- systemctl start auditd
|
||||
- growpart /dev/vda 1 || true
|
||||
- resize2fs /dev/vda1 || true
|
||||
|
||||
package_update: true
|
||||
package_upgrade: true
|
||||
package_reboot_if_required: false
|
||||
|
||||
timezone: UTC
|
||||
locale: en_US.UTF-8
|
||||
|
||||
output:
|
||||
all: '| tee -a /var/log/cloud-init-output.log'
|
||||
|
||||
final_message: "{{ os_distribution }} VM deployment completed. System is ready after $UPTIME seconds."
|
||||
dest: /tmp/cloud-init-{{ vm_name }}/user-data
|
||||
mode: '0644'
|
||||
when: distro_config.family == "debian"
|
||||
tags: [cloud-init]
|
||||
|
||||
- name: Create cloud-init user-data for RHEL/CentOS/Rocky/Alma
|
||||
copy:
|
||||
content: |
|
||||
#cloud-config
|
||||
hostname: {{ vm_hostname }}
|
||||
fqdn: {{ vm_hostname }}.{{ vm_domain }}
|
||||
manage_etc_hosts: true
|
||||
|
||||
# Create ansible user with sudo privileges
|
||||
users:
|
||||
- name: ansible
|
||||
groups: wheel
|
||||
shell: /bin/bash
|
||||
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
||||
ssh_authorized_keys:
|
||||
- {{ ansible_user_ssh_key }}
|
||||
- name: root
|
||||
lock_passwd: false
|
||||
|
||||
# Set root password (for emergency console access)
|
||||
chpasswd:
|
||||
list: |
|
||||
root:ChangeMe123!
|
||||
expire: false
|
||||
|
||||
# SSH configuration
|
||||
ssh_pwauth: false
|
||||
disable_root: false
|
||||
|
||||
# Install essential packages per CLAUDE.md guidelines
|
||||
packages:
|
||||
- sudo
|
||||
- vim
|
||||
- htop
|
||||
- tmux
|
||||
- curl
|
||||
- wget
|
||||
- rsync
|
||||
- git
|
||||
- python3
|
||||
- python3-pip
|
||||
- jq
|
||||
- bc
|
||||
- aide
|
||||
- audit
|
||||
- chrony
|
||||
- firewalld
|
||||
- lvm2
|
||||
- cloud-utils-growpart
|
||||
- gdisk
|
||||
- dnf-automatic
|
||||
- policycoreutils-python-utils
|
||||
|
||||
# Security configuration files
|
||||
write_files:
|
||||
- path: /etc/ssh/sshd_config.d/99-security.conf
|
||||
content: |
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication no
|
||||
PubkeyAuthentication yes
|
||||
MaxAuthTries 3
|
||||
MaxSessions 10
|
||||
ClientAliveInterval 300
|
||||
ClientAliveCountMax 2
|
||||
permissions: '0644'
|
||||
|
||||
- path: /etc/sudoers.d/ansible
|
||||
content: |
|
||||
ansible ALL=(ALL) NOPASSWD:ALL
|
||||
permissions: '0440'
|
||||
|
||||
- path: /etc/dnf/automatic.conf
|
||||
content: |
|
||||
[commands]
|
||||
upgrade_type = security
|
||||
download_updates = yes
|
||||
apply_updates = yes
|
||||
|
||||
[emitters]
|
||||
emit_via = stdio
|
||||
|
||||
[email]
|
||||
email_from = root@{{ vm_hostname }}.{{ vm_domain }}
|
||||
|
||||
[base]
|
||||
debuglevel = 1
|
||||
permissions: '0644'
|
||||
|
||||
# System configuration commands
|
||||
runcmd:
|
||||
- systemctl enable sshd
|
||||
- systemctl restart sshd
|
||||
- systemctl enable chronyd
|
||||
- systemctl start chronyd
|
||||
- systemctl enable firewalld
|
||||
- systemctl start firewalld
|
||||
- firewall-cmd --permanent --add-service=ssh
|
||||
- firewall-cmd --reload
|
||||
- systemctl enable auditd
|
||||
- systemctl start auditd
|
||||
- systemctl enable dnf-automatic.timer
|
||||
- systemctl start dnf-automatic.timer
|
||||
- setenforce 1
|
||||
- sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
|
||||
- growpart /dev/vda 1 || true
|
||||
- xfs_growfs / || resize2fs /dev/vda1 || true
|
||||
|
||||
package_update: true
|
||||
package_upgrade: true
|
||||
package_reboot_if_required: false
|
||||
|
||||
timezone: UTC
|
||||
locale: en_US.UTF-8
|
||||
|
||||
output:
|
||||
all: '| tee -a /var/log/cloud-init-output.log'
|
||||
|
||||
final_message: "{{ os_distribution }} VM deployment completed. System is ready after $UPTIME seconds."
|
||||
dest: /tmp/cloud-init-{{ vm_name }}/user-data
|
||||
mode: '0644'
|
||||
when: distro_config.family == "rhel"
|
||||
tags: [cloud-init]
|
||||
|
||||
- name: Create cloud-init user-data for SUSE/openSUSE
|
||||
copy:
|
||||
content: |
|
||||
#cloud-config
|
||||
hostname: {{ vm_hostname }}
|
||||
fqdn: {{ vm_hostname }}.{{ vm_domain }}
|
||||
manage_etc_hosts: true
|
||||
|
||||
# Create ansible user with sudo privileges
|
||||
users:
|
||||
- name: ansible
|
||||
groups: wheel
|
||||
shell: /bin/bash
|
||||
sudo: ['ALL=(ALL) NOPASSWD:ALL']
|
||||
ssh_authorized_keys:
|
||||
- {{ ansible_user_ssh_key }}
|
||||
- name: root
|
||||
lock_passwd: false
|
||||
|
||||
# Set root password (for emergency console access)
|
||||
chpasswd:
|
||||
list: |
|
||||
root:ChangeMe123!
|
||||
expire: false
|
||||
|
||||
# SSH configuration
|
||||
ssh_pwauth: false
|
||||
disable_root: false
|
||||
|
||||
# Install essential packages
|
||||
packages:
|
||||
- sudo
|
||||
- vim
|
||||
- htop
|
||||
- tmux
|
||||
- curl
|
||||
- wget
|
||||
- rsync
|
||||
- git
|
||||
- python3
|
||||
- python3-pip
|
||||
- jq
|
||||
- bc
|
||||
- aide
|
||||
- audit
|
||||
- chrony
|
||||
- firewalld
|
||||
- lvm2
|
||||
- cloud-utils-growpart
|
||||
- gdisk
|
||||
|
||||
# Security configuration files
|
||||
write_files:
|
||||
- path: /etc/ssh/sshd_config.d/99-security.conf
|
||||
content: |
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication no
|
||||
PubkeyAuthentication yes
|
||||
MaxAuthTries 3
|
||||
MaxSessions 10
|
||||
ClientAliveInterval 300
|
||||
ClientAliveCountMax 2
|
||||
permissions: '0644'
|
||||
|
||||
- path: /etc/sudoers.d/ansible
|
||||
content: |
|
||||
ansible ALL=(ALL) NOPASSWD:ALL
|
||||
permissions: '0440'
|
||||
|
||||
# System configuration commands
|
||||
runcmd:
|
||||
- systemctl enable sshd
|
||||
- systemctl restart sshd
|
||||
- systemctl enable chronyd
|
||||
- systemctl start chronyd
|
||||
- systemctl enable firewalld
|
||||
- systemctl start firewalld
|
||||
- firewall-cmd --permanent --add-service=ssh
|
||||
- firewall-cmd --reload
|
||||
- systemctl enable auditd
|
||||
- systemctl start auditd
|
||||
- growpart /dev/vda 1 || true
|
||||
- xfs_growfs / || resize2fs /dev/vda1 || btrfs filesystem resize max / || true
|
||||
|
||||
package_update: true
|
||||
package_upgrade: true
|
||||
package_reboot_if_required: false
|
||||
|
||||
timezone: UTC
|
||||
locale: en_US.UTF-8
|
||||
|
||||
output:
|
||||
all: '| tee -a /var/log/cloud-init-output.log'
|
||||
|
||||
final_message: "{{ os_distribution }} VM deployment completed. System is ready after $UPTIME seconds."
|
||||
dest: /tmp/cloud-init-{{ vm_name }}/user-data
|
||||
mode: '0644'
|
||||
when: distro_config.family == "suse"
|
||||
tags: [cloud-init]
|
||||
|
||||
- name: Create cloud-init ISO
|
||||
command: >
|
||||
genisoimage -output {{ cloud_init_iso_path }}
|
||||
-volid cidata -joliet -rock
|
||||
/tmp/cloud-init-{{ vm_name }}/user-data
|
||||
/tmp/cloud-init-{{ vm_name }}/meta-data
|
||||
args:
|
||||
creates: "{{ cloud_init_iso_path }}"
|
||||
tags: [cloud-init]
|
||||
|
||||
- name: Set proper permissions on cloud-init ISO (Debian/Ubuntu)
|
||||
file:
|
||||
path: "{{ 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: "{{ cloud_init_iso_path }}"
|
||||
owner: qemu
|
||||
group: qemu
|
||||
mode: '0644'
|
||||
when: ansible_os_family == "RedHat"
|
||||
tags: [cloud-init]
|
||||
|
||||
# =========================================================================
|
||||
# Create and Start VM
|
||||
# =========================================================================
|
||||
|
||||
- name: Create VM using virt-install
|
||||
command: >
|
||||
virt-install
|
||||
--name {{ vm_name }}
|
||||
--memory {{ vm_memory_mb }}
|
||||
--vcpus {{ vm_vcpus }}
|
||||
--disk path={{ vm_disk_path }},format=qcow2,bus=virtio
|
||||
--disk path={{ cloud_init_iso_path }},device=cdrom
|
||||
--network network={{ vm_network }},model=virtio
|
||||
--os-variant {{ distro_config.os_variant }}
|
||||
--graphics none
|
||||
--console pty,target_type=serial
|
||||
--import
|
||||
--noautoconsole
|
||||
register: vm_create
|
||||
tags: [deploy]
|
||||
|
||||
- name: Wait for VM to boot and cloud-init to complete
|
||||
pause:
|
||||
seconds: 90
|
||||
prompt: "Waiting for VM to boot and cloud-init to complete configuration..."
|
||||
tags: [deploy]
|
||||
|
||||
- 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: 15
|
||||
delay: 10
|
||||
until: vm_ip.stdout != ""
|
||||
changed_when: false
|
||||
tags: [deploy, validate]
|
||||
|
||||
- name: Display VM information
|
||||
debug:
|
||||
msg:
|
||||
- "=== VM Deployment Successful ==="
|
||||
- "VM Name: {{ vm_name }}"
|
||||
- "Distribution: {{ os_distribution }}"
|
||||
- "IP Address: {{ vm_ip.stdout }}"
|
||||
- "vCPUs: {{ vm_vcpus }}"
|
||||
- "Memory: {{ vm_memory_mb }} MB"
|
||||
- "Disk: {{ vm_disk_size_gb }} GB"
|
||||
- "OS Variant: {{ distro_config.os_variant }}"
|
||||
- "Package Manager: {{ distro_config.package_manager }}"
|
||||
- "Access: ssh ansible@{{ vm_ip.stdout }}"
|
||||
- ""
|
||||
- "Add to inventory:"
|
||||
- " {{ vm_name }}:"
|
||||
- " ansible_host: {{ vm_ip.stdout }}"
|
||||
- " ansible_user: ansible"
|
||||
- " ansible_ssh_common_args: '-o ProxyJump=grokbox -o StrictHostKeyChecking=accept-new'"
|
||||
- " os_distribution: {{ os_distribution }}"
|
||||
- " os_family: {{ distro_config.family }}"
|
||||
tags: [deploy, validate]
|
||||
|
||||
# =========================================================================
|
||||
# Validation
|
||||
# =========================================================================
|
||||
|
||||
- name: Test SSH connectivity to new VM
|
||||
wait_for:
|
||||
host: "{{ vm_ip.stdout }}"
|
||||
port: 22
|
||||
timeout: 300
|
||||
state: started
|
||||
tags: [validate]
|
||||
|
||||
- name: Get VM details
|
||||
command: virsh dominfo {{ vm_name }}
|
||||
register: vm_details
|
||||
changed_when: false
|
||||
tags: [validate]
|
||||
|
||||
- name: Display VM details
|
||||
debug:
|
||||
var: vm_details.stdout_lines
|
||||
tags: [validate]
|
||||
|
||||
# =========================================================================
|
||||
# Cleanup
|
||||
# =========================================================================
|
||||
|
||||
- name: Remove temporary cloud-init directory
|
||||
file:
|
||||
path: /tmp/cloud-init-{{ vm_name }}
|
||||
state: absent
|
||||
tags: [cleanup]
|
||||
|
||||
- name: Remove downloaded checksums
|
||||
file:
|
||||
path: /tmp/{{ os_distribution }}-CHECKSUM
|
||||
state: absent
|
||||
tags: [cleanup]
|
||||
|
||||
# =============================================================================
|
||||
# Post-Deployment Validation (Optional)
|
||||
# =============================================================================
|
||||
|
||||
- name: Validate deployed VM
|
||||
hosts: "{{ hostvars['grokbox']['vm_ip'].stdout }}"
|
||||
gather_facts: yes
|
||||
become: yes
|
||||
vars:
|
||||
ansible_user: ansible
|
||||
ansible_ssh_common_args: '-o ProxyJump=grokbox -o StrictHostKeyChecking=accept-new'
|
||||
|
||||
tasks:
|
||||
- name: Wait for cloud-init to complete
|
||||
command: cloud-init status --wait
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
tags: [validate]
|
||||
|
||||
- name: Gather system facts
|
||||
setup:
|
||||
tags: [validate]
|
||||
|
||||
- name: Display system information
|
||||
debug:
|
||||
msg:
|
||||
- "=== System Information ==="
|
||||
- "OS: {{ ansible_distribution }} {{ ansible_distribution_version }}"
|
||||
- "Kernel: {{ ansible_kernel }}"
|
||||
- "Architecture: {{ ansible_architecture }}"
|
||||
- "Hostname: {{ ansible_hostname }}"
|
||||
- "FQDN: {{ ansible_fqdn }}"
|
||||
- "Python: {{ ansible_python_version }}"
|
||||
- "Package Manager: {{ ansible_pkg_mgr }}"
|
||||
tags: [validate]
|
||||
|
||||
- name: Gather disk usage
|
||||
command: df -h
|
||||
register: disk_usage
|
||||
changed_when: false
|
||||
tags: [validate]
|
||||
|
||||
- name: Display disk usage
|
||||
debug:
|
||||
var: disk_usage.stdout_lines
|
||||
tags: [validate]
|
||||
|
||||
- name: Gather memory usage
|
||||
command: free -h
|
||||
register: memory_usage
|
||||
changed_when: false
|
||||
tags: [validate]
|
||||
|
||||
- name: Display memory usage
|
||||
debug:
|
||||
var: memory_usage.stdout_lines
|
||||
tags: [validate]
|
||||
|
||||
- name: Check SELinux status (RHEL family)
|
||||
command: getenforce
|
||||
register: selinux_status
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
when: ansible_os_family == "RedHat"
|
||||
tags: [validate]
|
||||
|
||||
- name: Display SELinux status
|
||||
debug:
|
||||
msg: "SELinux Status: {{ selinux_status.stdout }}"
|
||||
when: ansible_os_family == "RedHat"
|
||||
tags: [validate]
|
||||
Reference in New Issue
Block a user