Add support for Ubuntu containers and WSL verification
- Implemented tasks for managing Ubuntu containers using Podman, including inspection, creation, starting, and SSH setup. - Added verification tasks for WSL and Podman installation, machine existence, and NSSM service status. - Created PowerShell scripts for Podman auto-start on Windows boot. - Introduced Prometheus role with default configurations and installation tasks. - Updated Windows SSH role to improve authorized_keys management and permissions handling. - Modified inventory to include Windows containers host. - Updated Grafana datasource configurations with direct IP addresses for Prometheus instances.
This commit is contained in:
@@ -10,7 +10,9 @@ ssh_users:
|
|||||||
admin: true
|
admin: true
|
||||||
keys:
|
keys:
|
||||||
- "{{ lookup('file', 'keys/ansible_user.pub') }}"
|
- "{{ lookup('file', 'keys/ansible_user.pub') }}"
|
||||||
|
- "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN1YEqRDPq7lMd2n37OmzX1AEyeed17uf4LPgSgkb/Sb"
|
||||||
|
|
||||||
|
prometheus_install_dir: "D:\\Prometheus"
|
||||||
grafana_prometheus_sources:
|
grafana_prometheus_sources:
|
||||||
- 10.19.4.136
|
- 10.19.4.136
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@ windows_exporter_collectors:
|
|||||||
llama_server_windows_install_dir: "D:\\llama_server"
|
llama_server_windows_install_dir: "D:\\llama_server"
|
||||||
llama_server_windows_user: "llama"
|
llama_server_windows_user: "llama"
|
||||||
llama_server_windows_working_dir: "D:\\llama_server"
|
llama_server_windows_working_dir: "D:\\llama_server"
|
||||||
llama_server_cuda_version: "13.3"
|
llama_server_windows_backend: "vulkan"
|
||||||
|
|
||||||
llama_server_models:
|
llama_server_models:
|
||||||
- name: "luau-qwen3-4b-fim-v0.1"
|
- name: "luau-qwen3-4b-fim-v0.1"
|
||||||
@@ -83,4 +85,4 @@ llama_server_args_extra:
|
|||||||
"--mmap",
|
"--mmap",
|
||||||
]
|
]
|
||||||
|
|
||||||
llama_server_windows_backend: "vulkan"
|
windows_containers_service_password: "{{ lookup('env', 'WIN_CI_01_PASSWORD') }}"
|
||||||
|
|||||||
@@ -123,52 +123,118 @@ llama_server_models:
|
|||||||
model_id: "unsloth/gpt-oss-20b-GGUF"
|
model_id: "unsloth/gpt-oss-20b-GGUF"
|
||||||
quant: "Q4_0"
|
quant: "Q4_0"
|
||||||
revision: "main"
|
revision: "main"
|
||||||
|
- name: "gpt-oss-20b-q8-0"
|
||||||
|
model_id: "unsloth/gpt-oss-20b-GGUF"
|
||||||
|
quant: "Q8_0"
|
||||||
|
revision: "main"
|
||||||
|
- name: "gemma-4-12b-q8-0"
|
||||||
|
model_id: "unsloth/gemma-4-12b-it-GGUF"
|
||||||
|
quant: "Q8_0"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
- name: "gemma-4-26b-a4b-ud-iq4-xs"
|
- name: "gemma-4-26b-a4b-ud-iq4-xs"
|
||||||
model_id: "unsloth/gemma-4-26B-A4B-it-GGUF"
|
model_id: "unsloth/gemma-4-26B-A4B-it-GGUF"
|
||||||
quant: "UD-IQ4_XS"
|
quant: "UD-IQ4_XS"
|
||||||
revision: "main"
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
- name: "gemma-4-31b-iq4-xs"
|
- name: "gemma-4-31b-iq4-xs"
|
||||||
model_id: "unsloth/gemma-4-31B-it-GGUF"
|
model_id: "unsloth/gemma-4-31B-it-GGUF"
|
||||||
quant: "IQ4_XS"
|
quant: "IQ4_XS"
|
||||||
revision: "main"
|
revision: "main"
|
||||||
- name: "qwen3-6-35b-a3b-mtp-ud-iq4-xs"
|
preset:
|
||||||
model_id: "unsloth/Qwen3.6-35B-A3B-MTP-GGUF"
|
ctx-size: 131072
|
||||||
quant: "UD-IQ4_XS"
|
|
||||||
revision: "main"
|
|
||||||
- name: "qwen3-5-27b-mtp-iq4-xs"
|
|
||||||
model_id: "unsloth/Qwen3.5-27B-MTP-GGUF"
|
|
||||||
quant: "IQ4_XS"
|
|
||||||
revision: "main"
|
|
||||||
- name: "qwen3-5-35b-a3b-ud-iq4-xs"
|
|
||||||
model_id: "unsloth/Qwen3.5-35B-A3B-GGUF"
|
|
||||||
quant: "UD-IQ4_XS"
|
|
||||||
revision: "main"
|
|
||||||
- name: "ministral-3-14b-instruct-iq4-xs"
|
|
||||||
model_id: "unsloth/Ministral-3-14B-Instruct-2512-GGUF"
|
|
||||||
quant: "IQ4_XS"
|
|
||||||
revision: "main"
|
|
||||||
- name: "granite-4-1-30b-iq4-xs"
|
|
||||||
model_id: "unsloth/granite-4.1-30b-GGUF"
|
|
||||||
quant: "IQ4_XS"
|
|
||||||
revision: "main"
|
|
||||||
- name: "qwen3-5-9b-iq4-xs"
|
- name: "qwen3-5-9b-iq4-xs"
|
||||||
model_id: "unsloth/Qwen3.5-9B-GGUF"
|
model_id: "unsloth/Qwen3.5-9B-GGUF"
|
||||||
quant: "IQ4_XS"
|
quant: "IQ4_XS"
|
||||||
revision: "main"
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "qwen3-5-9b-q8-0"
|
||||||
|
model_id: "unsloth/Qwen3.5-9B-GGUF"
|
||||||
|
quant: "Q8_0"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "qwen3-5-27b-mtp-iq4-xs"
|
||||||
|
model_id: "unsloth/Qwen3.5-27B-MTP-GGUF"
|
||||||
|
quant: "IQ4_XS"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "qwen3-5-35b-a3b-ud-iq4-xs"
|
||||||
|
model_id: "unsloth/Qwen3.5-35B-A3B-GGUF"
|
||||||
|
quant: "UD-IQ4_XS"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "qwen3-5-35b-a3b-q4-k-m"
|
||||||
|
model_id: "unsloth/Qwen3.5-35B-A3B-GGUF"
|
||||||
|
quant: "Q4_K_M"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "qwen3-6-27b-mtp-q4-0"
|
||||||
|
model_id: "unsloth/Qwen3.6-27B-MTP-GGUF"
|
||||||
|
quant: "Q4_0"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "qwen3-6-27b-mtp-ud-q4-0-k-xl"
|
||||||
|
model_id: "unsloth/Qwen3.6-27B-MTP-GGUF"
|
||||||
|
quant: "UD-Q4_K_XL"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "qwen3-6-27b-mtp-ud-q4-xl"
|
||||||
|
model_id: "unsloth/Qwen3.6-27B-MTP-GGUF"
|
||||||
|
quant: "UD-Q4_K_XL"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "qwen3-6-35b-a3b-mtp-ud-iq4-xs"
|
||||||
|
model_id: "unsloth/Qwen3.6-35B-A3B-MTP-GGUF"
|
||||||
|
quant: "UD-IQ4_XS"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "qwen3-6-35b-a3b-mtp-ud-q4-m"
|
||||||
|
model_id: "unsloth/Qwen3.6-35B-A3B-MTP-GGUF"
|
||||||
|
quant: "UD-Q4_K_M"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "qwen3-6-35b-a3b-ud-q4-k-m"
|
||||||
|
model_id: "unsloth/Qwen3.6-35B-A3B-GGUF"
|
||||||
|
quant: "UD-Q4_K_M"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
- name: "qwen3-6-35b-a3b-claude47-distilled-iq4-xs"
|
- name: "qwen3-6-35b-a3b-claude47-distilled-iq4-xs"
|
||||||
model_id: "lordx64/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-IQ4_XS-GGUF"
|
model_id: "lordx64/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-IQ4_XS-GGUF"
|
||||||
quant: "IQ4_XS"
|
quant: "IQ4_XS"
|
||||||
revision: "main"
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "ministral-3-14b-instruct-iq4-xs"
|
||||||
|
model_id: "unsloth/Ministral-3-14B-Instruct-2512-GGUF"
|
||||||
|
quant: "IQ4_XS"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
|
- name: "granite-4-1-30b-iq4-xs"
|
||||||
|
model_id: "unsloth/granite-4.1-30b-GGUF"
|
||||||
|
quant: "IQ4_XS"
|
||||||
|
revision: "main"
|
||||||
|
preset:
|
||||||
|
ctx-size: 131072
|
||||||
- name: "devstral-small-2-24b-instruct-iq4-xs"
|
- name: "devstral-small-2-24b-instruct-iq4-xs"
|
||||||
model_id: "unsloth/Devstral-Small-2-24B-Instruct-2512-GGUF"
|
model_id: "unsloth/Devstral-Small-2-24B-Instruct-2512-GGUF"
|
||||||
quant: "IQ4_XS"
|
quant: "IQ4_XS"
|
||||||
revision: "main"
|
revision: "main"
|
||||||
- name: "qwen3-6-27b-mtp-iq4-xs"
|
|
||||||
model_id: "unsloth/Qwen3.6-27B-MTP-GGUF"
|
|
||||||
quant: "IQ4_XS"
|
|
||||||
revision: "main"
|
|
||||||
|
|
||||||
llama_server_args_extra:
|
llama_server_argv_extra:
|
||||||
[
|
[
|
||||||
"-t",
|
"-t",
|
||||||
10,
|
10,
|
||||||
@@ -201,6 +267,6 @@ llama_server_args_extra:
|
|||||||
|
|
||||||
# # Optional global model preset options applied under [*] in models.ini.
|
# # Optional global model preset options applied under [*] in models.ini.
|
||||||
# # Keys map to llama.cpp CLI args without leading dashes, short args, or LLAMA_ARG_* env names.
|
# # Keys map to llama.cpp CLI args without leading dashes, short args, or LLAMA_ARG_* env names.
|
||||||
# llama_preset_global:
|
# llama_server_preset_global:
|
||||||
# c: 131072
|
# ctx-size: 131072
|
||||||
# n-gpu-layers: all
|
# n-gpu-layers: all
|
||||||
|
|||||||
@@ -296,6 +296,164 @@ virt_machines:
|
|||||||
slot: "0x00"
|
slot: "0x00"
|
||||||
function: "0x0"
|
function: "0x0"
|
||||||
|
|
||||||
|
- name: win2019server
|
||||||
|
title: "Microsoft Windows Server 2019"
|
||||||
|
uuid: "51d5d091-67cb-4113-bd8e-817e7317e1b6"
|
||||||
|
autostart: false
|
||||||
|
memory: 16
|
||||||
|
cores: 5
|
||||||
|
threads: 2
|
||||||
|
physical_cpus: "3-11,4-12,5-13,6-14,7-15"
|
||||||
|
reserved_cpus: "0,8"
|
||||||
|
enable_hyperv: true
|
||||||
|
cdrom: true
|
||||||
|
console: false
|
||||||
|
audio: true
|
||||||
|
secure_boot: true
|
||||||
|
tpm: true
|
||||||
|
tablet: true
|
||||||
|
net_bridge: br0
|
||||||
|
disk_file: "win2019server.qcow2"
|
||||||
|
mac_address: "52:54:00:cd:dd:2f"
|
||||||
|
block_devs: []
|
||||||
|
guest_agent: true
|
||||||
|
host_devs:
|
||||||
|
# Micron/Crucial Technology T500 NVMe PCIe SSD
|
||||||
|
- type: "pci"
|
||||||
|
source:
|
||||||
|
address:
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x05"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
address:
|
||||||
|
type: "pci"
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x11"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
# Fresco Logic FL1100 USB 3.0 Host Controller
|
||||||
|
- type: "pci"
|
||||||
|
source:
|
||||||
|
address:
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x08"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
address:
|
||||||
|
type: "pci"
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x10"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
# NVIDIA Corporation M2000 [Maxwell GM107GL]
|
||||||
|
- type: "pci"
|
||||||
|
source:
|
||||||
|
address:
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x03"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
address:
|
||||||
|
type: "pci"
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x0b"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
# NVIDIA Corporation M2000 High Definition Audio Controller
|
||||||
|
- type: "pci"
|
||||||
|
source:
|
||||||
|
address:
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x03"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x1"
|
||||||
|
address:
|
||||||
|
type: "pci"
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x0f"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
|
||||||
|
- name: win2022server
|
||||||
|
title: "Microsoft Windows Server 2022"
|
||||||
|
uuid: "51d5d091-67cb-4113-bd8e-817e7317e1b7"
|
||||||
|
autostart: false
|
||||||
|
memory: 16
|
||||||
|
cores: 5
|
||||||
|
threads: 2
|
||||||
|
physical_cpus: "3-11,4-12,5-13,6-14,7-15"
|
||||||
|
reserved_cpus: "0,8"
|
||||||
|
enable_hyperv: true
|
||||||
|
cdrom: true
|
||||||
|
console: false
|
||||||
|
audio: true
|
||||||
|
secure_boot: true
|
||||||
|
tpm: true
|
||||||
|
tablet: true
|
||||||
|
net_bridge: br0
|
||||||
|
disk_file: "win2022server.qcow2"
|
||||||
|
mac_address: "52:54:00:cd:dd:2e"
|
||||||
|
block_devs: []
|
||||||
|
guest_agent: true
|
||||||
|
host_devs:
|
||||||
|
# Micron/Crucial Technology T500 NVMe PCIe SSD
|
||||||
|
- type: "pci"
|
||||||
|
source:
|
||||||
|
address:
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x05"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
address:
|
||||||
|
type: "pci"
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x11"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
# Fresco Logic FL1100 USB 3.0 Host Controller
|
||||||
|
- type: "pci"
|
||||||
|
source:
|
||||||
|
address:
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x08"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
address:
|
||||||
|
type: "pci"
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x10"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
# NVIDIA Corporation M2000 [Maxwell GM107GL]
|
||||||
|
- type: "pci"
|
||||||
|
source:
|
||||||
|
address:
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x03"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
address:
|
||||||
|
type: "pci"
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x0b"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
# NVIDIA Corporation M2000 High Definition Audio Controller
|
||||||
|
- type: "pci"
|
||||||
|
source:
|
||||||
|
address:
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x03"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x1"
|
||||||
|
address:
|
||||||
|
type: "pci"
|
||||||
|
domain: "0x0000"
|
||||||
|
bus: "0x0f"
|
||||||
|
slot: "0x00"
|
||||||
|
function: "0x0"
|
||||||
|
|
||||||
- name: dev-01
|
- name: dev-01
|
||||||
title: "Lab Kubernetes VM"
|
title: "Lab Kubernetes VM"
|
||||||
uuid: "55feda16-51ae-446e-9c83-4c0eee1e5e00"
|
uuid: "55feda16-51ae-446e-9c83-4c0eee1e5e00"
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
- name: Install Windows Containers
|
||||||
|
hosts: windows_containers
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- windows_containers
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
- name: Add ROCm repository (yum)
|
- name: Add ROCm repository (yum)
|
||||||
when: ansible_pkg_mgr == 'yum'
|
|
||||||
become: true
|
become: true
|
||||||
ansible.builtin.yum_repository:
|
ansible.builtin.yum_repository:
|
||||||
name: rocm
|
name: rocm
|
||||||
@@ -11,17 +10,6 @@
|
|||||||
enabled: true
|
enabled: true
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Add ROCm repository (dnf)
|
|
||||||
when: ansible_pkg_mgr == 'dnf'
|
|
||||||
become: true
|
|
||||||
ansible.builtin.dnf_repository:
|
|
||||||
name: rocm
|
|
||||||
description: ROCm Repository
|
|
||||||
baseurl: "{{ rocm_repo_baseurl }}"
|
|
||||||
gpgcheck: yes
|
|
||||||
gpgkey: "{{ rocm_repo_gpgkey }}"
|
|
||||||
enabled: yes
|
|
||||||
|
|
||||||
- name: Add AMD Graphics repository (yum)
|
- name: Add AMD Graphics repository (yum)
|
||||||
when: ansible_pkg_mgr == 'yum'
|
when: ansible_pkg_mgr == 'yum'
|
||||||
become: true
|
become: true
|
||||||
@@ -34,17 +22,6 @@
|
|||||||
enabled: true
|
enabled: true
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Add AMD Graphics repository (dnf)
|
|
||||||
when: ansible_pkg_mgr == 'dnf'
|
|
||||||
become: true
|
|
||||||
ansible.builtin.dnf_repository:
|
|
||||||
name: rocmgraphics
|
|
||||||
description: AMD Graphics Repository
|
|
||||||
baseurl: "{{ rocmgraphics_repo_baseurl }}"
|
|
||||||
gpgkey: "{{ rocm_repo_gpgkey }}"
|
|
||||||
gpgcheck: yes
|
|
||||||
enabled: yes
|
|
||||||
|
|
||||||
- name: Install rocm-dkms and dependencies
|
- name: Install rocm-dkms and dependencies
|
||||||
become: true
|
become: true
|
||||||
ansible.builtin.package:
|
ansible.builtin.package:
|
||||||
|
|||||||
@@ -34,9 +34,6 @@ llama_server_windows_working_dir: "C:\\llama_server"
|
|||||||
llama_server_windows_version: "b9442"
|
llama_server_windows_version: "b9442"
|
||||||
llama_server_windows_backend: "cuda"
|
llama_server_windows_backend: "cuda"
|
||||||
llama_server_cuda_version: "13.3"
|
llama_server_cuda_version: "13.3"
|
||||||
llama_server_windows_nssm_dir: "C:\\nssm"
|
|
||||||
llama_server_windows_nssm_version: "2.24"
|
|
||||||
llama_server_windows_nssm_url: "https://nssm.cc/release/nssm-{{ llama_server_windows_nssm_version }}.zip"
|
|
||||||
|
|
||||||
# Llama-server binary defaults for Windows
|
# Llama-server binary defaults for Windows
|
||||||
llama_server_windows_bin_name: "llama-server.exe"
|
llama_server_windows_bin_name: "llama-server.exe"
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
loop:
|
loop:
|
||||||
- models
|
- models
|
||||||
- .cache
|
- .cache
|
||||||
- .cache/llama.cpp
|
- .cache/llamacpp
|
||||||
|
|
||||||
- name: "Add SSH Authorized key"
|
- name: "Add SSH Authorized key"
|
||||||
become: true
|
become: true
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
|
|
||||||
- name: Create pods
|
- name: Create pods
|
||||||
containers.podman.podman_container:
|
containers.podman.podman_container:
|
||||||
name: "llama.cpp"
|
name: "llamacpp"
|
||||||
image: "{{ llama_server_image }}:{{ llama_server_tag }}"
|
image: "{{ llama_server_image }}:{{ llama_server_tag }}"
|
||||||
state: started
|
state: started
|
||||||
device: "{{ llama_server_devices | default(omit) }}"
|
device: "{{ llama_server_devices | default(omit) }}"
|
||||||
@@ -159,7 +159,7 @@
|
|||||||
become: true
|
become: true
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
src: podman.service.j2
|
src: podman.service.j2
|
||||||
dest: "/etc/systemd/system/podman-llama.cpp.service"
|
dest: "/etc/systemd/system/podman-llamacpp.service"
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
mode: "0644"
|
mode: "0644"
|
||||||
@@ -172,7 +172,7 @@
|
|||||||
- name: Enable containers at boot
|
- name: Enable containers at boot
|
||||||
become: true
|
become: true
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: "podman-llama.cpp"
|
name: "podman-llamacpp"
|
||||||
enabled: true
|
enabled: true
|
||||||
state: "started"
|
state: "started"
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@
|
|||||||
- name: Copy llama server Hugging Face sync helper
|
- name: Copy llama server Hugging Face sync helper
|
||||||
become: true
|
become: true
|
||||||
ansible.builtin.copy:
|
ansible.builtin.copy:
|
||||||
src: scripts/llama_hf_sync.py
|
src: scripts/linux/llama_hf_sync.py
|
||||||
dest: "{{ llama_server_home }}/models/.router/llama_hf_sync.py"
|
dest: "{{ llama_server_home }}/models/.router/llama_hf_sync.py"
|
||||||
owner: "{{ llama_server_user }}"
|
owner: "{{ llama_server_user }}"
|
||||||
group: "{{ llama_server_group }}"
|
group: "{{ llama_server_group }}"
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
- name: Install Windows Exporter service via NSSM
|
- name: Install Windows Exporter service via NSSM
|
||||||
ansible.windows.win_command:
|
ansible.windows.win_command:
|
||||||
argv:
|
argv:
|
||||||
- "{{ __nssm_exe }}"
|
- "nssm.exe"
|
||||||
- install
|
- install
|
||||||
- llama-exporter
|
- llama-exporter
|
||||||
- "{{ __exporter_venv_python }}"
|
- "{{ __exporter_venv_python }}"
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
- name: Set exporter AppDirectory via NSSM
|
- name: Set exporter AppDirectory via NSSM
|
||||||
ansible.windows.win_command:
|
ansible.windows.win_command:
|
||||||
argv:
|
argv:
|
||||||
- "{{ __nssm_exe }}"
|
- "nssm.exe"
|
||||||
- set
|
- set
|
||||||
- llama-exporter
|
- llama-exporter
|
||||||
- AppDirectory
|
- AppDirectory
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
- name: Configure exporter stdout log via NSSM
|
- name: Configure exporter stdout log via NSSM
|
||||||
ansible.windows.win_command:
|
ansible.windows.win_command:
|
||||||
argv:
|
argv:
|
||||||
- "{{ __nssm_exe }}"
|
- "nssm.exe"
|
||||||
- set
|
- set
|
||||||
- llama-exporter
|
- llama-exporter
|
||||||
- AppStdout
|
- AppStdout
|
||||||
@@ -96,7 +96,7 @@
|
|||||||
- name: Configure exporter stderr log via NSSM
|
- name: Configure exporter stderr log via NSSM
|
||||||
ansible.windows.win_command:
|
ansible.windows.win_command:
|
||||||
argv:
|
argv:
|
||||||
- "{{ __nssm_exe }}"
|
- "nssm.exe"
|
||||||
- set
|
- set
|
||||||
- llama-exporter
|
- llama-exporter
|
||||||
- AppStderr
|
- AppStderr
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
- name: Set exporter environment variables
|
- name: Set exporter environment variables
|
||||||
ansible.windows.win_command:
|
ansible.windows.win_command:
|
||||||
argv:
|
argv:
|
||||||
- "{{ __nssm_exe }}"
|
- "nssm.exe"
|
||||||
- set
|
- set
|
||||||
- llama-exporter
|
- llama-exporter
|
||||||
- AppEnvironmentExtra
|
- AppEnvironmentExtra
|
||||||
@@ -116,7 +116,7 @@
|
|||||||
- name: Set exporter Start mode to AUTO via NSSM
|
- name: Set exporter Start mode to AUTO via NSSM
|
||||||
ansible.windows.win_command:
|
ansible.windows.win_command:
|
||||||
argv:
|
argv:
|
||||||
- "{{ __nssm_exe }}"
|
- "nssm.exe"
|
||||||
- set
|
- set
|
||||||
- llama-exporter
|
- llama-exporter
|
||||||
- Start
|
- Start
|
||||||
|
|||||||
@@ -4,13 +4,11 @@
|
|||||||
- name: Define Windows paths and versions
|
- name: Define Windows paths and versions
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
__llama_user: "{{ llama_server_windows_user }}"
|
__llama_user: "{{ llama_server_windows_user }}"
|
||||||
__nssm_exe: "{{ llama_server_windows_nssm_dir }}\\nssm.exe"
|
|
||||||
__llama_release_asset_name: "{{ 'llama-' ~ llama_server_windows_version ~ '-bin-win-' ~ llama_server_windows_backend ~ (llama_server_windows_backend == 'cuda') | ternary('-' ~ llama_server_cuda_version, '') ~ '-x64.zip' }}"
|
__llama_release_asset_name: "{{ 'llama-' ~ llama_server_windows_version ~ '-bin-win-' ~ llama_server_windows_backend ~ (llama_server_windows_backend == 'cuda') | ternary('-' ~ llama_server_cuda_version, '') ~ '-x64.zip' }}"
|
||||||
__llama_release_zip_url: "https://github.com/ggml-org/llama.cpp/releases/download/{{ llama_server_windows_version }}/{{ 'llama-' ~ llama_server_windows_version ~ '-bin-win-' ~ llama_server_windows_backend ~ (llama_server_windows_backend == 'cuda') | ternary('-' ~ llama_server_cuda_version, '') ~ '-x64.zip' }}"
|
__llama_release_zip_url: "https://github.com/ggml-org/llama.cpp/releases/download/{{ llama_server_windows_version }}/{{ 'llama-' ~ llama_server_windows_version ~ '-bin-win-' ~ llama_server_windows_backend ~ (llama_server_windows_backend == 'cuda') | ternary('-' ~ llama_server_cuda_version, '') ~ '-x64.zip' }}"
|
||||||
__llama_release_zip_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\{{ 'llama-' ~ llama_server_windows_version ~ '-bin-win-' ~ llama_server_windows_backend ~ (llama_server_windows_backend == 'cuda') | ternary('-' ~ llama_server_cuda_version, '') ~ '-x64.zip' }}"
|
__llama_release_zip_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\{{ 'llama-' ~ llama_server_windows_version ~ '-bin-win-' ~ llama_server_windows_backend ~ (llama_server_windows_backend == 'cuda') | ternary('-' ~ llama_server_cuda_version, '') ~ '-x64.zip' }}"
|
||||||
__llama_release_marker: "{{ llama_server_windows_install_dir }}\\.release-{{ 'llama-' ~ llama_server_windows_version ~ '-bin-win-' ~ llama_server_windows_backend ~ (llama_server_windows_backend == 'cuda') | ternary('-' ~ llama_server_cuda_version, '') ~ '-x64.zip' }}"
|
__llama_release_marker: "{{ llama_server_windows_install_dir }}\\.release-{{ 'llama-' ~ llama_server_windows_version ~ '-bin-win-' ~ llama_server_windows_backend ~ (llama_server_windows_backend == 'cuda') | ternary('-' ~ llama_server_cuda_version, '') ~ '-x64.zip' }}"
|
||||||
__nssm_zip_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\nssm.zip"
|
__llama_sync_script: "{{ llama_server_windows_working_dir }}\\.router\\llama_hf_sync.py"
|
||||||
__llama_sync_script: "{{ llama_server_windows_working_dir }}\\.router\\llama_hf_sync_windows.py"
|
|
||||||
__llama_models_json: "{{ llama_server_windows_working_dir }}\\.router\\desired-models.json"
|
__llama_models_json: "{{ llama_server_windows_working_dir }}\\.router\\desired-models.json"
|
||||||
__llama_preset_global_json: "{{ llama_server_windows_working_dir }}\\.router\\preset-global.json"
|
__llama_preset_global_json: "{{ llama_server_windows_working_dir }}\\.router\\preset-global.json"
|
||||||
__llama_managed_dir: "{{ llama_server_windows_working_dir }}\\models\\managed"
|
__llama_managed_dir: "{{ llama_server_windows_working_dir }}\\models\\managed"
|
||||||
@@ -118,35 +116,13 @@
|
|||||||
Check download/unzip and llama_server_windows_backend settings.
|
Check download/unzip and llama_server_windows_backend settings.
|
||||||
when: not __llama_bin_stat.stat.exists
|
when: not __llama_bin_stat.stat.exists
|
||||||
|
|
||||||
- name: Check if NSSM is installed
|
- name: Install NSSM
|
||||||
ansible.windows.win_stat:
|
ansible.builtin.include_role:
|
||||||
path: "{{ llama_server_windows_nssm_dir }}\\nssm-{{ llama_server_windows_nssm_version }}\\win64\\nssm.exe"
|
name: nssm
|
||||||
register: __nssm_stat
|
|
||||||
|
|
||||||
- name: Download NSSM if not installed
|
|
||||||
ansible.windows.win_get_url:
|
|
||||||
url: "{{ llama_server_windows_nssm_url }}"
|
|
||||||
dest: "{{ __nssm_zip_path }}"
|
|
||||||
force: false
|
|
||||||
when: not __nssm_stat.stat.exists
|
|
||||||
|
|
||||||
- name: Extract NSSM if not installed
|
|
||||||
community.windows.win_unzip:
|
|
||||||
src: "{{ __nssm_zip_path }}"
|
|
||||||
dest: "{{ llama_server_windows_nssm_dir }}"
|
|
||||||
delete_archive: false
|
|
||||||
creates: "{{ llama_server_windows_nssm_dir }}\\nssm-{{ llama_server_windows_nssm_version }}\\win64\\nssm.exe"
|
|
||||||
when: not __nssm_stat.stat.exists
|
|
||||||
|
|
||||||
- name: Copy NSSM executable
|
|
||||||
ansible.windows.win_copy:
|
|
||||||
src: "{{ llama_server_windows_nssm_dir }}\\nssm-{{ llama_server_windows_nssm_version }}\\win64\\nssm.exe"
|
|
||||||
dest: "{{ __nssm_exe }}"
|
|
||||||
remote_src: true
|
|
||||||
|
|
||||||
- name: Copy Windows-compatible Hugging Face sync script
|
- name: Copy Windows-compatible Hugging Face sync script
|
||||||
ansible.windows.win_copy:
|
ansible.windows.win_copy:
|
||||||
src: scripts/llama_hf_sync_windows.py
|
src: scripts/windows/llama_hf_sync.py
|
||||||
dest: "{{ __llama_sync_script }}"
|
dest: "{{ __llama_sync_script }}"
|
||||||
mode: "0750"
|
mode: "0750"
|
||||||
|
|
||||||
@@ -244,7 +220,7 @@
|
|||||||
argv: >-
|
argv: >-
|
||||||
{{
|
{{
|
||||||
[
|
[
|
||||||
__nssm_exe,
|
'nssm.exe',
|
||||||
'install',
|
'install',
|
||||||
'llama-server',
|
'llama-server',
|
||||||
(llama_server_windows_install_dir ~ '\\' ~ llama_server_windows_bin_name),
|
(llama_server_windows_install_dir ~ '\\' ~ llama_server_windows_bin_name),
|
||||||
@@ -268,7 +244,7 @@
|
|||||||
- name: Set llama-server AppDirectory via NSSM
|
- name: Set llama-server AppDirectory via NSSM
|
||||||
ansible.windows.win_command:
|
ansible.windows.win_command:
|
||||||
argv:
|
argv:
|
||||||
- "{{ __nssm_exe }}"
|
- nssm.exe
|
||||||
- set
|
- set
|
||||||
- llama-server
|
- llama-server
|
||||||
- AppDirectory
|
- AppDirectory
|
||||||
@@ -277,7 +253,7 @@
|
|||||||
- name: Configure llama-server stdout log via NSSM
|
- name: Configure llama-server stdout log via NSSM
|
||||||
ansible.windows.win_command:
|
ansible.windows.win_command:
|
||||||
argv:
|
argv:
|
||||||
- "{{ __nssm_exe }}"
|
- nssm.exe
|
||||||
- set
|
- set
|
||||||
- llama-server
|
- llama-server
|
||||||
- AppStdout
|
- AppStdout
|
||||||
@@ -286,7 +262,7 @@
|
|||||||
- name: Configure llama-server stderr log via NSSM
|
- name: Configure llama-server stderr log via NSSM
|
||||||
ansible.windows.win_command:
|
ansible.windows.win_command:
|
||||||
argv:
|
argv:
|
||||||
- "{{ __nssm_exe }}"
|
- nssm.exe
|
||||||
- set
|
- set
|
||||||
- llama-server
|
- llama-server
|
||||||
- AppStderr
|
- AppStderr
|
||||||
@@ -295,7 +271,7 @@
|
|||||||
- name: Set llama-server Start mode to AUTO via NSSM
|
- name: Set llama-server Start mode to AUTO via NSSM
|
||||||
ansible.windows.win_command:
|
ansible.windows.win_command:
|
||||||
argv:
|
argv:
|
||||||
- "{{ __nssm_exe }}"
|
- nssm.exe
|
||||||
- set
|
- set
|
||||||
- llama-server
|
- llama-server
|
||||||
- Start
|
- Start
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ Type=oneshot
|
|||||||
User={{ llama_server_user }}
|
User={{ llama_server_user }}
|
||||||
Group={{ llama_server_group }}
|
Group={{ llama_server_group }}
|
||||||
RemainAfterExit=true
|
RemainAfterExit=true
|
||||||
ExecStart={{ podman_binary }} start podman-llama.cpp
|
ExecStart={{ podman_binary }} start llamacpp
|
||||||
ExecStop={{ podman_binary }} stop podman-llama.cpp
|
ExecStop={{ podman_binary }} stop llamacpp
|
||||||
|
|
||||||
StandardOutput=journal
|
StandardOutput=journal
|
||||||
StandardError=journal
|
StandardError=journal
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
# NSSM role defaults
|
||||||
|
nssm_version: "2.24"
|
||||||
|
nssm_install_dir: "C:\\nssm"
|
||||||
|
nssm_zip_url: "https://nssm.cc/release/nssm-{{ nssm_version }}.zip"
|
||||||
|
nssm_zip_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\nssm.zip"
|
||||||
|
nssm_exe: "{{ nssm_install_dir }}\\nssm-{{ nssm_version }}\\win64\\nssm.exe"
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
galaxy_info:
|
||||||
|
author: Alexandre Pires
|
||||||
|
description: Install NSSM (Non-Sucking Service Manager) on Windows
|
||||||
|
company: A13Labs
|
||||||
|
role_name: nssm
|
||||||
|
namespace: a13labs
|
||||||
|
license: MIT
|
||||||
|
min_ansible_version: "2.1"
|
||||||
|
platforms:
|
||||||
|
- name: Windows
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
# Install NSSM on Windows - reusable role
|
||||||
|
|
||||||
|
- name: Create NSSM installation directory
|
||||||
|
ansible.windows.win_file:
|
||||||
|
path: "{{ nssm_install_dir }}"
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- name: Check if NSSM is already installed
|
||||||
|
ansible.windows.win_stat:
|
||||||
|
path: "{{ nssm_exe }}"
|
||||||
|
register: __nssm_check
|
||||||
|
|
||||||
|
- name: Download NSSM if not installed
|
||||||
|
ansible.windows.win_get_url:
|
||||||
|
url: "{{ nssm_zip_url }}"
|
||||||
|
dest: "{{ nssm_zip_path }}"
|
||||||
|
force: false
|
||||||
|
when: not __nssm_check.stat.exists
|
||||||
|
|
||||||
|
- name: Extract NSSM if not installed
|
||||||
|
community.windows.win_unzip:
|
||||||
|
src: "{{ nssm_zip_path }}"
|
||||||
|
dest: "{{ nssm_install_dir }}"
|
||||||
|
delete_archive: false
|
||||||
|
creates: "{{ nssm_exe }}"
|
||||||
|
|
||||||
|
- name: Verify NSSM executable is present
|
||||||
|
ansible.windows.win_stat:
|
||||||
|
path: "{{ nssm_exe }}"
|
||||||
|
register: __nssm_stat
|
||||||
|
|
||||||
|
- name: Fail if NSSM executable is missing
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: >-
|
||||||
|
nssm binary not found at {{ nssm_exe }}.
|
||||||
|
Check download/unzip and nssm_version.
|
||||||
|
when: not __nssm_stat.stat.exists
|
||||||
|
|
||||||
|
# - name: Add NSSM to PATH (user level)
|
||||||
|
# ansible.windows.win_path:
|
||||||
|
# name: Path
|
||||||
|
# elements:
|
||||||
|
# - "{{ nssm_install_dir }}\\nssm-{{ nssm_version }}\\win64"
|
||||||
|
# state: present
|
||||||
|
|
||||||
|
- name: Add NSSM to PATH (system level)
|
||||||
|
ansible.windows.win_path:
|
||||||
|
name: Path
|
||||||
|
elements:
|
||||||
|
- "{{ nssm_install_dir }}\\nssm-{{ nssm_version }}\\win64"
|
||||||
|
state: present
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
# ── Mirantis Container Runtime (Windows Server) defaults ──────────────────
|
||||||
|
|
||||||
|
windows_containers_mcr_install_script_url: "https://get.mirantis.com/install.ps1"
|
||||||
|
windows_containers_mcr_channel: "stable"
|
||||||
|
windows_containers_mcr_version: ""
|
||||||
|
windows_containers_disable_telemetry: false
|
||||||
|
|
||||||
|
# --- Podman defaults (container behavior) ---
|
||||||
|
windows_containers_ubuntu_version: "latest"
|
||||||
|
windows_containers_install_dir: "C:\\Program Files\\RedHat\\Podman"
|
||||||
|
windows_containers_installer_url: "https://github.com/podman-container-tools/podman/releases/download/v5.8.2/podman-installer-windows-amd64.exe"
|
||||||
|
windows_containers_download_retries: 5
|
||||||
|
windows_containers_download_delay: 10
|
||||||
|
windows_containers_download_timeout: 120
|
||||||
|
windows_containers_machine_name: "podman-machine-default"
|
||||||
|
windows_containers_image: "ubuntu:{{ windows_containers_ubuntu_version }}"
|
||||||
|
windows_containers_container_name: "ubuntu-container"
|
||||||
|
windows_containers_container_port: "2222"
|
||||||
|
windows_containers_ssh_enabled: false
|
||||||
|
windows_containers_ssh_users:
|
||||||
|
- user: wsluser
|
||||||
|
key: ""
|
||||||
|
|
||||||
|
# --- WSL2 bootstrap defaults ---
|
||||||
|
windows_containers_wsl_enabled: true
|
||||||
|
windows_containers_wsl_features:
|
||||||
|
- Microsoft-Windows-Subsystem-Linux
|
||||||
|
- VirtualMachinePlatform
|
||||||
|
windows_containers_wsl_reboot: true
|
||||||
|
windows_containers_wsl_default_version: 2
|
||||||
|
windows_containers_wsl_install_no_distribution: true
|
||||||
|
|
||||||
|
# --- Dedicated service account ---
|
||||||
|
windows_containers_service_user: podman
|
||||||
|
windows_containers_service_password: ""
|
||||||
|
windows_containers_service_password_never_expires: true
|
||||||
|
|
||||||
|
windows_containers_machine_cpus: 2
|
||||||
|
windows_containers_machine_memory: 2048
|
||||||
|
windows_containers_machine_disk_size: 10000
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
- name: Restart podman machine
|
||||||
|
ansible.windows.win_shell: podman machine stop; podman machine start
|
||||||
|
failed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers
|
||||||
|
|
||||||
|
- name: Restart Ubuntu container
|
||||||
|
ansible.windows.win_shell: podman restart {{ windows_containers_container_name }}
|
||||||
|
failed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
galaxy_info:
|
||||||
|
author: Alexandre Pires
|
||||||
|
description: Install Mirantis Container Runtime on Windows Server and Podman on Windows Workstation
|
||||||
|
company: A13Labs
|
||||||
|
role_name: windows_containers
|
||||||
|
namespace: a13labs
|
||||||
|
license: MIT
|
||||||
|
min_ansible_version: "2.1"
|
||||||
|
platforms:
|
||||||
|
- name: Windows
|
||||||
|
categories: []
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- role: nssm
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
---
|
||||||
|
# ── Phase 0: WSL2 prerequisite bootstrap ─────────────────────────────────
|
||||||
|
|
||||||
|
- name: Enable Microsoft-Windows-Subsystem-Linux feature
|
||||||
|
ansible.windows.win_feature:
|
||||||
|
name: Microsoft-Windows-Subsystem-Linux
|
||||||
|
state: present
|
||||||
|
include_sub_features: true
|
||||||
|
include_management_tools: true
|
||||||
|
register: __wsl_feature
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::wsl_bootstrap
|
||||||
|
|
||||||
|
- name: Enable Virtual Machine Platform feature
|
||||||
|
ansible.windows.win_feature:
|
||||||
|
name: VirtualMachinePlatform
|
||||||
|
state: present
|
||||||
|
include_sub_features: true
|
||||||
|
include_management_tools: true
|
||||||
|
register: __vmp_feature
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::wsl_bootstrap
|
||||||
|
when: ansible_facts.os_product_type == "workstation"
|
||||||
|
|
||||||
|
- name: Enable Hyper-V feature
|
||||||
|
ansible.windows.win_feature:
|
||||||
|
name: Hyper-V
|
||||||
|
state: present
|
||||||
|
include_sub_features: true
|
||||||
|
include_management_tools: true
|
||||||
|
register: __hyperv_feature
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::wsl_bootstrap
|
||||||
|
when: ansible_facts.os_product_type == "server"
|
||||||
|
|
||||||
|
- name: Enable Containers feature
|
||||||
|
ansible.windows.win_feature:
|
||||||
|
name: Containers
|
||||||
|
state: present
|
||||||
|
include_sub_features: true
|
||||||
|
include_management_tools: true
|
||||||
|
register: __containers_feature
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::wsl_bootstrap
|
||||||
|
when: ansible_facts.os_product_type == "server"
|
||||||
|
|
||||||
|
- name: Reboot if WSL features were changed
|
||||||
|
ansible.windows.win_reboot:
|
||||||
|
reboot_timeout: 600
|
||||||
|
pre_reboot_delay: 5
|
||||||
|
post_reboot_delay: 15
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when:
|
||||||
|
- windows_containers_wsl_reboot | default(true)
|
||||||
|
- __wsl_feature.changed or __vmp_feature.changed or __hyperv_feature.changed or __containers_feature.changed
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::wsl_bootstrap
|
||||||
|
|
||||||
|
- name: Download WSL2 kernel update package
|
||||||
|
ansible.windows.win_get_url:
|
||||||
|
url: "https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi"
|
||||||
|
dest: "{{ ansible_env.TEMP | default('C:\\Windows\\Temp') }}\\wsl_update_x64.msi"
|
||||||
|
force: false
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::wsl_bootstrap
|
||||||
|
|
||||||
|
- name: Install WSL2 kernel update package
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
Start-Process "msiexec.exe" -ArgumentList "/i {{ ansible_env.TEMP | default('C:\\Windows\\Temp') }}\\wsl_update_x64.msi /quiet" -NoNewWindow -Wait
|
||||||
|
exit $LASTEXITCODE
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
register: __wsl_update_result
|
||||||
|
changed_when: __wsl_update_result.rc == 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::wsl_bootstrap
|
||||||
|
|
||||||
|
- name: Run wsl update to update WSL2 kernel
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
wsl --update
|
||||||
|
exit $LASTEXITCODE
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
register: __wsl_set_default_result
|
||||||
|
changed_when: __wsl_set_default_result.rc == 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::wsl_bootstrap
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
---
|
||||||
|
# ── Phase 1: Mirantis Container Runtime (MCR) installation ────────────────
|
||||||
|
|
||||||
|
- name: Check if MCR (Docker) is already installed
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$dockerCmd = Get-Command docker -ErrorAction SilentlyContinue
|
||||||
|
if ($dockerCmd) {
|
||||||
|
$version = (& docker --version 2>&1)
|
||||||
|
Write-Output "MCR_INSTALLED:$version"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
register: __mcr_installed_check
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::install
|
||||||
|
|
||||||
|
- name: Download Mirantis install script
|
||||||
|
ansible.windows.win_get_url:
|
||||||
|
url: "{{ windows_containers_mcr_install_script_url }}"
|
||||||
|
dest: "{{ ansible_env.TEMP | default('C:\\Windows\\Temp') }}\\mcr-install.ps1"
|
||||||
|
force: false
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when: __mcr_installed_check.rc != 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::install
|
||||||
|
|
||||||
|
- name: Set execution policy for current process
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force -Scope Process
|
||||||
|
exit 0
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when: __mcr_installed_check.rc != 0
|
||||||
|
changed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::install
|
||||||
|
|
||||||
|
- name: Install Mirantis Container Runtime
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
& "{{ ansible_env.TEMP | default('C:\\Windows\\Temp') }}\\mcr-install.ps1" \
|
||||||
|
-Channel "{{ windows_containers_mcr_channel }}" \
|
||||||
|
-DockerVersion "{{ windows_containers_mcr_version }}"
|
||||||
|
exit $LASTEXITCODE
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
register: __mcr_install_result
|
||||||
|
changed_when: __mcr_install_result.rc == 0
|
||||||
|
when: __mcr_installed_check.rc != 0
|
||||||
|
retries: 3
|
||||||
|
delay: 30
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::install
|
||||||
|
|
||||||
|
- name: Clean up MCR install script
|
||||||
|
ansible.windows.win_file:
|
||||||
|
path: "{{ ansible_env.TEMP | default('C:\\Windows\\Temp') }}\\mcr-install.ps1"
|
||||||
|
state: absent
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when: __mcr_installed_check.rc != 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::install
|
||||||
|
|
||||||
|
- name: Disable MCR telemetry (optional)
|
||||||
|
ansible.windows.win_copy:
|
||||||
|
content: '{"features":{"telemetry": false}}'
|
||||||
|
dest: "C:\\ProgramData\\docker\\config\\daemon.json"
|
||||||
|
mode: "0644"
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
notify: Restart Docker service
|
||||||
|
when: windows_containers_disable_telemetry | default(false)
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::install
|
||||||
|
|
||||||
|
- name: Restart Docker service
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
Restart-Service -Name docker -Force -ErrorAction SilentlyContinue
|
||||||
|
exit 0
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when: __mcr_installed_check.rc != 0
|
||||||
|
changed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::install
|
||||||
|
|
||||||
|
- name: Verify MCR (Docker) is running
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$dockerdRunning = Get-Service -Name docker -ErrorAction SilentlyContinue
|
||||||
|
if ($dockerdRunning -and $dockerdRunning.Status -eq 'Running') {
|
||||||
|
$version = (& docker --version 2>&1)
|
||||||
|
Write-Output "MCR_SERVICE_RUNNING:$version"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
Write-Error "Docker service is not running"
|
||||||
|
exit 1
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
register: __mcr_service_verify
|
||||||
|
changed_when: false
|
||||||
|
until: __mcr_service_verify.rc == 0
|
||||||
|
retries: 10
|
||||||
|
delay: 10
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::install
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
# ── Phase 1: WSL2 prerequisites ─────────────────────────────────────────
|
||||||
|
- name: Bootstrap WSL2 prerequisites
|
||||||
|
ansible.builtin.include_tasks: bootstrap_wsl.yml
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers
|
||||||
|
- roles::windows_containers::wsl_bootstrap
|
||||||
|
|
||||||
|
# ── Phase 0: Docker Engine (Windows Server) ──────────────────────────────
|
||||||
|
- name: Install Docker Engine for Windows Server (Mirantis Container Runtime)
|
||||||
|
ansible.builtin.include_tasks: containers_install.yml
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers
|
||||||
|
- roles::windows_containers::install
|
||||||
|
|
||||||
|
# ── Phase 2: Podman install, user, NSSM service ─────────────────────────
|
||||||
|
- name: Install Podman
|
||||||
|
ansible.builtin.include_tasks: podman_install.yml
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
# ── Phase 2: Ubuntu container ────────────────────────────────────────────
|
||||||
|
- name: Setup Ubuntu container
|
||||||
|
ansible.builtin.include_tasks: ubuntu_container.yml
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers
|
||||||
|
- roles::windows_containers::ubuntu_container
|
||||||
|
when: ansible_facts.os_product_type == "workstation"
|
||||||
|
|
||||||
|
# ── Phase 3: Verification ────────────────────────────────────────────────
|
||||||
|
- name: Verify installation
|
||||||
|
ansible.builtin.include_tasks: verify.yml
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers
|
||||||
|
- roles::windows_containers::verify
|
||||||
|
when: ansible_facts.os_product_type == "workstation"
|
||||||
@@ -0,0 +1,389 @@
|
|||||||
|
---
|
||||||
|
# ── Phase 1: Podman installer download & install ─────────────────────────
|
||||||
|
|
||||||
|
- name: Check if Podman is already installed
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
if (Get-Command podman -ErrorAction SilentlyContinue) {
|
||||||
|
Write-Output "__PODMAN_INSTALLED__"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
register: __podman_installed_check
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Download Podman installer on remote host
|
||||||
|
ansible.windows.win_get_url:
|
||||||
|
url: "{{ windows_containers_installer_url }}"
|
||||||
|
dest: "{{ ansible_env.TEMP | default('C:\\Windows\\Temp') }}\\podman-installer.exe"
|
||||||
|
force: false
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when: __podman_installed_check.rc != 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Install Podman silently
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
Start-Process "{{ ansible_env.TEMP | default('C:\\Windows\\Temp') }}\podman-installer.exe" -ArgumentList @("/S", "/D={{ windows_containers_install_dir }}") -Wait
|
||||||
|
exit $LASTEXITCODE
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
register: __podman_install_result
|
||||||
|
changed_when: __podman_install_result.rc == 0
|
||||||
|
when: __podman_installed_check.rc != 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Clean up Podman installer
|
||||||
|
ansible.windows.win_file:
|
||||||
|
path: "{{ ansible_env.TEMP | default('C:\\Windows\\Temp') }}\\podman-installer.exe"
|
||||||
|
state: absent
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when: __podman_installed_check.rc != 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Add Podman to PATH if not already present
|
||||||
|
ansible.windows.win_path:
|
||||||
|
name: Path
|
||||||
|
elements:
|
||||||
|
- "{{ windows_containers_install_dir }}"
|
||||||
|
state: present
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when: __podman_installed_check.rc != 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
# ── Phase 2: Dedicated service user ──────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Fail when podman service password is missing
|
||||||
|
ansible.builtin.fail:
|
||||||
|
msg: >-
|
||||||
|
windows_containers_service_password must be provided to configure service account
|
||||||
|
.\\{{ windows_containers_service_user }} for NSSM.
|
||||||
|
when: windows_containers_service_password | length == 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Create dedicated podman service user
|
||||||
|
ansible.windows.win_user:
|
||||||
|
name: "{{ windows_containers_service_user }}"
|
||||||
|
password: "{{ windows_containers_service_password }}"
|
||||||
|
account_disabled: false
|
||||||
|
password_never_expires: true
|
||||||
|
user_cannot_change_password: true
|
||||||
|
state: present
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when:
|
||||||
|
- windows_containers_service_password | length > 0
|
||||||
|
no_log: true
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Get localized Users group name via PowerShell
|
||||||
|
ansible.windows.win_powershell:
|
||||||
|
script: |
|
||||||
|
$sid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-545")
|
||||||
|
$ntAccount = $sid.Translate([System.Security.Principal.NTAccount])
|
||||||
|
# Handle both local and domain accounts - take the last part after backslash
|
||||||
|
$parts = $ntAccount.Value -split '\\'
|
||||||
|
$parts[-1]
|
||||||
|
register: __users_group_name
|
||||||
|
changed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Debug localized Users group name
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Localized Users group name is '{{ __users_group_name.output | first }}'"
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Add podman service user to Users group for interactive login
|
||||||
|
ansible.windows.win_group_membership:
|
||||||
|
name: "{{ __users_group_name.output | first }}"
|
||||||
|
members:
|
||||||
|
- ".\\{{ windows_containers_service_user }}"
|
||||||
|
state: present
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when:
|
||||||
|
- windows_containers_service_password | length > 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Grant "Log on as a service" right to podman service account
|
||||||
|
ansible.windows.win_user_right:
|
||||||
|
name: SeServiceLogonRight
|
||||||
|
users:
|
||||||
|
- ".\\{{ windows_containers_service_user }}"
|
||||||
|
action: add
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when:
|
||||||
|
- windows_containers_service_password | length > 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Grant "Log on locally" right to podman service account (required for Ansible become)
|
||||||
|
ansible.windows.win_user_right:
|
||||||
|
name: SeInteractiveLogonRight
|
||||||
|
users:
|
||||||
|
- ".\\{{ windows_containers_service_user }}"
|
||||||
|
action: add
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when:
|
||||||
|
- windows_containers_service_password | length > 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Grant "Log on as a batch job" right to podman service account
|
||||||
|
ansible.windows.win_user_right:
|
||||||
|
name: SeBatchLogonRight
|
||||||
|
users:
|
||||||
|
- ".\\{{ windows_containers_service_user }}"
|
||||||
|
action: add
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
when:
|
||||||
|
- windows_containers_service_password | length > 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
# ── Phase 3: Podman machine setup ──────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Get Podman executable path
|
||||||
|
ansible.windows.win_shell: where.exe podman.exe 2>&1
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
register: __podman_where
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Set Podman executable path from where output
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
__podman_exe: "{{ (__podman_where.stdout_lines | last).strip() }}"
|
||||||
|
when:
|
||||||
|
- __podman_where is not failed
|
||||||
|
- __podman_where.stdout | trim != ""
|
||||||
|
|
||||||
|
- name: Default Podman executable path if not on PATH or where failed
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
__podman_exe: "{{ windows_containers_install_dir }}\\podman.exe"
|
||||||
|
when: __podman_where is failed or __podman_where.stdout | trim == ""
|
||||||
|
|
||||||
|
# ── Phase 4: Podman machine init ────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Initialize Podman machine
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$machinesJson = (podman machine ls --format json 2>$null | Out-String).Trim()
|
||||||
|
$machines = @()
|
||||||
|
if ($machinesJson) {
|
||||||
|
$machines = $machinesJson | ConvertFrom-Json
|
||||||
|
}
|
||||||
|
|
||||||
|
$machine = $machines | Where-Object { $_.Name -eq "{{ windows_containers_machine_name }}" } | Select-Object -First 1
|
||||||
|
if (-not $machine) {
|
||||||
|
podman machine init "{{ windows_containers_machine_name }}" --cpus {{ windows_containers_machine_cpus }} --memory {{ windows_containers_machine_memory }} --disk-size {{ windows_containers_machine_disk_size }}
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Error "Failed to initialize Podman machine {{ windows_containers_machine_name }}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$afterInitJson = (podman machine ls --format json 2>$null | Out-String).Trim()
|
||||||
|
$afterInitMachines = @()
|
||||||
|
if ($afterInitJson) {
|
||||||
|
$afterInitMachines = $afterInitJson | ConvertFrom-Json
|
||||||
|
}
|
||||||
|
|
||||||
|
$createdMachine = $afterInitMachines | Where-Object { $_.Name -eq "{{ windows_containers_machine_name }}" } | Select-Object -First 1
|
||||||
|
if (-not $createdMachine) {
|
||||||
|
Write-Error "Podman machine {{ windows_containers_machine_name }} is still missing after init"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "__PODMAN_MACHINE_CREATED__"
|
||||||
|
}
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: "{{ windows_containers_service_user }}"
|
||||||
|
register: __podman_init
|
||||||
|
changed_when: "'__PODMAN_MACHINE_CREATED__' in (__podman_init.stdout + __podman_init.stderr)"
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Start Podman machine on boot via NSSM service only
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
# Podman machine will be started on boot via NSSM service (PodmanAutoStart)
|
||||||
|
# No need to start it during playbook execution
|
||||||
|
podman machine status "{{ windows_containers_machine_name }}" 2>$null | Out-Null
|
||||||
|
$status = $LASTEXITCODE
|
||||||
|
if ($status -eq 0) {
|
||||||
|
Write-Output "Podman machine {{ windows_containers_machine_name }} is already running"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
Write-Output "Podman machine not running (will start on boot)"
|
||||||
|
exit 0
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: "{{ windows_containers_service_user }}"
|
||||||
|
register: __podman_status_check
|
||||||
|
changed_when: false
|
||||||
|
failed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Deploy Podman auto-start PowerShell script
|
||||||
|
ansible.windows.win_template:
|
||||||
|
src: podman-auto-start.ps1.j2
|
||||||
|
dest: "{{ windows_containers_install_dir }}\\auto-start-podman.ps1"
|
||||||
|
mode: "0644"
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Deploy batch wrapper to avoid path-with-spaces issues in NSSM
|
||||||
|
ansible.windows.win_template:
|
||||||
|
src: podman-auto-start.bat.j2
|
||||||
|
dest: "{{ windows_containers_install_dir }}\\auto-start-podman.bat"
|
||||||
|
mode: "0644"
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Delete existing PodmanAutoStart service via NSSM
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$existing = Get-CimInstance Win32_Service -Filter "Name='PodmanAutoStart'" -ErrorAction SilentlyContinue
|
||||||
|
if ($existing) {
|
||||||
|
Stop-Service -Name PodmanAutoStart -Force -ErrorAction SilentlyContinue
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
$null = nssm.exe remove PodmanAutoStart confirm
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
}
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
changed_when: true
|
||||||
|
failed_when: false
|
||||||
|
no_log: true
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Register Podman auto-start service via NSSM (batch wrapper for proper path quoting)
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$installDir = "{{ windows_containers_install_dir }}"
|
||||||
|
$batchPath = Join-Path $installDir "auto-start-podman.bat"
|
||||||
|
nssm.exe install PodmanAutoStart "`"$batchPath`""
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
changed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Create log directory for Podman auto-start
|
||||||
|
ansible.windows.win_file:
|
||||||
|
path: C:\Logs\Podman
|
||||||
|
state: directory
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Grant podman service user full control over log directory
|
||||||
|
ansible.windows.win_acl:
|
||||||
|
path: C:\Logs\Podman
|
||||||
|
user: ".\\{{ windows_containers_service_user }}"
|
||||||
|
rights: FullControl
|
||||||
|
type: allow
|
||||||
|
state: present
|
||||||
|
inherit: ContainerInherit, ObjectInherit
|
||||||
|
propagation: None
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Configure Podman auto-start service via NSSM
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$installDir = "{{ windows_containers_install_dir }}"
|
||||||
|
nssm.exe set PodmanAutoStart AppDirectory $installDir
|
||||||
|
nssm.exe set PodmanAutoStart DisplayName "Podman Auto Start"
|
||||||
|
nssm.exe set PodmanAutoStart Description "Starts Podman machine and containers on boot"
|
||||||
|
nssm.exe set PodmanAutoStart Start SERVICE_AUTO_START
|
||||||
|
nssm.exe set PodmanAutoStart AppRestartDelay 30000
|
||||||
|
nssm.exe set PodmanAutoStart AppStdout "C:\Logs\Podman\auto-start.log"
|
||||||
|
nssm.exe set PodmanAutoStart AppStderr "C:\Logs\Podman\auto-start-error.log"
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
changed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Set PodmanAutoStart service account via NSSM
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
nssm.exe set PodmanAutoStart ObjectName ".\{{ windows_containers_service_user }}" "{{ windows_containers_service_password }}"
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
changed_when: true
|
||||||
|
no_log: true
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
|
||||||
|
- name: Start PodmanAutoStart service
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$svc = Get-CimInstance Win32_Service -Filter "Name='PodmanAutoStart'" -ErrorAction SilentlyContinue
|
||||||
|
if ($svc -and $svc.State -ne 'Running') {
|
||||||
|
nssm.exe start PodmanAutoStart
|
||||||
|
Start-Sleep -Seconds 5
|
||||||
|
$svc = Get-CimInstance Win32_Service -Filter "Name='PodmanAutoStart'"
|
||||||
|
Write-Output "PodmanAutoStart service state: $($svc.State)"
|
||||||
|
} else {
|
||||||
|
Write-Output "PodmanAutoStart service already running or not found"
|
||||||
|
}
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: SYSTEM
|
||||||
|
register: __podman_auto_start_service
|
||||||
|
changed_when: "'state: Running' in (__podman_auto_start_service.stdout)"
|
||||||
|
failed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::podman_install
|
||||||
|
# ansible.windows.win_shell: podman pull "{{ windows_containers_image }}"
|
||||||
|
# become: true
|
||||||
|
# become_method: ansible.builtin.runas
|
||||||
|
# become_user: "{{ windows_containers_service_user }}"
|
||||||
|
# register: __podman_pull
|
||||||
|
# changed_when: false
|
||||||
|
# tags:
|
||||||
|
# - roles::windows_containers::podman_install
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
---
|
||||||
|
- name: Inspect Ubuntu container state
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$containersJson = (podman ps -a --filter "name=^{{ windows_containers_container_name }}$" --format json 2>$null | Out-String).Trim()
|
||||||
|
if (-not $containersJson -or $containersJson -eq "[]") {
|
||||||
|
Write-Output "__CONTAINER_ABSENT__"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
$containers = $containersJson | ConvertFrom-Json
|
||||||
|
$container = $containers | Select-Object -First 1
|
||||||
|
if ($container) {
|
||||||
|
Write-Output "__CONTAINER_PRESENT__"
|
||||||
|
if ($container.State -eq "running") {
|
||||||
|
Write-Output "__CONTAINER_RUNNING__"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
register: container_state
|
||||||
|
changed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::ubuntu_container
|
||||||
|
|
||||||
|
- name: Create Ubuntu container
|
||||||
|
ansible.windows.win_shell: podman run -d --name {{ windows_containers_container_name }} -p {{ windows_containers_container_port }}:22 --restart unless-stopped "{{ windows_containers_image }}"
|
||||||
|
when: "'__CONTAINER_ABSENT__' in (container_state.stdout + container_state.stderr)"
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::ubuntu_container
|
||||||
|
|
||||||
|
- name: Start Ubuntu container when stopped
|
||||||
|
ansible.windows.win_shell: podman start {{ windows_containers_container_name }}
|
||||||
|
when:
|
||||||
|
- "'__CONTAINER_PRESENT__' in (container_state.stdout + container_state.stderr)"
|
||||||
|
- "'__CONTAINER_RUNNING__' not in (container_state.stdout + container_state.stderr)"
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::ubuntu_container
|
||||||
|
|
||||||
|
- name: Wait for container to be ready
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$status = (podman inspect --format "{{ '{{.State.Running}}' }}" {{ windows_containers_container_name }} 2>$null | Out-String).Trim()
|
||||||
|
if ($LASTEXITCODE -eq 0 -and $status -eq "true") {
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
Write-Error "Container {{ windows_containers_container_name }} is not running yet"
|
||||||
|
exit 1
|
||||||
|
register: container_ready
|
||||||
|
until: container_ready.rc == 0
|
||||||
|
retries: 20
|
||||||
|
delay: 5
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::ubuntu_container
|
||||||
|
|
||||||
|
- name: Set up SSH in Ubuntu container
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
podman exec {{ windows_containers_container_name }} sh -c 'mkdir -p /home/{{ windows_containers_user }}/.ssh'
|
||||||
|
podman exec {{ windows_containers_container_name }} sh -c 'touch /home/{{ windows_containers_user }}/.ssh/authorized_keys'
|
||||||
|
podman exec {{ windows_containers_container_name }} sh -c 'chown -R {{ windows_containers_user }}:$(id -g {{ windows_containers_user }}) /home/{{ windows_containers_user }}/.ssh'
|
||||||
|
podman exec {{ windows_containers_container_name }} sh -c 'chmod 700 /home/{{ windows_containers_user }}/.ssh && chmod 600 /home/{{ windows_containers_user }}/.ssh/authorized_keys'
|
||||||
|
register: ssh_dir_setup
|
||||||
|
changed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::ubuntu_container
|
||||||
|
|
||||||
|
- name: Deploy SSH authorized_keys
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$keysJson = '{{ windows_containers_ssh_users | map(attribute="key") | list | to_json }}'
|
||||||
|
$keys = @()
|
||||||
|
if ($keysJson) {
|
||||||
|
$keys = $keysJson | ConvertFrom-Json
|
||||||
|
}
|
||||||
|
$keys = $keys | Where-Object { $_ -and $_.Trim() -ne "" } | ForEach-Object { $_.Trim() } | Sort-Object -Unique
|
||||||
|
|
||||||
|
$desiredContent = ""
|
||||||
|
if ($keys.Count -gt 0) {
|
||||||
|
$desiredContent = ($keys -join "`n") + "`n"
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentContent = (podman exec {{ windows_containers_container_name }} sh -c "cat /home/{{ windows_containers_user }}/.ssh/authorized_keys 2>/dev/null || true" | Out-String)
|
||||||
|
if ($currentContent -ne $desiredContent) {
|
||||||
|
$encodedContent = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($desiredContent))
|
||||||
|
podman exec {{ windows_containers_container_name }} sh -c "echo $encodedContent | base64 -d > /home/{{ windows_containers_user }}/.ssh/authorized_keys"
|
||||||
|
podman exec {{ windows_containers_container_name }} sh -c 'chown {{ windows_containers_user }}:$(id -g {{ windows_containers_user }}) /home/{{ windows_containers_user }}/.ssh/authorized_keys'
|
||||||
|
podman exec {{ windows_containers_container_name }} sh -c 'chmod 600 /home/{{ windows_containers_user }}/.ssh/authorized_keys'
|
||||||
|
Write-Output "__AUTHORIZED_KEYS_UPDATED__"
|
||||||
|
}
|
||||||
|
register: authorized_keys_result
|
||||||
|
changed_when: "'__AUTHORIZED_KEYS_UPDATED__' in (authorized_keys_result.stdout + authorized_keys_result.stderr)"
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::ubuntu_container
|
||||||
|
|
||||||
|
- name: Enable and start sshd in Ubuntu container
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$changed = $false
|
||||||
|
|
||||||
|
podman exec {{ windows_containers_container_name }} sh -c "dpkg -s openssh-server >/dev/null 2>&1"
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
podman exec {{ windows_containers_container_name }} sh -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y openssh-server"
|
||||||
|
$changed = $true
|
||||||
|
}
|
||||||
|
|
||||||
|
podman exec {{ windows_containers_container_name }} sh -c "mkdir -p /run/sshd"
|
||||||
|
|
||||||
|
podman exec {{ windows_containers_container_name }} sh -c "pgrep -x sshd >/dev/null 2>&1"
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
podman exec {{ windows_containers_container_name }} /usr/sbin/sshd
|
||||||
|
$changed = $true
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($changed) {
|
||||||
|
Write-Output "__SSHD_PROVISIONED__"
|
||||||
|
}
|
||||||
|
register: sshd_result
|
||||||
|
changed_when: "'__SSHD_PROVISIONED__' in (sshd_result.stdout + sshd_result.stderr)"
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::ubuntu_container
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
---
|
||||||
|
# ── WSL verification ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Verify WSL is operational
|
||||||
|
ansible.windows.win_shell: wsl.exe --status --default
|
||||||
|
register: __wsl_verify
|
||||||
|
changed_when: false
|
||||||
|
failed_when: __wsl_verify.rc != 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::verify
|
||||||
|
|
||||||
|
# ── Podman verification ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Verify Podman is installed
|
||||||
|
ansible.windows.win_shell: podman version
|
||||||
|
register: __podman_version
|
||||||
|
changed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::verify
|
||||||
|
|
||||||
|
- name: Verify Podman machine exists
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$machinesJson = (podman machine ls --format json 2>$null | Out-String).Trim()
|
||||||
|
if (-not $machinesJson) {
|
||||||
|
Write-Error "No Podman machines found"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$machines = $machinesJson | ConvertFrom-Json
|
||||||
|
$machine = $machines | Where-Object { $_.Name -eq "{{ windows_containers_machine_name }}" } | Select-Object -First 1
|
||||||
|
if (-not $machine) {
|
||||||
|
Write-Error "Podman machine {{ windows_containers_machine_name }} not found"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output "__PODMAN_MACHINE_EXISTS__"
|
||||||
|
register: __podman_machine_ls
|
||||||
|
changed_when: false
|
||||||
|
failed_when: "'__PODMAN_MACHINE_EXISTS__' not in (__podman_machine_ls.stdout + __podman_machine_ls.stderr)"
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::verify
|
||||||
|
|
||||||
|
# ── NSSM service verification ────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Verify NSSM Podman machine service is installed and running
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$svc = (Get-Service -Name "{{ windows_containers_service_name }}" -ErrorAction SilentlyContinue)
|
||||||
|
if (-not $svc) { Write-Error "Service {{ windows_containers_service_name }} not found"; exit 1 }
|
||||||
|
if ($svc.StartType -ne 'Automatic') { Write-Error "Service {{ windows_containers_service_name }} is not Automatic"; exit 1 }
|
||||||
|
Write-Output "Service: $($svc.DisplayName) | Status: $($svc.Status) | StartType: $($svc.StartType)"
|
||||||
|
Write-Output "__NSSM_SERVICE_OK__"
|
||||||
|
register: __nssm_verify
|
||||||
|
changed_when: false
|
||||||
|
failed_when: "__NSSM_SERVICE_OK__ not in (__nssm_verify.stdout + __nssm_verify.stderr)"
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::verify
|
||||||
|
|
||||||
|
- name: Verify NSSM service runs as dedicated podman user
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
$svc = Get-CimInstance -ClassName Win32_Service -Filter "Name='{{ windows_containers_service_name }}'"
|
||||||
|
$owner = $svc.StartName
|
||||||
|
if ($owner -eq ".\\{{ windows_containers_service_user }}" -or $owner -eq "{{ windows_containers_service_user }}") {
|
||||||
|
Write-Output "Service runs as $owner"
|
||||||
|
Write-Output "__NSSM_USER_OK__"
|
||||||
|
} else {
|
||||||
|
Write-Error "Expected service to run as .\\{{ windows_containers_service_user }}, got $owner"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
register: __nssm_user_verify
|
||||||
|
changed_when: false
|
||||||
|
failed_when: "__NSSM_USER_OK__ not in (__nssm_user_verify.stdout + __nssm_user_verify.stderr)"
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::verify
|
||||||
|
|
||||||
|
# ── Container verification ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
- name: Verify Ubuntu container is running
|
||||||
|
ansible.windows.win_shell: podman inspect --format "{{ '{{.State.Running}}' }}" {{ windows_containers_container_name }}
|
||||||
|
register: __container_status
|
||||||
|
changed_when: false
|
||||||
|
failed_when: __container_status.rc != 0 or __container_status.stdout | trim != 'true'
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::verify
|
||||||
|
|
||||||
|
- name: Verify SSH access to Ubuntu container
|
||||||
|
ansible.windows.win_shell: podman exec {{ windows_containers_container_name }} id {{ windows_containers_user }}
|
||||||
|
register: __user_check
|
||||||
|
changed_when: false
|
||||||
|
failed_when: __user_check.rc != 0
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::verify
|
||||||
|
|
||||||
|
- name: Report SSH connection details
|
||||||
|
ansible.windows.win_shell: |
|
||||||
|
Write-Output "Podman is installed"
|
||||||
|
Write-Output "WSL version: wsl.exe --version"
|
||||||
|
Write-Output "NSSM service: {{ windows_containers_service_name }}"
|
||||||
|
Write-Output "Ubuntu container: {{ windows_containers_container_name }}"
|
||||||
|
Write-Output "SSH access: ssh {{ windows_containers_user }}@localhost -p {{ windows_containers_container_port }}"
|
||||||
|
changed_when: false
|
||||||
|
tags:
|
||||||
|
- roles::windows_containers::verify
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
@echo off
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0auto-start-podman.ps1"
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# Podman auto-start on Windows boot
|
||||||
|
# Runs as {{ windows_containers_service_user }} (set via NSSM ObjectName)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$LogDir = "C:\Logs\Podman"
|
||||||
|
$LogTimestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
|
||||||
|
$MachineName = "{{ windows_containers_machine_name }}"
|
||||||
|
|
||||||
|
function Write-Log {
|
||||||
|
param([string]$LogName, [System.Collections.ArrayList]$Messages)
|
||||||
|
$Log = Join-Path $LogDir "$LogName-$LogTimestamp.log"
|
||||||
|
$lines = @()
|
||||||
|
foreach ($m in $Messages) {
|
||||||
|
$lines += "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') $m"
|
||||||
|
}
|
||||||
|
[System.IO.File]::WriteAllText($Log, ($lines -join "`r`n") + "`r`n", [System.Text.Encoding]::UTF8)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$bootMessages = [System.Collections.ArrayList]::new()
|
||||||
|
$bootMessages.Add("Starting Podman auto-start process") > $null
|
||||||
|
|
||||||
|
# Check if machine is already running
|
||||||
|
$listOutput = & "{{ windows_containers_install_dir }}\podman.exe" @('machine', 'list', '--format', 'table {{ '{{' }}.Name{{ '}}' }}\t{{ '{{' }}.Running{{ '}}' }}') 2>&1 | Out-String
|
||||||
|
$listExit = $LASTEXITCODE
|
||||||
|
$bootMessages.Add("Machine list exit code: $listExit") > $null
|
||||||
|
$bootMessages.Add("Machine list output: $listOutput") > $null
|
||||||
|
|
||||||
|
$running = ($listOutput -match "$MachineName\s+true")
|
||||||
|
if ($running) {
|
||||||
|
$bootMessages.Add("Machine is already running") > $null
|
||||||
|
} else {
|
||||||
|
$startOutput = & "{{ windows_containers_install_dir }}\podman.exe" @('machine', 'start', $MachineName) 2>&1 | Out-String
|
||||||
|
$bootMessages.Add("Machine start output: $startOutput") > $null
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Log "auto-start" $bootMessages
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wait for the machine to be ready (poll podman info)
|
||||||
|
$bootMessages.Add("Waiting for machine to be ready...") > $null
|
||||||
|
$ready = $false
|
||||||
|
for ($i = 0; $i -lt 90; $i++) {
|
||||||
|
$infoOutput = & "{{ windows_containers_install_dir }}\podman.exe" @('info', '--format', 'json') 2>&1 | Out-String
|
||||||
|
if ($LASTEXITCODE -eq 0 -and $infoOutput -and $infoOutput.Trim()) {
|
||||||
|
$ready = true
|
||||||
|
$bootMessages.Add("Machine is ready after $(($i + 1) * 2) seconds") > $null
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $ready) {
|
||||||
|
Write-Log "auto-start" $bootMessages
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start any stopped containers
|
||||||
|
$startContainersOutput = & "{{ windows_containers_install_dir }}\podman.exe" @('start', '-a') 2>&1 | Out-String
|
||||||
|
$bootMessages.Add("Container start output: $startContainersOutput") > $null
|
||||||
|
$bootMessages.Add("Podman auto-start complete") > $null
|
||||||
|
Write-Log "auto-start" $bootMessages
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
$errMessages = [System.Collections.ArrayList]::new()
|
||||||
|
$errMessages.Add("Podman auto-start failed: $_") > $null
|
||||||
|
$errMessages.Add("Stack trace: $($_.ScriptStackTrace)") > $null
|
||||||
|
Write-Log "auto-start-ERROR" $errMessages
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
prometheus_version: "3.6.0"
|
||||||
|
prometheus_install_dir: "C:\\Prometheus"
|
||||||
|
prometheus_listen_address: "0.0.0.0:9090"
|
||||||
|
windows_exporter_version: "0.31.3"
|
||||||
|
windows_exporter_collectors:
|
||||||
|
- cache
|
||||||
|
- cpu
|
||||||
|
- cpu_info
|
||||||
|
- disk_drive
|
||||||
|
- memory
|
||||||
|
- net
|
||||||
|
- os
|
||||||
|
- process
|
||||||
|
- service
|
||||||
|
- tcp
|
||||||
|
- time
|
||||||
|
- update
|
||||||
@@ -8,4 +8,4 @@ galaxy_info:
|
|||||||
license: MIT
|
license: MIT
|
||||||
min_ansible_version: "2.1"
|
min_ansible_version: "2.1"
|
||||||
platforms:
|
platforms:
|
||||||
- name: windows
|
- name: Windows
|
||||||
|
|||||||
@@ -1,25 +1,16 @@
|
|||||||
---
|
---
|
||||||
# Install Prometheus + Windows Exporter on Windows and open firewall for Grafana
|
# Install Prometheus + Windows Exporter on Windows and open firewall for Grafana
|
||||||
- name: Define Prometheus Versions and install dir
|
- name: Define internal paths
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
prometheus_version: "{{ prometheus_version | default('3.6.0') }}"
|
__prometheus_zip_url: >-
|
||||||
prometheus_install_dir: "{{ prometheus_install_dir | default('C:\\Prometheus') }}"
|
https://github.com/prometheus/prometheus/releases/download/v{{
|
||||||
prometheus_listen_address: "{{ prometheus_listen_address | default('0.0.0.0:9090') }}"
|
prometheus_version }}/prometheus-{{ prometheus_version }}.windows-amd64.zip
|
||||||
nssm_dir: "{{ nssm_dir | default('C:\\nssm') }}"
|
|
||||||
nssm_version: "{{ nssm_version | default('2.24') }}"
|
|
||||||
windows_exporter_version: "{{ windows_exporter_version | default('0.31.3') }}"
|
|
||||||
windows_exporter_collectors: "{{ windows_exporter_collectors | default(['cache', 'cpu', 'cpu_info', 'diskdrive', 'memory', 'net', 'os', 'process', 'service', 'tcp', 'time', 'update']) }}"
|
|
||||||
|
|
||||||
- name: Define Windows Exporter defaults
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
__nssm_url: "https://nssm.cc/release/nssm-{{ nssm_version }}.zip"
|
|
||||||
__prometheus_zip_url: "https://github.com/prometheus/prometheus/releases/download/v{{ prometheus_version }}/prometheus-{{ prometheus_version }}.windows-amd64.zip"
|
|
||||||
__prometheus_zip_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\prometheus-{{ prometheus_version }}.zip"
|
__prometheus_zip_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\prometheus-{{ prometheus_version }}.zip"
|
||||||
__prometheus_home: "{{ prometheus_install_dir }}\\prometheus-{{ prometheus_version }}.windows-amd64"
|
__prometheus_home: "{{ prometheus_install_dir }}\\prometheus-{{ prometheus_version }}.windows-amd64"
|
||||||
__windows_exporter_msi_url: "https://github.com/prometheus-community/windows_exporter/releases/download/v{{ windows_exporter_version }}/windows_exporter-{{ windows_exporter_version }}-amd64.msi"
|
__windows_exporter_msi_url: >-
|
||||||
__windows_exporter_msi_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\windows_exporter-{{ windows_exporter_version }}-amd64.msi"
|
https://github.com/prometheus-community/windows_exporter/releases/download/v{{
|
||||||
__nssm_zip_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\nssm.zip"
|
windows_exporter_version }}/windows_exporter-{{ windows_exporter_version }}-amd64.msi
|
||||||
__nssm_exe: "{{ nssm_dir }}\\nssm.exe"
|
__windows_exporter_msi_path: "{{ (ansible_env.TEMP | default('C:\\Windows\\Temp')) }}\\windows_exporter-{{ windows_exporter_version }}.msi"
|
||||||
|
|
||||||
- name: Create Prometheus installation directories
|
- name: Create Prometheus installation directories
|
||||||
ansible.windows.win_file:
|
ansible.windows.win_file:
|
||||||
@@ -28,9 +19,8 @@
|
|||||||
loop:
|
loop:
|
||||||
- "{{ prometheus_install_dir }}"
|
- "{{ prometheus_install_dir }}"
|
||||||
- "{{ prometheus_install_dir }}\\data"
|
- "{{ prometheus_install_dir }}\\data"
|
||||||
- "{{ nssm_dir }}"
|
|
||||||
|
|
||||||
- name: Download required files (Prometheus, NSSM, Windows Exporter)
|
- name: Download required files (Prometheus, Windows Exporter)
|
||||||
ansible.windows.win_get_url:
|
ansible.windows.win_get_url:
|
||||||
url: "{{ item.url }}"
|
url: "{{ item.url }}"
|
||||||
dest: "{{ item.dest }}"
|
dest: "{{ item.dest }}"
|
||||||
@@ -38,8 +28,6 @@
|
|||||||
loop:
|
loop:
|
||||||
- url: "{{ __prometheus_zip_url }}"
|
- url: "{{ __prometheus_zip_url }}"
|
||||||
dest: "{{ __prometheus_zip_path }}"
|
dest: "{{ __prometheus_zip_path }}"
|
||||||
- url: "{{ __nssm_url }}"
|
|
||||||
dest: "{{ __nssm_zip_path }}"
|
|
||||||
- url: "{{ __windows_exporter_msi_url }}"
|
- url: "{{ __windows_exporter_msi_url }}"
|
||||||
dest: "{{ __windows_exporter_msi_path }}"
|
dest: "{{ __windows_exporter_msi_path }}"
|
||||||
|
|
||||||
@@ -53,8 +41,6 @@
|
|||||||
- src: "{{ __prometheus_zip_path }}"
|
- src: "{{ __prometheus_zip_path }}"
|
||||||
dest: "{{ prometheus_install_dir }}"
|
dest: "{{ prometheus_install_dir }}"
|
||||||
creates: "{{ __prometheus_home }}\\prometheus.exe"
|
creates: "{{ __prometheus_home }}\\prometheus.exe"
|
||||||
- src: "{{ __nssm_zip_path }}"
|
|
||||||
dest: "{{ nssm_dir }}"
|
|
||||||
|
|
||||||
- name: Verify Prometheus binary is present
|
- name: Verify Prometheus binary is present
|
||||||
ansible.windows.win_stat:
|
ansible.windows.win_stat:
|
||||||
@@ -100,11 +86,9 @@
|
|||||||
failed_when: promtool_check.rc != 0
|
failed_when: promtool_check.rc != 0
|
||||||
when: promtool_bin.stat.exists
|
when: promtool_bin.stat.exists
|
||||||
|
|
||||||
- name: Copy NSSM executable (win64)
|
- name: Install NSSM
|
||||||
ansible.windows.win_copy:
|
ansible.builtin.include_role:
|
||||||
src: "{{ nssm_dir }}\\nssm-2.24\\win64\\nssm.exe"
|
name: nssm
|
||||||
dest: "{{ __nssm_exe }}"
|
|
||||||
remote_src: true
|
|
||||||
|
|
||||||
- name: Remove existing Prometheus service if present
|
- name: Remove existing Prometheus service if present
|
||||||
ansible.windows.win_service:
|
ansible.windows.win_service:
|
||||||
@@ -114,7 +98,7 @@
|
|||||||
|
|
||||||
- name: Install Prometheus service via NSSM
|
- name: Install Prometheus service via NSSM
|
||||||
ansible.windows.win_command: >-
|
ansible.windows.win_command: >-
|
||||||
"{{ __nssm_exe }}"
|
"nssm.exe"
|
||||||
install Prometheus
|
install Prometheus
|
||||||
"{{ __prometheus_home }}\prometheus.exe"
|
"{{ __prometheus_home }}\prometheus.exe"
|
||||||
--config.file={{ prometheus_install_dir }}\prometheus.yml
|
--config.file={{ prometheus_install_dir }}\prometheus.yml
|
||||||
@@ -129,21 +113,21 @@
|
|||||||
|
|
||||||
- name: Set Prometheus AppDirectory via NSSM
|
- name: Set Prometheus AppDirectory via NSSM
|
||||||
ansible.windows.win_command: >-
|
ansible.windows.win_command: >-
|
||||||
"{{ __nssm_exe }}" set Prometheus AppDirectory "{{ __prometheus_home }}"
|
"nssm.exe" set Prometheus AppDirectory "{{ __prometheus_home }}"
|
||||||
|
|
||||||
- name: Configure Prometheus stdout log via NSSM
|
- name: Configure Prometheus stdout log via NSSM
|
||||||
ansible.windows.win_command: >-
|
ansible.windows.win_command: >-
|
||||||
"{{ __nssm_exe }}" set Prometheus AppStdout
|
"nssm.exe" set Prometheus AppStdout
|
||||||
"{{ prometheus_install_dir }}\prometheus-service.out.log"
|
"{{ prometheus_install_dir }}\prometheus-service.out.log"
|
||||||
|
|
||||||
- name: Configure Prometheus stderr log via NSSM
|
- name: Configure Prometheus stderr log via NSSM
|
||||||
ansible.windows.win_command: >-
|
ansible.windows.win_command: >-
|
||||||
"{{ __nssm_exe }}" set Prometheus AppStderr
|
"nssm.exe" set Prometheus AppStderr
|
||||||
"{{ prometheus_install_dir }}\prometheus-service.err.log"
|
"{{ prometheus_install_dir }}\prometheus-service.err.log"
|
||||||
|
|
||||||
- name: Set Prometheus Start mode to AUTO via NSSM
|
- name: Set Prometheus Start mode to AUTO via NSSM
|
||||||
ansible.windows.win_command: >-
|
ansible.windows.win_command: >-
|
||||||
"{{ __nssm_exe }}" set Prometheus Start SERVICE_AUTO_START
|
"nssm.exe" set Prometheus Start SERVICE_AUTO_START
|
||||||
|
|
||||||
- name: Ensure Prometheus service is running (skip in check mode)
|
- name: Ensure Prometheus service is running (skip in check mode)
|
||||||
ansible.windows.win_service:
|
ansible.windows.win_service:
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ galaxy_info:
|
|||||||
license: MIT
|
license: MIT
|
||||||
min_ansible_version: "2.1"
|
min_ansible_version: "2.1"
|
||||||
platforms:
|
platforms:
|
||||||
- name: windows
|
- name: Windows
|
||||||
|
|||||||
@@ -69,12 +69,14 @@
|
|||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
- name: Install OpenSSH Server capability when not installed
|
- name: Install OpenSSH Server capability when not installed
|
||||||
|
become: true
|
||||||
|
become_method: ansible.builtin.runas
|
||||||
|
become_user: "NT AUTHORITY\\SYSTEM"
|
||||||
ansible.windows.win_shell: |
|
ansible.windows.win_shell: |
|
||||||
$cap = Get-WindowsCapability -Online | Where-Object { $_.Name -like 'OpenSSH.Server*' } | Select-Object -First 1
|
$cap = Get-WindowsCapability -Online | Where-Object { $_.Name -like 'OpenSSH.Server*' } | Select-Object -First 1
|
||||||
if (-not $cap) {
|
if (-not $cap) {
|
||||||
throw 'OpenSSH.Server capability not found on this host.'
|
throw 'OpenSSH.Server capability not found on this host.'
|
||||||
}
|
}
|
||||||
|
|
||||||
Add-WindowsCapability -Online -Name $cap.Name
|
Add-WindowsCapability -Online -Name $cap.Name
|
||||||
args:
|
args:
|
||||||
executable: powershell.exe
|
executable: powershell.exe
|
||||||
@@ -149,8 +151,10 @@
|
|||||||
if ($keys -and $keys.Count -gt 0) {
|
if ($keys -and $keys.Count -gt 0) {
|
||||||
foreach ($k in $keys) {
|
foreach ($k in $keys) {
|
||||||
$before = (Get-Acl -Path $k.FullName).Sddl
|
$before = (Get-Acl -Path $k.FullName).Sddl
|
||||||
icacls.exe $k.FullName /inheritance:r
|
icacls.exe $k.FullName /inheritance:r | Out-Null
|
||||||
icacls.exe $k.FullName /grant:r "S-1-5-18:(F)"
|
if ($LASTEXITCODE -ne 0) { throw "icacls failed to disable inheritance on $($k.FullName)" }
|
||||||
|
icacls.exe $k.FullName /grant:r "*S-1-5-18:(F)" | Out-Null
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "icacls failed to grant SYSTEM on $($k.FullName)" }
|
||||||
if ($removePrincipal -and $removePrincipal -notmatch '^(?i:NT AUTHORITY\\SYSTEM|SYSTEM)$') {
|
if ($removePrincipal -and $removePrincipal -notmatch '^(?i:NT AUTHORITY\\SYSTEM|SYSTEM)$') {
|
||||||
icacls.exe $k.FullName /remove "$removePrincipal" 2>$null
|
icacls.exe $k.FullName /remove "$removePrincipal" 2>$null
|
||||||
}
|
}
|
||||||
@@ -181,8 +185,10 @@
|
|||||||
if (Test-Path $p) {
|
if (Test-Path $p) {
|
||||||
$before = (Get-Acl -Path $p).Sddl
|
$before = (Get-Acl -Path $p).Sddl
|
||||||
icacls.exe $p /inheritance:r | Out-Null
|
icacls.exe $p /inheritance:r | Out-Null
|
||||||
icacls.exe $p /grant:r "S-1-5-18:(OI)(CI)(F)" "S-1-5-32-544:(OI)(CI)(F)" | Out-Null
|
if ($LASTEXITCODE -ne 0) { throw "icacls failed to disable inheritance on $p" }
|
||||||
icacls.exe $p /remove "S-1-5-32-545" 2>$null
|
icacls.exe $p /grant:r "*S-1-5-18:(OI)(CI)(F)" "*S-1-5-32-544:(OI)(CI)(F)" | Out-Null
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "icacls failed to grant SYSTEM/Administrators on $p" }
|
||||||
|
icacls.exe $p /remove "*S-1-5-32-545" 2>$null
|
||||||
$after = (Get-Acl -Path $p).Sddl
|
$after = (Get-Acl -Path $p).Sddl
|
||||||
if ($before -ne $after) {
|
if ($before -ne $after) {
|
||||||
Write-Output 'ssh-dir-acl-changed'
|
Write-Output 'ssh-dir-acl-changed'
|
||||||
@@ -289,10 +295,34 @@
|
|||||||
become_user: "NT AUTHORITY\\SYSTEM"
|
become_user: "NT AUTHORITY\\SYSTEM"
|
||||||
|
|
||||||
- name: Deploy authorized_keys for each user
|
- name: Deploy authorized_keys for each user
|
||||||
ansible.windows.win_copy:
|
ansible.windows.win_shell: |
|
||||||
dest: "C:\\Users\\{{ item.name }}\\.ssh\\authorized_keys"
|
$path = "C:\Users\{{ item.name }}\.ssh\authorized_keys"
|
||||||
content: "{{ (item['keys'] | default([])) | join('\r\n') }}\r\n"
|
$json = @'
|
||||||
force: true
|
{{ (item['keys'] | default([])) | to_json }}
|
||||||
|
'@
|
||||||
|
$keys = $json | ConvertFrom-Json
|
||||||
|
if ($null -eq $keys) {
|
||||||
|
$keys = @()
|
||||||
|
} elseif ($keys -isnot [System.Array]) {
|
||||||
|
$keys = @($keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
$newContent = [string]::Join([Environment]::NewLine, $keys)
|
||||||
|
if ($keys.Count -gt 0) {
|
||||||
|
$newContent += [Environment]::NewLine
|
||||||
|
}
|
||||||
|
|
||||||
|
$oldContent = if (Test-Path $path) { [System.IO.File]::ReadAllText($path) } else { '' }
|
||||||
|
if ($oldContent -ne $newContent) {
|
||||||
|
[System.IO.File]::WriteAllText($path, $newContent, [System.Text.Encoding]::UTF8)
|
||||||
|
Write-Output 'authorized-keys-updated'
|
||||||
|
} else {
|
||||||
|
Write-Output 'authorized-keys-unchanged'
|
||||||
|
}
|
||||||
|
args:
|
||||||
|
executable: powershell.exe
|
||||||
|
register: user_authorized_keys_result
|
||||||
|
changed_when: "'authorized-keys-updated' in user_authorized_keys_result.stdout"
|
||||||
loop: "{{ __ssh_users__ | default([]) }}"
|
loop: "{{ __ssh_users__ | default([]) }}"
|
||||||
loop_control:
|
loop_control:
|
||||||
label: "{{ item.name }}"
|
label: "{{ item.name }}"
|
||||||
@@ -333,12 +363,34 @@
|
|||||||
become_user: "NT AUTHORITY\\SYSTEM"
|
become_user: "NT AUTHORITY\\SYSTEM"
|
||||||
|
|
||||||
- name: Create administrators_authorized_keys from admin users' keys (if any)
|
- name: Create administrators_authorized_keys from admin users' keys (if any)
|
||||||
ansible.windows.win_copy:
|
ansible.windows.win_shell: |
|
||||||
dest: 'C:\ProgramData\ssh\administrators_authorized_keys'
|
$path = 'C:\ProgramData\ssh\administrators_authorized_keys'
|
||||||
content: >-
|
$json = @'
|
||||||
{{ (__ssh_users__ | default([]) | selectattr('admin', 'equalto', true)
|
{{ (__ssh_users__ | default([]) | selectattr('admin', 'equalto', true) | map(attribute='keys') | list | flatten | default([])) | to_json }}
|
||||||
| map(attribute='keys') | list | flatten | default([])) | join('\r\n') }}\r\n
|
'@
|
||||||
force: true
|
$keys = $json | ConvertFrom-Json
|
||||||
|
if ($null -eq $keys) {
|
||||||
|
$keys = @()
|
||||||
|
} elseif ($keys -isnot [System.Array]) {
|
||||||
|
$keys = @($keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
$newContent = [string]::Join([Environment]::NewLine, $keys)
|
||||||
|
if ($keys.Count -gt 0) {
|
||||||
|
$newContent += [Environment]::NewLine
|
||||||
|
}
|
||||||
|
|
||||||
|
$oldContent = if (Test-Path $path) { [System.IO.File]::ReadAllText($path) } else { '' }
|
||||||
|
if ($oldContent -ne $newContent) {
|
||||||
|
[System.IO.File]::WriteAllText($path, $newContent, [System.Text.Encoding]::UTF8)
|
||||||
|
Write-Output 'admin-authorized-keys-updated'
|
||||||
|
} else {
|
||||||
|
Write-Output 'admin-authorized-keys-unchanged'
|
||||||
|
}
|
||||||
|
args:
|
||||||
|
executable: powershell.exe
|
||||||
|
register: admin_authorized_keys_result
|
||||||
|
changed_when: "'admin-authorized-keys-updated' in admin_authorized_keys_result.stdout"
|
||||||
when: (__ssh_users__ | default([]) | selectattr('admin','equalto',true) | list) | length > 0
|
when: (__ssh_users__ | default([]) | selectattr('admin','equalto',true) | list) | length > 0
|
||||||
become: true
|
become: true
|
||||||
become_method: ansible.builtin.runas
|
become_method: ansible.builtin.runas
|
||||||
@@ -350,7 +402,9 @@
|
|||||||
if (Test-Path $path) {
|
if (Test-Path $path) {
|
||||||
$before = (Get-Acl -Path $path).Sddl
|
$before = (Get-Acl -Path $path).Sddl
|
||||||
icacls.exe $path /inheritance:r | Out-Null
|
icacls.exe $path /inheritance:r | Out-Null
|
||||||
icacls.exe $path /grant:r "S-1-5-18:(F)" "S-1-5-32-544:(F)" | Out-Null
|
if ($LASTEXITCODE -ne 0) { throw "icacls failed to disable inheritance on $path" }
|
||||||
|
icacls.exe $path /grant:r "*S-1-5-18:(F)" "*S-1-5-32-544:(F)" | Out-Null
|
||||||
|
if ($LASTEXITCODE -ne 0) { throw "icacls failed to grant SYSTEM/Administrators on $path" }
|
||||||
$after = (Get-Acl -Path $path).Sddl
|
$after = (Get-Acl -Path $path).Sddl
|
||||||
if ($before -ne $after) {
|
if ($before -ne $after) {
|
||||||
Write-Output 'admin-auth-keys-acl-changed'
|
Write-Output 'admin-auth-keys-acl-changed'
|
||||||
|
|||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../sectool.json
|
||||||
@@ -129,3 +129,6 @@ gpu-01.lab.alexpires.me
|
|||||||
[gpu_monitoring]
|
[gpu_monitoring]
|
||||||
gpu-01.lab.alexpires.me
|
gpu-01.lab.alexpires.me
|
||||||
|
|
||||||
|
[windows_containers]
|
||||||
|
ci-01.lab.alexpires.me
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ datasources:
|
|||||||
timeInterval: 15s
|
timeInterval: 15s
|
||||||
- name: prometheus-ci-01
|
- name: prometheus-ci-01
|
||||||
type: prometheus
|
type: prometheus
|
||||||
url: http://ci-01.lab.alexpires.me:9090
|
url: http://10.19.4.207:9090
|
||||||
isDefault: false
|
isDefault: false
|
||||||
editable: false
|
editable: false
|
||||||
jsonData:
|
jsonData:
|
||||||
@@ -19,7 +19,7 @@ datasources:
|
|||||||
timeInterval: 15s
|
timeInterval: 15s
|
||||||
- name: prometheus-gpu-01
|
- name: prometheus-gpu-01
|
||||||
type: prometheus
|
type: prometheus
|
||||||
url: http://gpu-01.lab.alexpires.me:9091
|
url: http://10.19.4.106:9091
|
||||||
isDefault: false
|
isDefault: false
|
||||||
editable: false
|
editable: false
|
||||||
jsonData:
|
jsonData:
|
||||||
|
|||||||
Reference in New Issue
Block a user