feat: Add professional hierarchical documentation
Some checks are pending
Build and Release / build-sign-package (push) Waiting to run
Some checks are pending
Build and Release / build-sign-package (push) Waiting to run
- Created comprehensive README.md with Mermaid diagrams, badges, and TOC - Added docs/ directory with 7 sections and 14 markdown files - Included architecture diagrams, flowcharts, and sequence diagrams - All documentation is fully interlinked with cross-references - Added ISO storage location on Proxmox development server - Included troubleshooting guide and evaluation management docs - All config files (Packer, Terraform, Ansible, Forgejo) documented - Added icons and visual elements throughout documentation
This commit is contained in:
parent
faf04d69f8
commit
e4f03427b7
24 changed files with 3844 additions and 2 deletions
54
.forgejo/workflows/release.yml
Normal file
54
.forgejo/workflows/release.yml
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
name: Build and Release
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build-sign-package:
|
||||
runs-on: ubuntu-latest
|
||||
container: archlinux:latest
|
||||
steps:
|
||||
- name: Install Tools
|
||||
run: pacman -Syu --noconfirm mingw-w64-gcc nsis osslsigncode opentofu ansible python-pywinrm packer
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Cross-Compile (MinGW)
|
||||
run: x86_64-w64-mingw32-gcc src/main.c -o dist/app.exe
|
||||
|
||||
- name: Package (NSIS)
|
||||
run: makensis -DVERSION=${{ gitea.ref_name }} installer.nsi
|
||||
|
||||
- name: Code Sign (Linux Native)
|
||||
env:
|
||||
PFX_PASS: ${{ secrets.PFX_PASS }}
|
||||
run: |
|
||||
osslsigncode sign -pkcs12 cert.pfx -pass "$PFX_PASS" \
|
||||
-t http://timestamp.digicert.com \
|
||||
-in dist/installer.exe -out dist/installer_signed.exe
|
||||
|
||||
- name: Provision Windows VM (OpenTofu)
|
||||
env:
|
||||
PM_API_TOKEN_ID: ${{ secrets.PM_TOKEN_ID }}
|
||||
PM_API_TOKEN_SECRET: ${{ secrets.PM_TOKEN_SECRET }}
|
||||
TF_VAR_build_id: ${{ gitea.run_number }}
|
||||
run: |
|
||||
cd terraform
|
||||
tofu init
|
||||
tofu apply -auto-approve
|
||||
echo "VM_IP=$(tofu output -raw vm_ip)" >> $GITHUB_ENV
|
||||
|
||||
- name: Verify on Windows (Ansible)
|
||||
env:
|
||||
ANSIBLE_USER: Administrator
|
||||
ANSIBLE_PASSWORD: ${{ secrets.WIN_ADMIN_PASS }}
|
||||
run: |
|
||||
echo "[windows_vm]" > inventory.ini
|
||||
echo "$VM_IP ansible_user=$ANSIBLE_USER ansible_password=$ANSIBLE_PASSWORD ansible_connection=winrm ansible_winrm_server_cert_validation=ignore" >> inventory.ini
|
||||
|
||||
ansible-playbook -i inventory.ini ansible/pipeline.yml
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
cd terraform
|
||||
tofu destroy -auto-approve
|
||||
40
.gitignore
vendored
Normal file
40
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Packer
|
||||
*.pkr.hcl.pkr.hcl
|
||||
|
||||
# Terraform
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
.terraform/
|
||||
.terraform.lock.hcl
|
||||
crash.log
|
||||
override.tf
|
||||
override.tf.json
|
||||
*.tfplan
|
||||
|
||||
# Ansible
|
||||
*.retry
|
||||
inventory.ini
|
||||
|
||||
# Forgejo
|
||||
*.pfx
|
||||
|
||||
# Build artifacts
|
||||
dist/
|
||||
*.exe
|
||||
*.msi
|
||||
*.dll
|
||||
*.o
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
356
README.md
356
README.md
|
|
@ -1,3 +1,355 @@
|
|||
# windows-iac-vm-tooling
|
||||
# 🖥️ Windows Automation on Proxmox
|
||||
|
||||
This repo contains scripts and docs on how to create a golden image and then also how to use IaC tooling (OpenTofu, Ansibla and Jinja) to deploy windows build and test machines.
|
||||
<!-- Badges and metadata -->
|
||||
[](LICENSE)
|
||||
[](.forgejo/workflows/release.yml)
|
||||
[](https://www.microsoft.com/en-us/windows/windows-11-enterprise)
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
1. [Overview](#-overview)
|
||||
2. [Architecture](#-architecture)
|
||||
3. [Quick Start](#-quick-start)
|
||||
4. [Project Structure](#-project-structure)
|
||||
5. [Documentation Index](#-documentation-index)
|
||||
6. [Prerequisites](#-prerequisites)
|
||||
7. [Pipeline Phases](#-pipeline-phases)
|
||||
8. [Advanced Topics](#-advanced-topics)
|
||||
9. [Contributing](#-contributing)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Overview
|
||||
|
||||
This repository contains a complete **automated build, package, and test pipeline** for Windows applications using infrastructure as code. The system enables a **"One-Click"** Forgejo pipeline that produces signed, verified Windows installer artifacts without manual intervention.
|
||||
|
||||
### Key Features
|
||||
|
||||
- **🔧 Automated Golden Image Creation** - Packer builds reproducible Windows templates
|
||||
- **☁️ Ephemeral Infrastructure** - OpenTofu provisions temporary Windows VMs for testing
|
||||
- **🔐 Code Signing** - Linux-native code signing with timestamp verification
|
||||
- **✅ Automated Testing** - Ansible verifies installations on live Windows VMs
|
||||
- **🔄 Cross-Platform Compilation** - MinGW cross-compilation for Windows on Linux
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph CI["Forgejo CI/CD"]
|
||||
direction LR
|
||||
C[Checkout] --> X[Cross-Compile<br/>MinGW] --> P[Package<br/>NSIS] --> S[Sign<br/>osslsigncode]
|
||||
end
|
||||
|
||||
subgraph Build["Build Phase"]
|
||||
P --> B[Packer Build<br/>Windows Template]
|
||||
B --> T[OpenTofu Provision<br/>Windows VM]
|
||||
end
|
||||
|
||||
subgraph Verify["Verification Phase"]
|
||||
S --> A[Ansible Test<br/>Smoke Test]
|
||||
T --> A
|
||||
end
|
||||
|
||||
subgraph Artifacts["Output"]
|
||||
A --> EXE[ installer_signed.exe]
|
||||
EXE --> Release[Release Artifacts]
|
||||
end
|
||||
|
||||
CI --> Build --> Verify --> Artifacts
|
||||
|
||||
style CI fill:#e1f5fe
|
||||
style Build fill:#e8f5e9
|
||||
style Verify fill:#fff3e0
|
||||
style Artifacts fill:#fce4ec
|
||||
```
|
||||
|
||||
### Pipeline Flow
|
||||
|
||||
| Phase | Technology | Purpose |
|
||||
|-------|------------|---------|
|
||||
| **1. Build** | Packer | Create Windows golden image template |
|
||||
| **2. Provision** | OpenTofu | Spin up ephemeral Windows test VMs |
|
||||
| **3. Compile** | MinGW | Cross-compile Windows applications on Linux |
|
||||
| **4. Package** | NSIS | Create Windows installer packages |
|
||||
| **5. Sign** | osslsigncode | Code-sign binaries with timestamp |
|
||||
| **6. Verify** | Ansible | Test installation on live Windows VM |
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before beginning, ensure ISOs are available on Proxmox:
|
||||
|
||||
```bash
|
||||
# ISO Storage Location
|
||||
/mnt/pve-07-iso-nvme/template/iso/
|
||||
```
|
||||
|
||||
**Required Files:**
|
||||
- `CLIENT_LTSC_EVAL_x64FRE_en-us.iso` - Windows 11 LTSC 2024
|
||||
- `virtio-win.iso` - VirtIO drivers for I/O performance
|
||||
|
||||
**Download Sources:**
|
||||
- [Windows 11 Enterprise](https://info.microsoft.com/ww-landing-windows-11-enterprise.html)
|
||||
- [VirtIO Drivers](https://github.com/virtio-win/virtio-win-pkg-scripts/releases)
|
||||
|
||||
### Step 1: Build Golden Image
|
||||
|
||||
```bash
|
||||
cd packer
|
||||
packer init .
|
||||
packer build windows.pkr.hcl
|
||||
```
|
||||
|
||||
### Step 2: Provision Test Environment
|
||||
|
||||
```bash
|
||||
cd terraform
|
||||
tofu init
|
||||
export PM_API_TOKEN_ID="your-token-id"
|
||||
export PM_API_TOKEN_SECRET="your-token-secret"
|
||||
tofu apply -auto-approve
|
||||
```
|
||||
|
||||
### Step 3: Run Verification
|
||||
|
||||
```bash
|
||||
ansible-playbook -i inventory.ini ../ansible/pipeline.yml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
windows-iac-vm-tooling/
|
||||
├── 📄 README.md # ← Entry point (this file)
|
||||
├── 📄 doc.tex # Full LaTeX documentation
|
||||
├── 📄 LICENSE # MIT License
|
||||
├── 📄 installer.nsi # NSIS installer script
|
||||
├── 📁 .forgejo/
|
||||
│ └── 📁 workflows/
|
||||
│ └── 📄 release.yml # Forgejo CI/CD pipeline
|
||||
├── 📁 ansible/
|
||||
│ └── 📄 pipeline.yml # Ansible verification playbook
|
||||
├── 📁 docs/ # Hierarchical documentation
|
||||
│ ├── 📄 index.md # Documentation index
|
||||
│ ├── 📁 01-overview/
|
||||
│ │ └── 📄 architecture.md # Detailed architecture
|
||||
│ ├── 📁 02-prerequisites/
|
||||
│ │ ├── 📄 isos.md # ISO requirements
|
||||
│ │ └── 📄 secrets.md # Secret management
|
||||
│ ├── 📁 03-packer/
|
||||
│ │ ├── 📄 configuration.md # Packer HCL config
|
||||
│ │ └── 📄 autounattend.md # Windows answer file
|
||||
│ ├── 📁 04-terraform/
|
||||
│ │ ├── 📄 main.tf.md # OpenTofu resources
|
||||
│ │ └── 📄 variables.md # Terraform variables
|
||||
│ ├── 📁 05-ansible/
|
||||
│ │ └── 📄 pipeline.md # Ansible playbook guide
|
||||
│ ├── 📁 06-ci-cd/
|
||||
│ │ └── 📄 forgejo-workflows.md # CI/CD pipeline details
|
||||
│ └── 📁 07-advanced/
|
||||
│ ├── 📄 evaluation.md # 90-day evaluation management
|
||||
│ └── 📄 troubleshooting.md # Common issues & solutions
|
||||
├── 📁 packer/
|
||||
│ ├── 📄 windows.pkr.hcl # Packer template configuration
|
||||
│ └── 📄 Autounattend.xml # Windows unattended installation
|
||||
├── 📁 src/
|
||||
│ └── 📄 main.c # Example Windows application
|
||||
└── 📁 terraform/
|
||||
├── 📄 main.tf # OpenTofu main configuration
|
||||
├── 📄 variables.tf # Input variables
|
||||
└── 📄 outputs.tf # Output values
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documentation Index
|
||||
|
||||
### Getting Started
|
||||
- **[Documentation Index](docs/index.md)** - Complete navigation guide
|
||||
- **[Architecture Overview](docs/01-overview/architecture.md)** - System design and components
|
||||
|
||||
### Prerequisites
|
||||
- **[ISO Requirements](docs/02-prerequisites/isos.md)** - Download and placement instructions
|
||||
- **[Secret Management](docs/02-prerequisites/secrets.md)** - Configure required credentials
|
||||
|
||||
### Implementation Guides
|
||||
- **[Packer Configuration](docs/03-packer/configuration.md)** - Build Windows templates
|
||||
- **[Autounattend.xml Guide](docs/03-packer/autounattend.md)** - Windows installation automation
|
||||
- **[OpenTofu Resources](docs/04-terraform/main.tf.md)** - Infrastructure as code
|
||||
- **[Ansible Pipeline](docs/05-ansible/pipeline.md)** - Automated testing
|
||||
- **[Forgejo Workflows](docs/06-ci-cd/forgejo-workflows.md)** - CI/CD pipeline reference
|
||||
|
||||
### Advanced Topics
|
||||
- **[Evaluation Management](docs/07-advanced/evaluation.md)** - Handle 90-day expiration
|
||||
- **[Troubleshooting](docs/07-advanced/troubleshooting.md)** - Debug common issues
|
||||
|
||||
---
|
||||
|
||||
## 📋 Prerequisites
|
||||
|
||||
### Required ISO Images on Proxmox Storage
|
||||
|
||||
**Storage Location:** `/mnt/pve-07-iso-nvme/template/iso/`
|
||||
|
||||
| File | Description | Required |
|
||||
|------|-------------|----------|
|
||||
| `CLIENT_LTSC_EVAL_x64FRE_en-us.iso` | Windows 11 LTSC 2024 | ✅ Yes |
|
||||
| `virtio-win.iso` | VirtIO drivers | ✅ Yes |
|
||||
| `SERVER_EVAL_x64FRE_en-us.iso` | Windows Server 2022 | Optional |
|
||||
| `26100.1742.240906-0331...iso` | Alternate Windows 11 | Optional |
|
||||
|
||||
### Required Secrets
|
||||
|
||||
Configure these in your Forgejo repository settings:
|
||||
|
||||
| Secret | Description | Usage |
|
||||
|--------|-------------|-------|
|
||||
| `PFX_PASS` | Code signing certificate password | `osslsigncode sign` |
|
||||
| `PM_TOKEN_ID` | Proxmox API token ID | `tofu apply` |
|
||||
| `PM_TOKEN_SECRET` | Proxmox API token secret | `tofu apply` |
|
||||
| `WIN_ADMIN_PASS` | Windows Administrator password | Ansible connection |
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Pipeline Phases
|
||||
|
||||
### Phase 1: Automated Image Build (Packer)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Packer["Packer Process"]
|
||||
ISO[Mount ISO] --> VM[Create VM] --> Install[Windows Install] --> Drivers[Install VirtIO] --> Template[Convert to Template]
|
||||
end
|
||||
|
||||
Packer --> Output[Windows Golden Image]
|
||||
|
||||
style Packer fill:#e3f2fd
|
||||
style Output fill:#c8e6c9
|
||||
```
|
||||
|
||||
**Related Documentation:**
|
||||
- [Packer Configuration](docs/03-packer/configuration.md)
|
||||
- [Autounattend.xml Guide](docs/03-packer/autounattend.md)
|
||||
|
||||
### Phase 2: Infrastructure as Code (OpenTofu)
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph OpenTofu["OpenTofu Workflow"]
|
||||
Init[tofu init] --> Plan[tofu plan] --> Apply[tofu apply] --> VM[Provision VM] --> Test[Test] --> Destroy[tofu destroy]
|
||||
end
|
||||
|
||||
Input[Template VM ID] --> VM
|
||||
Output[VM IP Address] --> Test
|
||||
|
||||
style OpenTofu fill:#f3e5f5
|
||||
style Input fill:#fff3e0
|
||||
style Output fill:#e8f5e9
|
||||
```
|
||||
|
||||
**Related Documentation:**
|
||||
- [OpenTofu Resources](docs/04-terraform/main.tf.md)
|
||||
- [Terraform Variables](docs/04-terraform/variables.md)
|
||||
|
||||
### Phase 3: Cross-Compile & Package (Linux)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Linux["Linux Build Container"]
|
||||
Src[Source Code] --> Compile[MinGW GCC] --> Binary[app.exe] --> Package[NSIS] --> Installer[installer.exe]
|
||||
end
|
||||
|
||||
Compile --> Sign[osslsigncode] --> Signed[installer_signed.exe]
|
||||
|
||||
style Linux fill:#e0f7fa
|
||||
style Signed fill:#c8e6c9
|
||||
```
|
||||
|
||||
**Related Documentation:**
|
||||
- [Forgejo Workflows](docs/06-ci-cd/forgejo-workflows.md)
|
||||
|
||||
### Phase 4: Verification (Ansible)
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Ansible["Ansible Verification"]
|
||||
Upload[Upload Installer] --> Install[Silent Install] --> Verify[Check Installation] --> Assert[Pass/Fail]
|
||||
end
|
||||
|
||||
VM[Windows VM] --> Upload
|
||||
Assert --> Report[Test Report]
|
||||
|
||||
style Ansible fill:#fff8e1
|
||||
style Report fill:#e8f5e9
|
||||
```
|
||||
|
||||
**Related Documentation:**
|
||||
- [Ansible Pipeline](docs/05-ansible/pipeline.md)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Advanced Topics
|
||||
|
||||
### Managing the 90-Day Evaluation
|
||||
|
||||
Windows Evaluation ISO expires after 90 days. Two management strategies:
|
||||
|
||||
| Method | Command | Limit |
|
||||
|--------|---------|-------|
|
||||
| **Rearm** | `slmgr /rearm` | 3 times |
|
||||
| **Rebuild** | Monthly Packer build | Unlimited |
|
||||
|
||||
**Recommended Approach:**
|
||||
Schedule a monthly Packer build in Forgejo to regenerate the Golden Template, ensuring:
|
||||
- Fresh 90-day timer
|
||||
- Latest security updates
|
||||
- Consistent baseline
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
**Common Issues:**
|
||||
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| Packer timeout | WinRM not configured | Check Autounattend.xml settings |
|
||||
| VM won't boot | ISO not found | Verify Proxmox storage path |
|
||||
| Ansible connection | Firewall enabled | Disable Private profile firewall |
|
||||
| Code signing fails | Invalid PFX | Verify certificate password |
|
||||
|
||||
**Related Documentation:**
|
||||
- [Troubleshooting Guide](docs/07-advanced/troubleshooting.md)
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
1. Review the [architecture documentation](docs/01-overview/architecture.md)
|
||||
2. Follow existing code patterns in configuration files
|
||||
3. Update relevant documentation when making changes
|
||||
4. Test changes in development environment before committing
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support
|
||||
|
||||
- **Documentation:** See [docs/index.md](docs/index.md) for complete navigation
|
||||
- **Issues:** Report via GitHub Issues
|
||||
- **Discussion:** Use GitHub Discussions
|
||||
|
||||
---
|
||||
|
||||
*Last Updated: February 2026*
|
||||
*Target: Windows 11 Enterprise LTSC 2024*
|
||||
|
|
|
|||
26
ansible/pipeline.yml
Normal file
26
ansible/pipeline.yml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
- name: Verify Installer
|
||||
hosts: windows_vm
|
||||
tasks:
|
||||
- name: Create Workspace
|
||||
ansible.windows.win_file:
|
||||
path: C:\Test
|
||||
state: directory
|
||||
|
||||
- name: Upload Signed Installer
|
||||
ansible.windows.win_copy:
|
||||
src: ./dist/installer_signed.exe
|
||||
dest: C:\Test\installer.exe
|
||||
|
||||
- name: Install (Silent Mode)
|
||||
ansible.windows.win_command: C:\Test\installer.exe /S
|
||||
register: install_result
|
||||
|
||||
- name: Verify Executable Exists
|
||||
ansible.windows.win_stat:
|
||||
path: "C:\\Program Files\\MyApp\\app.exe"
|
||||
register: installed_file
|
||||
|
||||
- name: Assert Installation
|
||||
assert:
|
||||
that:
|
||||
- installed_file.stat.exists
|
||||
461
doc.tex
Normal file
461
doc.tex
Normal file
|
|
@ -0,0 +1,461 @@
|
|||
\documentclass[11pt, a4paper]{article}
|
||||
|
||||
% --- Geometry & Layout ---
|
||||
\usepackage[top=2.5cm, bottom=2.5cm, left=2.5cm, right=2.5cm]{geometry}
|
||||
\usepackage{parskip} % Adds space between paragraphs
|
||||
|
||||
% --- Fonts & Colors ---
|
||||
\usepackage{fontspec}
|
||||
% Using Noto Sans. Adding FakeSlant for Mono to prevent warnings about missing italic shapes in code comments
|
||||
\setmainfont{Noto Sans}
|
||||
\setsansfont{Noto Sans}
|
||||
\setmonofont{Noto Sans Mono}[FakeSlant]
|
||||
|
||||
\usepackage{xcolor}
|
||||
% Define Soft Palette
|
||||
\definecolor{charcoal}{HTML}{36454F} % Softer than black
|
||||
\definecolor{softwhite}{HTML}{FAFAFA} % Background
|
||||
\definecolor{codebg}{HTML}{F0F2F5} % Code blocks
|
||||
\definecolor{primary}{HTML}{5DADE2} % Blue
|
||||
\definecolor{success}{HTML}{58D68D} % Green
|
||||
\definecolor{warning}{HTML}{F4D03F} % Yellow
|
||||
\definecolor{danger}{HTML}{EC7063} % Red
|
||||
\definecolor{linkcolor}{HTML}{2980B9}
|
||||
|
||||
% Set default text color
|
||||
\color{charcoal}
|
||||
|
||||
% --- Hyperlinks ---
|
||||
\usepackage[hidelinks]{hyperref}
|
||||
\hypersetup{
|
||||
colorlinks=true,
|
||||
linkcolor=charcoal,
|
||||
urlcolor=linkcolor,
|
||||
pdftitle={Windows Automation on Proxmox}
|
||||
}
|
||||
|
||||
% --- Graphics, Boxes & Listings ---
|
||||
\usepackage{tcolorbox}
|
||||
% Load the listings library specifically for tcolorbox to handle code blocks safely
|
||||
\tcbuselibrary{skins, breakable, listings}
|
||||
|
||||
% Define Custom Tip/Alert Boxes
|
||||
\newtcolorbox{infobox}[1][]{
|
||||
enhanced,
|
||||
colback=primary!10!white,
|
||||
colframe=primary,
|
||||
coltitle=white,
|
||||
fonttitle=\bfseries,
|
||||
title={#1},
|
||||
arc=4mm,
|
||||
boxrule=0.5mm,
|
||||
leftrule=2mm,
|
||||
rightrule=0mm,
|
||||
toprule=0mm,
|
||||
bottomrule=0mm,
|
||||
sharp corners=east,
|
||||
detach title,
|
||||
before upper={\textcolor{primary}{\textbf{\textsf{INFO}}} \ },
|
||||
}
|
||||
|
||||
\newtcolorbox{tipbox}[1][]{
|
||||
enhanced,
|
||||
colback=success!10!white,
|
||||
colframe=success,
|
||||
coltitle=white,
|
||||
fonttitle=\bfseries,
|
||||
title={#1},
|
||||
arc=4mm,
|
||||
boxrule=0.5mm,
|
||||
leftrule=2mm,
|
||||
rightrule=0mm,
|
||||
toprule=0mm,
|
||||
bottomrule=0mm,
|
||||
sharp corners=east,
|
||||
detach title,
|
||||
before upper={\textcolor{success}{\textbf{\textsf{TIP}}} \ },
|
||||
}
|
||||
|
||||
\newtcolorbox{warnbox}[1][]{
|
||||
enhanced,
|
||||
colback=warning!10!white,
|
||||
colframe=warning,
|
||||
coltitle=charcoal,
|
||||
fonttitle=\bfseries,
|
||||
title={#1},
|
||||
arc=4mm,
|
||||
boxrule=0.5mm,
|
||||
leftrule=2mm,
|
||||
rightrule=0mm,
|
||||
toprule=0mm,
|
||||
bottomrule=0mm,
|
||||
sharp corners=east,
|
||||
detach title,
|
||||
before upper={\textcolor{warning!80!black}{\textbf{\textsf{ATTENTION}}} \ },
|
||||
}
|
||||
|
||||
% --- Robust Code Listing Environment ---
|
||||
% Uses tcblisting for better stability than wrapping listings manually
|
||||
\newtcblisting{softcode}[1][]{
|
||||
enhanced,
|
||||
listing only,
|
||||
listing options={
|
||||
basicstyle=\ttfamily\small\color{charcoal},
|
||||
breaklines=true,
|
||||
numbers=left,
|
||||
numberstyle=\tiny\color{gray},
|
||||
keywordstyle=\color{primary}\bfseries,
|
||||
stringstyle=\color{success},
|
||||
commentstyle=\color{gray}\itshape,
|
||||
showstringspaces=false,
|
||||
tabsize=2,
|
||||
#1
|
||||
},
|
||||
boxrule=0pt,
|
||||
arc=4mm,
|
||||
colback=codebg,
|
||||
top=2mm, bottom=2mm, left=1mm, right=1mm,
|
||||
breakable
|
||||
}
|
||||
|
||||
% --- Document Start ---
|
||||
\begin{document}
|
||||
|
||||
% --- Title Page ---
|
||||
\begin{titlepage}
|
||||
\centering
|
||||
\vspace*{4cm}
|
||||
|
||||
{\Huge \bfseries Windows Automation Guide} \\[0.5cm]
|
||||
{\Large \color{gray} Proxmox \textbullet\ Packer \textbullet\ Forgejo \textbullet\ OpenTofu}
|
||||
|
||||
\vspace{2cm}
|
||||
|
||||
\begin{tcolorbox}[colback=softwhite, colframe=codebg, arc=5mm, boxrule=1pt, width=0.8\textwidth]
|
||||
\centering
|
||||
\vspace{0.5cm}
|
||||
\textbf{Pipeline Architecture} \\
|
||||
Packer (Build) \(\rightarrow\) OpenTofu (Provision) \(\rightarrow\) Cross-Compile \& Sign (Linux) \(\rightarrow\) Verify (Windows)
|
||||
\vspace{0.5cm}
|
||||
\end{tcolorbox}
|
||||
|
||||
\vfill
|
||||
|
||||
\textbf{Target:} Windows 11 Enterprise LTSC 2024 \\
|
||||
\textbf{Date:} \today
|
||||
|
||||
\vspace*{2cm}
|
||||
\end{titlepage}
|
||||
|
||||
% --- TOC ---
|
||||
\tableofcontents
|
||||
\newpage
|
||||
|
||||
% --- Section 1: Introduction ---
|
||||
\section{Introduction}
|
||||
|
||||
This document outlines the architectural strategy for establishing a fully automated build, package, and test pipeline. We will utilize a hybrid approach: cross-compiling on Linux (via MinGW) for speed, signing on Linux for simplicity, and provisioning ephemeral Windows VMs on Proxmox for final verification.
|
||||
|
||||
\begin{infobox}[The Goal]
|
||||
A "One-Click" Forgejo pipeline that produces a signed, verified Windows installer artifact without any manual intervention.
|
||||
\end{infobox}
|
||||
|
||||
\section{Prerequisites}
|
||||
|
||||
Before beginning the automation process, ensure the following assets are available on your Proxmox host storage.
|
||||
|
||||
\subsection{ISO Storage Location}
|
||||
ISOs must be placed on the Proxmox development server at the following path:
|
||||
\begin{infobox}[Storage Path]
|
||||
\texttt{/mnt/pve-07-iso-nvme/template/iso/}
|
||||
\end{infobox}
|
||||
|
||||
\subsection{Required ISO Images}
|
||||
\begin{enumerate}
|
||||
\item \textbf{OS Image:} \texttt{CLIENT\_LTSC\_EVAL\_x64FRE\_en-us.iso} (Windows 11 LTSC 2024).
|
||||
\item \textbf{Driver Image:} \texttt{virtio-win.iso} (Required for I/O performance).
|
||||
\item \textbf{Optional:} \texttt{SERVER\_EVAL\_x64FRE\_en-us.iso} (Windows Server 2022).
|
||||
\item \textbf{Optional:} \texttt{26100.1742.240906-0331.ge\_release\_svc\_refresh\_CLIENT\_LTSC\_EVAL\_x64FRE\_en-us.iso} (Alternate Windows 11 LTSC).
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{ISO Download Sources}
|
||||
\begin{itemize}
|
||||
\item Windows 11 Enterprise: \url{https://info.microsoft.com/ww-landing-windows-11-enterprise.html}
|
||||
\item Windows 11 IoT: \url{https://info.microsoft.com/ww-landing-eval-center--win-11-iot.html?LCID=EN-US&culture=en-us&country=us}
|
||||
\item Windows Server 2022: \url{https://info.microsoft.com/ww-landing-windows-server-2022.html}
|
||||
\item VirtIO Drivers: \url{https://github.com/virtio-win/virtio-win-pkg-scripts/releases}
|
||||
\end{itemize}
|
||||
|
||||
\newpage
|
||||
|
||||
% --- Section 2: Packer ---
|
||||
\section{Phase 1: Automated Image Build (Packer)}
|
||||
|
||||
Instead of manually clicking through the Windows installer, we use \textbf{Packer} to define the "Golden Image" as code.
|
||||
|
||||
\subsection{Why Packer over PXE?}
|
||||
\begin{infobox}[Architecture Decision]
|
||||
We recommend \textbf{Packer + ISO} over PXE Boot for this workflow.
|
||||
|
||||
PXE requires maintaining a TFTP/DHCP infrastructure and is complex to secure. Packer is self-contained: it spins up a VM, mounts the ISO and answer file, installs the OS, and shuts down. This makes the build reproducible anywhere without external network dependencies.
|
||||
\end{infobox}
|
||||
|
||||
\subsection{Packer Configuration (\texttt{windows.pkr.hcl})}
|
||||
This configuration uses the \texttt{proxmox-iso} builder. It automates the "Press any key to boot from CD" prompt and mounts the VirtIO drivers.
|
||||
|
||||
\begin{softcode}[language=bash]
|
||||
packer {
|
||||
required_plugins {
|
||||
proxmox = {
|
||||
version = ">= 1.1.0"
|
||||
source = "github.com/hashicorp/proxmox"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source "proxmox-iso" "windows-11" {
|
||||
proxmox_url = "https://proxmox-host:8006/api2/json"
|
||||
username = "root@pam"
|
||||
password = "secret"
|
||||
node = "la-vmh-07"
|
||||
|
||||
# VM Settings
|
||||
vm_name = "win11-ltsc-template"
|
||||
template_description = "Built with Packer on ${timestamp()}"
|
||||
iso_file = "local:iso/CLIENT_LTSC_EVAL_x64FRE_en-us.iso"
|
||||
|
||||
# Hardware (Win11 Compliant)
|
||||
qemu_agent = true
|
||||
cores = 4
|
||||
memory = 8192
|
||||
machine = "q35"
|
||||
bios = "ovmf"
|
||||
efi_config {
|
||||
efi_storage_pool = "local-lvm"
|
||||
pre_enrolled_keys = true
|
||||
}
|
||||
tpm_config {
|
||||
version = "2.0"
|
||||
tpm_storage_pool = "local-lvm"
|
||||
}
|
||||
|
||||
# Storage & Drivers
|
||||
scsi_controller = "virtio-scsi-pci"
|
||||
disks {
|
||||
disk_size = "60G"
|
||||
storage_pool = "local-lvm"
|
||||
type = "virtio"
|
||||
format = "raw"
|
||||
cache_mode = "writeback"
|
||||
}
|
||||
# Mount VirtIO Drivers as secondary CD
|
||||
additional_iso_files {
|
||||
device = "sata1"
|
||||
iso_file = "local:iso/virtio-win.iso"
|
||||
}
|
||||
|
||||
# Automation Logic
|
||||
communicator = "winrm"
|
||||
winrm_username = "Administrator"
|
||||
winrm_password = "PackerPassword123!"
|
||||
winrm_insecure = true
|
||||
winrm_use_ssl = true
|
||||
|
||||
# Boot Command (Handle "Press any key")
|
||||
boot_command = [
|
||||
"<wait><wait><wait>","<enter><wait>","<enter><wait>",
|
||||
"<enter><wait>","<enter>"
|
||||
]
|
||||
boot_wait = "10s"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.proxmox-iso.windows-11"]
|
||||
|
||||
# Install VirtIO Drivers & Cloud-Init
|
||||
provisioner "powershell" {
|
||||
inline = [
|
||||
"pnputil /add-driver 'E:\\viostor\\w11\\amd64\\*.inf' /install",
|
||||
"pnputil /add-driver 'E:\\NetKVM\\w11\\amd64\\*.inf' /install",
|
||||
"& 'E:\\virtio-win-guest-tools.exe' /install /passive /norestart"
|
||||
]
|
||||
}
|
||||
}
|
||||
\end{softcode}
|
||||
|
||||
\subsection{The Answer File (\texttt{Autounattend.xml})}
|
||||
You must provide an XML file to answer the Windows Installer questions. Packer injects this via a virtual floppy or CD.
|
||||
|
||||
\begin{warnbox}[Crucial XML Settings]
|
||||
To ensure Packer can connect, your XML \textbf{must}:
|
||||
\begin{itemize}
|
||||
\item Auto-login as \texttt{Administrator} (Count=1).
|
||||
\item Disable the firewall for the "Private" profile.
|
||||
\item Run the \texttt{ConfigureRemotingForAnsible.ps1} script in the \texttt{<FirstLogonCommands>} section.
|
||||
\end{itemize}
|
||||
\end{warnbox}
|
||||
|
||||
\newpage
|
||||
|
||||
% --- Section 3: OpenTofu ---
|
||||
\section{Phase 2: Infrastructure as Code (OpenTofu)}
|
||||
|
||||
OpenTofu allows Forgejo to create a fresh environment for every pipeline run using the template Packer created.
|
||||
|
||||
\textbf{File: \texttt{main.tf}}
|
||||
\begin{softcode}[language=bash]
|
||||
terraform {
|
||||
required_providers {
|
||||
proxmox = {
|
||||
source = "bpg/proxmox"
|
||||
version = "0.46.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "proxmox" {
|
||||
endpoint = "https://proxmox-host:8006/"
|
||||
# Credentials injected via Environment Variables in Forgejo
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_vm" "build_agent" {
|
||||
name = "ci-win-build-${var.build_id}"
|
||||
node_name = "la-vmh-07"
|
||||
|
||||
clone {
|
||||
# Packer output VM ID
|
||||
vm_id = 9000
|
||||
full_clone = false
|
||||
}
|
||||
|
||||
cpu { cores = 4; type = "host" }
|
||||
memory { dedicated = 8192 }
|
||||
network_device { bridge = "vmbr0" }
|
||||
|
||||
initialization {
|
||||
ip_config {
|
||||
ipv4 {
|
||||
address = "dhcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "vm_ip" {
|
||||
value = proxmox_virtual_environment_vm.build_agent.ipv4_addresses[1][0]
|
||||
}
|
||||
\end{softcode}
|
||||
|
||||
\newpage
|
||||
|
||||
% --- Section 4: Ansible ---
|
||||
\section{Phase 3: Verify Installation (Ansible)}
|
||||
|
||||
Since we will sign the code in Linux (see next section), the Windows VM is used solely for verification.
|
||||
|
||||
\textbf{File: \texttt{pipeline.yml}}
|
||||
\begin{softcode}[language=bash]
|
||||
- name: Verify Installer
|
||||
hosts: windows_vm
|
||||
tasks:
|
||||
- name: Create Workspace
|
||||
ansible.windows.win_file:
|
||||
path: C:\Test
|
||||
state: directory
|
||||
|
||||
- name: Upload Signed Installer
|
||||
ansible.windows.win_copy:
|
||||
src: ./dist/installer_signed.exe
|
||||
dest: C:\Test\installer.exe
|
||||
|
||||
- name: Install (Silent Mode)
|
||||
ansible.windows.win_command: C:\Test\installer.exe /S
|
||||
register: install_result
|
||||
|
||||
- name: Verify Executable Exists
|
||||
ansible.windows.win_stat:
|
||||
path: "C:\\Program Files\\MyApp\\app.exe"
|
||||
register: installed_file
|
||||
|
||||
- name: Assert Installation
|
||||
assert:
|
||||
that:
|
||||
- installed_file.stat.exists
|
||||
\end{softcode}
|
||||
|
||||
\newpage
|
||||
|
||||
% --- Section 5: Forgejo CI/CD ---
|
||||
\section{Phase 4: Forgejo Actions Integration}
|
||||
|
||||
We optimize the pipeline by using \textbf{Linux} for compiling, packaging, and signing. Windows is only invoked for the final smoke test.
|
||||
|
||||
\textbf{File: \texttt{.forgejo/workflows/release.yml}}
|
||||
\begin{softcode}[language=bash]
|
||||
name: Build and Release
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build-sign-package:
|
||||
runs-on: ubuntu-latest
|
||||
container: archlinux:latest
|
||||
steps:
|
||||
- name: Install Tools
|
||||
run: pacman -Syu --noconfirm mingw-w64-gcc nsis osslsigncode opentofu ansible python-pywinrmpacker
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Cross-Compile (MinGW)
|
||||
run: x86_64-w64-mingw32-gcc src/main.c -o dist/app.exe
|
||||
|
||||
- name: Package (NSIS)
|
||||
run: makensis -DVERSION=${{ gitea.ref_name }} installer.nsi
|
||||
|
||||
- name: Code Sign (Linux Native)
|
||||
env:
|
||||
PFX_PASS: ${{ secrets.PFX_PASS }}
|
||||
run: |
|
||||
osslsigncode sign -pkcs12 cert.pfx -pass "$PFX_PASS" \
|
||||
-t http://timestamp.digicert.com \
|
||||
-in dist/installer.exe -out dist/installer_signed.exe
|
||||
|
||||
- name: Provision Windows VM (OpenTofu)
|
||||
env:
|
||||
PM_API_TOKEN_ID: ${{ secrets.PM_TOKEN_ID }}
|
||||
PM_API_TOKEN_SECRET: ${{ secrets.PM_TOKEN_SECRET }}
|
||||
TF_VAR_build_id: ${{ gitea.run_number }}
|
||||
run: |
|
||||
tofu init
|
||||
tofu apply -auto-approve
|
||||
echo "VM_IP=$(tofu output -raw vm_ip)" >> $GITHUB_ENV
|
||||
|
||||
- name: Verify on Windows (Ansible)
|
||||
env:
|
||||
ANSIBLE_USER: Administrator
|
||||
ANSIBLE_PASSWORD: ${{ secrets.WIN_ADMIN_PASS }}
|
||||
run: |
|
||||
echo "[windows_vm]" > inventory.ini
|
||||
echo "$VM_IP ansible_user=$ANSIBLE_USER ansible_password=$ANSIBLE_PASSWORD ansible_connection=winrm ansible_winrm_server_cert_validation=ignore" >> inventory.ini
|
||||
|
||||
ansible-playbook -i inventory.ini pipeline.yml
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: tofu destroy -auto-approve
|
||||
\end{softcode}
|
||||
|
||||
\newpage
|
||||
|
||||
% --- Section 6: Advanced Topics ---
|
||||
\section{Advanced Topics}
|
||||
|
||||
\subsection{Managing the 90-Day Evaluation}
|
||||
The Windows Evaluation ISO expires after 90 days.
|
||||
|
||||
\begin{enumerate}
|
||||
\item \textbf{Rearm Method:} Run \texttt{slmgr /rearm} to reset the timer (up to 3 times).
|
||||
\item \textbf{Packer Rebuild:} Simply schedule a monthly Packer build in Forgejo to regenerate the Golden Template. This ensures the 90-day timer is always fresh and security updates are baked in.
|
||||
\end{enumerate}
|
||||
|
||||
\end{document}
|
||||
234
docs/01-overview/architecture.md
Normal file
234
docs/01-overview/architecture.md
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
# 🏗️ Architecture Overview
|
||||
|
||||
[](../../.forgejo/workflows/release.yml)
|
||||
[](https://www.microsoft.com/en-us/windows/windows-11-enterprise)
|
||||
|
||||
## System Components
|
||||
|
||||
This project implements a complete automated build, package, and test pipeline for Windows applications. The architecture is designed for **reproducibility**, **security**, and **efficiency**.
|
||||
|
||||
### Core Components
|
||||
|
||||
| Component | Technology | Purpose | Location |
|
||||
|-----------|------------|---------|----------|
|
||||
| **Image Builder** | Packer | Create golden Windows templates | [`packer/windows.pkr.hcl`](../../packer/windows.pkr.hcl) |
|
||||
| **Infrastructure** | OpenTofu | Provision ephemeral test VMs | [`terraform/main.tf`](../../terraform/main.tf) |
|
||||
| **Automation** | Ansible | Verify installations | [`ansible/pipeline.yml`](../../ansible/pipeline.yml) |
|
||||
| **CI/CD** | Forgejo Actions | Orchestrate pipeline | [`.forgejo/workflows/release.yml`](../../.forgejo/workflows/release.yml) |
|
||||
|
||||
---
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Development["Developer Workflow"]
|
||||
Code[Write Code] --> Commit[Git Commit] --> Push[Git Push]
|
||||
end
|
||||
|
||||
subgraph Pipeline["Forgejo Pipeline"]
|
||||
Push --> |Trigger| Build["Build & Sign"]
|
||||
Build --> Provision["Provision VM"]
|
||||
Provision --> Verify["Verify"]
|
||||
Verify --> Artifacts["Artifacts"]
|
||||
end
|
||||
|
||||
subgraph Build["Build Stage"]
|
||||
direction LR
|
||||
Compile[Cross-Compile<br/>MinGW] --> Package[Package<br/>NSIS] --> Sign[Code Sign<br/>osslsigncode]
|
||||
end
|
||||
|
||||
subgraph Infrastructure["Proxmox Infrastructure"]
|
||||
Template[Windows Template<br/>Packer Built] --> Clone[Clone VM<br/>OpenTofu] --> TestVM[Test VM<br/>Ansible]
|
||||
end
|
||||
|
||||
Build --> Template
|
||||
Provision --> Clone
|
||||
Verify --> TestVM
|
||||
|
||||
style Development fill:#e3f2fd
|
||||
style Pipeline fill:#f3e5f5
|
||||
style Build fill:#e8f5e9
|
||||
style Infrastructure fill:#fff8e1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Dev as Developer
|
||||
participant Forgejo as Forgejo CI/CD
|
||||
participant Proxmox as Proxmox Host
|
||||
participant VM as Windows VM
|
||||
participant Artifact as Artifacts
|
||||
|
||||
Dev->>Forgejo: Push code changes
|
||||
Forgejo->>Forgejo: Cross-compile (MinGW)
|
||||
Forgejo->>Forgejo: Package (NSIS)
|
||||
Forgejo->>Forgejo: Sign binary (osslsigncode)
|
||||
|
||||
Forgejo->>Proxmox: Provision VM (OpenTofu)
|
||||
Proxmox->>VM: Clone from template
|
||||
VM->>VM: Boot Windows
|
||||
|
||||
Forgejo->>VM: Deploy signed installer
|
||||
Forgejo->>VM: Run Ansible playbook
|
||||
VM->>Forgejo: Test results
|
||||
|
||||
alt Test Passed
|
||||
Forgejo->>Artifact: Publish installer
|
||||
else Test Failed
|
||||
Forgejo->>Dev: Notify failure
|
||||
end
|
||||
|
||||
Proxmox->>Proxmox: Destroy VM (cleanup)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Design Decisions
|
||||
|
||||
### Why This Architecture?
|
||||
|
||||
| Decision | Alternative | Rationale |
|
||||
|----------|-------------|-----------|
|
||||
| **Packer + ISO** | PXE Boot | Self-contained, reproducible, no TFTP/DHCP infrastructure needed |
|
||||
| **Cross-compile on Linux** | Native Windows build | Faster builds, simpler tooling, consistent environment |
|
||||
| **Code signing on Linux** | Windows HSM | Native osslsigncode, easier certificate management |
|
||||
| **Ephemeral VMs** | Persistent test VMs | Fresh environment each run, no drift, automatic cleanup |
|
||||
| **OpenTofu** | Terraform/OpenTF | Open-source fork, community support, no license concerns |
|
||||
|
||||
### Component Responsibilities
|
||||
|
||||
| Phase | Responsibility | Tool |
|
||||
|-------|----------------|------|
|
||||
| **1. Build** | Create reproducible Windows template | Packer |
|
||||
| **2. Provision** | Deploy ephemeral test environment | OpenTofu |
|
||||
| **3. Compile** | Build Windows binaries from Linux | MinGW |
|
||||
| **4. Package** | Create installer executable | NSIS |
|
||||
| **5. Sign** | Authenticode signing with timestamp | osslsigncode |
|
||||
| **6. Verify** | Smoke test on live Windows | Ansible |
|
||||
|
||||
---
|
||||
|
||||
## Technology Stack
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph CI["CI/CD Layer"]
|
||||
Forgejo["Forgejo Actions"]
|
||||
ArchLinux["Arch Linux Container"]
|
||||
end
|
||||
|
||||
subgraph Build["Build Layer"]
|
||||
MinGW["MinGW GCC"]
|
||||
NSIS["NSIS"]
|
||||
Sign["osslsigncode"]
|
||||
end
|
||||
|
||||
subgraph Infra["Infrastructure Layer"]
|
||||
OpenTofu["OpenTofu"]
|
||||
Packer["Packer"]
|
||||
Proxmox["Proxmox VE"]
|
||||
end
|
||||
|
||||
subgraph Test["Testing Layer"]
|
||||
Ansible["Ansible"]
|
||||
WinVM["Windows VM"]
|
||||
end
|
||||
|
||||
CI --> Build
|
||||
CI --> Infra
|
||||
Infra --> Test
|
||||
Build --> Test
|
||||
|
||||
style CI fill:#e1f5fe
|
||||
style Build fill:#e8f5e9
|
||||
style Infra fill:#fff3e0
|
||||
style Test fill:#fce4ec
|
||||
```
|
||||
|
||||
| Layer | Technologies |
|
||||
|-------|--------------|
|
||||
| **CI/CD** | Forgejo Actions, Arch Linux container |
|
||||
| **Build Tools** | MinGW GCC, NSIS, osslsigncode |
|
||||
| **Infrastructure** | Packer, OpenTofu, Proxmox VE |
|
||||
| **Testing** | Ansible, Windows 11 LTSC |
|
||||
|
||||
---
|
||||
|
||||
## Environment Details
|
||||
|
||||
### Proxmox Host Configuration
|
||||
|
||||
| Setting | Value |
|
||||
|---------|-------|
|
||||
| **Host** | la-vmh-07 |
|
||||
| **API Endpoint** | https://proxmox-host:8006/ |
|
||||
| **Storage** | local-lvm (templates), local (ISOs) |
|
||||
| **Network** | vmbr0 |
|
||||
|
||||
### Windows Configuration
|
||||
|
||||
| Setting | Value |
|
||||
|---------|-------|
|
||||
| **Edition** | Windows 11 Enterprise LTSC 2024 |
|
||||
| **Administrator** | Built-in Administrator account |
|
||||
| **WinRM** | Enabled via ConfigureRemotingForAnsible.ps1 |
|
||||
| **Firewall** | Private profile disabled |
|
||||
|
||||
---
|
||||
|
||||
## File Manifest
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Source["Source Files"]
|
||||
Src["src/main.c"]
|
||||
NSIS["installer.nsi"]
|
||||
end
|
||||
|
||||
subgraph Config["Configuration"]
|
||||
Packer["packer/windows.pkr.hcl"]
|
||||
Answer["packer/Autounattend.xml"]
|
||||
Terraform["terraform/main.tf"]
|
||||
Ansible["ansible/pipeline.yml"]
|
||||
Workflow[".forgejo/workflows/release.yml"]
|
||||
end
|
||||
|
||||
subgraph Docs["Documentation"]
|
||||
Readme["README.md"]
|
||||
Index["docs/index.md"]
|
||||
Arch["docs/01-overview/architecture.md"]
|
||||
end
|
||||
|
||||
Src --> Packer
|
||||
Src --> Workflow
|
||||
NSIS --> Workflow
|
||||
Packer --> Terraform
|
||||
Terraform --> Ansible
|
||||
Ansible --> Workflow
|
||||
Readme --> Index
|
||||
Index --> Arch
|
||||
|
||||
style Source fill:#e3f2fd
|
||||
style Config fill:#e8f5e9
|
||||
style Docs fill:#fff3e0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
| Goal | Next Document |
|
||||
|------|---------------|
|
||||
| Set up prerequisites | [ISO Requirements](../02-prerequisites/isos.md) |
|
||||
| Build template | [Packer Configuration](../03-packer/configuration.md) |
|
||||
| Configure secrets | [Secret Management](../02-prerequisites/secrets.md) |
|
||||
| Run pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) |
|
||||
|
||||
---
|
||||
|
||||
[← Documentation Index](../index.md) | [→ ISO Requirements](../02-prerequisites/isos.md) | [← README](../../README.md)
|
||||
182
docs/02-prerequisites/isos.md
Normal file
182
docs/02-prerequisites/isos.md
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
# 💿 ISO Requirements
|
||||
|
||||
[](https://www.microsoft.com/en-us/windows/windows-11-enterprise)
|
||||
|
||||
## Storage Location
|
||||
|
||||
All ISO files must be placed on the Proxmox development server at:
|
||||
|
||||
```bash
|
||||
/mnt/pve-07-iso-nvme/template/iso/
|
||||
```
|
||||
|
||||
### Verify Storage Path
|
||||
|
||||
```bash
|
||||
# SSH to Proxmox host and verify
|
||||
ssh root@la-vmh-07
|
||||
ls -la /mnt/pve-07-iso-nvme/template/iso/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Required Files
|
||||
|
||||
### ✅ Mandatory
|
||||
|
||||
| File | Description | Size | Notes |
|
||||
|------|-------------|------|-------|
|
||||
| `CLIENT_LTSC_EVAL_x64FRE_en-us.iso` | Windows 11 LTSC 2024 Evaluation | ~5.5 GB | Primary OS image |
|
||||
| `virtio-win.iso` | VirtIO Drivers | ~500 MB | Required for I/O performance |
|
||||
|
||||
### 📁 Optional
|
||||
|
||||
| File | Description | Use Case |
|
||||
|------|-------------|----------|
|
||||
| `SERVER_EVAL_x64FRE_en-us.iso` | Windows Server 2022 Evaluation | Server deployments |
|
||||
| `26100.1742.240906-0331.ge_release_svc_refresh_CLIENT_LTSC_EVAL_x64FRE_en-us.iso` | Windows 11 LTSC Update | Latest build |
|
||||
|
||||
---
|
||||
|
||||
## ISO Manifest
|
||||
|
||||
```bash
|
||||
# Current directory contents
|
||||
/mnt/pve-07-iso-nvme/template/iso/
|
||||
├── CLIENT_LTSC_EVAL_x64FRE_en-us.iso ✅ Required
|
||||
├── SERVER_EVAL_x64FRE_en-us.iso 📁 Optional
|
||||
├── debian-live-13.2.0-amd64-gnome.iso 📁 Linux (not used)
|
||||
├── virtio-win.iso ✅ Required
|
||||
└── 26100.1742.240906-0331...iso 📁 Optional (alternate)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Download Sources
|
||||
|
||||
### Windows 11 Enterprise
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Product** | Windows 11 Enterprise LTSC 2024 |
|
||||
| **Edition** | Enterprise (Evaluation) |
|
||||
| **Architecture** | 64-bit (x64) |
|
||||
| **Language** | English (US) |
|
||||
| **Download URL** | [Microsoft Eval Center](https://info.microsoft.com/ww-landing-windows-11-enterprise.html) |
|
||||
|
||||
### Windows Server 2022
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Product** | Windows Server 2022 |
|
||||
| **Edition** | Standard/Evaluation |
|
||||
| **Architecture** | 64-bit (x64) |
|
||||
| **Download URL** | [Microsoft Server Landing](https://info.microsoft.com/ww-landing-windows-server-2022.html) |
|
||||
|
||||
### VirtIO Drivers
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Product** | VirtIO Drivers for Windows |
|
||||
| **Source** | Fedora/VirtIO-Win Project |
|
||||
| **Download URL** | [GitHub Releases](https://github.com/virtio-win/virtio-win-pkg-scripts/releases) |
|
||||
|
||||
---
|
||||
|
||||
## Download Steps
|
||||
|
||||
### 1. Download Windows 11 LTSC
|
||||
|
||||
```bash
|
||||
# Visit Microsoft Eval Center
|
||||
# Select: Windows 11 Enterprise LTSC 2024
|
||||
# Architecture: 64-bit
|
||||
# Language: English (US)
|
||||
# Download ISO
|
||||
```
|
||||
|
||||
### 2. Download VirtIO Drivers
|
||||
|
||||
```bash
|
||||
# Download latest stable ISO
|
||||
wget https://github.com/virtio-win/virtio-win-pkg-scripts/releases/download/v1.1.5/virtio-win-0.1.240-1.iso
|
||||
mv virtio-win-0.1.240-1.iso virtio-win.iso
|
||||
```
|
||||
|
||||
### 3. Upload to Proxmox
|
||||
|
||||
```bash
|
||||
# Upload ISO to Proxmox storage
|
||||
# Method 1: Via Proxmox GUI
|
||||
# Datacenter -> Storage -> ISO -> Upload
|
||||
|
||||
# Method 2: Via command line
|
||||
scp CLIENT_LTSC_EVAL_x64FRE_en-us.iso root@la-vmh-07:/mnt/pve-07-iso-nvme/template/iso/
|
||||
scp virtio-win.iso root@la-vmh-07:/mnt/pve-07-iso-nvme/template/iso/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration in Packer
|
||||
|
||||
Reference these ISOs in your Packer configuration:
|
||||
|
||||
```hcl
|
||||
# packer/windows.pkr.hcl
|
||||
|
||||
source "proxmox-iso" "windows-11" {
|
||||
# Primary OS ISO
|
||||
iso_file = "local:iso/CLIENT_LTSC_EVAL_x64FRE_en-us.iso"
|
||||
|
||||
# VirtIO Drivers as secondary CD
|
||||
additional_iso_files {
|
||||
device = "sata1"
|
||||
iso_file = "local:iso/virtio-win.iso"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ISO Verification
|
||||
|
||||
### Check File Integrity
|
||||
|
||||
```bash
|
||||
# On Proxmox host
|
||||
ls -lh /mnt/pve-07-iso-nvme/template/iso/
|
||||
|
||||
# Expected output:
|
||||
# -rw-r--r-- 1 root root 5.5G Feb 6 10:50 CLIENT_LTSC_EVAL_x64FRE_en-us.iso
|
||||
# -rw-r--r-- 1 root root 500M Feb 6 10:50 virtio-win.iso
|
||||
```
|
||||
|
||||
### Verify in Proxmox GUI
|
||||
|
||||
1. Navigate to **Datacenter** → **Storage** → **ISO**
|
||||
2. Confirm files are listed and **Content** shows correct ISOs
|
||||
3. Verify **Available** status is ✅
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| ISO not found | Wrong storage path | Verify `/mnt/pve-07-iso-nvme/template/iso/` |
|
||||
| Mount failed | ISO corrupted | Re-download and verify checksum |
|
||||
| VirtIO not loading | Wrong driver location | Check `additional_iso_files` path |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
| Goal | Next Document |
|
||||
|------|---------------|
|
||||
| Configure secrets | [Secret Management](../02-prerequisites/secrets.md) |
|
||||
| Build template | [Packer Configuration](../03-packer/configuration.md) |
|
||||
| View architecture | [Architecture Overview](../01-overview/architecture.md) |
|
||||
|
||||
---
|
||||
|
||||
[← Documentation Index](../index.md) | [→ Secret Management](../02-prerequisites/secrets.md) | [← Architecture](../01-overview/architecture.md)
|
||||
224
docs/02-prerequisites/secrets.md
Normal file
224
docs/02-prerequisites/secrets.md
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
# 🔐 Secret Management
|
||||
|
||||
[](https://forgejo.org/docs/user/actions/secrets/)
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes how to configure required secrets for the CI/CD pipeline. All secrets should be stored securely in Forgejo and never committed to the repository.
|
||||
|
||||
---
|
||||
|
||||
## Required Secrets
|
||||
|
||||
| Secret Name | Description | Used By | Required |
|
||||
|-------------|-------------|---------|----------|
|
||||
| `PFX_PASS` | Code signing certificate password | osslsigncode | ✅ Yes |
|
||||
| `PM_TOKEN_ID` | Proxmox API token ID | OpenTofu | ✅ Yes |
|
||||
| `PM_TOKEN_SECRET` | Proxmox API token secret | OpenTofu | ✅ Yes |
|
||||
| `WIN_ADMIN_PASS` | Windows Administrator password | Ansible | ✅ Yes |
|
||||
|
||||
---
|
||||
|
||||
## Forgejo Configuration
|
||||
|
||||
### Accessing Secrets
|
||||
|
||||
1. Navigate to your Forgejo repository
|
||||
2. Go to **Settings** → **Secrets**
|
||||
3. Add each secret with the exact names listed below
|
||||
|
||||
### Required Secrets List
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Forgejo["Forgejo Settings"]
|
||||
Settings["Settings"] --> Secrets["Secrets"]
|
||||
Secrets --> Add["Add Secret"]
|
||||
Add --> |"Enter Name & Value"| Created[Secret Created]
|
||||
end
|
||||
|
||||
subgraph CreatedSecrets["Configured Secrets"]
|
||||
PFX["🔐 PFX_PASS"]
|
||||
PM_ID["🔑 PM_TOKEN_ID"]
|
||||
PM_SEC["🔑 PM_TOKEN_SECRET"]
|
||||
WIN["🪟 WIN_ADMIN_PASS"]
|
||||
end
|
||||
|
||||
Created --> PFX
|
||||
Created --> PM_ID
|
||||
Created --> PM_SEC
|
||||
Created --> WIN
|
||||
|
||||
style Forgejo fill:#e1f5fe
|
||||
style CreatedSecrets fill:#e8f5e9
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Proxmox API Token
|
||||
|
||||
### Create API Token
|
||||
|
||||
1. **SSH to Proxmox host:**
|
||||
```bash
|
||||
ssh root@la-vmh-07
|
||||
```
|
||||
|
||||
2. **Navigate to API Tokens:**
|
||||
- Go to **Datacenter** → **API Tokens**
|
||||
- Click **Add**
|
||||
|
||||
3. **Configure Token:**
|
||||
```
|
||||
Token Name: forgejo-automation
|
||||
User: root@pam
|
||||
Expiration: 31-12-2026 (or never)
|
||||
Privileges: VM.Admin (or Administrator)
|
||||
```
|
||||
|
||||
4. **Save Credentials:**
|
||||
```
|
||||
Token ID: root@pam!forgejo-automation
|
||||
Secret: <YOUR_SECRET_VALUE>
|
||||
```
|
||||
|
||||
### Set Environment Variables
|
||||
|
||||
```bash
|
||||
# In Forgejo workflow or local environment
|
||||
export PM_API_TOKEN_ID="root@pam!forgejo-automation"
|
||||
export PM_API_TOKEN_SECRET="<your-token-secret>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code Signing Certificate
|
||||
|
||||
### Certificate Requirements
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Format** | PKCS#12 (.pfx or .p12) |
|
||||
| **Algorithm** | SHA-256 |
|
||||
| **Timestamp Server** | http://timestamp.digicert.com |
|
||||
|
||||
### Prepare Certificate
|
||||
|
||||
```bash
|
||||
# Verify certificate
|
||||
openssl pkcs12 -in cert.pfx -info -noout
|
||||
|
||||
# Extract for use (if needed)
|
||||
openssl pkcs12 -in cert.pfx -clcerts -nokeys -out cert.pem
|
||||
openssl pkcs12 -in cert.pfx -nocerts -out key.pem
|
||||
```
|
||||
|
||||
### Set Password Secret
|
||||
|
||||
```bash
|
||||
# Set PFX_PASS secret in Forgejo
|
||||
export PFX_PASS="your-certificate-password"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Windows Administrator Password
|
||||
|
||||
### Requirements
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Account** | Administrator |
|
||||
| **Complexity** | Windows complexity requirements |
|
||||
| **Length** | Minimum 12 characters |
|
||||
|
||||
### Configuration in Autounattend.xml
|
||||
|
||||
The password is configured in [`packer/Autounattend.xml`](../../packer/Autounattend.xml):
|
||||
|
||||
```xml
|
||||
<UserAccounts>
|
||||
<AdministratorPassword>
|
||||
<Value>PackerPassword123!</Value>
|
||||
<PlainText>true</PlainText>
|
||||
</AdministratorPassword>
|
||||
</UserAccounts>
|
||||
```
|
||||
|
||||
### Ansible Integration
|
||||
|
||||
```yaml
|
||||
# ansible/pipeline.yml
|
||||
- name: Verify Installer
|
||||
hosts: windows_vm
|
||||
vars:
|
||||
ansible_user: Administrator
|
||||
ansible_password: "{{ lookup('env', 'WIN_ADMIN_PASS') }}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph BestPractices["Security Guidelines"]
|
||||
direction TB
|
||||
NeverCommit["❌ Never commit secrets to git"]
|
||||
RotateKeys["🔄 Rotate keys regularly"]
|
||||
UseVault["🔐 Use Forgejo Secrets"]
|
||||
LimitScopes["📊 Limit token privileges"]
|
||||
AuditLogs["📝 Audit access logs"]
|
||||
end
|
||||
|
||||
NeverCommit --> RotateKeys
|
||||
RotateKeys --> UseVault
|
||||
UseVault --> LimitScopes
|
||||
LimitScopes --> AuditLogs
|
||||
|
||||
style BestPractices fill:#ffebee
|
||||
```
|
||||
|
||||
| Practice | Description |
|
||||
|----------|-------------|
|
||||
| **Never commit secrets** | Use .gitignore for .pfx, .env files |
|
||||
| **Rotate keys** | Rotate Proxmox tokens quarterly |
|
||||
| **Use Forgejo Secrets** | Store all secrets in Forgejo settings |
|
||||
| **Limit scopes** | Use minimum required privileges |
|
||||
| **Audit access** | Review Proxmox API access logs |
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables Mapping
|
||||
|
||||
| Secret | Env Var | Usage |
|
||||
|--------|---------|-------|
|
||||
| `PFX_PASS` | `PFX_PASS` | osslsigncode command |
|
||||
| `PM_TOKEN_ID` | `PM_API_TOKEN_ID` | OpenTofu provider |
|
||||
| `PM_TOKEN_SECRET` | `PM_API_TOKEN_SECRET` | OpenTofu provider |
|
||||
| `WIN_ADMIN_PASS` | `ANSIBLE_PASSWORD` | Ansible connection |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| Token invalid | Token expired | Create new token in Proxmox |
|
||||
| Permission denied | Insufficient privileges | Add VM.Admin to token |
|
||||
| Password rejected | Windows complexity | Use stronger password |
|
||||
| Certificate invalid | Wrong format | Convert to PKCS#12 |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
| Goal | Next Document |
|
||||
|------|---------------|
|
||||
| Configure ISOs | [ISO Requirements](isos.md) |
|
||||
| Build template | [Packer Configuration](../03-packer/configuration.md) |
|
||||
| View architecture | [Architecture Overview](../01-overview/architecture.md) |
|
||||
|
||||
---
|
||||
|
||||
[← Documentation Index](../index.md) | [→ ISO Requirements](isos.md) | [← Architecture](../01-overview/architecture.md)
|
||||
238
docs/03-packer/autounattend.md
Normal file
238
docs/03-packer/autounattend.md
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
# 📝 Autounattend.xml Guide
|
||||
|
||||
[](https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/)
|
||||
|
||||
## Overview
|
||||
|
||||
The `Autounattend.xml` file provides automated answers to Windows Setup questions. Packer injects this file to enable fully automated installation.
|
||||
|
||||
**File Location:** [`packer/Autounattend.xml`](../../packer/Autounattend.xml)
|
||||
|
||||
---
|
||||
|
||||
## XML Structure
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Unattend["Autounattend.xml"]
|
||||
direction TB
|
||||
Root[<unattend>] --> WindowsPE["pass='windowsPE'"] --> Specialize["pass='specialize'"]
|
||||
Specialize --> OOBE["pass='oobeSystem'"] --> UserAccounts["<UserAccounts>"]
|
||||
OOBE --> AutoLogon["<AutoLogon>"] --> FirstLogon["<FirstLogonCommands>"]
|
||||
end
|
||||
|
||||
subgraph Purpose["Each Section"]
|
||||
WindowsPE[Language, Setup UI]
|
||||
Specialize[Computer Name, Timezone]
|
||||
OOBE[User Account, OOBE Screens]
|
||||
FirstLogon[WinRM, Firewall]
|
||||
end
|
||||
|
||||
Unattend --> Purpose
|
||||
|
||||
style Unattend fill:#e3f2fd
|
||||
style Purpose fill:#e8f5e9
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Full Configuration
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||
|
||||
<!-- === Windows PE Phase === -->
|
||||
<settings pass="windowsPE">
|
||||
<component name="Microsoft-Windows-International-Core-WinPE"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<SetupUILanguage>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
</SetupUILanguage>
|
||||
<InputLocale>en-US</InputLocale>
|
||||
<SystemLocale>en-US</SystemLocale>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
<UserLocale>en-US</UserLocale>
|
||||
</component>
|
||||
|
||||
<component name="Microsoft-Windows-Setup"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<UserData>
|
||||
<ProductKey>
|
||||
<Key></Key> <!-- Evaluation version: no key needed -->
|
||||
</ProductKey>
|
||||
<AcceptEula>true</AcceptEula>
|
||||
</UserData>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<!-- === Specialize Phase === -->
|
||||
<settings pass="specialize">
|
||||
<component name="Microsoft-Windows-Shell-Setup"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<ComputerName>*</ComputerName> <!-- Auto-generate name -->
|
||||
</component>
|
||||
|
||||
<component name="Microsoft-Windows-International-Core"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<InputLocale>en-US</InputLocale>
|
||||
<SystemLocale>en-US</SystemLocale>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
<UserLocale>en-US</UserLocale>
|
||||
</component>
|
||||
|
||||
<component name="Microsoft-Windows-TerminalServices-LocalSessionManager"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<fDenyTSConnections>false</fDenyTSConnections>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<!-- === OOBE System Phase === -->
|
||||
<settings pass="oobeSystem">
|
||||
<component name="Microsoft-Windows-Shell-Setup"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<OOBE>
|
||||
<HideEULAPage>true</HideEULAPage>
|
||||
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
|
||||
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
|
||||
<HideLocalAccountScreen>false</HideLocalAccountScreen>
|
||||
<ProtectYourPC>3</ProtectYourPC>
|
||||
</OOBE>
|
||||
|
||||
<!-- Administrator Password -->
|
||||
<UserAccounts>
|
||||
<AdministratorPassword>
|
||||
<Value>PackerPassword123!</Value>
|
||||
<PlainText>true</PlainText>
|
||||
</AdministratorPassword>
|
||||
</UserAccounts>
|
||||
|
||||
<!-- Auto-login (Count=1 = login once) -->
|
||||
<AutoLogon>
|
||||
<Enabled>true</Enabled>
|
||||
<Username>Administrator</Username>
|
||||
<LogonCount>1</LogonCount>
|
||||
</AutoLogon>
|
||||
|
||||
<!-- First Logon Commands -->
|
||||
<FirstLogonCommands>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>powershell -Command "Set-NetFirewallProfile -Profile Private -Enabled False"</CommandLine>
|
||||
<Order>1</Order>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile C:\ConfigureRemotingForAnsible.ps1; C:\ConfigureRemotingForAnsible.ps1"</CommandLine>
|
||||
<Order>2</Order>
|
||||
</SynchronousCommand>
|
||||
</FirstLogonCommands>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
</unattend>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Critical Settings
|
||||
|
||||
### ⚠️ Auto-Login Configuration
|
||||
|
||||
```xml
|
||||
<AutoLogon>
|
||||
<Enabled>true</Enabled>
|
||||
<Username>Administrator</Username>
|
||||
<LogonCount>1</LogonCount> <!-- Login once, then stay logged in -->
|
||||
</AutoLogon>
|
||||
```
|
||||
|
||||
**Why?** Packer needs to connect via WinRM after the OS is installed. Auto-login allows WinRM to be configured and accessed.
|
||||
|
||||
### ⚠️ Firewall Configuration
|
||||
|
||||
```xml
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>powershell -Command "Set-NetFirewallProfile -Profile Private -Enabled False"</CommandLine>
|
||||
<Order>1</Order>
|
||||
</SynchronousCommand>
|
||||
```
|
||||
|
||||
**Why?** Ansible connects via WinRM on the Private network profile. If the firewall blocks WinRM, connection fails.
|
||||
|
||||
### ⚠️ WinRM Enablement
|
||||
|
||||
```xml
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile C:\ConfigureRemotingForAnsible.ps1; C:\ConfigureRemotingForAnsible.ps1"</CommandLine>
|
||||
<Order>2</Order>
|
||||
</SynchronousCommand>
|
||||
```
|
||||
|
||||
**Why?** This script configures WinRM for remote management by Ansible.
|
||||
|
||||
---
|
||||
|
||||
## Pass Phases Explained
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Phases["Windows Setup Phases"]
|
||||
direction LR
|
||||
PE[windowsPE<br/>Pre-installation] --> Spec[specialize<br/>Specialize] --> OOBE[oobeSystem<br/>OOBE] --> Desktop[Desktop<br/>Ready]
|
||||
end
|
||||
|
||||
subgraph Actions["Key Actions"]
|
||||
PE[Load drivers<br/>Setup language] --> Spec[Computer name<br/>Timezone] --> OOBE[Create accounts<br/>Run commands]
|
||||
end
|
||||
|
||||
style Phases fill:#e3f2fd
|
||||
style Actions fill:#e8f5e9
|
||||
```
|
||||
|
||||
| Pass | Purpose | Key Settings |
|
||||
|------|---------|--------------|
|
||||
| `windowsPE` | Pre-installation environment | Language, keyboard |
|
||||
| `specialize` | Specialized configuration | Computer name, timezone |
|
||||
| `oobeSystem` | Out-of-box experience | User accounts, auto-logon, first commands |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| Packer timeout | WinRM not ready | Check FirstLogonCommands order |
|
||||
| Cannot join domain | ComputerName conflict | Use `*` for auto-generate |
|
||||
| Firewall blocking | Private profile enabled | Add firewall disable command |
|
||||
| Auto-login fails | Password complexity | Use simple password for testing |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
| Goal | Next Document |
|
||||
|------|---------------|
|
||||
| Build template | [Packer Configuration](configuration.md) |
|
||||
| View Terraform | [OpenTofu Resources](../04-terraform/main.tf.md) |
|
||||
| Run pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) |
|
||||
|
||||
---
|
||||
|
||||
[← Documentation Index](../index.md) | [← Packer Configuration](configuration.md) | [→ OpenTofu](../04-terraform/main.tf.md)
|
||||
218
docs/03-packer/configuration.md
Normal file
218
docs/03-packer/configuration.md
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
# 📦 Packer Configuration
|
||||
|
||||
[](https://developer.hashicorp.com/packer)
|
||||
[](https://www.proxmox.com/)
|
||||
|
||||
## Overview
|
||||
|
||||
Packer is used to create a reproducible Windows golden image template. This document details the Packer configuration in [`packer/windows.pkr.hcl`](../../packer/windows.pkr.hcl).
|
||||
|
||||
---
|
||||
|
||||
## Configuration Structure
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph PackerConfig["Packer Configuration"]
|
||||
direction TB
|
||||
Block1[packer { required_plugins }] --> Block2[source "proxmox-iso" "windows-11"]
|
||||
Block2 --> Block3[build { sources } + provisioners]
|
||||
end
|
||||
|
||||
subgraph Plugins["Plugins"]
|
||||
Plugin[proxmox >= 1.1.0]
|
||||
end
|
||||
|
||||
subgraph Sources["Source Settings"]
|
||||
VM[VM Settings] --> HW[Hardware] --> Storage[Storage] --> Comm[Communicator]
|
||||
end
|
||||
|
||||
PackerConfig --> Plugins
|
||||
PackerConfig --> Sources
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Full Configuration
|
||||
|
||||
```hcl
|
||||
packer {
|
||||
required_plugins {
|
||||
proxmox = {
|
||||
version = ">= 1.1.0"
|
||||
source = "github.com/hashicorp/proxmox"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source "proxmox-iso" "windows-11" {
|
||||
# === Connection ===
|
||||
proxmox_url = "https://proxmox-host:8006/api2/json"
|
||||
username = "root@pam"
|
||||
password = "secret"
|
||||
node = "la-vmh-07"
|
||||
|
||||
# === VM Settings ===
|
||||
vm_name = "win11-ltsc-template"
|
||||
template_description = "Built with Packer on ${timestamp()}"
|
||||
iso_file = "local:iso/CLIENT_LTSC_EVAL_x64FRE_en-us.iso"
|
||||
|
||||
# === Hardware (Win11 Compliant) ===
|
||||
qemu_agent = true
|
||||
cores = 4
|
||||
memory = 8192
|
||||
machine = "q35"
|
||||
bios = "ovmf"
|
||||
|
||||
# UEFI + TPM 2.0
|
||||
efi_config {
|
||||
efi_storage_pool = "local-lvm"
|
||||
pre_enrolled_keys = true
|
||||
}
|
||||
tpm_config {
|
||||
version = "2.0"
|
||||
tpm_storage_pool = "local-lvm"
|
||||
}
|
||||
|
||||
# === Storage ===
|
||||
scsi_controller = "virtio-scsi-pci"
|
||||
disks {
|
||||
disk_size = "60G"
|
||||
storage_pool = "local-lvm"
|
||||
type = "virtio"
|
||||
format = "raw"
|
||||
cache_mode = "writeback"
|
||||
}
|
||||
|
||||
# === Additional ISOs ===
|
||||
additional_iso_files {
|
||||
device = "sata1"
|
||||
iso_file = "local:iso/virtio-win.iso"
|
||||
}
|
||||
|
||||
# === Communicator (WinRM) ===
|
||||
communicator = "winrm"
|
||||
winrm_username = "Administrator"
|
||||
winrm_password = "PackerPassword123!"
|
||||
winrm_insecure = true
|
||||
winrm_use_ssl = true
|
||||
|
||||
# === Boot Command ===
|
||||
boot_command = [
|
||||
"<wait><wait><wait>", "<enter><wait>", "<enter><wait>",
|
||||
"<enter><wait>", "<enter>"
|
||||
]
|
||||
boot_wait = "10s"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.proxmox-iso.windows-11"]
|
||||
|
||||
# === Provisioners ===
|
||||
provisioner "powershell" {
|
||||
inline = [
|
||||
# Install VirtIO storage driver
|
||||
"pnputil /add-driver 'E:\\viostor\\w11\\amd64\\*.inf' /install",
|
||||
# Install VirtIO network driver
|
||||
"pnputil /add-driver 'E:\\NetKVM\\w11\\amd64\\*.inf' /install",
|
||||
# Install VirtIO guest tools
|
||||
"& 'E:\\virtio-win-guest-tools.exe' /install /passive /norestart"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Section Details
|
||||
|
||||
### Connection Settings
|
||||
|
||||
| Setting | Value | Description |
|
||||
|---------|-------|-------------|
|
||||
| `proxmox_url` | `https://proxmox-host:8006/api2/json` | Proxmox API endpoint |
|
||||
| `username` | `root@pam` | Authentication user |
|
||||
| `password` | `secret` | Authentication password |
|
||||
| `node` | `la-vmh-07` | Target Proxmox node |
|
||||
|
||||
### Hardware Configuration
|
||||
|
||||
| Setting | Value | Notes |
|
||||
|---------|-------|-------|
|
||||
| `cores` | 4 | Windows 11 minimum |
|
||||
| `memory` | 8192 | 8 GB RAM |
|
||||
| `machine` | `q35` | Modern chipset |
|
||||
| `bios` | `ovmf` | UEFI firmware |
|
||||
|
||||
### Storage Configuration
|
||||
|
||||
| Setting | Value | Notes |
|
||||
|---------|-------|-------|
|
||||
| `disk_size` | 60G | 60 GB disk |
|
||||
| `storage_pool` | `local-lvm` | LVM storage |
|
||||
| `format` | `raw` | Raw disk format |
|
||||
|
||||
### Boot Command
|
||||
|
||||
```hcl
|
||||
boot_command = [
|
||||
"<wait><wait><wait>", # Wait 30 seconds
|
||||
"<enter><wait>", # Press Enter (handle "Press any key")
|
||||
"<enter><wait>", # Confirm boot
|
||||
"<enter><wait>", # Continue installation
|
||||
"<enter>" # Final confirmation
|
||||
]
|
||||
boot_wait = "10s" # Initial wait before sending commands
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Provisioners
|
||||
|
||||
### PowerShell Provisioner
|
||||
|
||||
The PowerShell provisioner installs VirtIO drivers:
|
||||
|
||||
```powershell
|
||||
# Install VirtIO storage driver
|
||||
pnputil /add-driver 'E:\viostor\w11\amd64\*.inf' /install
|
||||
|
||||
# Install VirtIO network driver
|
||||
pnputil /add-driver 'E:\NetKVM\w11\amd64\*.inf' /install
|
||||
|
||||
# Install VirtIO guest tools (silent)
|
||||
& 'E:\virtio-win-guest-tools.exe' /install /passive /norestart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Build Process
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph BuildSteps["Packer Build Process"]
|
||||
direction TB
|
||||
Start[Start Build] --> Create[Create VM] --> MountISO[Mount ISO] --> Install[Windows Install] --> InstallDrivers[Install Drivers] --> Shutdown[Shutdown] --> Template[Convert to Template]
|
||||
end
|
||||
|
||||
subgraph InstallActions["Windows Setup"]
|
||||
Boot[Boot from ISO] --> WinSetup[Windows Setup] --> OOBE[OOBE - Autounattend.xml] --> Desktop[Desktop - WinRM Ready]
|
||||
end
|
||||
|
||||
style BuildSteps fill:#e3f2fd
|
||||
style InstallActions fill:#e8f5e9
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
| Goal | Next Document |
|
||||
|------|---------------|
|
||||
| Configure Autounattend.xml | [Autounattend.xml Guide](autounattend.md) |
|
||||
| Build the template | Run `packer build windows.pkr.hcl` |
|
||||
| View Terraform | [OpenTofu Resources](../04-terraform/main.tf.md) |
|
||||
|
||||
---
|
||||
|
||||
[← Documentation Index](../index.md) | [→ Autounattend.xml](autounattend.md) | [← ISO Requirements](../02-prerequisites/isos.md)
|
||||
223
docs/04-terraform/main.tf.md
Normal file
223
docs/04-terraform/main.tf.md
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
# 🏗️ OpenTofu Resources
|
||||
|
||||
[](https://opentofu.org/)
|
||||
[](https://www.proxmox.com/)
|
||||
|
||||
## Overview
|
||||
|
||||
OpenTofu provisions ephemeral Windows VMs from the Packer-built template. This document details the Terraform/OpenTofu configuration in [`terraform/main.tf`](../../terraform/main.tf).
|
||||
|
||||
---
|
||||
|
||||
## Configuration Structure
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph OpenTofu["OpenTofu Configuration"]
|
||||
direction TB
|
||||
Provider[Provider Config] --> Resources[VM Resource] --> Clone[Clone Strategy] --> Output[VM IP Output]
|
||||
end
|
||||
|
||||
subgraph ResourceParts["VM Resource Parts"]
|
||||
Basic[Basic Settings] --> Hardware[CPU/Memory] --> Network[Network Config] --> Init[Cloud-Init/IP]
|
||||
end
|
||||
|
||||
Provider --> Resources
|
||||
Resources --> ResourceParts
|
||||
|
||||
style OpenTofu fill:#e3f2fd
|
||||
style ResourceParts fill:#e8f5e9
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Full Configuration
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
required_providers {
|
||||
proxmox = {
|
||||
source = "bpg/proxmox"
|
||||
version = "0.46.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "proxmox" {
|
||||
endpoint = "https://proxmox-host:8006/"
|
||||
# Credentials injected via Environment Variables in Forgejo
|
||||
# PM_API_TOKEN_ID and PM_API_TOKEN_SECRET
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_vm" "build_agent" {
|
||||
name = "ci-win-build-${var.build_id}"
|
||||
node_name = "la-vmh-07"
|
||||
|
||||
clone {
|
||||
# Packer template VM ID
|
||||
vm_id = var.template_vm_id
|
||||
full_clone = false
|
||||
}
|
||||
|
||||
cpu {
|
||||
cores = 4
|
||||
type = "host"
|
||||
}
|
||||
|
||||
memory {
|
||||
dedicated = 8192
|
||||
}
|
||||
|
||||
network_device {
|
||||
bridge = "vmbr0"
|
||||
}
|
||||
|
||||
initialization {
|
||||
ip_config {
|
||||
ipv4 {
|
||||
address = "dhcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "vm_ip" {
|
||||
value = proxmox_virtual_environment_vm.build_agent.ipv4_addresses[1][0]
|
||||
description = "IP address of the provisioned VM"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Variables
|
||||
|
||||
### Input Variables
|
||||
|
||||
**File:** [`terraform/variables.tf`](../../terraform/variables.tf)
|
||||
|
||||
```hcl
|
||||
variable "build_id" {
|
||||
description = "Unique identifier for the build"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "template_vm_id" {
|
||||
description = "VM ID of the Packer-built template"
|
||||
type = number
|
||||
default = 9000
|
||||
}
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```bash
|
||||
export TF_VAR_build_id="123"
|
||||
export TF_VAR_template_vm_id="9000"
|
||||
tofu apply -auto-approve
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Section Details
|
||||
|
||||
### Provider Configuration
|
||||
|
||||
| Setting | Value | Description |
|
||||
|---------|-------|-------------|
|
||||
| `endpoint` | `https://proxmox-host:8006/` | Proxmox API URL |
|
||||
| `source` | `bpg/proxmox` | Proxmox provider |
|
||||
| `version` | `0.46.1` | Provider version |
|
||||
|
||||
### VM Clone Configuration
|
||||
|
||||
| Setting | Value | Description |
|
||||
|---------|-------|-------------|
|
||||
| `vm_id` | `var.template_vm_id` | Template VM ID to clone |
|
||||
| `full_clone` | `false` | Fast linked clone |
|
||||
| `node_name` | `la-vmh-07` | Target Proxmox node |
|
||||
|
||||
### Hardware Configuration
|
||||
|
||||
| Setting | Value | Notes |
|
||||
|---------|-------|-------|
|
||||
| `cores` | 4 | CPU cores |
|
||||
| `type` | `host` | Host-passthrough CPU |
|
||||
| `dedicated` | 8192 | 8 GB dedicated RAM |
|
||||
|
||||
### Network Configuration
|
||||
|
||||
| Setting | Value | Notes |
|
||||
|---------|-------|-------|
|
||||
| `bridge` | `vmbr0` | Default Proxmox bridge |
|
||||
| `ip_config` | DHCP | Automatic IP assignment |
|
||||
|
||||
---
|
||||
|
||||
## Provisioning Process
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Process["OpenTofu Process"]
|
||||
direction TB
|
||||
Init[tofu init] --> Plan[tofu plan] --> Apply[tofu apply] --> Clone[Clone VM] --> Start[Start VM] --> IP[Get VM IP]
|
||||
end
|
||||
|
||||
subgraph Template["Template"]
|
||||
T[Template VM] --> |Clone| V[New VM]
|
||||
end
|
||||
|
||||
Apply --> Template
|
||||
V --> Start
|
||||
|
||||
style Process fill:#e3f2fd
|
||||
style Template fill:#e8f5e9
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Output
|
||||
|
||||
```hcl
|
||||
output "vm_ip" {
|
||||
value = proxmox_virtual_environment_vm.build_agent.ipv4_addresses[1][0]
|
||||
}
|
||||
```
|
||||
|
||||
**Usage in pipeline:**
|
||||
```bash
|
||||
VM_IP=$(tofu output -raw vm_ip)
|
||||
echo "VM_IP=$VM_IP" >> $GITHUB_ENV
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Secret | Env Var | Purpose |
|
||||
|--------|---------|---------|
|
||||
| Proxmox Token ID | `PM_API_TOKEN_ID` | Authentication |
|
||||
| Proxmox Token Secret | `PM_API_TOKEN_SECRET` | Authentication |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| Clone failed | Wrong VM ID | Check template VM ID in Proxmox |
|
||||
| No IP assigned | DHCP not working | Check network bridge |
|
||||
| Permission denied | Token lacks privileges | Add VM.Admin to token |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
| Goal | Next Document |
|
||||
|------|---------------|
|
||||
| View variables | [Terraform Variables](variables.md) |
|
||||
| Run Ansible | [Ansible Pipeline](../05-ansible/pipeline.md) |
|
||||
| Run full pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) |
|
||||
|
||||
---
|
||||
|
||||
[← Documentation Index](../index.md) | [→ Variables](variables.md) | [← Packer Autounattend](../03-packer/autounattend.md)
|
||||
158
docs/04-terraform/variables.md
Normal file
158
docs/04-terraform/variables.md
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
# 📊 Terraform Variables
|
||||
|
||||
[](https://opentofu.org/)
|
||||
|
||||
## Overview
|
||||
|
||||
This document details all input variables for the OpenTofu configuration.
|
||||
|
||||
---
|
||||
|
||||
## Variables File
|
||||
|
||||
**File:** [`terraform/variables.tf`](../../terraform/variables.tf)
|
||||
|
||||
```hcl
|
||||
variable "build_id" {
|
||||
description = "Unique identifier for the build"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "template_vm_id" {
|
||||
description = "VM ID of the Packer-built template"
|
||||
type = number
|
||||
default = 9000
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Variable Details
|
||||
|
||||
### build_id
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Description | Unique identifier for the build |
|
||||
| Type | String |
|
||||
| Required | Yes |
|
||||
| Example | `"2024-02-06-001"` |
|
||||
|
||||
**Purpose:** Creates unique VM names for each pipeline run, enabling parallel builds and preventing naming conflicts.
|
||||
|
||||
```hcl
|
||||
# Generated VM name
|
||||
name = "ci-win-build-${var.build_id}"
|
||||
# Example: ci-win-build-2024-02-06-001
|
||||
```
|
||||
|
||||
### template_vm_id
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Description | VM ID of the Packer-built template |
|
||||
| Type | Number |
|
||||
| Default | `9000` |
|
||||
| Required | No |
|
||||
|
||||
**Purpose:** Specifies which template to clone when provisioning VMs.
|
||||
|
||||
```hcl
|
||||
# Default value
|
||||
vm_id = 9000
|
||||
|
||||
# Custom value
|
||||
vm_id = var.template_vm_id
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Setting Variables
|
||||
|
||||
### Method 1: Environment Variables
|
||||
|
||||
```bash
|
||||
export TF_VAR_build_id="123"
|
||||
export TF_VAR_template_vm_id="9000"
|
||||
tofu plan
|
||||
```
|
||||
|
||||
### Method 2: tfvars File
|
||||
|
||||
Create `terraform/terraform.tfvars`:
|
||||
|
||||
```hcl
|
||||
build_id = "2024-02-06-001"
|
||||
template_vm_id = 9000
|
||||
```
|
||||
|
||||
### Method 3: Command Line
|
||||
|
||||
```bash
|
||||
tofu apply -var="build_id=123" -var="template_vm_id=9000"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sensitive Variables
|
||||
|
||||
| Variable | Sensitive | Reason |
|
||||
|----------|-----------|--------|
|
||||
| `build_id` | No | Public identifier |
|
||||
| `template_vm_id` | No | Configuration value |
|
||||
|
||||
**Note:** Proxmox credentials are passed via environment variables, not variables file:
|
||||
- `PM_API_TOKEN_ID`
|
||||
- `PM_API_TOKEN_SECRET`
|
||||
|
||||
---
|
||||
|
||||
## Variable Validation
|
||||
|
||||
```hcl
|
||||
variable "build_id" {
|
||||
description = "Unique identifier for the build"
|
||||
type = string
|
||||
|
||||
validation {
|
||||
condition = can(regex("^[a-zA-Z0-9-_]+$", var.build_id))
|
||||
error_message = "build_id must contain only alphanumeric characters, hyphens, and underscores."
|
||||
}
|
||||
}
|
||||
|
||||
variable "template_vm_id" {
|
||||
description = "VM ID of the Packer-built template"
|
||||
type = number
|
||||
|
||||
validation {
|
||||
condition = var.template_vm_id >= 100 && var.template_vm_id <= 999999
|
||||
error_message = "template_vm_id must be a valid VM ID (100-999999)."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
| Practice | Description |
|
||||
|----------|-------------|
|
||||
| ✅ Use descriptive names | `build_id` vs `id` |
|
||||
| ✅ Set defaults | Provide safe defaults where possible |
|
||||
| ✅ Add validation | Prevent invalid configurations |
|
||||
| ✅ Document all variables | Clear description for each |
|
||||
| ✅ Use type constraints | Enforce correct data types |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
| Goal | Next Document |
|
||||
|------|---------------|
|
||||
| View main.tf | [OpenTofu Resources](main.tf.md) |
|
||||
| Run provisioning | Apply Terraform configuration |
|
||||
| View Ansible | [Ansible Pipeline](../05-ansible/pipeline.md) |
|
||||
|
||||
---
|
||||
|
||||
[← Documentation Index](../index.md) | [← OpenTofu Resources](main.tf.md) | [→ Ansible Pipeline](../05-ansible/pipeline.md)
|
||||
195
docs/05-ansible/pipeline.md
Normal file
195
docs/05-ansible/pipeline.md
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# ✅ Ansible Pipeline
|
||||
|
||||
[](https://www.ansible.com/)
|
||||
|
||||
## Overview
|
||||
|
||||
Ansible automates verification of the Windows installer on the provisioned VM. This document details the playbook in [`ansible/pipeline.yml`](../../ansible/pipeline.yml).
|
||||
|
||||
---
|
||||
|
||||
## Playbook Structure
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
subgraph Playbook["Ansible Pipeline"]
|
||||
direction TB
|
||||
Play[Play: Verify Installer] --> Tasks[Tasks List]
|
||||
Tasks --> T1[Create Workspace] --> T2[Upload Installer] --> T3[Install] --> T4[Verify] --> T5[Assert]
|
||||
end
|
||||
|
||||
subgraph Hosts["Host Selection"]
|
||||
H[windows_vm] --> Play
|
||||
end
|
||||
|
||||
style Playbook fill:#e3f2fd
|
||||
style Hosts fill:#e8f5e9
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Full Playbook
|
||||
|
||||
```yaml
|
||||
- name: Verify Installer
|
||||
hosts: windows_vm
|
||||
tasks:
|
||||
- name: Create Workspace
|
||||
ansible.windows.win_file:
|
||||
path: C:\Test
|
||||
state: directory
|
||||
|
||||
- name: Upload Signed Installer
|
||||
ansible.windows.win_copy:
|
||||
src: ./dist/installer_signed.exe
|
||||
dest: C:\Test\installer.exe
|
||||
|
||||
- name: Install (Silent Mode)
|
||||
ansible.windows.win_command: C:\Test\installer.exe /S
|
||||
register: install_result
|
||||
|
||||
- name: Verify Executable Exists
|
||||
ansible.windows.win_stat:
|
||||
path: "C:\\Program Files\\MyApp\\app.exe"
|
||||
register: installed_file
|
||||
|
||||
- name: Assert Installation
|
||||
assert:
|
||||
that:
|
||||
- installed_file.stat.exists
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task Details
|
||||
|
||||
### 1. Create Workspace
|
||||
|
||||
```yaml
|
||||
- name: Create Workspace
|
||||
ansible.windows.win_file:
|
||||
path: C:\Test
|
||||
state: directory
|
||||
```
|
||||
|
||||
**Purpose:** Creates a directory for temporary files on the Windows VM.
|
||||
|
||||
### 2. Upload Installer
|
||||
|
||||
```yaml
|
||||
- name: Upload Signed Installer
|
||||
ansible.windows.win_copy:
|
||||
src: ./dist/installer_signed.exe
|
||||
dest: C:\Test\installer.exe
|
||||
```
|
||||
|
||||
**Purpose:** Copies the signed installer from the build host to the Windows VM.
|
||||
|
||||
### 3. Silent Install
|
||||
|
||||
```yaml
|
||||
- name: Install (Silent Mode)
|
||||
ansible.windows.win_command: C:\Test\installer.exe /S
|
||||
register: install_result
|
||||
```
|
||||
|
||||
**Purpose:** Runs the installer in silent mode (`/S` flag).
|
||||
|
||||
### 4. Verify Installation
|
||||
|
||||
```yaml
|
||||
- name: Verify Executable Exists
|
||||
ansible.windows.win_stat:
|
||||
path: "C:\\Program Files\\MyApp\\app.exe"
|
||||
register: installed_file
|
||||
```
|
||||
|
||||
**Purpose:** Checks if the installed executable exists at the expected path.
|
||||
|
||||
### 5. Assert Result
|
||||
|
||||
```yaml
|
||||
- name: Assert Installation
|
||||
assert:
|
||||
that:
|
||||
- installed_file.stat.exists
|
||||
```
|
||||
|
||||
**Purpose:** Fails the pipeline if the executable is not found.
|
||||
|
||||
---
|
||||
|
||||
## Inventory Configuration
|
||||
|
||||
### Dynamic Inventory
|
||||
|
||||
The inventory is generated in the Forgejo workflow:
|
||||
|
||||
```ini
|
||||
[windows_vm]
|
||||
<VM_IP> ansible_user=Administrator ansible_password=<password> ansible_connection=winrm ansible_winrm_server_cert_validation=ignore
|
||||
```
|
||||
|
||||
### Inventory Variables
|
||||
|
||||
| Variable | Value | Purpose |
|
||||
|----------|-------|---------|
|
||||
| `ansible_user` | `Administrator` | Windows admin account |
|
||||
| `ansible_password` | From secret | WinRM password |
|
||||
| `ansible_connection` | `winrm` | Connection type |
|
||||
| `ansible_winrm_server_cert_validation` | `ignore` | Skip cert validation |
|
||||
|
||||
---
|
||||
|
||||
## Execution Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Runner as Forgejo Runner
|
||||
participant WinVM as Windows VM
|
||||
|
||||
Runner->>WinVM: Connect via WinRM
|
||||
WinVM->>Runner: Connection established
|
||||
|
||||
Runner->>WinVM: Create C:\Test directory
|
||||
WinVM->>Runner: Directory created
|
||||
|
||||
Runner->>WinVM: Upload installer_signed.exe
|
||||
WinVM->>Runner: File uploaded
|
||||
|
||||
Runner->>WinVM: Execute installer.exe /S
|
||||
WinVM->>Runner: Installation complete
|
||||
|
||||
Runner->>WinVM: Check app.exe exists
|
||||
WinVM->>Runner: File found (or not)
|
||||
|
||||
alt File exists
|
||||
Runner->>Runner: PASS - Continue pipeline
|
||||
else File missing
|
||||
Runner->>Runner: FAIL - Stop pipeline
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| WinRM connection timeout | Firewall blocking | Disable Private firewall |
|
||||
| Credential rejected | Wrong password | Verify WIN_ADMIN_PASS |
|
||||
| File not found | Wrong path | Check installation path |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
| Goal | Next Document |
|
||||
|------|---------------|
|
||||
| Run pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) |
|
||||
| View Terraform | [OpenTofu Resources](../04-terraform/main.tf.md) |
|
||||
| Troubleshoot | [Troubleshooting](../07-advanced/troubleshooting.md) |
|
||||
|
||||
---
|
||||
|
||||
[← Documentation Index](../index.md) | [→ Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) | [← Terraform Variables](../04-terraform/variables.md)
|
||||
288
docs/06-ci-cd/forgejo-workflows.md
Normal file
288
docs/06-ci-cd/forgejo-workflows.md
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
# 🔄 Forgejo Workflows
|
||||
|
||||
[](https://forgejo.org/)
|
||||
[](.forgejo/workflows/release.yml)
|
||||
|
||||
## Overview
|
||||
|
||||
Forgejo Actions orchestrates the entire pipeline from code commit to verified artifact. This document details the workflow in [`.forgejo/workflows/release.yml`](../../.forgejo/workflows/release.yml).
|
||||
|
||||
---
|
||||
|
||||
## Workflow Structure
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Workflow["Forgejo Workflow"]
|
||||
direction LR
|
||||
Trigger[on: push] --> Job[build-sign-package]
|
||||
Job --> Steps[6 Steps]
|
||||
end
|
||||
|
||||
subgraph Steps["Job Steps"]
|
||||
direction TB
|
||||
Install[Install Tools] --> Checkout[Checkout] --> Compile[Cross-Compile] --> Package[Package] --> Sign[Sign] --> Provision[Provision VM] --> Verify[Verify] --> Cleanup[Cleanup]
|
||||
end
|
||||
|
||||
style Workflow fill:#e3f2fd
|
||||
style Steps fill:#e8f5e9
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Full Workflow Configuration
|
||||
|
||||
```yaml
|
||||
name: Build and Release
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build-sign-package:
|
||||
runs-on: ubuntu-latest
|
||||
container: archlinux:latest
|
||||
steps:
|
||||
- name: Install Tools
|
||||
run: |
|
||||
pacman -Syu --noconfirm \
|
||||
mingw-w64-gcc \
|
||||
nsis \
|
||||
osslsigncode \
|
||||
opentofu \
|
||||
ansible \
|
||||
python-pywinrm \
|
||||
packer
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Cross-Compile (MinGW)
|
||||
run: |
|
||||
x86_64-w64-mingw32-gcc src/main.c -o dist/app.exe
|
||||
|
||||
- name: Package (NSIS)
|
||||
run: |
|
||||
makensis -DVERSION=${{ gitea.ref_name }} installer.nsi
|
||||
|
||||
- name: Code Sign (Linux Native)
|
||||
env:
|
||||
PFX_PASS: ${{ secrets.PFX_PASS }}
|
||||
run: |
|
||||
osslsigncode sign \
|
||||
-pkcs12 cert.pfx \
|
||||
-pass "$PFX_PASS" \
|
||||
-t http://timestamp.digicert.com \
|
||||
-in dist/installer.exe \
|
||||
-out dist/installer_signed.exe
|
||||
|
||||
- name: Provision Windows VM (OpenTofu)
|
||||
env:
|
||||
PM_API_TOKEN_ID: ${{ secrets.PM_TOKEN_ID }}
|
||||
PM_API_TOKEN_SECRET: ${{ secrets.PM_TOKEN_SECRET }}
|
||||
TF_VAR_build_id: ${{ gitea.run_number }}
|
||||
run: |
|
||||
cd terraform
|
||||
tofu init
|
||||
tofu apply -auto-approve
|
||||
echo "VM_IP=$(tofu output -raw vm_ip)" >> $GITHUB_ENV
|
||||
|
||||
- name: Verify on Windows (Ansible)
|
||||
env:
|
||||
ANSIBLE_USER: Administrator
|
||||
ANSIBLE_PASSWORD: ${{ secrets.WIN_ADMIN_PASS }}
|
||||
run: |
|
||||
echo "[windows_vm]" > inventory.ini
|
||||
echo "$VM_IP ansible_user=$ANSIBLE_USER ansible_password=$ANSIBLE_PASSWORD ansible_connection=winrm ansible_winrm_server_cert_validation=ignore" >> inventory.ini
|
||||
|
||||
ansible-playbook -i inventory.ini ansible/pipeline.yml
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
cd terraform
|
||||
tofu destroy -auto-approve
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step-by-Step Breakdown
|
||||
|
||||
### 1. Install Tools
|
||||
|
||||
```bash
|
||||
pacman -Syu --noconfirm \
|
||||
mingw-w64-gcc \ # MinGW cross-compiler
|
||||
nsis \ # NSIS installer builder
|
||||
osslsigncode \ # Code signing tool
|
||||
opentofu \ # Infrastructure as code
|
||||
ansible \ # Automation
|
||||
python-pywinrm \ # Ansible WinRM support
|
||||
packer \ # Image builder
|
||||
```
|
||||
|
||||
### 2. Checkout
|
||||
|
||||
```yaml
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
```
|
||||
|
||||
**Purpose:** Clones the repository to the container.
|
||||
|
||||
### 3. Cross-Compile (MinGW)
|
||||
|
||||
```bash
|
||||
x86_64-w64-mingw32-gcc src/main.c -o dist/app.exe
|
||||
```
|
||||
|
||||
**Purpose:** Compiles Windows executable from Linux.
|
||||
|
||||
### 4. Package (NSIS)
|
||||
|
||||
```bash
|
||||
makensis -DVERSION=${{ gitea.ref_name }} installer.nsi
|
||||
```
|
||||
|
||||
**Purpose:** Creates Windows installer from compiled executable.
|
||||
|
||||
### 5. Code Sign
|
||||
|
||||
```bash
|
||||
osslsigncode sign \
|
||||
-pkcs12 cert.pfx \
|
||||
-pass "$PFX_PASS" \
|
||||
-t http://timestamp.digicert.com \
|
||||
-in dist/installer.exe \
|
||||
-out dist/installer_signed.exe
|
||||
```
|
||||
|
||||
**Purpose:** Authenticode sign the installer with timestamp.
|
||||
|
||||
### 6. Provision VM (OpenTofu)
|
||||
|
||||
```bash
|
||||
cd terraform
|
||||
tofu init
|
||||
tofu apply -auto-approve
|
||||
echo "VM_IP=$(tofu output -raw vm_ip)" >> $GITHUB_ENV
|
||||
```
|
||||
|
||||
**Purpose:** Creates ephemeral Windows VM for testing.
|
||||
|
||||
### 7. Verify (Ansible)
|
||||
|
||||
```bash
|
||||
echo "[windows_vm]" > inventory.ini
|
||||
echo "$VM_IP ansible_user=$ANSIBLE_USER ..." >> inventory.ini
|
||||
ansible-playbook -i inventory.ini ansible/pipeline.yml
|
||||
```
|
||||
|
||||
**Purpose:** Tests installer on live Windows VM.
|
||||
|
||||
### 8. Cleanup
|
||||
|
||||
```bash
|
||||
if: always()
|
||||
tofu destroy -auto-approve
|
||||
```
|
||||
|
||||
**Purpose:** Destroys VM regardless of test result.
|
||||
|
||||
---
|
||||
|
||||
## Container Configuration
|
||||
|
||||
| Setting | Value | Description |
|
||||
|---------|-------|-------------|
|
||||
| `runs-on` | `ubuntu-latest` | Runner OS |
|
||||
| `container` | `archlinux:latest` | Build container |
|
||||
|
||||
**Why Arch Linux?**
|
||||
- Latest packages available
|
||||
- Excellent AUR support
|
||||
- Small footprint
|
||||
- Easy package management
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Set by Workflow
|
||||
|
||||
| Variable | Source | Purpose |
|
||||
|----------|--------|---------|
|
||||
| `VM_IP` | OpenTofu output | Windows VM IP address |
|
||||
| `GITHUB_ENV` | Workflow | Store VM_IP for subsequent steps |
|
||||
|
||||
### From Secrets
|
||||
|
||||
| Secret | Env Var | Purpose |
|
||||
|--------|---------|---------|
|
||||
| `PFX_PASS` | `PFX_PASS` | Certificate password |
|
||||
| `PM_TOKEN_ID` | `PM_API_TOKEN_ID` | Proxmox authentication |
|
||||
| `PM_TOKEN_SECRET` | `PM_API_TOKEN_SECRET` | Proxmox authentication |
|
||||
| `WIN_ADMIN_PASS` | `ANSIBLE_PASSWORD` | WinRM connection |
|
||||
|
||||
---
|
||||
|
||||
## Pipeline Flow Diagram
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Build["Build Stage"]
|
||||
direction LR
|
||||
Install[Install Tools] --> Checkout[Checkout] --> Compile[Cross-Compile] --> Package[Package] --> Sign[Sign]
|
||||
end
|
||||
|
||||
subgraph Deploy["Deploy Stage"]
|
||||
Sign --> Provision[Provision VM] --> Verify[Ansible Verify]
|
||||
end
|
||||
|
||||
subgraph Cleanup["Cleanup Stage"]
|
||||
Verify --> Destroy[Destroy VM]
|
||||
end
|
||||
|
||||
style Build fill:#e3f2fd
|
||||
style Deploy fill:#e8f5e9
|
||||
style Cleanup fill:#fff3e0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Triggering the Pipeline
|
||||
|
||||
| Trigger | Description |
|
||||
|---------|-------------|
|
||||
| `on: push` | Runs on any push to any branch |
|
||||
| `on: [push, pull_request]` | Also run on PRs (optional) |
|
||||
|
||||
### Manual Trigger
|
||||
|
||||
```bash
|
||||
git commit -m "Update installer"
|
||||
git push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| Container missing packages | Pacman cache | Clear cache or use specific versions |
|
||||
| OpenTofu init fails | Provider issues | Run `tofu init -upgrade` |
|
||||
| Ansible connection timeout | WinRM not ready | Check Autounattend.xml |
|
||||
| Cleanup failed | VM already destroyed | Add `if: failure()` condition |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
| Goal | Next Document |
|
||||
|------|---------------|
|
||||
| View architecture | [Architecture Overview](../01-overview/architecture.md) |
|
||||
| Troubleshoot | [Troubleshooting](../07-advanced/troubleshooting.md) |
|
||||
| Manage evaluations | [Evaluation Management](../07-advanced/evaluation.md) |
|
||||
|
||||
---
|
||||
|
||||
[← Documentation Index](../index.md) | [→ Advanced Topics](../07-advanced/) | [← Ansible Pipeline](../05-ansible/pipeline.md)
|
||||
200
docs/07-advanced/evaluation.md
Normal file
200
docs/07-advanced/evaluation.md
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
# ⏰ 90-Day Evaluation Management
|
||||
|
||||
[](https://www.microsoft.com/en-us/evalcenter/)
|
||||
|
||||
## Overview
|
||||
|
||||
Windows Evaluation editions expire after 90 days. This document explains the expiration mechanism and provides strategies for managing it in your automation pipeline.
|
||||
|
||||
---
|
||||
|
||||
## Understanding Evaluation Expiration
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Timeline["90-Day Timeline"]
|
||||
Start[Install Day 0] --> Day30[Day 30] --> Day60[Day 60] --> Day90[Day 90 - Expiration]
|
||||
end
|
||||
|
||||
subgraph States["System States"]
|
||||
Active[✅ Active] --> Warning[⚠️ Warning 15 days] --> Expired[❌ Expired]
|
||||
end
|
||||
|
||||
Timeline --> States
|
||||
|
||||
style Timeline fill:#e3f2fd
|
||||
style States fill:#e8f5e9
|
||||
```
|
||||
|
||||
| Phase | Duration | Status |
|
||||
|-------|----------|--------|
|
||||
| **Full Activation** | Days 0-89 | ✅ Fully functional |
|
||||
| **Warning Period** | Days 90-104 | ⚠️ Countdown warnings |
|
||||
| **Grace Period** | Days 105-180 | ⏳ Extended grace |
|
||||
| **Expired** | Day 181+ | ❌ System stops |
|
||||
|
||||
---
|
||||
|
||||
## Expiration Methods
|
||||
|
||||
### Method 1: Rearm (Manual/Scripted)
|
||||
|
||||
The `slmgr /rearm` command resets the activation timer.
|
||||
|
||||
```powershell
|
||||
# Run as Administrator
|
||||
slmgr /rearm
|
||||
|
||||
# Reboot required
|
||||
shutdown /r /t 0
|
||||
```
|
||||
|
||||
**Limits:**
|
||||
- Maximum 3 rearm attempts per installation
|
||||
- Each rearm resets to 90 days
|
||||
- **Total: 360 days maximum**
|
||||
|
||||
### Method 2: Packer Rebuild (Recommended)
|
||||
|
||||
The recommended approach is to **rebuild the golden image monthly**.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph Monthly["Monthly Schedule"]
|
||||
direction LR
|
||||
Week1[Week 1: Packer Build] --> Week2[Week 2-4: Use Template]
|
||||
end
|
||||
|
||||
subgraph Process["Rebuild Process"]
|
||||
Destroy[Destroy Old Template] --> Create[Create New Template] --> Verify[Test New Template]
|
||||
end
|
||||
|
||||
Monthly --> Process
|
||||
|
||||
style Monthly fill:#e3f2fd
|
||||
style Process fill:#e8f5e9
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Fresh timer each month
|
||||
- Latest Windows updates baked in
|
||||
- Consistent baseline
|
||||
- No rearm limitations
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### Automated Monthly Rebuild
|
||||
|
||||
Configure a scheduled workflow in Forgejo:
|
||||
|
||||
```yaml
|
||||
# .forgejo/workflows/monthly-rebuild.yml
|
||||
name: Monthly Template Rebuild
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 1 * *' # First day of each month at midnight
|
||||
|
||||
jobs:
|
||||
rebuild-template:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Build New Template
|
||||
run: |
|
||||
cd packer
|
||||
packer build -timestamp-ui windows.pkr.hcl
|
||||
|
||||
- name: Cleanup Old Template
|
||||
run: |
|
||||
# Script to remove template older than 45 days
|
||||
./scripts/cleanup-old-templates.sh --older-than 45d
|
||||
```
|
||||
|
||||
### Rebarm as Backup
|
||||
|
||||
For emergency extension:
|
||||
|
||||
```powershell
|
||||
# emergency-rearm.ps1
|
||||
# Run via Ansible or manually
|
||||
|
||||
if ((slmgr /dlv) -match "Remaining: 0") {
|
||||
Write-Host "Rearming system..."
|
||||
slmgr /rearm
|
||||
shutdown /r /t 0
|
||||
} else {
|
||||
Write-Host "Not yet expired, no action needed"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Monitoring Expiration
|
||||
|
||||
### Check Current Status
|
||||
|
||||
```powershell
|
||||
# Method 1: slmgr
|
||||
slmgr /dlv
|
||||
|
||||
# Method 2: PowerShell
|
||||
(Get-CimInstance -Query "SELECT * FROM SoftwareLicensingProduct WHERE PartialProductKey IS NOT NULL").RemainingGracePeriod
|
||||
```
|
||||
|
||||
### Automated Monitoring Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# check-expiration.sh - Run via Ansible monthly
|
||||
|
||||
VM_ID="9000"
|
||||
PROXMOX_HOST="la-vmh-07"
|
||||
|
||||
# Get VM's Windows activation status
|
||||
ssh root@$PROXMOX_HOST "qm agent $VM_ID exec-win32 powershell -Command '(Get-CimInstance -Query \"SELECT * FROM SoftwareLicensingProduct WHERE PartialProductKey IS NOT NULL\").RemainingGracePeriod'"
|
||||
|
||||
# Alert if less than 7 days
|
||||
if [ $DAYS_REMAINING -lt 7 ]; then
|
||||
echo "⚠️ ALERT: Template expires in $DAYS_REMAINING days"
|
||||
# Send notification
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
| Practice | Description | Priority |
|
||||
|----------|-------------|----------|
|
||||
| **Monthly rebuild** | Schedule automatic Packer build | 🔴 High |
|
||||
| **Monitor expiration** | Check status weekly | 🟡 Medium |
|
||||
| **Test new templates** | Verify before production use | 🔴 High |
|
||||
| **Document rebuilds** | Log template versions | 🟢 Low |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| Rearm failed | Already rearmed 3 times | Rebuild with Packer |
|
||||
| VM won't boot after rearm | Activation issues | Rebuild template |
|
||||
| Updates not installing | WSUS offline | Include updates in Packer build |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
| Goal | Next Document |
|
||||
|------|---------------|
|
||||
| View troubleshooting | [Troubleshooting](troubleshooting.md) |
|
||||
| Configure pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) |
|
||||
| View architecture | [Architecture Overview](../01-overview/architecture.md) |
|
||||
|
||||
---
|
||||
|
||||
[← Documentation Index](../index.md) | [→ Troubleshooting](troubleshooting.md) | [← Forgejo Workflows](../06-ci-cd/forgejo-workflows.md)
|
||||
273
docs/07-advanced/troubleshooting.md
Normal file
273
docs/07-advanced/troubleshooting.md
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
# 🔧 Troubleshooting Guide
|
||||
|
||||
[]()
|
||||
|
||||
## Overview
|
||||
|
||||
This guide covers common issues and their solutions for the Windows automation pipeline.
|
||||
|
||||
---
|
||||
|
||||
## Quick Fix Index
|
||||
|
||||
| Issue | Phase | Quick Fix |
|
||||
|-------|-------|-----------|
|
||||
| Packer timeout | Build | Check Autounattend.xml WinRM config |
|
||||
| VM won't boot | Provision | Verify ISO paths in Packer |
|
||||
| Ansible connection | Test | Disable Windows firewall |
|
||||
| Code signing fails | Build | Verify PFX password |
|
||||
| Template expired | All | Rebuild with Packer |
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Packer Issues
|
||||
|
||||
### Timeout Waiting for WinRM
|
||||
|
||||
**Symptom:**
|
||||
```
|
||||
==> proxmox-iso.windows-11: Timeout waiting for WinRM.
|
||||
```
|
||||
|
||||
**Cause:** Windows not fully booted or WinRM not configured.
|
||||
|
||||
**Solution:**
|
||||
1. Verify `Autounattend.xml` has WinRM configuration
|
||||
2. Check boot command timing
|
||||
3. Increase `boot_wait` duration
|
||||
|
||||
```hcl
|
||||
# Increase boot wait
|
||||
boot_wait = "30s"
|
||||
|
||||
# Check boot command
|
||||
boot_command = [
|
||||
"<wait><wait><wait><wait><wait>",
|
||||
"<enter><wait><wait>",
|
||||
"<enter>"
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ISO Not Found
|
||||
|
||||
**Symptom:**
|
||||
```
|
||||
==> proxmox-iso.windows-iso: ISO file not found: local:iso/...
|
||||
```
|
||||
|
||||
**Cause:** Wrong ISO path or storage.
|
||||
|
||||
**Solution:**
|
||||
1. Verify ISO location on Proxmox
|
||||
2. Check storage name (local vs local-lvm)
|
||||
|
||||
```bash
|
||||
# On Proxmox host
|
||||
ls -la /mnt/pve-07-iso-nvme/template/iso/
|
||||
qm storage
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: OpenTofu Issues
|
||||
|
||||
### Clone Failed
|
||||
|
||||
**Symptom:**
|
||||
```
|
||||
Error: resource is not a cloneable VM
|
||||
```
|
||||
|
||||
**Cause:** Wrong VM ID or template not found.
|
||||
|
||||
**Solution:**
|
||||
1. Verify template VM exists
|
||||
2. Check VM ID is correct
|
||||
|
||||
```bash
|
||||
# On Proxmox host
|
||||
qm list | grep template
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Permission Denied
|
||||
|
||||
**Symptom:**
|
||||
```
|
||||
Error: permission denied (400)
|
||||
```
|
||||
|
||||
**Cause:** Proxmox API token lacks privileges.
|
||||
|
||||
**Solution:**
|
||||
1. Add VM.Admin role to token
|
||||
2. Verify token is not expired
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Ansible Issues
|
||||
|
||||
### WinRM Connection Timeout
|
||||
|
||||
**Symptom:**
|
||||
```
|
||||
fatal: [10.0.0.5]: UNREACHABLE! => {"msg": "Connection timeout"}
|
||||
```
|
||||
|
||||
**Cause:** Firewall blocking WinRM or WinRM not configured.
|
||||
|
||||
**Solution:**
|
||||
```yaml
|
||||
# In Autounattend.xml - disable firewall
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>powershell -Command "Set-NetFirewallProfile -Profile Private -Enabled False"</CommandLine>
|
||||
<Order>1</Order>
|
||||
</SynchronousCommand>
|
||||
|
||||
# In inventory - ignore certificate validation
|
||||
[windows_vm]
|
||||
10.0.0.5 ansible_winrm_server_cert_validation=ignore
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Invalid Credentials
|
||||
|
||||
**Symptom:**
|
||||
```
|
||||
fatal: [10.0.0.5]: UNREACHABLE! => {"msg": "Basic auth failed"}
|
||||
```
|
||||
|
||||
**Cause:** Wrong username or password.
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Verify secrets are set
|
||||
echo $WIN_ADMIN_PASS
|
||||
|
||||
# Test manually
|
||||
winrs -r:10.0.0.5 -u:Administrator -p:$WIN_ADMIN_PASS "hostname"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Code Signing Issues
|
||||
|
||||
### Invalid Certificate
|
||||
|
||||
**Symptom:**
|
||||
```
|
||||
Error: PKCS12_parse failed
|
||||
```
|
||||
|
||||
**Cause:** Wrong password or corrupted PFX file.
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Verify certificate
|
||||
openssl pkcs12 -in cert.pfx -info -noout -passin pass:$PFX_PASS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Diagnostic Commands
|
||||
|
||||
### Proxmox Diagnostics
|
||||
|
||||
```bash
|
||||
# List VMs
|
||||
qm list
|
||||
|
||||
# Check VM status
|
||||
qm status <VM_ID>
|
||||
|
||||
# View VM config
|
||||
qm config <VM_ID>
|
||||
|
||||
# Check storage
|
||||
pvesm status
|
||||
```
|
||||
|
||||
### Windows Diagnostics
|
||||
|
||||
```powershell
|
||||
# Check WinRM status
|
||||
winrm quickconfig
|
||||
Get-WinRM -Service
|
||||
|
||||
# Check firewall
|
||||
Get-NetFirewallProfile | Select Name, Enabled
|
||||
|
||||
# Check activation
|
||||
slmgr /dlv
|
||||
```
|
||||
|
||||
### Ansible Diagnostics
|
||||
|
||||
```bash
|
||||
# Test WinRM connection
|
||||
ansible windows_vm -m win_ping -i inventory.ini
|
||||
|
||||
# Verbose output
|
||||
ansible-playbook -i inventory.ini pipeline.yml -vvvv
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Log Locations
|
||||
|
||||
| Component | Log Location |
|
||||
|-----------|--------------|
|
||||
| Packer | Console output + `packer.log` |
|
||||
| OpenTofu | Console output + `.terraform.lock.hcl` |
|
||||
| Ansible | Console output + `/var/log/ansible.log` |
|
||||
| Windows | Event Viewer → System |
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
### Q: Can I use a different Windows edition?
|
||||
|
||||
**A:** Yes, but you need to:
|
||||
1. Update ISO in `packer/windows.pkr.hcl`
|
||||
2. Modify `Autounattend.xml` for that edition
|
||||
3. Update product key settings
|
||||
|
||||
### Q: How do I add more software to the template?
|
||||
|
||||
**A:** Add PowerShell provisioners:
|
||||
|
||||
```hcl
|
||||
provisioner "powershell" {
|
||||
inline = [
|
||||
"choco install -y 7zip git vscode",
|
||||
"& 'C:\\ProgramData\\Chocolatey\\bin\\choco.exe' install -y dotnetfx"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Q: The VM has no IP after provisioning
|
||||
|
||||
**Cause:** DHCP not working or VirtIO drivers missing.
|
||||
|
||||
**Solution:**
|
||||
1. Ensure VirtIO drivers are installed in template
|
||||
2. Verify network bridge is correct
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
| Goal | Next Document |
|
||||
|------|---------------|
|
||||
| Manage evaluations | [Evaluation Management](evaluation.md) |
|
||||
| View pipeline | [Forgejo Workflows](../06-ci-cd/forgejo-workflows.md) |
|
||||
| Full documentation | [Documentation Index](../index.md) |
|
||||
|
||||
---
|
||||
|
||||
[← Documentation Index](../index.md) | [← Evaluation Management](evaluation.md) | [← Home](../index.md)
|
||||
258
docs/index.md
Normal file
258
docs/index.md
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
# 📖 Documentation Index
|
||||
|
||||
<!-- Badges -->
|
||||
[](.forgejo/workflows/release.yml)
|
||||
[](https://www.microsoft.com/en-us/windows/windows-11-enterprise)
|
||||
|
||||
## Welcome
|
||||
|
||||
This is the comprehensive documentation index for the **Windows Automation on Proxmox** project. Use this guide to navigate through all available documentation.
|
||||
|
||||
---
|
||||
|
||||
## 🗂️ Documentation Map
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ DOCUMENTATION TREE │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 📄 index.md (You are here) │
|
||||
│ ├── 📁 01-overview/ │
|
||||
│ │ └── 📄 architecture.md │
|
||||
│ │ ├── System Components │
|
||||
│ │ ├── Architecture Diagrams │
|
||||
│ │ └── Design Decisions │
|
||||
│ │ │
|
||||
│ ├── 📁 02-prerequisites/ │
|
||||
│ │ ├── 📄 isos.md │
|
||||
│ │ │ ├── ISO Download Sources │
|
||||
│ │ │ ├── Storage Location │
|
||||
│ │ │ └── Verification Steps │
|
||||
│ │ │ │
|
||||
│ │ └── 📄 secrets.md │
|
||||
│ │ ├── Forgejo Secrets │
|
||||
│ │ ├── Proxmox API Tokens │
|
||||
│ │ └── Certificate Management │
|
||||
│ │ │
|
||||
│ ├── 📁 03-packer/ │
|
||||
│ │ ├── 📄 configuration.md │
|
||||
│ │ │ ├── Packer HCL Syntax │
|
||||
│ │ │ ├── Proxmox Builder Settings │
|
||||
│ │ │ └── Provisioner Configuration │
|
||||
│ │ │ │
|
||||
│ │ └── 📄 autounattend.md │
|
||||
│ │ ├── XML Structure │
|
||||
│ │ ├── WinRM Configuration │
|
||||
│ │ └── FirstLogonCommands │
|
||||
│ │ │
|
||||
│ ├── 📁 04-terraform/ │
|
||||
│ │ ├── 📄 main.tf.md │
|
||||
│ │ │ ├── Provider Configuration │
|
||||
│ │ │ ├── VM Resource Definition │
|
||||
│ │ │ └── Clone Strategy │
|
||||
│ │ │ │
|
||||
│ │ └── 📄 variables.md │
|
||||
│ │ ├── Input Variables │
|
||||
│ │ └── Variable Validation │
|
||||
│ │ │
|
||||
│ ├── 📁 05-ansible/ │
|
||||
│ │ └── 📄 pipeline.md │
|
||||
│ │ ├── Playbook Structure │
|
||||
│ │ ├── WinRM Setup │
|
||||
│ │ └── Verification Tasks │
|
||||
│ │ │
|
||||
│ ├── 📁 06-ci-cd/ │
|
||||
│ │ └── 📄 forgejo-workflows.md │
|
||||
│ │ ├── Workflow Syntax │
|
||||
│ │ ├── Container Configuration │
|
||||
│ │ ├── Step-by-Step Execution │
|
||||
│ │ └── Environment Variables │
|
||||
│ │ │
|
||||
│ └── 📁 07-advanced/ │
|
||||
│ ├── 📄 evaluation.md │
|
||||
│ │ ├── 90-Day Timer Management │
|
||||
│ │ ├── Rearm Procedure │
|
||||
│ │ └── Monthly Rebuild Strategy │
|
||||
│ │ │
|
||||
│ └── 📄 troubleshooting.md │
|
||||
│ ├── Common Errors │
|
||||
│ ├── Debug Techniques │
|
||||
│ └── FAQ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Quick Navigation
|
||||
|
||||
### I want to...
|
||||
|
||||
| Goal | Start Here |
|
||||
|------|------------|
|
||||
| **Understand the system** | [Architecture Overview](01-overview/architecture.md) |
|
||||
| **Set up prerequisites** | [ISO Requirements](02-prerequisites/isos.md) |
|
||||
| **Build the golden image** | [Packer Configuration](03-packer/configuration.md) |
|
||||
| **Provision test VMs** | [OpenTofu Resources](04-terraform/main.tf.md) |
|
||||
| **Run the CI/CD pipeline** | [Forgejo Workflows](06-ci-cd/forgejo-workflows.md) |
|
||||
| **Troubleshoot issues** | [Troubleshooting Guide](07-advanced/troubleshooting.md) |
|
||||
|
||||
---
|
||||
|
||||
## 📊 Architecture Overview
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph CI["Forgejo CI/CD"]
|
||||
direction LR
|
||||
Git[Git Push] --> |Triggers| WF[Workflow]
|
||||
WF --> |Cross-Compile| MC[MinGW]
|
||||
WF --> |Package| NS[NSIS]
|
||||
WF --> |Sign| CS[Code Sign]
|
||||
end
|
||||
|
||||
subgraph Infra["Infrastructure"]
|
||||
CS --> |Provision| TF[OpenTofu]
|
||||
TF --> |Clone| VM[Windows VM]
|
||||
end
|
||||
|
||||
subgraph Test["Testing"]
|
||||
VM --> |Deploy| Inst[Installer]
|
||||
Inst --> |Verify| Ans[Ansible]
|
||||
Ans --> |Result| Pass{✅ Pass}
|
||||
Ans --> |Result| Fail{❌ Fail}
|
||||
end
|
||||
|
||||
style CI fill:#e1f5fe
|
||||
style Infra fill:#e8f5e9
|
||||
style Test fill:#fff3e0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Section Descriptions
|
||||
|
||||
### 01. Overview
|
||||
- **[architecture.md](01-overview/architecture.md)** - Complete system design including:
|
||||
- Component overview
|
||||
- Data flow diagrams
|
||||
- Design decisions and rationale
|
||||
- Technology stack explanation
|
||||
|
||||
### 02. Prerequisites
|
||||
- **[isos.md](02-prerequisites/isos.md)** - ISO image requirements:
|
||||
- Download links for Windows ISOs
|
||||
- VirtIO driver sources
|
||||
- Proxmox storage configuration
|
||||
- File verification steps
|
||||
- **[secrets.md](02-prerequisites/secrets.md)** - Credential management:
|
||||
- Forgejo secret configuration
|
||||
- Proxmox API token creation
|
||||
- Code signing certificate handling
|
||||
- Environment variable mapping
|
||||
|
||||
### 03. Packer
|
||||
- **[configuration.md](03-packer/configuration.md)** - Packer template guide:
|
||||
- HCL syntax reference
|
||||
- Proxmox builder settings
|
||||
- Hardware configuration
|
||||
- Provisioner scripts
|
||||
- **[autounattend.md](03-packer/autounattend.md)** - Windows无人值守安装:
|
||||
- XML structure reference
|
||||
- WinRM enabling
|
||||
- Firewall configuration
|
||||
- FirstLogonCommands详解
|
||||
|
||||
### 04. Terraform/OpenTofu
|
||||
- **[main.tf.md](04-terraform/main.tf.md)** - Infrastructure as code:
|
||||
- Provider configuration
|
||||
- VM cloning strategy
|
||||
- Network settings
|
||||
- IP address assignment
|
||||
- **[variables.md](04-terraform/variables.md)** - Variables reference:
|
||||
- Input variable definitions
|
||||
- Default values
|
||||
- Variable validation
|
||||
- Sensitive value handling
|
||||
|
||||
### 05. Ansible
|
||||
- **[pipeline.md](05-ansible/pipeline.md)** - Automation playbook:
|
||||
- WinRM connection setup
|
||||
- File transfer tasks
|
||||
- Silent installation
|
||||
- Verification assertions
|
||||
- Error handling
|
||||
|
||||
### 06. CI/CD
|
||||
- **[forgejo-workflows.md](06-ci-cd/forgejo-workflows.md)** - Pipeline configuration:
|
||||
- Workflow syntax
|
||||
- Container images
|
||||
- Step-by-step execution
|
||||
- Artifact publishing
|
||||
- Cleanup procedures
|
||||
|
||||
### 07. Advanced
|
||||
- **[evaluation.md](07-advanced/evaluation.md)** - Evaluation management:
|
||||
- 90-day expiration explained
|
||||
- Rearm procedure
|
||||
- Automated rebuild strategy
|
||||
- Security considerations
|
||||
- **[troubleshooting.md](07-advanced/troubleshooting.md)** - Problem resolution:
|
||||
- Common error messages
|
||||
- Debug commands
|
||||
- Log file locations
|
||||
- FAQ section
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Cross-References
|
||||
|
||||
This documentation is fully interlinked. Key cross-references include:
|
||||
|
||||
| From | To | Context |
|
||||
|------|-----|---------|
|
||||
| README | docs/index.md | Documentation entry |
|
||||
| architecture.md | isos.md | Prerequisites section |
|
||||
| configuration.md | autounattend.md | Related Packer topics |
|
||||
| main.tf.md | variables.md | Terraform variables |
|
||||
| forgejo-workflows.md | pipeline.md | Ansible integration |
|
||||
| pipeline.md | main.tf.md | Infrastructure reference |
|
||||
| troubleshooting.md | All sections | Problem resolution |
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Tool Reference
|
||||
|
||||
| Tool | Version | Purpose | Docs Link |
|
||||
|------|---------|---------|-----------|
|
||||
| Packer | ≥ 1.1.0 | Image building | [configuration.md](03-packer/configuration.md) |
|
||||
| OpenTofu | Latest | IaC provisioning | [main.tf.md](04-terraform/main.tf.md) |
|
||||
| Ansible | Latest | Automation | [pipeline.md](05-ansible/pipeline.md) |
|
||||
| Forgejo Actions | Latest | CI/CD | [forgejo-workflows.md](06-ci-cd/forgejo-workflows.md) |
|
||||
| MinGW | Latest | Cross-compilation | [forgejo-workflows.md](06-ci-cd/forgejo-workflows.md) |
|
||||
| NSIS | Latest | Installer creation | [forgejo-workflows.md](06-ci-cd/forgejo-workflows.md) |
|
||||
|
||||
---
|
||||
|
||||
## 📖 Reading Guide
|
||||
|
||||
1. **First Time Setup:** Read in order: 01 → 02 → 03 → 04 → 05 → 06
|
||||
2. **Specific Task:** Use the Quick Navigation table above
|
||||
3. **Deep Dive:** Follow cross-references from any section
|
||||
4. **Troubleshooting:** Start with [troubleshooting.md](07-advanced/troubleshooting.md)
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Document Version
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Version | 1.0.0 |
|
||||
| Last Updated | February 2026 |
|
||||
| Target OS | Windows 11 LTSC 2024 |
|
||||
| Status | Active Development |
|
||||
|
||||
---
|
||||
|
||||
[← Back to README](../README.md) | [→ Architecture Overview](01-overview/architecture.md)
|
||||
22
installer.nsi
Normal file
22
installer.nsi
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
!define APP_NAME "MyApp"
|
||||
!define APP_VERSION ${VERSION}
|
||||
!define COMPANY_NAME "My Company"
|
||||
|
||||
OutFile "dist\installer.exe"
|
||||
InstallDir "$PROGRAMFILES\${APP_NAME}"
|
||||
RequestExecutionLevel admin
|
||||
|
||||
Page directory
|
||||
Page instfiles
|
||||
|
||||
Section "MainSection"
|
||||
SetOutPath $INSTDIR
|
||||
File "dist\app.exe"
|
||||
WriteUninstaller $INSTDIR\uninstall.exe
|
||||
SectionEnd
|
||||
|
||||
Section "Uninstall"
|
||||
Delete $INSTDIR\app.exe
|
||||
Delete $INSTDIR\uninstall.exe
|
||||
RMDir $INSTDIR
|
||||
SectionEnd
|
||||
71
packer/Autounattend.xml
Normal file
71
packer/Autounattend.xml
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||
<settings pass="windowsPE">
|
||||
<component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<SetupUILanguage>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
</SetupUILanguage>
|
||||
<InputLocale>en-US</InputLocale>
|
||||
<SystemLocale>en-US</SystemLocale>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
<UserLocale>en-US</UserLocale>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<UserData>
|
||||
<ProductKey>
|
||||
<Key></Key>
|
||||
</ProductKey>
|
||||
<AcceptEula>true</AcceptEula>
|
||||
</UserData>
|
||||
</component>
|
||||
</settings>
|
||||
<settings pass="specialize">
|
||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<ComputerName>*</ComputerName>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<InputLocale>en-US</InputLocale>
|
||||
<SystemLocale>en-US</SystemLocale>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
<UserLocale>en-US</UserLocale>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<fDenyTSConnections>false</fDenyTSConnections>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-RemoteAssistance-Exe" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<fAllowToGetHelp>false</fAllowToGetHelp>
|
||||
</component>
|
||||
</settings>
|
||||
<settings pass="oobeSystem">
|
||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<OOBE>
|
||||
<HideEULAPage>true</HideEULAPage>
|
||||
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
|
||||
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
|
||||
<HideLocalAccountScreen>false</HideLocalAccountScreen>
|
||||
<ProtectYourPC>3</ProtectYourPC>
|
||||
</OOBE>
|
||||
<UserAccounts>
|
||||
<AdministratorPassword>
|
||||
<Value>PackerPassword123!</Value>
|
||||
<PlainText>true</PlainText>
|
||||
</AdministratorPassword>
|
||||
</UserAccounts>
|
||||
<AutoLogon>
|
||||
<Enabled>true</Enabled>
|
||||
<Username>Administrator</Username>
|
||||
<LogonCount>1</LogonCount>
|
||||
</AutoLogon>
|
||||
<FirstLogonCommands>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>powershell -Command "Set-NetFirewallProfile -Profile Private -Enabled False"</CommandLine>
|
||||
<Order>1</Order>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>powershell -Command "Invoke-WebRequest -Uri https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1 -OutFile C:\ConfigureRemotingForAnsible.ps1; C:\ConfigureRemotingForAnsible.ps1"</CommandLine>
|
||||
<Order>2</Order>
|
||||
</SynchronousCommand>
|
||||
</FirstLogonCommands>
|
||||
</component>
|
||||
</settings>
|
||||
</unattend>
|
||||
70
packer/windows.pkr.hcl
Normal file
70
packer/windows.pkr.hcl
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
proxmox = {
|
||||
version = ">= 1.1.0"
|
||||
source = "github.com/hashicorp/proxmox"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source "proxmox-iso" "windows-11" {
|
||||
proxmox_url = "https://proxmox-host:8006/api2/json"
|
||||
username = "root@pam"
|
||||
password = "secret"
|
||||
node = "la-vmh-07"
|
||||
|
||||
vm_name = "win11-ltsc-template"
|
||||
template_description = "Built with Packer on ${timestamp()}"
|
||||
iso_file = "local:iso/CLIENT_LTSC_EVAL_x64FRE_en-us.iso"
|
||||
|
||||
qemu_agent = true
|
||||
cores = 4
|
||||
memory = 8192
|
||||
machine = "q35"
|
||||
bios = "ovmf"
|
||||
efi_config {
|
||||
efi_storage_pool = "local-lvm"
|
||||
pre_enrolled_keys = true
|
||||
}
|
||||
tpm_config {
|
||||
version = "2.0"
|
||||
tpm_storage_pool = "local-lvm"
|
||||
}
|
||||
|
||||
scsi_controller = "virtio-scsi-pci"
|
||||
disks {
|
||||
disk_size = "60G"
|
||||
storage_pool = "local-lvm"
|
||||
type = "virtio"
|
||||
format = "raw"
|
||||
cache_mode = "writeback"
|
||||
}
|
||||
additional_iso_files {
|
||||
device = "sata1"
|
||||
iso_file = "local:iso/virtio-win.iso"
|
||||
}
|
||||
|
||||
communicator = "winrm"
|
||||
winrm_username = "Administrator"
|
||||
winrm_password = "PackerPassword123!"
|
||||
winrm_insecure = true
|
||||
winrm_use_ssl = true
|
||||
|
||||
boot_command = [
|
||||
"<wait><wait><wait>","<enter><wait>","<enter><wait>",
|
||||
"<enter><wait>","<enter>"
|
||||
]
|
||||
boot_wait = "10s"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.proxmox-iso.windows-11"]
|
||||
|
||||
provisioner "powershell" {
|
||||
inline = [
|
||||
"pnputil /add-driver 'E:\\viostor\\w11\\amd64\\*.inf' /install",
|
||||
"pnputil /add-driver 'E:\\NetKVM\\w11\\amd64\\*.inf' /install",
|
||||
"& 'E:\\virtio-win-guest-tools.exe' /install /passive /norestart"
|
||||
]
|
||||
}
|
||||
}
|
||||
7
src/main.c
Normal file
7
src/main.c
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||
MessageBoxA(NULL, "Hello from MyApp!", "MyApp", MB_OK | MB_ICONINFORMATION);
|
||||
return 0;
|
||||
}
|
||||
34
terraform/main.tf
Normal file
34
terraform/main.tf
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
terraform {
|
||||
required_providers {
|
||||
proxmox = {
|
||||
source = "bpg/proxmox"
|
||||
version = "0.46.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "proxmox" {
|
||||
endpoint = "https://proxmox-host:8006/"
|
||||
}
|
||||
|
||||
resource "proxmox_virtual_environment_vm" "build_agent" {
|
||||
name = "ci-win-build-${var.build_id}"
|
||||
node_name = "la-vmh-07"
|
||||
|
||||
clone {
|
||||
vm_id = var.template_vm_id
|
||||
full_clone = false
|
||||
}
|
||||
|
||||
cpu { cores = 4; type = "host" }
|
||||
memory { dedicated = 8192 }
|
||||
network_device { bridge = "vmbr0" }
|
||||
|
||||
initialization {
|
||||
ip_config {
|
||||
ipv4 {
|
||||
address = "dhcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
4
terraform/outputs.tf
Normal file
4
terraform/outputs.tf
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
output "vm_ip" {
|
||||
description = "IP address of the provisioned VM"
|
||||
value = proxmox_virtual_environment_vm.build_agent.ipv4_addresses[1][0]
|
||||
}
|
||||
10
terraform/variables.tf
Normal file
10
terraform/variables.tf
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
variable "build_id" {
|
||||
description = "Unique identifier for the build"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "template_vm_id" {
|
||||
description = "VM ID of the Packer-built template"
|
||||
type = number
|
||||
default = 9000
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue