Handoff
This commit is contained in:
509
HANDOFF.md
Normal file
509
HANDOFF.md
Normal file
@@ -0,0 +1,509 @@
|
||||
# Hyper-V Automation Project - Handoff Document
|
||||
|
||||
**Date**: 2026-04-29
|
||||
**Status**: Development - Core provisioning implemented
|
||||
**Next Session**: Ready for Hyper-V host setup and VM testing
|
||||
|
||||
## Project Overview
|
||||
|
||||
Enterprise-grade automation for Windows Server VM lifecycle management on Hyper-V using Ansible Automation Platform. Demonstrates GitOps and Infrastructure as Code principles for demo/lab environments.
|
||||
|
||||
**Primary Use Case**: Automated VM provisioning with unattended Windows installation
|
||||
|
||||
**Target Environment**: Demo/Lab (not production-hardened)
|
||||
|
||||
## Current State
|
||||
|
||||
### ✅ Completed
|
||||
|
||||
1. **Project Structure**
|
||||
- Integrated with toallab standard inventory (`/home/ptoal/Dev/inventories/toallab-inventory`)
|
||||
- Group variables organized (hyperv, windows_servers, web_servers)
|
||||
- Host variables configured for hyperv1.lan.toal.ca (192.168.1.182)
|
||||
- Collections requirements defined
|
||||
|
||||
2. **Hyper-V Host Provisioning** ⭐ NEW
|
||||
- Playbook: `playbooks/provision-hyperv-host.yml`
|
||||
- Installs Hyper-V role and management tools
|
||||
- Creates storage structure (D:\VMs, D:\ISOs, D:\Templates)
|
||||
- Configures virtual switches (External-NAT, Internal-Lab)
|
||||
- Sets up NAT networking (192.168.100.0/24)
|
||||
- Hardens WinRM with HTTPS listener
|
||||
- Demo-optimized settings (power, firewall, etc.)
|
||||
|
||||
3. **VM Provisioning Workflow**
|
||||
- Playbook: `playbooks/provision-vm.yml`
|
||||
- Creates VMs with configurable resources (CPU, RAM, disk)
|
||||
- Generates autounattend.xml for unattended Windows installation
|
||||
- Validates virtual switch availability
|
||||
- Supports tags for selective execution (create/install/verify)
|
||||
- Idempotent operations
|
||||
- AAP-ready with survey support
|
||||
|
||||
4. **Templates**
|
||||
- `templates/autounattend.xml.j2` - Complete Windows unattended install
|
||||
- Configures: network, WinRM, RDP, computer name, timezone, admin password
|
||||
- Static IP or DHCP support
|
||||
- First-logon commands for Ansible readiness
|
||||
|
||||
5. **Helper Playbooks**
|
||||
- `playbooks/list-hyperv-switches.yml` - Discover available switches
|
||||
- `playbooks/create-autounattend-iso.yml` - Helper for ISO creation
|
||||
- `playbooks/install-iis.yml` - IIS deployment demo (existing)
|
||||
- `playbooks/patch-vms.yml` - Windows Update automation (existing)
|
||||
|
||||
6. **Documentation**
|
||||
- `QUICKSTART.md` - Complete step-by-step guide from scratch
|
||||
- `playbooks/README-provision.md` - Detailed VM provisioning guide
|
||||
- `CLAUDE.md` - Architecture and development guidelines
|
||||
- `README.md` - Project overview
|
||||
|
||||
### ⚠️ Known Issues / Limitations
|
||||
|
||||
1. **Virtual Switch Discovery**
|
||||
- Fixed: Playbook now validates switches before VM creation
|
||||
- Default switch changed from "Internal Switch" → "External-NAT"
|
||||
- Run `list-hyperv-switches.yml` to see available switches
|
||||
|
||||
2. **AutoUnattend.xml Delivery**
|
||||
- Currently requires manual intervention or helper playbook
|
||||
- Windows Setup needs to find autounattend.xml (second DVD drive, floppy, or custom ISO)
|
||||
- Helper playbook provided but requires Windows ADK on host
|
||||
|
||||
3. **Circular Variable References**
|
||||
- Fixed: Moved variable defaults from `vars:` to `set_fact` in `pre_tasks`
|
||||
- Variables now compute correctly with extra vars or group_vars fallbacks
|
||||
|
||||
4. **WinRM Configuration**
|
||||
- Currently using NTLM over HTTP (port 5985) for hyperv1.lan.toal.ca
|
||||
- Demo-appropriate but not production-ready
|
||||
- Host provisioning playbook sets up HTTPS for new hosts
|
||||
|
||||
### 🔄 In Progress
|
||||
|
||||
- **Testing**: Hyper-V host provisioning playbook not yet tested on actual host
|
||||
- **VM Provisioning**: Ready to test once host is configured
|
||||
- **AutoUnattend ISO**: Helper playbook exists but untested
|
||||
|
||||
### ❌ Not Yet Implemented
|
||||
|
||||
1. **Windows Baseline Configuration** (future role)
|
||||
- Security hardening
|
||||
- Monitoring agent installation
|
||||
- Compliance scanning
|
||||
|
||||
2. **ServiceNow CMDB Integration**
|
||||
- Playbook exists (`sync-cmdb.yml`) but needs implementation
|
||||
- Requires ServiceNow credentials and table configuration
|
||||
|
||||
3. **Custom Execution Environment**
|
||||
- Currently using `aap.toal.ca/ee-demo`
|
||||
- Could build project-specific EE with all dependencies
|
||||
|
||||
4. **Event-Driven Ansible**
|
||||
- Phase 3 enhancement
|
||||
- React to Hyper-V events, ServiceNow incidents, etc.
|
||||
|
||||
5. **VM Templates**
|
||||
- Sysprep and convert base VM to reusable template
|
||||
- Faster provisioning than full install
|
||||
|
||||
## Inventory Configuration
|
||||
|
||||
### Hypervisor
|
||||
|
||||
**Host**: `hyperv1.lan.toal.ca`
|
||||
**IP**: `192.168.1.182`
|
||||
**Connection**: WinRM over HTTP (NTLM auth, port 5985)
|
||||
**Group**: `hyperv`
|
||||
|
||||
**Inventory Location**: `/home/ptoal/Dev/inventories/toallab-inventory/static.yml`
|
||||
|
||||
```yaml
|
||||
hyperv:
|
||||
hosts:
|
||||
hyperv1.lan.toal.ca:
|
||||
ansible_host: 192.168.1.182
|
||||
```
|
||||
|
||||
### Group Variables
|
||||
|
||||
**Location**: `/home/ptoal/Dev/inventories/toallab-inventory/group_vars/`
|
||||
|
||||
**hyperv/vars.yml**:
|
||||
```yaml
|
||||
default_vm_cpu_count: 2
|
||||
default_vm_memory_gb: 4
|
||||
default_vm_disk_size_gb: 60
|
||||
default_vm_switch: "External-NAT" # Changed from "Internal Switch"
|
||||
vm_storage_path: "D:\\VMs"
|
||||
iso_storage_path: "D:\\ISOs"
|
||||
windows_server_iso: "D:\\ISOs\\Windows_Server_2022.iso"
|
||||
```
|
||||
|
||||
**windows_servers/vars.yml**:
|
||||
- Windows Update categories
|
||||
- DNS servers
|
||||
- Timezone settings
|
||||
- Features to remove
|
||||
|
||||
**web_servers/vars.yml**:
|
||||
- IIS features list
|
||||
- Application pool settings
|
||||
- Website configuration
|
||||
|
||||
### Host Variables
|
||||
|
||||
**hyperv1.lan.toal.ca/vars.yml**:
|
||||
```yaml
|
||||
ansible_connection: winrm
|
||||
ansible_winrm_transport: ntlm
|
||||
ansible_winrm_server_cert_validation: ignore
|
||||
ansible_port: 5985
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Immediate (Next Session)
|
||||
|
||||
1. **Configure Hyper-V Host** (if fresh install)
|
||||
```bash
|
||||
source ~/.venv/ansible/bin/activate
|
||||
cd /home/ptoal/Dev/Projects/HyperV
|
||||
|
||||
# Test connectivity
|
||||
ansible hyperv -m ansible.windows.win_ping
|
||||
|
||||
# Configure host
|
||||
ansible-playbook playbooks/provision-hyperv-host.yml
|
||||
|
||||
# Verify switches
|
||||
ansible-playbook playbooks/list-hyperv-switches.yml
|
||||
```
|
||||
|
||||
2. **Upload Windows Server ISO**
|
||||
- Copy ISO to D:\ISOs\Windows_Server_2022.iso on Hyper-V host
|
||||
- Or download directly on host
|
||||
- Verify path matches `windows_server_iso` in group_vars
|
||||
|
||||
3. **Test VM Provisioning**
|
||||
```bash
|
||||
# Provision first test VM
|
||||
ansible-playbook playbooks/provision-vm.yml \
|
||||
-e vm_name=TEST01 \
|
||||
-e vm_ip_address=192.168.100.10
|
||||
|
||||
# Monitor installation via Hyper-V console
|
||||
# Wait for WinRM to become available (~20-30 min)
|
||||
|
||||
# Test connectivity
|
||||
ansible TEST01 -i "192.168.100.10," -m ansible.windows.win_ping
|
||||
```
|
||||
|
||||
4. **Add VM to Inventory**
|
||||
```bash
|
||||
vi /home/ptoal/Dev/inventories/toallab-inventory/static.yml
|
||||
# Add under web_servers or appropriate group
|
||||
```
|
||||
|
||||
5. **Test Application Deployment**
|
||||
```bash
|
||||
# Deploy IIS
|
||||
ansible-playbook playbooks/install-iis.yml --limit TEST01
|
||||
|
||||
# Verify
|
||||
curl http://192.168.100.10
|
||||
```
|
||||
|
||||
### Short Term (Next Few Sessions)
|
||||
|
||||
1. **Resolve AutoUnattend Delivery**
|
||||
- Test `create-autounattend-iso.yml` helper
|
||||
- OR: Create custom Windows ISO with embedded autounattend.xml
|
||||
- OR: Document manual second-DVD-drive approach
|
||||
- Update provisioning playbook with working method
|
||||
|
||||
2. **Create Windows Baseline Role**
|
||||
```
|
||||
roles/windows_baseline/
|
||||
├── tasks/
|
||||
│ ├── main.yml
|
||||
│ ├── security.yml
|
||||
│ ├── monitoring.yml
|
||||
│ └── compliance.yml
|
||||
├── templates/
|
||||
└── defaults/
|
||||
```
|
||||
- Security hardening (CIS benchmarks subset)
|
||||
- Time sync with domain/NTP
|
||||
- Windows Update configuration
|
||||
- Logging and auditing
|
||||
- Monitoring agent (if available)
|
||||
|
||||
3. **Implement ServiceNow CMDB Sync**
|
||||
- Test ServiceNow API connectivity
|
||||
- Implement `sync-cmdb.yml` playbook
|
||||
- Create/update CI records
|
||||
- Sync on VM create/update/delete
|
||||
|
||||
4. **Test Workflow in AAP**
|
||||
- Create job templates with surveys
|
||||
- Test webhook integration
|
||||
- Create workflow template (provision → baseline → deploy → CMDB)
|
||||
|
||||
### Medium Term
|
||||
|
||||
1. **VM Template Creation**
|
||||
- Build golden image VM
|
||||
- Sysprep and generalize
|
||||
- Convert to template/library
|
||||
- Create playbook to clone from template (faster than full install)
|
||||
|
||||
2. **Backup and Recovery**
|
||||
- Hyper-V checkpoint management playbook
|
||||
- Export/import VM playbooks
|
||||
- Backup scheduling
|
||||
|
||||
3. **Network Configuration**
|
||||
- VLAN tagging playbooks
|
||||
- Multiple NIC configuration
|
||||
- DNS/DHCP integration
|
||||
|
||||
4. **Application Deployment**
|
||||
- Expand beyond IIS demo
|
||||
- SQL Server installation role
|
||||
- Custom application deployment patterns
|
||||
|
||||
### Long Term (Future Phases)
|
||||
|
||||
1. **Event-Driven Ansible**
|
||||
- ServiceNow incident → remediation playbook
|
||||
- Hyper-V event monitoring → capacity management
|
||||
- Windows Event Log → security response
|
||||
|
||||
2. **Multi-Host Hyper-V**
|
||||
- Cluster configuration
|
||||
- Live migration support
|
||||
- Shared storage
|
||||
|
||||
3. **Advanced Features**
|
||||
- Nested virtualization
|
||||
- Container deployment on Windows VMs
|
||||
- Azure Arc integration
|
||||
|
||||
## Key Files Reference
|
||||
|
||||
### Playbooks
|
||||
```
|
||||
playbooks/
|
||||
├── provision-hyperv-host.yml # Configure Hyper-V host (one-time)
|
||||
├── provision-vm.yml # Create Windows VMs
|
||||
├── list-hyperv-switches.yml # Discover switches
|
||||
├── create-autounattend-iso.yml # AutoUnattend helper
|
||||
├── install-iis.yml # IIS deployment
|
||||
├── patch-vms.yml # Windows Updates
|
||||
└── sync-cmdb.yml # ServiceNow (stub)
|
||||
```
|
||||
|
||||
### Configuration
|
||||
```
|
||||
ansible.cfg # Points to toallab-inventory
|
||||
collections/requirements.yml # Required collections
|
||||
templates/autounattend.xml.j2 # Windows unattended install
|
||||
```
|
||||
|
||||
### Documentation
|
||||
```
|
||||
README.md # Project overview
|
||||
QUICKSTART.md # Step-by-step guide
|
||||
HANDOFF.md # This file
|
||||
CLAUDE.md # Architecture details
|
||||
playbooks/README-provision.md # Provisioning deep-dive
|
||||
```
|
||||
|
||||
### Inventory (External)
|
||||
```
|
||||
/home/ptoal/Dev/inventories/toallab-inventory/
|
||||
├── static.yml # Hypervisor and VMs
|
||||
├── group_vars/
|
||||
│ ├── hyperv/vars.yml
|
||||
│ ├── windows_servers/vars.yml
|
||||
│ └── web_servers/vars.yml
|
||||
└── host_vars/
|
||||
└── hyperv1.lan.toal.ca/vars.yml
|
||||
```
|
||||
|
||||
## Quick Reference Commands
|
||||
|
||||
### Setup
|
||||
```bash
|
||||
# Activate environment
|
||||
source ~/.venv/ansible/bin/activate
|
||||
cd /home/ptoal/Dev/Projects/HyperV
|
||||
|
||||
# Test connectivity
|
||||
ansible hyperv -m ansible.windows.win_ping
|
||||
|
||||
# Configure host (one-time)
|
||||
ansible-playbook playbooks/provision-hyperv-host.yml
|
||||
```
|
||||
|
||||
### VM Operations
|
||||
```bash
|
||||
# List switches
|
||||
ansible-playbook playbooks/list-hyperv-switches.yml
|
||||
|
||||
# Provision VM
|
||||
ansible-playbook playbooks/provision-vm.yml \
|
||||
-e vm_name=WEB01 \
|
||||
-e vm_ip_address=192.168.100.10
|
||||
|
||||
# List all VMs
|
||||
ansible hyperv -m ansible.windows.win_shell \
|
||||
-a "Get-VM | Select-Object Name, State, CPUUsage | Format-Table"
|
||||
|
||||
# VM power operations
|
||||
ansible hyperv -m ansible.windows.win_shell -a "Start-VM -Name WEB01"
|
||||
ansible hyperv -m ansible.windows.win_shell -a "Stop-VM -Name WEB01 -Force"
|
||||
ansible hyperv -m ansible.windows.win_shell -a "Remove-VM -Name WEB01 -Force"
|
||||
```
|
||||
|
||||
### Application Deployment
|
||||
```bash
|
||||
# Deploy IIS
|
||||
ansible-playbook playbooks/install-iis.yml --limit WEB01
|
||||
|
||||
# Patch VMs
|
||||
ansible-playbook playbooks/patch-vms.yml --limit windows_servers
|
||||
|
||||
# Test connectivity to VM
|
||||
ansible WEB01 -m ansible.windows.win_ping
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
```bash
|
||||
# Verbose output
|
||||
ansible hyperv -m ansible.windows.win_ping -vvv
|
||||
|
||||
# Check WinRM
|
||||
ansible hyperv -m ansible.windows.win_shell -a "Get-Service WinRM"
|
||||
|
||||
# Verify paths
|
||||
ansible hyperv -m ansible.windows.win_stat -a "path=D:\\ISOs\\Windows_Server_2022.iso"
|
||||
|
||||
# Get Hyper-V info
|
||||
ansible hyperv -m ansible.windows.win_shell -a "Get-VMHost | ConvertTo-Json"
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
### Security Considerations
|
||||
⚠️ **Current configuration is for DEMO/LAB only**
|
||||
|
||||
**Current State**:
|
||||
- WinRM over HTTP (not HTTPS)
|
||||
- NTLM authentication (not Kerberos)
|
||||
- Certificate validation disabled
|
||||
- Permissive firewall rules
|
||||
- No backup/DR
|
||||
- No monitoring
|
||||
|
||||
**For Production**:
|
||||
- Enable HTTPS for WinRM (port 5986)
|
||||
- Use Kerberos authentication
|
||||
- Enable certificate validation
|
||||
- Implement network segmentation
|
||||
- Configure backup and DR
|
||||
- Deploy monitoring/alerting
|
||||
- Implement change management
|
||||
- Regular security patching
|
||||
- Compliance scanning
|
||||
|
||||
### AutoUnattend.xml Gotchas
|
||||
|
||||
1. **Delivery Methods** (in order of difficulty):
|
||||
- Second DVD drive (easiest, use helper playbook)
|
||||
- Rebuild ISO with autounattend in root (moderate)
|
||||
- Floppy image (legacy, difficult)
|
||||
|
||||
2. **Common Issues**:
|
||||
- File not found → wrong location
|
||||
- Interactive prompts → XML syntax error
|
||||
- Network not configured → check IP settings in template
|
||||
- WinRM not available → first logon commands didn't run
|
||||
|
||||
3. **Debugging**:
|
||||
- Check logs: `C:\Windows\Panther\setupact.log`
|
||||
- Watch VM console during install
|
||||
- Verify XML with validator before use
|
||||
|
||||
### Variable Precedence Reminder
|
||||
|
||||
```
|
||||
1. Extra vars (-e on command line) [highest]
|
||||
2. Task vars (in playbook)
|
||||
3. Host vars (host_vars/)
|
||||
4. Group vars (group_vars/)
|
||||
5. Role defaults
|
||||
6. Inventory vars [lowest]
|
||||
```
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
Before declaring completion:
|
||||
|
||||
- [ ] Hyper-V host provisioning successful
|
||||
- [ ] Virtual switches created and accessible
|
||||
- [ ] VM provisioning creates VM successfully
|
||||
- [ ] AutoUnattend.xml performs unattended install
|
||||
- [ ] WinRM available after installation
|
||||
- [ ] VM pingable from Ansible
|
||||
- [ ] IIS deployment works
|
||||
- [ ] Windows Update playbook works
|
||||
- [ ] AAP job template with survey works
|
||||
- [ ] Documentation is accurate
|
||||
|
||||
## Questions for Next Session
|
||||
|
||||
1. **Hyper-V Host Status**:
|
||||
- Is hyperv1.lan.toal.ca a fresh install or already configured?
|
||||
- Are virtual switches already created?
|
||||
- Is storage already set up?
|
||||
|
||||
2. **ISO Availability**:
|
||||
- Is Windows Server 2022 ISO available?
|
||||
- Where is it located?
|
||||
|
||||
3. **Network**:
|
||||
- What network should VMs be on?
|
||||
- Static IPs or DHCP?
|
||||
- Internet access required?
|
||||
|
||||
4. **Scope**:
|
||||
- How many VMs to provision initially?
|
||||
- What applications to deploy?
|
||||
- Integration with existing systems needed?
|
||||
|
||||
## Contact / References
|
||||
|
||||
**Project Location**: `/home/ptoal/Dev/Projects/HyperV`
|
||||
**Inventory Location**: `/home/ptoal/Dev/inventories/toallab-inventory`
|
||||
**Virtual Environment**: `~/.venv/ansible`
|
||||
**Execution Environment**: `aap.toal.ca/ee-demo`
|
||||
|
||||
**Key Technologies**:
|
||||
- Ansible Core 2.15+
|
||||
- Ansible Automation Platform 2.x
|
||||
- Microsoft Hyper-V (Windows Server 2019/2022)
|
||||
- Windows Server 2019/2022
|
||||
|
||||
**Collections Used**:
|
||||
- ansible.windows (>=2.0.0)
|
||||
- community.windows (>=2.0.0)
|
||||
- servicenow.itsm (>=2.0.0)
|
||||
|
||||
---
|
||||
|
||||
**Ready for next session**: Yes
|
||||
**Blockers**: None - ready to test on actual Hyper-V host
|
||||
**Recommended first task**: Run `provision-hyperv-host.yml` to set up the environment
|
||||
394
QUICKSTART.md
Normal file
394
QUICKSTART.md
Normal file
@@ -0,0 +1,394 @@
|
||||
# Hyper-V Automation - Quick Start Guide
|
||||
|
||||
This guide walks through setting up a Hyper-V host and provisioning Windows VMs using Ansible.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Fresh Windows Server 2019/2022 installation
|
||||
- Network connectivity from Ansible control node
|
||||
- Windows Server ISO image
|
||||
|
||||
## Step 1: Initial Hyper-V Host Setup
|
||||
|
||||
### 1.1 Configure WinRM on Hyper-V Host
|
||||
|
||||
On the Windows Server (as Administrator):
|
||||
|
||||
```powershell
|
||||
# Enable PowerShell remoting
|
||||
Enable-PSRemoting -Force
|
||||
|
||||
# Configure WinRM for Ansible
|
||||
winrm quickconfig -transport:http
|
||||
Set-Item WSMan:\localhost\Service\Auth\Basic -Value $true
|
||||
Set-Item WSMan:\localhost\Service\Auth\NTLM -Value $true
|
||||
|
||||
# Allow unencrypted traffic for initial setup (demo only!)
|
||||
Set-Item WSMan:\localhost\Service\AllowUnencrypted -Value $true
|
||||
|
||||
# Configure firewall
|
||||
Enable-NetFirewallRule -Name "WINRM-HTTP-In-TCP"
|
||||
```
|
||||
|
||||
### 1.2 Test Ansible Connectivity
|
||||
|
||||
```bash
|
||||
# Activate virtual environment
|
||||
source ~/.venv/ansible/bin/activate
|
||||
|
||||
# Test connection
|
||||
ansible hyperv -m ansible.windows.win_ping
|
||||
|
||||
# If successful, you should see:
|
||||
# hyperv1.lan.toal.ca | SUCCESS => {
|
||||
# "changed": false,
|
||||
# "ping": "pong"
|
||||
# }
|
||||
```
|
||||
|
||||
## Step 2: Provision Hyper-V Host
|
||||
|
||||
This playbook configures the Hyper-V host with:
|
||||
- Hyper-V role and management tools
|
||||
- Storage directories for VMs and ISOs
|
||||
- Virtual switches (External-NAT and Internal-Lab)
|
||||
- NAT networking for VM internet access
|
||||
- WinRM security hardening
|
||||
- Demo-appropriate settings
|
||||
|
||||
```bash
|
||||
# Run the provisioning playbook
|
||||
ansible-playbook playbooks/provision-hyperv-host.yml
|
||||
|
||||
# This takes 5-10 minutes and may reboot the host
|
||||
```
|
||||
|
||||
### What Gets Created
|
||||
|
||||
```
|
||||
D:\
|
||||
├── VMs\ # VM storage
|
||||
├── ISOs\ # ISO images
|
||||
└── Templates\ # VHD templates (future)
|
||||
|
||||
Virtual Switches:
|
||||
├── External-NAT # For internet access via NAT
|
||||
└── Internal-Lab # Isolated internal network
|
||||
|
||||
NAT Network: 192.168.100.0/24
|
||||
Gateway: 192.168.100.1
|
||||
```
|
||||
|
||||
## Step 3: Upload Windows ISO
|
||||
|
||||
### Option 1: Manual Upload
|
||||
|
||||
```powershell
|
||||
# On Hyper-V host or via RDP
|
||||
# Copy ISO to D:\ISOs\Windows_Server_2022.iso
|
||||
```
|
||||
|
||||
### Option 2: Ansible Copy (slower)
|
||||
|
||||
```bash
|
||||
# From Ansible control node
|
||||
ansible hyperv -m ansible.windows.win_copy \
|
||||
-a "src=/path/to/Windows_Server_2022.iso dest=D:\\ISOs\\Windows_Server_2022.iso"
|
||||
```
|
||||
|
||||
### Option 3: Direct Download (if internet available)
|
||||
|
||||
```bash
|
||||
ansible hyperv -m ansible.windows.win_get_url \
|
||||
-a "url=https://your-iso-source/Windows_Server_2022.iso dest=D:\\ISOs\\Windows_Server_2022.iso"
|
||||
```
|
||||
|
||||
## Step 4: Verify Configuration
|
||||
|
||||
### 4.1 List Available Virtual Switches
|
||||
|
||||
```bash
|
||||
ansible-playbook playbooks/list-hyperv-switches.yml
|
||||
```
|
||||
|
||||
Expected output:
|
||||
```
|
||||
Available Virtual Switches:
|
||||
- External-NAT
|
||||
- Internal-Lab
|
||||
```
|
||||
|
||||
### 4.2 Verify ISO Path
|
||||
|
||||
```bash
|
||||
ansible hyperv -m ansible.windows.win_stat \
|
||||
-a "path=D:\\ISOs\\Windows_Server_2022.iso"
|
||||
```
|
||||
|
||||
## Step 5: Provision Your First VM
|
||||
|
||||
### 5.1 Basic VM Provisioning
|
||||
|
||||
```bash
|
||||
ansible-playbook playbooks/provision-vm.yml \
|
||||
-e vm_name=WEB01 \
|
||||
-e vm_ip_address=192.168.100.10
|
||||
```
|
||||
|
||||
### 5.2 Custom VM Configuration
|
||||
|
||||
```bash
|
||||
ansible-playbook playbooks/provision-vm.yml \
|
||||
-e vm_name=APP01 \
|
||||
-e vm_ip_address=192.168.100.20 \
|
||||
-e vm_cpu_count=4 \
|
||||
-e vm_memory_gb=8 \
|
||||
-e vm_disk_size_gb=100
|
||||
```
|
||||
|
||||
### 5.3 What Happens
|
||||
|
||||
1. ✓ Creates VM with specified resources
|
||||
2. ✓ Generates autounattend.xml for unattended installation
|
||||
3. ✓ Attaches Windows Server ISO
|
||||
4. ✓ Starts VM
|
||||
5. ⏸ Waits for you to verify installation (15-30 min)
|
||||
6. ✓ Verifies WinRM connectivity
|
||||
|
||||
## Step 6: Monitor Installation
|
||||
|
||||
### Via Hyper-V Manager
|
||||
|
||||
```powershell
|
||||
# On Hyper-V host
|
||||
vmconnect.exe localhost WEB01
|
||||
```
|
||||
|
||||
### Via PowerShell
|
||||
|
||||
```bash
|
||||
ansible hyperv -m ansible.windows.win_shell \
|
||||
-a "Get-VM WEB01 | Select-Object Name, State, CPUUsage, Uptime"
|
||||
```
|
||||
|
||||
### Installation Progress
|
||||
|
||||
- **0-5 min**: Windows Setup boots from ISO
|
||||
- **5-20 min**: Windows installation (with autounattend.xml)
|
||||
- **20-25 min**: First boot and configuration
|
||||
- **25-30 min**: WinRM configuration completes
|
||||
|
||||
## Step 7: Add VM to Inventory
|
||||
|
||||
Once installation completes:
|
||||
|
||||
```bash
|
||||
# Edit inventory
|
||||
vi /home/ptoal/Dev/inventories/toallab-inventory/static.yml
|
||||
|
||||
# Add under web_servers:
|
||||
web_servers:
|
||||
hosts:
|
||||
WEB01:
|
||||
ansible_host: 192.168.100.10
|
||||
```
|
||||
|
||||
## Step 8: Verify VM Connectivity
|
||||
|
||||
```bash
|
||||
# Test WinRM
|
||||
ansible WEB01 -m ansible.windows.win_ping
|
||||
|
||||
# Gather facts
|
||||
ansible WEB01 -m ansible.windows.setup
|
||||
```
|
||||
|
||||
## Step 9: Deploy Applications
|
||||
|
||||
### Install IIS
|
||||
|
||||
```bash
|
||||
ansible-playbook playbooks/install-iis.yml --limit WEB01
|
||||
```
|
||||
|
||||
### Apply Windows Updates
|
||||
|
||||
```bash
|
||||
ansible-playbook playbooks/patch-vms.yml --limit WEB01
|
||||
```
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### List All VMs
|
||||
|
||||
```bash
|
||||
ansible hyperv -m ansible.windows.win_shell \
|
||||
-a "Get-VM | Select-Object Name, State, CPUUsage | Format-Table"
|
||||
```
|
||||
|
||||
### Start/Stop VM
|
||||
|
||||
```bash
|
||||
# Start
|
||||
ansible hyperv -m ansible.windows.win_shell -a "Start-VM -Name WEB01"
|
||||
|
||||
# Stop
|
||||
ansible hyperv -m ansible.windows.win_shell -a "Stop-VM -Name WEB01"
|
||||
|
||||
# Shutdown gracefully
|
||||
ansible hyperv -m ansible.windows.win_shell -a "Stop-VM -Name WEB01 -Force"
|
||||
```
|
||||
|
||||
### Delete VM
|
||||
|
||||
```bash
|
||||
ansible hyperv -m ansible.windows.win_shell -a "Remove-VM -Name WEB01 -Force"
|
||||
```
|
||||
|
||||
### Check VM State
|
||||
|
||||
```bash
|
||||
ansible hyperv -m ansible.windows.win_shell \
|
||||
-a "Get-VM WEB01 | ConvertTo-Json"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### WinRM Connection Failed
|
||||
|
||||
**Problem**: `unreachable` or `connection timeout`
|
||||
|
||||
**Solutions**:
|
||||
1. Verify firewall allows WinRM:
|
||||
```powershell
|
||||
Get-NetFirewallRule -Name "WINRM-HTTP-In-TCP" | Select-Object Name, Enabled
|
||||
```
|
||||
|
||||
2. Check WinRM service:
|
||||
```powershell
|
||||
Get-Service WinRM
|
||||
winrm enumerate winrm/config/listener
|
||||
```
|
||||
|
||||
3. Test from Ansible host:
|
||||
```bash
|
||||
ansible hyperv -m ansible.windows.win_ping -vvv
|
||||
```
|
||||
|
||||
### Virtual Switch Not Found
|
||||
|
||||
**Problem**: `Hyper-V was unable to find a virtual switch`
|
||||
|
||||
**Solutions**:
|
||||
1. List available switches:
|
||||
```bash
|
||||
ansible-playbook playbooks/list-hyperv-switches.yml
|
||||
```
|
||||
|
||||
2. Update group_vars or pass correct switch:
|
||||
```bash
|
||||
-e vm_switch="External-NAT"
|
||||
```
|
||||
|
||||
3. Create missing switch on Hyper-V host:
|
||||
```powershell
|
||||
New-VMSwitch -Name "External-NAT" -SwitchType External -NetAdapterName "Ethernet"
|
||||
```
|
||||
|
||||
### AutoUnattend Not Working
|
||||
|
||||
**Problem**: Windows installation shows interactive prompts
|
||||
|
||||
**Solutions**:
|
||||
1. Verify autounattend.xml was created:
|
||||
```bash
|
||||
ansible hyperv -m ansible.windows.win_stat \
|
||||
-a "path=D:\\VMs\\WEB01\\autounattend.xml"
|
||||
```
|
||||
|
||||
2. Check XML syntax in file
|
||||
|
||||
3. Mount as second DVD drive (requires manual step or helper playbook)
|
||||
|
||||
4. Review Windows Setup logs on VM:
|
||||
```
|
||||
C:\Windows\Panther\setupact.log
|
||||
```
|
||||
|
||||
### VM Won't Start
|
||||
|
||||
**Problem**: `failed to start` or `invalid configuration`
|
||||
|
||||
**Solutions**:
|
||||
1. Check VM configuration:
|
||||
```bash
|
||||
ansible hyperv -m ansible.windows.win_shell \
|
||||
-a "Get-VM WEB01 | Select-Object *"
|
||||
```
|
||||
|
||||
2. Verify VHD exists:
|
||||
```bash
|
||||
ansible hyperv -m ansible.windows.win_stat \
|
||||
-a "path=D:\\VMs\\WEB01\\WEB01.vhdx"
|
||||
```
|
||||
|
||||
3. Check Hyper-V event logs:
|
||||
```powershell
|
||||
Get-EventLog -LogName "Microsoft-Windows-Hyper-V-*" -Newest 20
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
/home/ptoal/Dev/Projects/HyperV/
|
||||
├── playbooks/
|
||||
│ ├── provision-hyperv-host.yml # Configure Hyper-V host
|
||||
│ ├── provision-vm.yml # Create VMs
|
||||
│ ├── list-hyperv-switches.yml # List available switches
|
||||
│ ├── install-iis.yml # Deploy IIS
|
||||
│ └── patch-vms.yml # Windows Updates
|
||||
├── templates/
|
||||
│ └── autounattend.xml.j2 # Unattended install template
|
||||
└── ansible.cfg # Project config
|
||||
|
||||
/home/ptoal/Dev/inventories/toallab-inventory/
|
||||
├── static.yml # Static inventory
|
||||
├── group_vars/
|
||||
│ ├── hyperv/vars.yml # Hyper-V defaults
|
||||
│ └── windows_servers/vars.yml # Windows defaults
|
||||
└── host_vars/
|
||||
└── hyperv1.lan.toal.ca/vars.yml # Host-specific config
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Create VM templates** - Sysprep a base VM and convert to template
|
||||
2. **Implement backups** - Use Hyper-V checkpoints or backup playbooks
|
||||
3. **Configure monitoring** - Integrate with Grafana/Prometheus
|
||||
4. **Domain join** - Add VMs to Active Directory
|
||||
5. **Application deployment** - Deploy real applications beyond IIS demo
|
||||
6. **CMDB sync** - Implement ServiceNow integration
|
||||
7. **Event-Driven Ansible** - React to Hyper-V events automatically
|
||||
|
||||
## Production Considerations
|
||||
|
||||
⚠️ **This is a demo configuration.** For production:
|
||||
|
||||
- [ ] Enable HTTPS for WinRM (not HTTP)
|
||||
- [ ] Use Kerberos authentication (not NTLM/Basic)
|
||||
- [ ] Configure storage on SAN/redundant storage
|
||||
- [ ] Implement Hyper-V clustering for HA
|
||||
- [ ] Network segmentation and VLANs
|
||||
- [ ] Security hardening (CIS benchmarks)
|
||||
- [ ] Backup and disaster recovery
|
||||
- [ ] Monitoring and alerting
|
||||
- [ ] Change management and approvals
|
||||
- [ ] Documentation and runbooks
|
||||
|
||||
## Resources
|
||||
|
||||
- [Hyper-V Documentation](https://docs.microsoft.com/en-us/windows-server/virtualization/hyper-v/)
|
||||
- [Ansible Windows Guide](https://docs.ansible.com/ansible/latest/os_guide/windows_usage.html)
|
||||
- [WinRM Setup](https://docs.ansible.com/ansible/latest/os_guide/windows_setup.html)
|
||||
- [Project CLAUDE.md](CLAUDE.md) - Architecture documentation
|
||||
- [Provisioning Guide](playbooks/README-provision.md) - Detailed VM provisioning
|
||||
42
playbooks/list-hyperv-switches.yml
Normal file
42
playbooks/list-hyperv-switches.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
# Quick playbook to list available Hyper-V virtual switches
|
||||
# Usage: ansible-playbook playbooks/list-hyperv-switches.yml
|
||||
|
||||
- name: List Hyper-V Virtual Switches
|
||||
hosts: hyperv
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Get virtual switches
|
||||
ansible.windows.win_shell: |
|
||||
Get-VMSwitch | Select-Object Name, SwitchType, NetAdapterInterfaceDescription | Format-Table -AutoSize
|
||||
register: switches
|
||||
changed_when: false
|
||||
|
||||
- name: Display switches
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ switches.stdout_lines }}"
|
||||
|
||||
- name: Get switches in JSON format
|
||||
ansible.windows.win_shell: |
|
||||
Get-VMSwitch | Select-Object Name, SwitchType | ConvertTo-Json
|
||||
register: switches_json
|
||||
changed_when: false
|
||||
|
||||
- name: Parse switches
|
||||
ansible.builtin.set_fact:
|
||||
switch_list: "{{ switches_json.stdout | from_json }}"
|
||||
|
||||
- name: Display switch names
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "========================================="
|
||||
- "Available Virtual Switches:"
|
||||
- "========================================="
|
||||
- "{{ switch_list | map(attribute='Name') | list }}"
|
||||
- ""
|
||||
- "To use a switch, either:"
|
||||
- "1. Pass as variable: -e vm_switch='<switch_name>'"
|
||||
- "2. Update default in: /home/ptoal/Dev/inventories/toallab-inventory/group_vars/hyperv/vars.yml"
|
||||
- ""
|
||||
- "Current default: {{ default_vm_switch }}"
|
||||
388
playbooks/provision-hyperv-host.yml
Normal file
388
playbooks/provision-hyperv-host.yml
Normal file
@@ -0,0 +1,388 @@
|
||||
---
|
||||
# Provision Hyper-V Host for Demo Environment
|
||||
# This playbook configures a fresh Windows Server with Hyper-V for demonstration purposes
|
||||
#
|
||||
# WARNING: This is for DEMO environments only. Production deployments require:
|
||||
# - Proper security hardening
|
||||
# - Network segmentation
|
||||
# - Storage configuration (SAN, clustering, etc.)
|
||||
# - Backup and DR planning
|
||||
# - Monitoring and alerting
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/provision-hyperv-host.yml
|
||||
|
||||
- name: Provision Hyper-V Host
|
||||
hosts: hyperv
|
||||
gather_facts: true
|
||||
|
||||
vars:
|
||||
|
||||
# Virtual switch configuration
|
||||
demo_switches:
|
||||
- name: "External-NAT"
|
||||
type: "External"
|
||||
notes: "External switch with NAT for internet access"
|
||||
- name: "Internal-Lab"
|
||||
type: "Internal"
|
||||
notes: "Internal switch for isolated lab network"
|
||||
|
||||
# NAT configuration for demo
|
||||
nat_network: "192.168.100.0/24"
|
||||
nat_gateway: "192.168.100.1"
|
||||
nat_name: "DemoNAT"
|
||||
|
||||
tasks:
|
||||
- name: Display provisioning plan
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "========================================="
|
||||
- "Hyper-V Host Provisioning Plan"
|
||||
- "========================================="
|
||||
- "Host: {{ inventory_hostname }}"
|
||||
- "Storage Drive: {{ vm_storage_drive }}"
|
||||
- "VM Path: {{ vm_storage_path }}"
|
||||
- "ISO Path: {{ iso_storage_path }}"
|
||||
- "Virtual Switches: {{ demo_switches | map(attribute='name') | list | join(', ') }}"
|
||||
- "NAT Network: {{ nat_network }}"
|
||||
- "========================================="
|
||||
|
||||
- name: Check if Hyper-V is installed
|
||||
ansible.windows.win_shell: |
|
||||
Get-WindowsFeature -Name Hyper-V | Select-Object -ExpandProperty InstallState
|
||||
register: hyperv_state
|
||||
changed_when: false
|
||||
|
||||
- name: Install Hyper-V role and management tools
|
||||
ansible.windows.win_feature:
|
||||
name:
|
||||
- Hyper-V
|
||||
- Hyper-V-PowerShell
|
||||
- RSAT-Hyper-V-Tools
|
||||
state: present
|
||||
include_management_tools: true
|
||||
register: hyperv_install
|
||||
when: hyperv_state.stdout | trim != 'Installed'
|
||||
|
||||
- name: Reboot if Hyper-V was installed
|
||||
ansible.windows.win_reboot:
|
||||
reboot_timeout: 600
|
||||
post_reboot_delay: 60
|
||||
when:
|
||||
- hyperv_install is defined
|
||||
- hyperv_install.reboot_required | default(false)
|
||||
|
||||
- name: Wait for system to be ready after reboot
|
||||
ansible.windows.win_ping:
|
||||
retries: 10
|
||||
delay: 30
|
||||
when:
|
||||
- hyperv_install is defined
|
||||
- hyperv_install.reboot_required | default(false)
|
||||
|
||||
- name: Create storage directories
|
||||
ansible.windows.win_file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
loop:
|
||||
- "{{ vm_storage_path }}"
|
||||
- "{{ iso_storage_path }}"
|
||||
- "{{ vhd_template_path }}"
|
||||
|
||||
- name: Set storage directory permissions
|
||||
ansible.windows.win_shell: |
|
||||
# Grant Hyper-V full control to storage directories
|
||||
icacls "{{ item }}" /grant "NT VIRTUAL MACHINE\Virtual Machines:(OI)(CI)F"
|
||||
loop:
|
||||
- "{{ vm_storage_path }}"
|
||||
- "{{ iso_storage_path }}"
|
||||
- "{{ vhd_template_path }}"
|
||||
register: acl_result
|
||||
changed_when: "'Successfully processed' in acl_result.stdout"
|
||||
|
||||
- name: Get existing virtual switches
|
||||
ansible.windows.win_shell: |
|
||||
Get-VMSwitch | Select-Object Name, SwitchType | ConvertTo-Json
|
||||
register: existing_switches
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Parse existing switches
|
||||
ansible.builtin.set_fact:
|
||||
existing_switch_names: "{{ (existing_switches.stdout | from_json | default([])) | map(attribute='Name') | list }}"
|
||||
when: existing_switches.stdout | trim | length > 0
|
||||
|
||||
- name: Set empty switch list if none exist
|
||||
ansible.builtin.set_fact:
|
||||
existing_switch_names: []
|
||||
when: existing_switches.stdout | trim | length == 0
|
||||
|
||||
- name: Display existing switches
|
||||
ansible.builtin.debug:
|
||||
msg: "Existing switches: {{ existing_switch_names | join(', ') if existing_switch_names | length > 0 else 'None' }}"
|
||||
|
||||
- name: Create External virtual switch
|
||||
ansible.windows.win_shell: |
|
||||
# Get the first network adapter that is up and has a default gateway
|
||||
$adapter = Get-NetAdapter | Where-Object {
|
||||
$_.Status -eq 'Up' -and
|
||||
(Get-NetIPConfiguration -InterfaceIndex $_.ifIndex).IPv4DefaultGateway -ne $null
|
||||
} | Select-Object -First 1
|
||||
|
||||
if ($adapter) {
|
||||
New-VMSwitch -Name "External-NAT" `
|
||||
-NetAdapterName $adapter.Name `
|
||||
-AllowManagementOS $true `
|
||||
-Notes "External switch for VM internet access"
|
||||
Write-Host "Created External-NAT switch using adapter: $($adapter.Name)"
|
||||
} else {
|
||||
Write-Host "No suitable network adapter found for external switch"
|
||||
exit 1
|
||||
}
|
||||
register: external_switch
|
||||
when: "'External-NAT' not in existing_switch_names"
|
||||
failed_when: external_switch.rc != 0
|
||||
changed_when: "'Created External-NAT' in external_switch.stdout"
|
||||
|
||||
- name: Create Internal virtual switch
|
||||
ansible.windows.win_shell: |
|
||||
New-VMSwitch -Name "Internal-Lab" `
|
||||
-SwitchType Internal `
|
||||
-Notes "Internal switch for isolated lab network"
|
||||
when: "'Internal-Lab' not in existing_switch_names"
|
||||
|
||||
- name: Configure NAT for internal network
|
||||
block:
|
||||
- name: Get Internal-Lab switch interface index
|
||||
ansible.windows.win_shell: |
|
||||
$adapter = Get-NetAdapter | Where-Object { $_.Name -like '*Internal-Lab*' }
|
||||
$adapter.ifIndex
|
||||
register: internal_adapter_index
|
||||
changed_when: false
|
||||
|
||||
- name: Configure IP address on Internal-Lab switch
|
||||
ansible.windows.win_shell: |
|
||||
$ifIndex = {{ internal_adapter_index.stdout | trim }}
|
||||
# Remove existing IP if present
|
||||
Remove-NetIPAddress -InterfaceIndex $ifIndex -Confirm:$false -ErrorAction SilentlyContinue
|
||||
# Add new IP address
|
||||
New-NetIPAddress -InterfaceIndex $ifIndex `
|
||||
-IPAddress {{ nat_gateway }} `
|
||||
-PrefixLength 24 `
|
||||
-ErrorAction Stop
|
||||
register: ip_config
|
||||
changed_when: true
|
||||
failed_when: false
|
||||
|
||||
- name: Check if NAT already exists
|
||||
ansible.windows.win_shell: |
|
||||
Get-NetNat -Name "{{ nat_name }}" -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name
|
||||
register: existing_nat
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Create NAT for internal network
|
||||
ansible.windows.win_shell: |
|
||||
New-NetNat -Name "{{ nat_name }}" `
|
||||
-InternalIPInterfaceAddressPrefix "{{ nat_network }}"
|
||||
when: existing_nat.stdout | trim | length == 0
|
||||
|
||||
- name: Configure WinRM for Ansible
|
||||
block:
|
||||
- name: Enable WinRM HTTPS listener
|
||||
ansible.windows.win_shell: |
|
||||
# Check if HTTPS listener exists
|
||||
$httpsListener = Get-ChildItem WSMan:\localhost\Listener |
|
||||
Where-Object { $_.Keys -contains 'Transport=HTTPS' }
|
||||
|
||||
if (-not $httpsListener) {
|
||||
# Create self-signed certificate
|
||||
$cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME `
|
||||
-CertStoreLocation Cert:\LocalMachine\My `
|
||||
-NotAfter (Get-Date).AddYears(5)
|
||||
|
||||
# Create HTTPS listener
|
||||
New-Item -Path WSMan:\localhost\Listener `
|
||||
-Transport HTTPS `
|
||||
-Address * `
|
||||
-CertificateThumbPrint $cert.Thumbprint -Force
|
||||
|
||||
Write-Host "Created HTTPS listener"
|
||||
} else {
|
||||
Write-Host "HTTPS listener already exists"
|
||||
}
|
||||
register: winrm_https
|
||||
changed_when: "'Created HTTPS listener' in winrm_https.stdout"
|
||||
|
||||
- name: Configure WinRM service settings
|
||||
ansible.windows.win_shell: |
|
||||
# Set WinRM service to start automatically
|
||||
Set-Service WinRM -StartupType Automatic
|
||||
|
||||
# Configure WinRM settings for Ansible
|
||||
Set-Item WSMan:\localhost\Service\Auth\Basic -Value $true
|
||||
Set-Item WSMan:\localhost\Service\Auth\CredSSP -Value $true
|
||||
Set-Item WSMan:\localhost\Service\AllowUnencrypted -Value $false
|
||||
Set-Item WSMan:\localhost\MaxTimeoutms -Value 1800000
|
||||
|
||||
# Restart WinRM
|
||||
Restart-Service WinRM
|
||||
register: winrm_config
|
||||
changed_when: true
|
||||
|
||||
- name: Configure Windows Firewall for demo
|
||||
ansible.windows.win_shell: |
|
||||
# Enable WinRM firewall rules
|
||||
Enable-NetFirewallRule -Name "WINRM-HTTP-In-TCP-PUBLIC"
|
||||
Enable-NetFirewallRule -Name "WINRM-HTTPS-In-TCP-PUBLIC"
|
||||
|
||||
# Enable RDP for management
|
||||
Enable-NetFirewallRule -Name "RemoteDesktop-UserMode-In-TCP"
|
||||
|
||||
# Enable Hyper-V management
|
||||
Enable-NetFirewallRule -DisplayGroup "Hyper-V*"
|
||||
register: firewall_config
|
||||
changed_when: true
|
||||
|
||||
- name: Set Hyper-V default VM storage locations
|
||||
ansible.windows.win_shell: |
|
||||
Set-VMHost -VirtualHardDiskPath "{{ vm_storage_path }}" `
|
||||
-VirtualMachinePath "{{ vm_storage_path }}"
|
||||
register: vm_defaults
|
||||
changed_when: true
|
||||
|
||||
- name: Enable Hyper-V Enhanced Session Mode
|
||||
ansible.windows.win_shell: |
|
||||
Set-VMHost -EnableEnhancedSessionMode $true
|
||||
changed_when: true
|
||||
|
||||
- name: Configure power settings for demo
|
||||
ansible.windows.win_shell: |
|
||||
# Set to High Performance power plan
|
||||
powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
|
||||
|
||||
# Disable sleep and hibernation
|
||||
powercfg /change monitor-timeout-ac 0
|
||||
powercfg /change disk-timeout-ac 0
|
||||
powercfg /change standby-timeout-ac 0
|
||||
powercfg /hibernate off
|
||||
register: power_config
|
||||
changed_when: true
|
||||
|
||||
- name: Install helpful PowerShell modules
|
||||
ansible.windows.win_shell: |
|
||||
# Install PowerShell modules for Hyper-V management
|
||||
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -ErrorAction SilentlyContinue
|
||||
|
||||
# Install modules if not present
|
||||
$modules = @('Posh-SSH', 'PSWindowsUpdate')
|
||||
foreach ($module in $modules) {
|
||||
if (-not (Get-Module -ListAvailable -Name $module)) {
|
||||
Install-Module -Name $module -Force -SkipPublisherCheck -Scope AllUsers
|
||||
Write-Host "Installed $module"
|
||||
} else {
|
||||
Write-Host "$module already installed"
|
||||
}
|
||||
}
|
||||
register: ps_modules
|
||||
changed_when: "'Installed' in ps_modules.stdout"
|
||||
|
||||
- name: Create README file on Hyper-V host
|
||||
ansible.windows.win_copy:
|
||||
content: |
|
||||
HYPER-V DEMO HOST CONFIGURATION
|
||||
================================
|
||||
|
||||
This host has been configured by Ansible for demonstration purposes.
|
||||
|
||||
Storage Locations:
|
||||
- VMs: {{ vm_storage_path }}
|
||||
- ISOs: {{ iso_storage_path }}
|
||||
- Templates: {{ vhd_template_path }}
|
||||
|
||||
Virtual Switches:
|
||||
{% for switch in demo_switches %}
|
||||
- {{ switch.name }} ({{ switch.type }}): {{ switch.notes }}
|
||||
{% endfor %}
|
||||
|
||||
NAT Configuration:
|
||||
- Network: {{ nat_network }}
|
||||
- Gateway: {{ nat_gateway }}
|
||||
- NAT Name: {{ nat_name }}
|
||||
|
||||
Management:
|
||||
- WinRM: Enabled (HTTP: 5985, HTTPS: 5986)
|
||||
- RDP: Enabled
|
||||
- Enhanced Session Mode: Enabled
|
||||
|
||||
Next Steps:
|
||||
1. Copy Windows Server ISOs to {{ iso_storage_path }}
|
||||
2. Use Ansible to provision VMs: ansible-playbook provision-vm.yml
|
||||
3. Access Hyper-V Manager remotely or via RDP
|
||||
|
||||
WARNING: This is a DEMO configuration - not suitable for production!
|
||||
- Firewall rules are permissive
|
||||
- Self-signed certificates for WinRM
|
||||
- No backup/DR configuration
|
||||
- No monitoring configured
|
||||
|
||||
Managed by: Ansible Automation Platform
|
||||
Provisioned: {{ ansible_date_time.iso8601 }}
|
||||
dest: "{{ vm_storage_drive }}\\HYPERV-README.txt"
|
||||
|
||||
- name: Get Hyper-V host information
|
||||
ansible.windows.win_shell: |
|
||||
$host = Get-VMHost
|
||||
[PSCustomObject]@{
|
||||
ComputerName = $host.ComputerName
|
||||
LogicalProcessorCount = $host.LogicalProcessorCount
|
||||
MemoryCapacity = [math]::Round($host.MemoryCapacity / 1GB, 2)
|
||||
VirtualHardDiskPath = $host.VirtualHardDiskPath
|
||||
VirtualMachinePath = $host.VirtualMachinePath
|
||||
MacAddressMinimum = $host.MacAddressMinimum
|
||||
MacAddressMaximum = $host.MacAddressMaximum
|
||||
EnhancedSessionModeEnabled = $host.EnableEnhancedSessionMode
|
||||
} | ConvertTo-Json
|
||||
register: hyperv_info
|
||||
changed_when: false
|
||||
|
||||
- name: Display Hyper-V configuration summary
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "========================================="
|
||||
- "Hyper-V Host Provisioning Complete"
|
||||
- "========================================="
|
||||
- "{{ hyperv_info.stdout | from_json | to_nice_json }}"
|
||||
- ""
|
||||
- "Virtual Switches Created:"
|
||||
- "{{ demo_switches | map(attribute='name') | list }}"
|
||||
- ""
|
||||
- "Storage Configured:"
|
||||
- " VMs: {{ vm_storage_path }}"
|
||||
- " ISOs: {{ iso_storage_path }}"
|
||||
- " Templates: {{ vhd_template_path }}"
|
||||
- ""
|
||||
- "NAT Network:"
|
||||
- " Network: {{ nat_network }}"
|
||||
- " Gateway: {{ nat_gateway }}"
|
||||
- ""
|
||||
- "Next Steps:"
|
||||
- "1. Upload Windows Server ISO to {{ iso_storage_path }}"
|
||||
- "2. Update group_vars/hyperv/vars.yml with:"
|
||||
- " - windows_server_iso: {{ iso_storage_path }}\\Windows_Server_2022.iso"
|
||||
- " - default_vm_switch: External-NAT or Internal-Lab"
|
||||
- "3. Run: ansible-playbook playbooks/list-hyperv-switches.yml"
|
||||
- "4. Provision VMs: ansible-playbook playbooks/provision-vm.yml"
|
||||
- ""
|
||||
- "WARNING: Demo configuration - not production ready!"
|
||||
- "========================================="
|
||||
|
||||
- name: Update inventory group_vars with discovered configuration
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Update /home/ptoal/Dev/inventories/toallab-inventory/group_vars/hyperv/vars.yml:"
|
||||
- ""
|
||||
- "vm_storage_path: '{{ vm_storage_path }}'"
|
||||
- "iso_storage_path: '{{ iso_storage_path }}'"
|
||||
- "default_vm_switch: 'External-NAT' # or 'Internal-Lab'"
|
||||
delegate_to: localhost
|
||||
Reference in New Issue
Block a user