Create provisioning

This commit is contained in:
2026-04-28 22:45:25 -04:00
parent 7bc1f8f702
commit 1717081550
6 changed files with 965 additions and 44 deletions

View File

@@ -1,25 +1,274 @@
---
# Provision Windows Server VM on Hyper-V
# This playbook creates a new Windows Server VM with unattended installation
#
# Variables (can be provided via survey in AAP or command line):
# vm_name: Name of the VM to create (required)
# vm_ip_address: Static IP address for the VM (optional)
# vm_cpu_count: Number of CPUs (default: from group_vars)
# vm_memory_gb: Memory in GB (default: from group_vars)
# vm_disk_size_gb: Disk size in GB (default: from group_vars)
# vm_admin_password: Initial administrator password (default: P@ssw0rd123!)
#
# Tags:
# - create: Create VM and configuration
# - install: Start VM and wait for installation
# - verify: Verify VM is accessible
#
# Usage:
# ansible-playbook provision-vm.yml -e vm_name=WEB01 -e vm_ip_address=192.168.1.101
# ansible-playbook provision-vm.yml --tags create -e vm_name=WEB01
- name: Provision Windows Server VM on Hyper-V
hosts: hyperv_hosts
hosts: hyperv
gather_facts: false
vars_prompt:
- name: vm_name
prompt: "Enter VM name"
private: false
vars:
# Use defaults from group_vars if not specified
vm_cpu_count: "{{ vm_cpu_count | default(default_vm_cpu_count) }}"
vm_memory_gb: "{{ vm_memory_gb | default(default_vm_memory_gb) }}"
vm_disk_size_gb: "{{ vm_disk_size_gb | default(default_vm_disk_size_gb) }}"
vm_switch: "{{ vm_switch | default(default_vm_switch) }}"
- name: vm_ip_address
prompt: "Enter IP address for VM"
private: false
# Derived paths
vm_path: "{{ vm_storage_path }}\\{{ vm_name }}"
vm_vhd_path: "{{ vm_storage_path }}\\{{ vm_name }}\\{{ vm_name }}.vhdx"
autounattend_path: "{{ vm_storage_path }}\\{{ vm_name }}\\autounattend.xml"
pre_tasks:
- name: Validate required variables
ansible.builtin.assert:
that:
- vm_name is defined
- vm_name | length > 0
- vm_name is match('^[a-zA-Z0-9-]+$')
fail_msg: "vm_name is required and must contain only letters, numbers, and hyphens"
tasks:
- name: Placeholder - Create VM
ansible.builtin.debug:
msg: "Will create VM {{ vm_name }} with IP {{ vm_ip_address }}"
- name: Check if VM already exists
ansible.windows.win_shell: |
Get-VM -Name "{{ vm_name }}" -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty Name
register: vm_exists_check
changed_when: false
failed_when: false
tags: [create, verify]
# TODO: Implement VM creation using hyper-v modules
# TODO: Generate autounattend.xml from template
# TODO: Attach autounattend.xml to VM
# TODO: Start VM and wait for provisioning
# TODO: Add VM to inventory
# TODO: Update ServiceNow CMDB
- name: Set VM exists fact
ansible.builtin.set_fact:
vm_exists: "{{ vm_exists_check.stdout | trim | length > 0 }}"
tags: [create, verify]
- name: Display VM status
ansible.builtin.debug:
msg: "VM {{ vm_name }} {{ 'already exists' if vm_exists else 'will be created' }}"
tags: [create, verify]
- name: VM Creation Block
when: not vm_exists
tags: [create]
block:
- name: Create VM directory
ansible.windows.win_file:
path: "{{ vm_path }}"
state: directory
- name: Generate autounattend.xml
ansible.windows.win_template:
src: ../templates/autounattend.xml.j2
dest: "{{ autounattend_path }}"
- name: Create new VHD
ansible.windows.win_shell: |
New-VHD -Path "{{ vm_vhd_path }}" `
-SizeBytes {{ vm_disk_size_gb }}GB `
-Dynamic
args:
creates: "{{ vm_vhd_path }}"
- name: Create new VM
ansible.windows.win_shell: |
New-VM -Name "{{ vm_name }}" `
-MemoryStartupBytes {{ vm_memory_gb }}GB `
-Generation 2 `
-VHDPath "{{ vm_vhd_path }}" `
-SwitchName "{{ vm_switch }}"
register: vm_create
- name: Configure VM processor count
ansible.windows.win_shell: |
Set-VMProcessor -VMName "{{ vm_name }}" -Count {{ vm_cpu_count }}
- name: Enable dynamic memory
ansible.windows.win_shell: |
Set-VMMemory -VMName "{{ vm_name }}" `
-DynamicMemoryEnabled $true `
-MinimumBytes 2GB `
-MaximumBytes {{ vm_memory_gb }}GB
- name: Disable secure boot (for compatibility)
ansible.windows.win_shell: |
Set-VMFirmware -VMName "{{ vm_name }}" -EnableSecureBoot Off
- name: Create DVD drive for ISO
ansible.windows.win_shell: |
Add-VMDvdDrive -VMName "{{ vm_name }}" -Path "{{ windows_server_iso }}"
- name: Set DVD as first boot device
ansible.windows.win_shell: |
$dvd = Get-VMDvdDrive -VMName "{{ vm_name }}"
Set-VMFirmware -VMName "{{ vm_name }}" -FirstBootDevice $dvd
- name: Create VFD for autounattend.xml
ansible.windows.win_shell: |
# Create a temporary VFD file
$vfdPath = "{{ vm_path }}\autounattend.vfd"
# PowerShell to create VFD and add autounattend.xml
# Note: This is a simplified approach
# For production, consider using a pre-built VFD or ISO with autounattend.xml
# Copy autounattend.xml to a location accessible during Windows Setup
# Alternative: Use NoCloud data source or inject into ISO
Write-Host "AutoUnattend.xml created at {{ autounattend_path }}"
Write-Host "Manual step: Mount autounattend.xml to VM or inject into ISO"
register: vfd_create
changed_when: false
- name: Display next steps for autounattend.xml
ansible.builtin.debug:
msg:
- "AutoUnattend.xml has been generated at: {{ autounattend_path }}"
- "To use it, manually:"
- "1. Create an ISO with autounattend.xml in the root"
- "2. Or copy it to a floppy image and attach to VM"
- "3. Or use UEFI boot with the file in the EFI partition"
- ""
- "For automated approach, consider:"
- "- Creating a custom Windows ISO with autounattend.xml embedded"
- "- Using MDT/WDS for network-based deployment"
- name: VM Installation Block
when: not vm_exists
tags: [install]
block:
- name: Start VM for installation
ansible.windows.win_shell: |
Start-VM -Name "{{ vm_name }}"
register: vm_start
- name: Wait for VM to start
ansible.builtin.pause:
seconds: 30
- name: Display installation progress message
ansible.builtin.debug:
msg:
- "VM {{ vm_name }} has been started"
- "Windows Server installation is in progress..."
- "This may take 15-30 minutes depending on hardware"
- ""
- "Installation steps:"
- "1. Windows Setup will boot from ISO"
- "2. AutoUnattend.xml will configure installation (if properly mounted)"
- "3. System will reboot after installation"
- "4. First logon commands will configure WinRM"
- name: Wait for Windows installation to complete
ansible.builtin.pause:
prompt: |
Manual step required:
1. Monitor the VM installation through Hyper-V Manager
2. Verify autounattend.xml is being used (watch for automated setup)
3. Wait for installation to complete and system to reach login screen
4. Verify WinRM is enabled (first logon commands should run)
Press Enter when installation is complete and VM is at login screen...
when: ansible_check_mode is not defined or not ansible_check_mode
- name: VM Verification Block
tags: [verify]
block:
- name: Get VM state
ansible.windows.win_shell: |
Get-VM -Name "{{ vm_name }}" |
Select-Object Name, State, CPUUsage, MemoryAssigned, Uptime |
ConvertTo-Json
register: vm_state
changed_when: false
- name: Display VM state
ansible.builtin.debug:
var: vm_state.stdout | from_json
- name: Wait for WinRM to be available on new VM
ansible.builtin.wait_for:
host: "{{ vm_ip_address }}"
port: 5985
timeout: 600
state: started
when:
- vm_ip_address is defined
- not vm_exists
ignore_errors: true
- name: Test WinRM connectivity
ansible.builtin.command:
cmd: >
ansible {{ vm_name }} -m ansible.windows.win_ping
-i {{ vm_ip_address }},
delegate_to: localhost
when:
- vm_ip_address is defined
register: winrm_test
failed_when: false
changed_when: false
- name: Display connectivity test result
ansible.builtin.debug:
msg: "{{ 'WinRM connectivity successful' if winrm_test.rc == 0 else 'WinRM connectivity failed - manual verification needed' }}"
when: vm_ip_address is defined
- name: Post-provisioning tasks
when: not vm_exists
tags: [create]
block:
- name: Summary message
ansible.builtin.debug:
msg:
- "========================================="
- "VM Provisioning Summary"
- "========================================="
- "VM Name: {{ vm_name }}"
- "CPU Count: {{ vm_cpu_count }}"
- "Memory: {{ vm_memory_gb }} GB"
- "Disk Size: {{ vm_disk_size_gb }} GB"
- "IP Address: {{ vm_ip_address | default('DHCP') }}"
- "VHD Path: {{ vm_vhd_path }}"
- "AutoUnattend: {{ autounattend_path }}"
- "========================================="
- ""
- "Next Steps:"
- "1. Verify VM installation completed successfully"
- "2. Test WinRM connectivity: ansible {{ vm_name }} -m win_ping"
- "3. Add VM to inventory if using static groups"
- "4. Run baseline configuration playbook"
- "5. Deploy applications as needed"
- ""
- "To add to inventory, update:"
- "/home/ptoal/Dev/inventories/toallab-inventory/static.yml"
- name: Create inventory addition snippet
ansible.builtin.set_fact:
inventory_snippet: |
# Add this to /home/ptoal/Dev/inventories/toallab-inventory/static.yml
# Under the appropriate group (web_servers, app_servers, db_servers):
{{ vm_name }}:
ansible_host: {{ vm_ip_address | default('SET_IP_HERE') }}
- name: Display inventory addition snippet
ansible.builtin.debug:
var: inventory_snippet