--- # windows_ollama_models.yml — Manage local Ollama model variants on Windows GPU hosts. # # This is the small, Ansible-like control surface for the two Windows NVIDIA # machines that run Ollama for Prole embedding workloads. # # Usage: # cd infrastructure # ansible-playbook playbooks/windows_ollama_models.yml --ask-pass # # Single host: # ansible-playbook playbooks/windows_ollama_models.yml --limit morgoth.prole.org --ask-pass # # Dry-run intent only: # ansible-playbook playbooks/windows_ollama_models.yml --check --diff --ask-pass # # Inventory target: # [workstations_windows] # morgoth.prole.org # fairyland.prole.org # # What this deploys: # ollama create mxbai-embed-large-2k FROM mxbai-embed-large PARAMETER num_ctx 2048 # # The desired Modelfile is written to C:\ProgramData\Prole\Ollama\Models and a # SHA-256 marker is recorded after successful creation. Re-running the playbook # is safe: it recreates the model only when the target model is missing or the # managed Modelfile content changes. - name: Configure Prole Ollama models on Windows GPU hosts hosts: workstations_windows gather_facts: false become: false vars: ansible_become: false ansible_become_method: runas prole_ollama_models_dir: 'C:\ProgramData\Prole\Ollama\Models' prole_ollama_models: - name: mxbai-embed-large-2k base: mxbai-embed-large parameters: num_ctx: 2048 # Override per-host if WinRM cannot see ollama.exe in PATH. # Common installs include: # C:\Program Files\Ollama\ollama.exe # C:\Users\\AppData\Local\Programs\Ollama\ollama.exe ollama_windows_exe: '' tasks: - name: Resolve ollama.exe path ansible.windows.win_shell: | $ErrorActionPreference = 'Stop' $candidates = @() if ('{{ ollama_windows_exe }}') { $candidates += '{{ ollama_windows_exe }}' } $cmd = Get-Command ollama.exe -ErrorAction SilentlyContinue if ($cmd) { $candidates += $cmd.Source } $candidates += @( 'C:\Program Files\Ollama\ollama.exe', 'C:\Users\{{ ansible_user }}\AppData\Local\Programs\Ollama\ollama.exe' ) foreach ($candidate in $candidates | Select-Object -Unique) { if ($candidate -and (Test-Path -LiteralPath $candidate)) { Write-Output $candidate exit 0 } } throw 'ollama.exe was not found. Set ollama_windows_exe for this host or install Ollama first.' args: executable: powershell.exe register: ollama_exe_result changed_when: false - name: Set resolved Ollama executable fact ansible.builtin.set_fact: ollama_resolved_exe: "{{ ollama_exe_result.stdout_lines[0] }}" - name: Ensure Prole Ollama model state directory exists ansible.windows.win_file: path: "{{ prole_ollama_models_dir }}" state: directory - name: Show planned Ollama model configuration in check mode ansible.builtin.debug: msg: >- Would ensure {{ item.name }} exists from {{ item.base }} with num_ctx={{ item.parameters.num_ctx }} using {{ ollama_resolved_exe }}. loop: "{{ prole_ollama_models }}" when: ansible_check_mode - name: Create or update managed Ollama model variants ansible.windows.win_shell: | $ErrorActionPreference = 'Stop' $ollama = '{{ ollama_resolved_exe }}' $modelName = '{{ item.name }}' $baseModel = '{{ item.base }}' $modelDir = '{{ prole_ollama_models_dir }}' $modelfilePath = Join-Path $modelDir "$modelName.Modelfile" $markerPath = Join-Path $modelDir "$modelName.Modelfile.sha256" $modelfile = @" FROM {{ item.base }} PARAMETER num_ctx {{ item.parameters.num_ctx }} "@.TrimStart() Set-Content -LiteralPath $modelfilePath -Value $modelfile -Encoding ascii -NoNewline $desiredHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $modelfilePath).Hash $recordedHash = if (Test-Path -LiteralPath $markerPath) { (Get-Content -LiteralPath $markerPath -Raw).Trim() } else { '' } & $ollama show $modelName *> $null $modelExists = ($LASTEXITCODE -eq 0) if ($modelExists -and ($recordedHash -eq $desiredHash)) { Write-Output "unchanged: $modelName already matches managed Modelfile" exit 0 } & $ollama pull $baseModel if ($LASTEXITCODE -ne 0) { throw "ollama pull failed for $baseModel" } & $ollama create $modelName -f $modelfilePath if ($LASTEXITCODE -ne 0) { throw "ollama create failed for $modelName" } Set-Content -LiteralPath $markerPath -Value $desiredHash -Encoding ascii -NoNewline Write-Output "changed: created or updated $modelName from $baseModel" args: executable: powershell.exe loop: "{{ prole_ollama_models }}" register: ollama_model_results changed_when: "'changed:' in ollama_model_results.stdout" when: not ansible_check_mode - name: Verify managed Ollama model variants ansible.windows.win_shell: | $ErrorActionPreference = 'Stop' & '{{ ollama_resolved_exe }}' list args: executable: powershell.exe register: ollama_list_result changed_when: false when: not ansible_check_mode - name: Show Ollama model list ansible.builtin.debug: var: ollama_list_result.stdout_lines when: not ansible_check_mode