--- # ── 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