Add working provisioning and configuration for MS SQL data warehouse
This commit is contained in:
20
configuration/ansible_mssql/ansible.cfg
Normal file
20
configuration/ansible_mssql/ansible.cfg
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[defaults]
|
||||||
|
|
||||||
|
inventory = inventories/production/hosts.yml
|
||||||
|
|
||||||
|
roles_path = roles
|
||||||
|
|
||||||
|
host_key_checking = False
|
||||||
|
|
||||||
|
remote_user = Administrator
|
||||||
|
|
||||||
|
timeout = 30
|
||||||
|
interpreter_python = auto_silent
|
||||||
|
forks = 20
|
||||||
|
pipelining = True
|
||||||
|
bin_ansible_callbacks = True
|
||||||
|
retry_files_enabled = False
|
||||||
|
|
||||||
|
[ssh_connection]
|
||||||
|
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no
|
||||||
|
transfer_method = scp
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
$ANSIBLE_VAULT;1.1;AES256
|
||||||
|
34613730306335623333623230346639323439343264366138623465656138346535663236336635
|
||||||
|
3933323931303236313761656337383735373332393366620a396664653239623437353263306563
|
||||||
|
64643237666633343165633230363065306561376166613735396562386464623532393730643765
|
||||||
|
3135326437616236640a363463383363626539383465663731313833306138633061386666313535
|
||||||
|
37636564373437313933636234636339613330613935336666343433376630346664336336383538
|
||||||
|
62623761323539363536313031623135333831643638336234643264343632393863363539653461
|
||||||
|
32393333646131316337653636386563396562613961383335323431623835653434333839613635
|
||||||
|
63353433656630366166336239643766653938363033373137623532353237353261383261623437
|
||||||
|
31366237353462623731343766653832343936363738373031633231373038376435613662616234
|
||||||
|
34373861656361353863326432616436316537643065313564306131616636383939343438333838
|
||||||
|
37326532663639666332313239316635313637333262633636376237653036343465646638303263
|
||||||
|
31333866633966346534303564623164373637303337646632326135666535663566333833356537
|
||||||
|
30323061613231393332346262393261343731363462623536313964313466666238363532613762
|
||||||
|
65666163376231313065393861643635626136316434643761386137306530346533653366643830
|
||||||
|
63363738366134323665323232313439323865323235313331316164393431373362646630336261
|
||||||
|
39313732376531336230663032363437343862646331613831623063336164373465343136643037
|
||||||
|
66643130636538383339393435616563323930386262343134636134373434326561
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
mssql_server_password: ""
|
||||||
|
|
||||||
|
domain_name: ""
|
||||||
|
domain_join_user: ""
|
||||||
|
domain_join_password: ""
|
||||||
|
domain_ou_path: ""
|
||||||
|
|
||||||
|
mssql_sa_password: ""
|
||||||
10
configuration/ansible_mssql/inventories/production/hosts.yml
Normal file
10
configuration/ansible_mssql/inventories/production/hosts.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
all:
|
||||||
|
children:
|
||||||
|
mssql_servers:
|
||||||
|
hosts:
|
||||||
|
SMSSQLDW1P.ad.cwx.hr:
|
||||||
|
ansible_host: 10.10.2.100
|
||||||
|
ansible_connection: ssh
|
||||||
|
ansible_shell_type: powershell
|
||||||
|
ansible_user: Administrator
|
||||||
|
ansible_password: "{{ mssql_server_password }}"
|
||||||
8
configuration/ansible_mssql/playbooks/install-mssql.yml
Normal file
8
configuration/ansible_mssql/playbooks/install-mssql.yml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
- name: Configure MSSQL servers
|
||||||
|
hosts: mssql_servers
|
||||||
|
roles:
|
||||||
|
- common
|
||||||
|
- mssql_prepare
|
||||||
|
- mssql_install
|
||||||
|
- db_restore
|
||||||
12
configuration/ansible_mssql/roles/common/defaults/main.yml
Normal file
12
configuration/ansible_mssql/roles/common/defaults/main.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
domain_name: "example.local"
|
||||||
|
domain_join_user: "{{ domain_join_user }}"
|
||||||
|
domain_join_password: "{{ domain_join_password }}"
|
||||||
|
domain_ou_path: ""
|
||||||
|
|
||||||
|
data_disk_number: 1
|
||||||
|
data_disk_size_gb: 80
|
||||||
|
|
||||||
|
sql_data_part_gb: 35
|
||||||
|
sql_log_part_gb: 15
|
||||||
|
sql_tempdb_part_gb: 10
|
||||||
123
configuration/ansible_mssql/roles/common/tasks/main.yml
Normal file
123
configuration/ansible_mssql/roles/common/tasks/main.yml
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
---
|
||||||
|
- name: Wait for system to be fully booted
|
||||||
|
ansible.builtin.wait_for_connection:
|
||||||
|
timeout: 300
|
||||||
|
sleep: 10
|
||||||
|
|
||||||
|
- name: Ensure Windows Update service is running
|
||||||
|
ansible.windows.win_service:
|
||||||
|
name: wuauserv
|
||||||
|
state: started
|
||||||
|
start_mode: auto
|
||||||
|
|
||||||
|
- name: Ensure BITS service is running
|
||||||
|
ansible.windows.win_service:
|
||||||
|
name: BITS
|
||||||
|
state: started
|
||||||
|
start_mode: auto
|
||||||
|
|
||||||
|
- name: Install Windows updates (loop until no more pending)
|
||||||
|
ansible.windows.win_updates:
|
||||||
|
category_names:
|
||||||
|
- SecurityUpdates
|
||||||
|
- CriticalUpdates
|
||||||
|
- UpdateRollups
|
||||||
|
- Updates
|
||||||
|
state: installed
|
||||||
|
reboot: true
|
||||||
|
reboot_timeout: 3600
|
||||||
|
server_selection: windows_update
|
||||||
|
register: win_updates_result
|
||||||
|
until: win_updates_result.installed_update_count == 0
|
||||||
|
retries: 5
|
||||||
|
delay: 30
|
||||||
|
|
||||||
|
- name: Report Windows Update result
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: >-
|
||||||
|
Windows Update complete.
|
||||||
|
Last pass installed {{ win_updates_result.installed_update_count }} update(s).
|
||||||
|
Reboot required: {{ win_updates_result.reboot_required }}.
|
||||||
|
|
||||||
|
- name: Join Active Directory domain
|
||||||
|
microsoft.ad.membership:
|
||||||
|
dns_domain_name: "{{ domain_name }}"
|
||||||
|
hostname: "{{ inventory_hostname_short }}"
|
||||||
|
domain_admin_user: "{{ domain_join_user }}"
|
||||||
|
domain_admin_password: "{{ domain_join_password }}"
|
||||||
|
domain_ou_path: "{{ domain_ou_path | default(omit) }}"
|
||||||
|
state: domain
|
||||||
|
reboot: true
|
||||||
|
|
||||||
|
- name: Initialize data disk as GPT
|
||||||
|
community.windows.win_initialize_disk:
|
||||||
|
disk_number: "{{ data_disk_number }}"
|
||||||
|
style: gpt
|
||||||
|
online: true
|
||||||
|
|
||||||
|
- name: Create SQL Data partition (F:)
|
||||||
|
community.windows.win_partition:
|
||||||
|
disk_number: "{{ data_disk_number }}"
|
||||||
|
partition_size: "{{ sql_data_part_gb }} GiB"
|
||||||
|
drive_letter: F
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Format SQL Data partition (F:)
|
||||||
|
community.windows.win_format:
|
||||||
|
drive_letter: F
|
||||||
|
file_system: NTFS
|
||||||
|
new_label: SQLData
|
||||||
|
allocation_unit_size: 65536
|
||||||
|
|
||||||
|
- name: Create SQL Log partition (G:)
|
||||||
|
community.windows.win_partition:
|
||||||
|
disk_number: "{{ data_disk_number }}"
|
||||||
|
partition_size: "{{ sql_log_part_gb }} GiB"
|
||||||
|
drive_letter: G
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Format SQL Log partition (G:)
|
||||||
|
community.windows.win_format:
|
||||||
|
drive_letter: G
|
||||||
|
file_system: NTFS
|
||||||
|
new_label: SQLLog
|
||||||
|
allocation_unit_size: 65536
|
||||||
|
|
||||||
|
- name: Create SQL TempDB partition (H:)
|
||||||
|
community.windows.win_partition:
|
||||||
|
disk_number: "{{ data_disk_number }}"
|
||||||
|
partition_size: "{{ sql_tempdb_part_gb }} GiB"
|
||||||
|
drive_letter: H
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Format SQL TempDB partition (H:)
|
||||||
|
community.windows.win_format:
|
||||||
|
drive_letter: H
|
||||||
|
file_system: NTFS
|
||||||
|
new_label: SQLTempDB
|
||||||
|
allocation_unit_size: 65536
|
||||||
|
|
||||||
|
- name: Create SQL Backup partition (I:)
|
||||||
|
community.windows.win_partition:
|
||||||
|
disk_number: "{{ data_disk_number }}"
|
||||||
|
partition_size: "{{ (data_disk_size_gb | int) - (sql_data_part_gb | int) - (sql_log_part_gb | int) - (sql_tempdb_part_gb | int) - 1 }} GiB"
|
||||||
|
drive_letter: I
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Format SQL Backup partition (I:)
|
||||||
|
community.windows.win_format:
|
||||||
|
drive_letter: I
|
||||||
|
file_system: NTFS
|
||||||
|
new_label: SQLBackup
|
||||||
|
allocation_unit_size: 65536
|
||||||
|
|
||||||
|
- name: Create SQL Server directories
|
||||||
|
ansible.windows.win_file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
loop:
|
||||||
|
- 'F:\Data'
|
||||||
|
- 'G:\Log'
|
||||||
|
- 'H:\TempDB\Data'
|
||||||
|
- 'H:\TempDB\Log'
|
||||||
|
- 'I:\Backup'
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
db_backup_dir: 'I:\Backup'
|
||||||
|
db_data_dir: 'F:\Data'
|
||||||
|
db_log_dir: 'G:\Log'
|
||||||
|
|
||||||
|
db_backups:
|
||||||
|
- name: AdventureWorksDW2022
|
||||||
|
filename: AdventureWorksDW2022.bak
|
||||||
|
url: "https://github.com/Microsoft/sql-server-samples/releases/download/adventureworks/AdventureWorksDW2022.bak"
|
||||||
|
|
||||||
|
- name: WideWorldImportersDW
|
||||||
|
filename: WideWorldImportersDW-Full.bak
|
||||||
|
url: "https://github.com/Microsoft/sql-server-samples/releases/download/wide-world-importers-v1.0/WideWorldImportersDW-Full.bak"
|
||||||
67
configuration/ansible_mssql/roles/db_restore/tasks/main.yml
Normal file
67
configuration/ansible_mssql/roles/db_restore/tasks/main.yml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
---
|
||||||
|
- name: Find sqlcmd.exe
|
||||||
|
ansible.windows.win_powershell:
|
||||||
|
script: |
|
||||||
|
$sqlcmd = Get-ChildItem 'C:\Program Files\Microsoft SQL Server' -Filter 'sqlcmd.exe' `
|
||||||
|
-Recurse -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.FullName -notlike '*\x86\*' } |
|
||||||
|
Sort-Object LastWriteTime -Descending |
|
||||||
|
Select-Object -First 1 -ExpandProperty FullName
|
||||||
|
if (-not $sqlcmd) { throw 'sqlcmd.exe not found' }
|
||||||
|
$Ansible.Result = $sqlcmd
|
||||||
|
$Ansible.Changed = $false
|
||||||
|
register: sqlcmd_path
|
||||||
|
|
||||||
|
- name: Download database backups
|
||||||
|
ansible.windows.win_get_url:
|
||||||
|
url: "{{ item.url }}"
|
||||||
|
dest: "{{ db_backup_dir }}\\{{ item.filename }}"
|
||||||
|
loop: "{{ db_backups }}"
|
||||||
|
|
||||||
|
- name: Restore databases
|
||||||
|
ansible.windows.win_powershell:
|
||||||
|
script: |
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
$sqlcmd = '{{ sqlcmd_path.result }}'
|
||||||
|
$bakFile = '{{ db_backup_dir }}\{{ item.filename }}'
|
||||||
|
$dbName = '{{ item.name }}'
|
||||||
|
|
||||||
|
# Idempotent: skip if database already exists
|
||||||
|
$exists = (& $sqlcmd -S . -E -h -1 `
|
||||||
|
-Q "SET NOCOUNT ON; SELECT name FROM sys.databases WHERE name = N'$dbName'" |
|
||||||
|
Out-String).Trim()
|
||||||
|
if ($exists -eq $dbName) {
|
||||||
|
Write-Output "$dbName already exists — skipping restore."
|
||||||
|
$Ansible.Changed = $false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get logical file list from the backup
|
||||||
|
$raw = & $sqlcmd -S . -E -s "|" -W `
|
||||||
|
-Q "RESTORE FILELISTONLY FROM DISK = N'$bakFile'"
|
||||||
|
|
||||||
|
$files = $raw | Select-Object -Skip 2 | Where-Object { $_ -match '\|' } | ForEach-Object {
|
||||||
|
$cols = $_ -split '\|'
|
||||||
|
[PSCustomObject]@{
|
||||||
|
LogicalName = $cols[0].Trim()
|
||||||
|
PhysicalName = $cols[1].Trim()
|
||||||
|
FileType = $cols[2].Trim() # D = data, L = log
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build MOVE clauses — keep original filename, redirect to correct partition
|
||||||
|
$moves = $files | ForEach-Object {
|
||||||
|
$dir = if ($_.FileType -eq 'L') { '{{ db_log_dir }}' } else { '{{ db_data_dir }}' }
|
||||||
|
$file = [System.IO.Path]::GetFileName($_.PhysicalName)
|
||||||
|
"MOVE N'$($_.LogicalName)' TO N'$dir\$file'"
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "RESTORE DATABASE [$dbName] FROM DISK = N'$bakFile' WITH $($moves -join ', '), REPLACE, STATS = 10"
|
||||||
|
Write-Output "Restoring $dbName ..."
|
||||||
|
& $sqlcmd -S . -E -Q $sql -t 3600
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "RESTORE failed with exit code $LASTEXITCODE" }
|
||||||
|
loop: "{{ db_backups }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.name }}"
|
||||||
|
timeout: 7200
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
mssql_instance_name: MSSQLSERVER
|
||||||
|
mssql_features: SQLENGINE,AS,IS,CONN
|
||||||
|
mssql_collation: SQL_Latin1_General_CP1_CI_AS
|
||||||
|
mssql_iso_drive: "E:\\"
|
||||||
|
|
||||||
|
mssql_security_mode: SQL
|
||||||
|
mssql_sa_password: ""
|
||||||
|
mssql_sysadmin_accounts:
|
||||||
|
- "CWX\\srvadmin-dandric"
|
||||||
|
- "{{ inventory_hostname_short }}\\Administrator"
|
||||||
|
|
||||||
|
mssql_sql_svc_account: "NT AUTHORITY\\NETWORK SERVICE"
|
||||||
|
mssql_sql_svc_password: ""
|
||||||
|
mssql_agt_svc_account: "NT AUTHORITY\\NETWORK SERVICE"
|
||||||
|
mssql_agt_svc_password: ""
|
||||||
|
mssql_as_svc_account: "NT AUTHORITY\\NETWORK SERVICE"
|
||||||
|
mssql_is_svc_account: "NT AUTHORITY\\NETWORK SERVICE"
|
||||||
|
|
||||||
|
mssql_as_server_mode: "TABULAR"
|
||||||
|
|
||||||
|
mssql_data_dir: 'F:\Data'
|
||||||
|
mssql_log_dir: 'G:\Log'
|
||||||
|
mssql_backup_dir: 'I:\Backup'
|
||||||
|
mssql_tempdb_dir: 'H:\TempDB\Data'
|
||||||
|
mssql_tempdb_log_dir: 'H:\TempDB\Log'
|
||||||
|
|
||||||
|
mssql_max_memory_mb: 12288
|
||||||
|
mssql_min_memory_mb: 4096
|
||||||
|
|
||||||
|
mssql_tcp_enabled: 1
|
||||||
|
mssql_tcp_port: 1433
|
||||||
132
configuration/ansible_mssql/roles/mssql_install/tasks/main.yml
Normal file
132
configuration/ansible_mssql/roles/mssql_install/tasks/main.yml
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
---
|
||||||
|
- name: Create SQL Server data directories
|
||||||
|
ansible.windows.win_file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
state: directory
|
||||||
|
loop:
|
||||||
|
- "{{ mssql_data_dir }}"
|
||||||
|
- "{{ mssql_log_dir }}"
|
||||||
|
- "{{ mssql_backup_dir }}"
|
||||||
|
- "{{ mssql_tempdb_dir }}"
|
||||||
|
- "{{ mssql_tempdb_log_dir }}"
|
||||||
|
|
||||||
|
- name: Install SQL Server 2022
|
||||||
|
block:
|
||||||
|
- name: Run SQL Server 2022 setup
|
||||||
|
ansible.windows.win_powershell:
|
||||||
|
script: |
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
$sapwd = '{{ mssql_sa_password | replace("'", "''") }}'
|
||||||
|
|
||||||
|
$proc = Start-Process `
|
||||||
|
-FilePath '{{ mssql_iso_drive }}\setup.exe' `
|
||||||
|
-ArgumentList @(
|
||||||
|
'/Action=Install',
|
||||||
|
'/QUIET',
|
||||||
|
'/IACCEPTSQLSERVERLICENSETERMS',
|
||||||
|
'/FEATURES={{ mssql_features }}',
|
||||||
|
'/INSTANCENAME={{ mssql_instance_name }}',
|
||||||
|
'/SQLCOLLATION={{ mssql_collation }}',
|
||||||
|
'/SECURITYMODE={{ mssql_security_mode }}',
|
||||||
|
"/SAPWD=$sapwd",
|
||||||
|
'/SQLSYSADMINACCOUNTS="{{ mssql_sysadmin_accounts | join('" "') }}"',
|
||||||
|
'/SQLSVCACCOUNT="{{ mssql_sql_svc_account }}"',
|
||||||
|
'/AGTSVCACCOUNT="{{ mssql_agt_svc_account }}"',
|
||||||
|
'/AGTSVCSTARTUPTYPE=Automatic',
|
||||||
|
'/BROWSERSVCSTARTUPTYPE=Automatic',
|
||||||
|
'/TCPENABLED={{ mssql_tcp_enabled }}',
|
||||||
|
'/SQLUSERDBDIR="{{ mssql_data_dir }}"',
|
||||||
|
'/SQLUSERDBLOGDIR="{{ mssql_log_dir }}"',
|
||||||
|
'/SQLBACKUPDIR="{{ mssql_backup_dir }}"',
|
||||||
|
'/SQLTEMPDBDIR="{{ mssql_tempdb_dir }}"',
|
||||||
|
'/SQLTEMPDBLOGDIR="{{ mssql_tempdb_log_dir }}"',
|
||||||
|
'/ASSVCACCOUNT="{{ mssql_as_svc_account }}"',
|
||||||
|
'/ASSERVERMODE={{ mssql_as_server_mode }}',
|
||||||
|
'/ASSYSADMINACCOUNTS="{{ mssql_sysadmin_accounts | join('" "') }}"',
|
||||||
|
'/ISSVCACCOUNT="{{ mssql_is_svc_account }}"',
|
||||||
|
'/UPDATEENABLED=False'
|
||||||
|
) `
|
||||||
|
-Wait -PassThru
|
||||||
|
|
||||||
|
if ($proc.ExitCode -notin @(0, 3010)) {
|
||||||
|
throw "SQL Server setup failed with exit code: $($proc.ExitCode)"
|
||||||
|
}
|
||||||
|
|
||||||
|
$Ansible.Result = $proc.ExitCode
|
||||||
|
register: mssql_install_result
|
||||||
|
timeout: 3600
|
||||||
|
|
||||||
|
- name: Report install exit code
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "SQL Server installed (exit code {{ mssql_install_result.result }}{% if mssql_install_result.result == 3010 %} — reboot required{% endif %})"
|
||||||
|
|
||||||
|
rescue:
|
||||||
|
- name: Display setup summary log
|
||||||
|
ansible.windows.win_powershell:
|
||||||
|
script: |
|
||||||
|
$log = Get-ChildItem 'C:\Program Files\Microsoft SQL Server' -Filter 'Summary*.txt' `
|
||||||
|
-Recurse -ErrorAction SilentlyContinue |
|
||||||
|
Sort-Object LastWriteTime | Select-Object -Last 1
|
||||||
|
if ($log) {
|
||||||
|
Write-Output "=== $($log.FullName) ==="
|
||||||
|
Get-Content $log.FullName | Select-Object -Last 100
|
||||||
|
} else {
|
||||||
|
Write-Output "No summary log found."
|
||||||
|
}
|
||||||
|
register: setup_log_content
|
||||||
|
|
||||||
|
- name: Show log
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ setup_log_content.output }}"
|
||||||
|
|
||||||
|
- name: Fail
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: "SQL Server installation failed — see log output above."
|
||||||
|
|
||||||
|
- name: Ensure SQL Server service is started
|
||||||
|
ansible.windows.win_service:
|
||||||
|
name: "{{ 'MSSQLSERVER' if mssql_instance_name == 'MSSQLSERVER' else 'MSSQL$' + mssql_instance_name }}"
|
||||||
|
state: started
|
||||||
|
start_mode: auto
|
||||||
|
|
||||||
|
- name: Ensure SQL Server Agent is started
|
||||||
|
ansible.windows.win_service:
|
||||||
|
name: "{{ 'SQLSERVERAGENT' if mssql_instance_name == 'MSSQLSERVER' else 'SQLAgent$' + mssql_instance_name }}"
|
||||||
|
state: started
|
||||||
|
start_mode: auto
|
||||||
|
|
||||||
|
- name: Open SQL Server firewall port
|
||||||
|
community.windows.win_firewall_rule:
|
||||||
|
name: "SQL Server ({{ mssql_instance_name }}) TCP {{ mssql_tcp_port }}"
|
||||||
|
localport: "{{ mssql_tcp_port }}"
|
||||||
|
action: allow
|
||||||
|
direction: in
|
||||||
|
protocol: tcp
|
||||||
|
state: present
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
- name: Configure SQL Server memory limits
|
||||||
|
ansible.windows.win_powershell:
|
||||||
|
script: |
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
$sqlcmd = Get-ChildItem 'C:\Program Files\Microsoft SQL Server' -Filter 'sqlcmd.exe' `
|
||||||
|
-Recurse -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.FullName -notlike '*\x86\*' } |
|
||||||
|
Sort-Object LastWriteTime -Descending |
|
||||||
|
Select-Object -First 1 -ExpandProperty FullName
|
||||||
|
if (-not $sqlcmd) { throw 'sqlcmd.exe not found under C:\Program Files\Microsoft SQL Server' }
|
||||||
|
|
||||||
|
$instance = if ('{{ mssql_instance_name }}' -eq 'MSSQLSERVER') { '.' } `
|
||||||
|
else { '.\{{ mssql_instance_name }}' }
|
||||||
|
|
||||||
|
$queries = @(
|
||||||
|
"EXEC sp_configure 'show advanced options', 1; RECONFIGURE;",
|
||||||
|
"EXEC sp_configure 'max server memory (MB)', {{ mssql_max_memory_mb }}; RECONFIGURE;",
|
||||||
|
"EXEC sp_configure 'min server memory (MB)', {{ mssql_min_memory_mb }}; RECONFIGURE;"
|
||||||
|
)
|
||||||
|
foreach ($q in $queries) {
|
||||||
|
& $sqlcmd -S $instance -E -Q $q | Out-Null
|
||||||
|
}
|
||||||
|
$Ansible.Result = "max={{ mssql_max_memory_mb }} MB, min={{ mssql_min_memory_mb }} MB"
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
mssql_staging_dir: 'C:\SQLInstall'
|
||||||
|
|
||||||
|
mssql_bootstrapper_url: "https://go.microsoft.com/fwlink/p/?linkid=2215158&clcid=0x409&culture=en-us&country=US"
|
||||||
|
mssql_bootstrapper_path: 'C:\SQLInstall\SQLServer2022-setup.exe'
|
||||||
|
|
||||||
|
mssql_iso_path: 'C:\SQLInstall\SQLServer2022-x64-ENU.iso'
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
- name: Create SQL Server staging directory
|
||||||
|
ansible.windows.win_file:
|
||||||
|
path: "{{ mssql_staging_dir }}"
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: Download SQL Server 2022 setup bootstrapper
|
||||||
|
ansible.windows.win_get_url:
|
||||||
|
url: "{{ mssql_bootstrapper_url }}"
|
||||||
|
dest: "{{ mssql_bootstrapper_path }}"
|
||||||
|
timeout: 120
|
||||||
|
|
||||||
|
- name: Download SQL Server 2022 ISO via bootstrapper
|
||||||
|
ansible.windows.win_command: >-
|
||||||
|
"{{ mssql_bootstrapper_path }}"
|
||||||
|
/Action=Download
|
||||||
|
/MEDIATYPE=ISO
|
||||||
|
/MEDIAPATH="{{ mssql_staging_dir }}"
|
||||||
|
/QUIET
|
||||||
|
args:
|
||||||
|
creates: "{{ mssql_iso_path }}"
|
||||||
|
timeout: 3600
|
||||||
|
|
||||||
|
- name: Find downloaded SQL Server ISO
|
||||||
|
ansible.windows.win_find:
|
||||||
|
paths: "{{ mssql_staging_dir }}"
|
||||||
|
patterns: "*.iso"
|
||||||
|
register: iso_files
|
||||||
|
|
||||||
|
- name: Fail if no ISO found in staging directory
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: >-
|
||||||
|
No ISO file found in {{ mssql_staging_dir }}.
|
||||||
|
The bootstrapper download may have failed.
|
||||||
|
Check {{ mssql_staging_dir }} on the target host.
|
||||||
|
when: iso_files.files | length == 0
|
||||||
|
|
||||||
|
- name: Mount SQL Server 2022 ISO
|
||||||
|
ansible.windows.win_powershell:
|
||||||
|
script: |
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$imagePath = '{{ iso_files.files[0].path }}'
|
||||||
|
|
||||||
|
$diskImage = Get-DiskImage -ImagePath $imagePath
|
||||||
|
if (-not $diskImage.Attached) {
|
||||||
|
Mount-DiskImage -ImagePath $imagePath | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
$driveLetter = (Get-DiskImage -ImagePath $imagePath | Get-Volume).DriveLetter
|
||||||
|
if (-not $driveLetter) {
|
||||||
|
throw "ISO mounted but no drive letter was assigned"
|
||||||
|
}
|
||||||
|
|
||||||
|
$Ansible.Result = "${driveLetter}:"
|
||||||
|
register: mount_result
|
||||||
|
|
||||||
|
- name: Set SQL Server ISO drive letter fact
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
mssql_iso_drive: "{{ mount_result.result }}"
|
||||||
|
|
||||||
|
- name: Show mounted drive letter
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "SQL Server 2022 ISO mounted at {{ mssql_iso_drive }} ({{ iso_files.files[0].path }})"
|
||||||
13
provisioning/SMSSQLDW1P/backend.tfbackend
Normal file
13
provisioning/SMSSQLDW1P/backend.tfbackend
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
bucket = "cwxbkp1-prod"
|
||||||
|
key = "proxmox/prod/SMSSQLDW1P/terraform.tfstate"
|
||||||
|
region = "eu-central"
|
||||||
|
|
||||||
|
endpoints = {
|
||||||
|
s3 = "https://nbg1.your-objectstorage.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
force_path_style = true
|
||||||
|
skip_credentials_validation = true
|
||||||
|
skip_metadata_api_check = true
|
||||||
|
skip_region_validation = true
|
||||||
|
skip_requesting_account_id = true
|
||||||
58
provisioning/SMSSQLDW1P/main.tf
Normal file
58
provisioning/SMSSQLDW1P/main.tf
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
terraform {
|
||||||
|
required_version = ">= 1.6.0"
|
||||||
|
|
||||||
|
required_providers {
|
||||||
|
proxmox = {
|
||||||
|
source = "bpg/proxmox"
|
||||||
|
version = "~> 0.73"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
backend "s3" {}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "proxmox" {
|
||||||
|
endpoint = var.proxmox_endpoint
|
||||||
|
insecure = var.proxmox_insecure
|
||||||
|
api_token = var.proxmox_api_token
|
||||||
|
|
||||||
|
ssh {
|
||||||
|
username = var.proxmox_ssh_user
|
||||||
|
password = var.proxmox_ssh_password
|
||||||
|
agent = var.proxmox_ssh_agent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module "vm" {
|
||||||
|
source = "../modules/vm"
|
||||||
|
|
||||||
|
node_name = var.node_name
|
||||||
|
vm_id = var.vm_id
|
||||||
|
name = var.name
|
||||||
|
description = var.description
|
||||||
|
tags = var.tags
|
||||||
|
bios = "ovmf"
|
||||||
|
os_type = "win11"
|
||||||
|
|
||||||
|
cpu_cores = var.cpu_cores
|
||||||
|
memory_dedicated = var.memory_dedicated
|
||||||
|
|
||||||
|
clone_vm_id = var.clone_vm_id
|
||||||
|
clone_datastore_id = var.clone_datastore_id
|
||||||
|
|
||||||
|
init_ipv4_address = var.init_ipv4_address
|
||||||
|
init_ipv4_gateway = var.init_ipv4_gateway
|
||||||
|
init_dns_servers = var.init_dns_servers
|
||||||
|
init_username = var.init_username
|
||||||
|
admin_password = var.admin_password
|
||||||
|
cloud_init_datastore = var.cloud_init_datastore
|
||||||
|
|
||||||
|
disk_datastore = var.disk_datastore
|
||||||
|
disk_size = var.disk_size
|
||||||
|
|
||||||
|
data_disk_size = var.data_disk_size
|
||||||
|
data_disk_datastore = var.data_disk_datastore
|
||||||
|
|
||||||
|
network_bridge = var.network_bridge
|
||||||
|
network_vlan_id = var.network_vlan_id
|
||||||
|
}
|
||||||
19
provisioning/SMSSQLDW1P/outputs.tf
Normal file
19
provisioning/SMSSQLDW1P/outputs.tf
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
output "vm_id" {
|
||||||
|
description = "The Proxmox VM ID"
|
||||||
|
value = module.vm.vm_id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "name" {
|
||||||
|
description = "The VM hostname"
|
||||||
|
value = module.vm.name
|
||||||
|
}
|
||||||
|
|
||||||
|
output "ipv4_addresses" {
|
||||||
|
description = "IPv4 addresses reported by the QEMU agent"
|
||||||
|
value = module.vm.ipv4_addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
output "mac_addresses" {
|
||||||
|
description = "MAC addresses of the VM's network interfaces"
|
||||||
|
value = module.vm.mac_addresses
|
||||||
|
}
|
||||||
27
provisioning/SMSSQLDW1P/terraform.tfvars.example
Normal file
27
provisioning/SMSSQLDW1P/terraform.tfvars.example
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
proxmox_endpoint = "https://proxmox.example.local:8006/api2/json"
|
||||||
|
proxmox_insecure = true
|
||||||
|
proxmox_api_token = "packer@pve!packer=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||||
|
|
||||||
|
proxmox_ssh_user = "root"
|
||||||
|
proxmox_ssh_password = "changeme"
|
||||||
|
proxmox_ssh_agent = false
|
||||||
|
|
||||||
|
node_name = "pve"
|
||||||
|
|
||||||
|
vm_id = 200
|
||||||
|
name = "SMSSQLDW1P"
|
||||||
|
init_ipv4_address = "10.0.0.100/24"
|
||||||
|
init_ipv4_gateway = "10.0.0.1"
|
||||||
|
init_dns_servers = ["10.0.0.2", "10.0.0.3"]
|
||||||
|
admin_password = "ChangeMe-StrongPassword!"
|
||||||
|
|
||||||
|
cpu_cores = 4
|
||||||
|
memory_dedicated = 16384
|
||||||
|
disk_size = 80
|
||||||
|
disk_datastore = "local-lvm"
|
||||||
|
data_disk_size = 80
|
||||||
|
data_disk_datastore = "local-lvm"
|
||||||
|
network_bridge = "vmbr0"
|
||||||
|
cloud_init_datastore = "local-lvm"
|
||||||
|
|
||||||
|
clone_vm_id = 1002
|
||||||
152
provisioning/SMSSQLDW1P/variables.tf
Normal file
152
provisioning/SMSSQLDW1P/variables.tf
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
variable "proxmox_endpoint" {
|
||||||
|
description = "URL of the Proxmox API (e.g. https://192.168.1.10:8006/)"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "proxmox_insecure" {
|
||||||
|
description = "Skip TLS certificate verification (set true for self-signed certs)"
|
||||||
|
type = bool
|
||||||
|
default = false
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "proxmox_api_token" {
|
||||||
|
description = "Proxmox API token in the form user@realm!tokenid=secret"
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "proxmox_ssh_user" {
|
||||||
|
description = "SSH username for the Proxmox node"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "proxmox_ssh_password" {
|
||||||
|
description = "SSH password for connecting to the Proxmox node"
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "proxmox_ssh_agent" {
|
||||||
|
description = "Use SSH agent for authentication"
|
||||||
|
type = bool
|
||||||
|
default = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "node_name" {
|
||||||
|
description = "Proxmox cluster node name"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "vm_id" {
|
||||||
|
description = "Unique Proxmox VM ID"
|
||||||
|
type = number
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "name" {
|
||||||
|
description = "VM hostname"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "description" {
|
||||||
|
description = "VM description"
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "tags" {
|
||||||
|
description = "Tags to apply to the VM"
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "cpu_cores" {
|
||||||
|
type = number
|
||||||
|
default = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "memory_dedicated" {
|
||||||
|
description = "RAM in MB"
|
||||||
|
type = number
|
||||||
|
default = 2048
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "clone_vm_id" {
|
||||||
|
description = "VM ID of the Windows template to clone"
|
||||||
|
type = number
|
||||||
|
default = 1002
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "clone_datastore_id" {
|
||||||
|
description = "Target datastore for the cloned disks (null = keep on source datastore)"
|
||||||
|
type = string
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "disk_datastore" {
|
||||||
|
type = string
|
||||||
|
default = "local-lvm"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "disk_size" {
|
||||||
|
description = "Disk size in GB"
|
||||||
|
type = number
|
||||||
|
default = 60
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "data_disk_size" {
|
||||||
|
description = "Size in GB of the data disk. Set to null to skip."
|
||||||
|
type = number
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "data_disk_datastore" {
|
||||||
|
description = "Proxmox datastore ID for the data disk."
|
||||||
|
type = string
|
||||||
|
default = "local-lvm"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "network_bridge" {
|
||||||
|
type = string
|
||||||
|
default = "vmbr11"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "network_vlan_id" {
|
||||||
|
type = number
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "init_ipv4_address" {
|
||||||
|
description = "IPv4 address in CIDR notation (e.g. 10.10.2.100/24) or dhcp"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "init_ipv4_gateway" {
|
||||||
|
description = "IPv4 gateway address"
|
||||||
|
type = string
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "init_dns_servers" {
|
||||||
|
description = "List of DNS servers for initialization"
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "init_username" {
|
||||||
|
description = "Username for the initial account"
|
||||||
|
type = string
|
||||||
|
default = "Administrator"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "admin_password" {
|
||||||
|
description = "Password for the initial account"
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "cloud_init_datastore" {
|
||||||
|
description = "Datastore used to store the cloud-init drive"
|
||||||
|
type = string
|
||||||
|
default = "local"
|
||||||
|
}
|
||||||
103
provisioning/modules/vm/main.tf
Normal file
103
provisioning/modules/vm/main.tf
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
resource "proxmox_virtual_environment_vm" "this" {
|
||||||
|
node_name = var.node_name
|
||||||
|
vm_id = var.vm_id
|
||||||
|
name = var.name
|
||||||
|
description = var.description
|
||||||
|
tags = var.tags
|
||||||
|
on_boot = var.on_boot
|
||||||
|
bios = var.bios
|
||||||
|
machine = var.machine
|
||||||
|
|
||||||
|
dynamic "clone" {
|
||||||
|
for_each = var.clone_vm_id != null ? [1] : []
|
||||||
|
content {
|
||||||
|
vm_id = var.clone_vm_id
|
||||||
|
full = var.clone_full
|
||||||
|
datastore_id = var.clone_datastore_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operating_system {
|
||||||
|
type = var.os_type
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu {
|
||||||
|
cores = var.cpu_cores
|
||||||
|
sockets = var.cpu_sockets
|
||||||
|
type = var.cpu_type
|
||||||
|
numa = true
|
||||||
|
}
|
||||||
|
|
||||||
|
memory {
|
||||||
|
dedicated = var.memory_dedicated
|
||||||
|
}
|
||||||
|
|
||||||
|
disk {
|
||||||
|
datastore_id = var.disk_datastore
|
||||||
|
interface = var.disk_interface
|
||||||
|
size = var.disk_size
|
||||||
|
file_id = var.clone_vm_id == null ? var.disk_file_id : null
|
||||||
|
discard = "on"
|
||||||
|
file_format = "raw"
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic "disk" {
|
||||||
|
for_each = var.data_disk_size != null ? [1] : []
|
||||||
|
content {
|
||||||
|
datastore_id = var.data_disk_datastore
|
||||||
|
interface = var.data_disk_interface
|
||||||
|
size = var.data_disk_size
|
||||||
|
discard = "on"
|
||||||
|
file_format = "raw"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic "efi_disk" {
|
||||||
|
for_each = var.bios == "ovmf" ? [1] : []
|
||||||
|
content {
|
||||||
|
datastore_id = var.disk_datastore
|
||||||
|
file_format = "raw"
|
||||||
|
type = "4m"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
network_device {
|
||||||
|
bridge = var.network_bridge
|
||||||
|
model = "virtio"
|
||||||
|
vlan_id = var.network_vlan_id
|
||||||
|
}
|
||||||
|
|
||||||
|
agent {
|
||||||
|
enabled = true
|
||||||
|
trim = true
|
||||||
|
}
|
||||||
|
|
||||||
|
initialization {
|
||||||
|
datastore_id = var.cloud_init_datastore
|
||||||
|
|
||||||
|
dynamic "dns" {
|
||||||
|
for_each = length(var.init_dns_servers) > 0 ? [1] : []
|
||||||
|
content {
|
||||||
|
servers = var.init_dns_servers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_config {
|
||||||
|
ipv4 {
|
||||||
|
address = var.init_ipv4_address
|
||||||
|
gateway = var.init_ipv4_gateway
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user_account {
|
||||||
|
username = var.init_username
|
||||||
|
password = var.admin_password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
ignore_changes = [
|
||||||
|
disk[0].file_id,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
19
provisioning/modules/vm/outputs.tf
Normal file
19
provisioning/modules/vm/outputs.tf
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
output "vm_id" {
|
||||||
|
description = "The Proxmox VM ID"
|
||||||
|
value = proxmox_virtual_environment_vm.this.vm_id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "name" {
|
||||||
|
description = "The VM hostname"
|
||||||
|
value = proxmox_virtual_environment_vm.this.name
|
||||||
|
}
|
||||||
|
|
||||||
|
output "ipv4_addresses" {
|
||||||
|
description = "All IPv4 addresses reported by the QEMU agent"
|
||||||
|
value = proxmox_virtual_environment_vm.this.ipv4_addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
output "mac_addresses" {
|
||||||
|
description = "MAC addresses of the network interfaces"
|
||||||
|
value = proxmox_virtual_environment_vm.this.mac_addresses
|
||||||
|
}
|
||||||
187
provisioning/modules/vm/variables.tf
Normal file
187
provisioning/modules/vm/variables.tf
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
variable "node_name" {
|
||||||
|
description = "The name of the Proxmox node to provision the VM on"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "vm_id" {
|
||||||
|
description = "The unique ID for the VM (100-999999999)"
|
||||||
|
type = number
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "name" {
|
||||||
|
description = "The VM name (must be a valid DNS name)"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "description" {
|
||||||
|
description = "A description for the VM"
|
||||||
|
type = string
|
||||||
|
default = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "tags" {
|
||||||
|
description = "List of tags to apply to the VM"
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "on_boot" {
|
||||||
|
description = "Whether to start the VM automatically on host boot"
|
||||||
|
type = bool
|
||||||
|
default = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "os_type" {
|
||||||
|
description = "OS type hint for Proxmox (l26 = Linux 2.6+, win10, etc.)"
|
||||||
|
type = string
|
||||||
|
default = "l26"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "bios" {
|
||||||
|
description = "BIOS type: seabios or ovmf (UEFI)"
|
||||||
|
type = string
|
||||||
|
default = "seabios"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "machine" {
|
||||||
|
description = "Machine type: pc or q35"
|
||||||
|
type = string
|
||||||
|
default = "q35"
|
||||||
|
}
|
||||||
|
|
||||||
|
# CPU
|
||||||
|
variable "cpu_cores" {
|
||||||
|
description = "Number of CPU cores per socket"
|
||||||
|
type = number
|
||||||
|
default = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "cpu_sockets" {
|
||||||
|
description = "Number of CPU sockets"
|
||||||
|
type = number
|
||||||
|
default = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "cpu_type" {
|
||||||
|
description = "CPU emulation type (host for best performance, qemu64 for compatibility)"
|
||||||
|
type = string
|
||||||
|
default = "host"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Memory
|
||||||
|
variable "memory_dedicated" {
|
||||||
|
description = "Dedicated RAM in MB"
|
||||||
|
type = number
|
||||||
|
default = 2048
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clone
|
||||||
|
variable "clone_vm_id" {
|
||||||
|
description = "VM ID of the template to clone. When set, a clone block is used instead of disk_file_id."
|
||||||
|
type = number
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "clone_full" {
|
||||||
|
description = "Perform a full clone (true) or linked clone (false)"
|
||||||
|
type = bool
|
||||||
|
default = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "clone_datastore_id" {
|
||||||
|
description = "Target datastore for the cloned disks (null = keep on source datastore)"
|
||||||
|
type = string
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disk
|
||||||
|
variable "disk_datastore" {
|
||||||
|
description = "Proxmox datastore ID for the VM disk"
|
||||||
|
type = string
|
||||||
|
default = "local-lvm"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "disk_interface" {
|
||||||
|
description = "Disk interface (scsi0, virtio0, sata0)"
|
||||||
|
type = string
|
||||||
|
default = "scsi0"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "disk_size" {
|
||||||
|
description = "Disk size in GB"
|
||||||
|
type = number
|
||||||
|
default = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "disk_file_id" {
|
||||||
|
description = "File ID of the base disk image to import (e.g. local:iso/debian-12-cloud.img). Ignored when clone_vm_id is set."
|
||||||
|
type = string
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "data_disk_size" {
|
||||||
|
description = "Size in GB of an optional second data disk. Set to null to skip."
|
||||||
|
type = number
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "data_disk_datastore" {
|
||||||
|
description = "Proxmox datastore ID for the data disk."
|
||||||
|
type = string
|
||||||
|
default = "local-lvm"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "data_disk_interface" {
|
||||||
|
description = "Disk interface for the data disk (must differ from the OS disk)."
|
||||||
|
type = string
|
||||||
|
default = "scsi1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Network
|
||||||
|
variable "network_bridge" {
|
||||||
|
description = "The Linux bridge to attach the network device to"
|
||||||
|
type = string
|
||||||
|
default = "vmbr0"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "network_vlan_id" {
|
||||||
|
description = "Optional VLAN tag for the network device (null = no VLAN)"
|
||||||
|
type = number
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialization (provider-native)
|
||||||
|
variable "init_ipv4_address" {
|
||||||
|
description = "IPv4 address in CIDR notation (e.g. 10.10.2.100/24) or dhcp"
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "init_ipv4_gateway" {
|
||||||
|
description = "IPv4 gateway address"
|
||||||
|
type = string
|
||||||
|
default = null
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "init_dns_servers" {
|
||||||
|
description = "List of DNS servers for initialization"
|
||||||
|
type = list(string)
|
||||||
|
default = []
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "init_username" {
|
||||||
|
description = "Username for the initial account"
|
||||||
|
type = string
|
||||||
|
default = "Administrator"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "admin_password" {
|
||||||
|
description = "Password for the initial account"
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "cloud_init_datastore" {
|
||||||
|
description = "Datastore used to store the cloud-init drive"
|
||||||
|
type = string
|
||||||
|
default = "local"
|
||||||
|
}
|
||||||
8
provisioning/modules/vm/versions.tf
Normal file
8
provisioning/modules/vm/versions.tf
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
proxmox = {
|
||||||
|
source = "bpg/proxmox"
|
||||||
|
version = "~> 0.73"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user