diff --git a/AGENTS.md b/AGENTS.md index 8284f36..f70d793 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # AGENTS.md -Ansible-driven personal infrastructure repo for Void desktops, Linux workstations, Windows+WSL, and an Ubuntu server. +Ansible-driven personal infrastructure repo for Void desktops, Linux workstations, WSL, and an Ubuntu server. ## Source Of Truth - Main orchestration: `ansible/site.yml` @@ -12,8 +12,8 @@ Ansible-driven personal infrastructure repo for Void desktops, Linux workstation ## Topology - Void desktops: `ikaros`, `nymph` -- Native Linux workstations: `deadalus-ubuntu`, `deadalus-fedora` -- Windows host + WSL dev: `deadalus-win`, `deadalus-wsl` +- Native Linux workstation: `deadalus-fedora` +- WSL dev: `deadalus-wsl` - Ubuntu server: `prometheus` - Hosts intentionally belong to multiple groups; trust `ansible/site.yml` over hostname assumptions. @@ -21,7 +21,7 @@ Ansible-driven personal infrastructure repo for Void desktops, Linux workstation - Preserve layering `all -> OS -> profile -> host`. - Keep `ansible/site.yml` small; orchestration belongs there, implementation belongs in roles. - Prefer minimal, targeted edits. Preserve idempotency and existing ordering. -- Most hosts use `ansible_connection: local`; Windows host is the exception. +- All hosts use `ansible_connection: local`. - Treat `secrets/` as sensitive. Never print secret values. - Tmux plugins are bootstrapped by TPM on the host; the repo only keeps tmux config and custom helper scripts. - Read the relevant role tasks, templates, vars, and deployed dotfiles before editing. @@ -35,14 +35,12 @@ Ansible-driven personal infrastructure repo for Void desktops, Linux workstation - `yamllint ansible/` - Host-focused dry runs: - Void desktop work: `ansible-playbook ansible/site.yml --limit ikaros --check --diff` or `--limit nymph --check --diff` - - Ubuntu workstation: `ansible-playbook ansible/site.yml --limit deadalus-ubuntu --check --diff` - Fedora workstation: `ansible-playbook ansible/site.yml --limit deadalus-fedora --check --diff` - WSL dev: `ansible-playbook ansible/site.yml --limit deadalus-wsl --check --diff` - Server: `ansible-playbook ansible/site.yml --limit prometheus --check --diff` - Focused checks: - Emacs dotfiles only: `ansible-playbook ansible/site.yml --limit ikaros --tags emacs --check --diff` or `--limit nymph --tags emacs --check --diff` - Mail bootstrap: `sh -n scripts/bootstrap_mail.sh` and `shellcheck scripts/bootstrap_mail.sh` - - Windows bootstrap parse: `pwsh -NoProfile -Command "[void][System.Management.Automation.Language.Parser]::ParseFile('scripts/bootstrap_windows_workstation.ps1', [ref]$null, [ref]$null)"` - Server compose render: `docker compose -f /opt/docker/server/docker-compose.yml config` ## Conventions @@ -74,12 +72,9 @@ The four Void desktop package lists in `ansible/inventory/group_vars/void.yml` a `profile_packages` in the same file is cross-distro and is overridden by `group_vars/server.yml` and the workstation group vars; do not move desktop-specific Void entries through it. The dotfile vars follow the same split: `desktop_common_dotfiles` (in `group_vars/desktop.yml`) carries WM-agnostic GUI config and user scripts (Thunar, mimeapps, GTK theme setup, Udiskie, fontconfig, WirePlumber, mpv, …); `desktop_void_dotfiles` (in `group_vars/void.yml`) is reserved for files that need Void runtime (turnstile services, bash runit/dbus/ssh-agent fragments, `update-turnstile-env`). -## Workstation / Windows Notes +## Workstation Notes - Native Linux workstation hosts can combine `workstation_host_linux` with an OS-specific dev group. - `deadalus-fedora` keeps GNOME managed settings in `ansible/inventory/host_vars/deadalus-fedora.yml`. -- Ubuntu workstation follow-up work is still open around YubiKey/GPG/SSH-FIDO2 package verification, GPG signing setup on the YubiKey, and evaluating `ed25519-sk` SSH key generation. -- `workstation_host_windows` runs with `gather_facts: false` and validates PSRP settings plus `windows_package_backend` before role execution. -- Windows taskbar pins are driven by `windows_taskbar_pins` in `ansible/inventory/group_vars/workstation_host_windows.yml`; validate identifiers from a real Windows session before changing them. ## Coding Agent Notes - Shared agent packages live in `ai_agents_npm_packages` in `ansible/inventory/group_vars/all.yml`. @@ -92,7 +87,7 @@ The dotfile vars follow the same split: `desktop_common_dotfiles` (in `group_var - Install local tooling with: - `python3 -m pip install ansible ansible-lint yamllint shellcheck-py` - `ansible-galaxy collection install -r ansible/collections/requirements.yml` -- Required collections currently include `ansible.posix`, `ansible.windows`, `community.general`, and `community.windows`. +- Required collections currently include `ansible.posix` and `community.general`. - `.yamllint` treats `line-length` as a warning at 120 chars and disables `document-start` and `comments-indentation`. ## When Updating Docs diff --git a/CLAUDE.md b/CLAUDE.md index 9e21055..a6d1a2d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## What this repo is -Ansible-driven personal infrastructure as code for Void Linux desktops (`ikaros`, `nymph`), Linux/Windows workstations (`deadalus-*`), and an Ubuntu server (`prometheus`). See `AGENTS.md` for topology and `README.md` for full profile descriptions. +Ansible-driven personal infrastructure as code for Void Linux desktops (`ikaros`, `nymph`), Linux workstations (`deadalus-fedora`, `deadalus-wsl`), and an Ubuntu server (`prometheus`). See `AGENTS.md` for topology and `README.md` for full profile descriptions. ## Validation commands @@ -15,7 +15,6 @@ ansible-playbook ansible/site.yml --syntax-check # Dry-run per host ansible-playbook ansible/site.yml --limit ikaros --check --diff ansible-playbook ansible/site.yml --limit nymph --check --diff -ansible-playbook ansible/site.yml --limit deadalus-ubuntu --check --diff ansible-playbook ansible/site.yml --limit deadalus-fedora --check --diff ansible-playbook ansible/site.yml --limit deadalus-wsl --check --diff ansible-playbook ansible/site.yml --limit prometheus --check --diff @@ -34,7 +33,7 @@ sh -n scripts/bootstrap_mail.sh && shellcheck scripts/bootstrap_mail.sh ## Architecture -Configuration is composed in layers: `all → OS → profile → host`. Most hosts use `ansible_connection: local`; `deadalus-win` is the PSRP/Windows exception. +Configuration is composed in layers: `all → OS → profile → host`. All hosts use `ansible_connection: local`. `ansible/site.yml` is the sole orchestration entry point — keep it thin. Implementation belongs in roles under `ansible/roles/`. diff --git a/README.md b/README.md index b2b9b39..5c87e6e 100644 --- a/README.md +++ b/README.md @@ -55,13 +55,13 @@ Il repository è diviso in due componenti principali: # Macchine gestite -Il repository modella attualmente tre tipologie di profilo e prepara due filoni workstation: Linux nativa e Windows + WSL. +Il repository modella attualmente tre tipologie di profilo, con i filoni workstation Linux nativa e WSL. Nota sullo stato attuale del playbook principale: - `ansible/site.yml` applica oggi in automatico il profilo desktop su host Void Linux - `ansible/site.yml` applica la workstation Linux nativa separando il layer dev comune dal layer host GNOME -- `ansible/site.yml` applica anche il ramo `workstation_host_windows` + `workstation_dev_wsl` per il modello Windows 11 + WSL +- `ansible/site.yml` applica anche il ramo `workstation_dev_wsl` per il modello dev in WSL - `ansible/site.yml` applica anche il profilo `ubuntu_server` con baseline apt, systemd, dotfiles server e firewall UFW ## Desktop @@ -107,9 +107,8 @@ Lo stato attuale del profilo desktop include, tra le altre cose: Sistemi operativi supportati: -- Ubuntu LTS nativa - Fedora Workstation nativa -- Windows 11 host + Ubuntu WSL +- Ubuntu WSL Desktop environment host Linux: @@ -117,9 +116,8 @@ Desktop environment host Linux: Macchine attuali: -- `deadalus-ubuntu` come workstation Ubuntu nativa - `deadalus-fedora` come workstation Fedora nativa -- supporto attivo per host Windows 11 + WSL tramite `deadalus-win` e `deadalus-wsl` +- `deadalus-wsl` come ambiente dev Ubuntu in WSL Questo profilo è pensato per sviluppo e lavoro, con separazione tra layer host e layer dev. @@ -127,13 +125,12 @@ Nel modello Ansible usato qui, un singolo inventory host puo appartenere intenzi Il profilo workstation e agganciato al playbook principale e ora distingue: -- layer dev Ubuntu condiviso tra workstation Linux nativa e Ubuntu in WSL -- layer dev Fedora nativo parallelo a Ubuntu +- layer dev Ubuntu condiviso tra WSL e server +- layer dev Fedora nativo - layer host Linux GNOME -- layer host Windows 11 con bootstrap WSL, remoting `PSRP` su `HTTPS/5986`, gestione app via `winget` con backend configurabile e VS Code lato Windows - layer WSL dedicato per sviluppo con `systemd` -Per esempio, lo stesso host Linux puo stare in `workstation_host_linux` e in `workstation_dev_fedora` oppure `workstation_dev_ubuntu`, a seconda del layering che vuoi comporre. +Per esempio, lo stesso host Linux puo stare in `workstation_host_linux` e in `workstation_dev_fedora`, a seconda del layering che vuoi comporre. Lo stato attuale del profilo workstation include: @@ -141,42 +138,18 @@ Lo stato attuale del profilo workstation include: - installazione pacchetti base Fedora via dnf per il ramo workstation nativo - installazione e configurazione di Docker dal repository ufficiale - gestione dei dotfiles workstation e rendering dei template dev condivisi -- installazione di Google Chrome su Ubuntu e Fedora, `VS Code` su Fedora via repository RPM Microsoft, `IntelliJ IDEA Ultimate` su Fedora via COPR RPM, e applicazioni workstation residue su Fedora via Flatpak -- installazione di applicazioni workstation su Ubuntu nativa via Snap, oltre alle estensioni GNOME sul solo host Linux nativo -- configurazione del ramo Windows 11 host con app installate dal playbook via `winget`, con backend predefinito `winget_psrp`, tema scuro, pin della taskbar gestiti via policy locale e profilo predefinito di Windows Terminal impostato su `Ubuntu` +- installazione di Google Chrome su Fedora, `VS Code` su Fedora via repository RPM Microsoft, `IntelliJ IDEA Ultimate` su Fedora via COPR RPM, e applicazioni workstation residue su Fedora via Flatpak +- estensioni GNOME sul solo host Linux nativo - preparazione del ramo WSL Ubuntu con `systemd` per il toolchain di sviluppo -- attivazione del firewall UFW su Ubuntu nativa e `firewalld` su Fedora nativa +- attivazione del firewall `firewalld` su Fedora nativa - gestione di `gsettings` GNOME host-specifici su `deadalus-fedora`, inclusi shell, Files/Nautilus, file chooser GTK e GNOME Text Editor, allineati allo stato reale della macchina -Workflow Windows + WSL previsto: +Workflow WSL previsto: -Prima di eseguire il bootstrap Windows, apri PowerShell come amministratore e verifica la policy di esecuzione: - -```powershell -Get-ExecutionPolicy -List -``` - -Se necessario, abilita l'esecuzione degli script per l'utente corrente: - -```powershell -Set-ExecutionPolicy -Scope CurrentUser RemoteSigned -``` - -Se Windows ha bloccato il file di bootstrap, sbloccalo esplicitamente: - -```powershell -Unblock-File .\scripts\bootstrap_windows_workstation.ps1 -``` - -1. eseguire `scripts/bootstrap_windows_workstation.ps1` su Windows come amministratore -2. riavviare Windows se richiesto dalle feature WSL -3. avviare Ubuntu WSL almeno una volta e completare la creazione dell'utente Linux -4. installare Ansible dentro WSL Ubuntu -5. lanciare il playbook da WSL su `deadalus-wsl` per configurare l'ambiente dev locale -6. lanciare da WSL anche il playbook su `deadalus-win` via `psrp` per configurare l'host Windows; per default il backend pacchetti Windows e `winget_psrp` -7. usare VS Code con le estensioni Remote (`WSL`, `SSH`, `Dev Containers`) dal lato Windows - -Per il remoting Windows il repository usa di default `PSRP` con `Negotiate` su `HTTPS/5986`. L'utente di default puo essere un `MicrosoftAccount\...`, con host, utente e password forniti via vault o extra vars. Il backend pacchetti Windows e configurabile con `windows_package_backend` oppure `vault_windows_package_backend`; il default e `winget_psrp`. +1. avviare Ubuntu WSL almeno una volta e completare la creazione dell'utente Linux +2. installare Ansible dentro WSL Ubuntu +3. lanciare il playbook da WSL su `deadalus-wsl` per configurare l'ambiente dev locale +4. usare VS Code con le estensioni Remote (`WSL`, `SSH`, `Dev Containers`) dal lato Windows --- @@ -281,7 +254,6 @@ I principali ruoli attualmente presenti sono: | profile_workstation_dev_common | configurazione dev workstation condivisa | | profile_workstation_gnome | configurazione host workstation GNOME | | profile_workstation_dev_wsl | configurazione WSL Ubuntu per sviluppo | -| profile_workstation_host_windows | configurazione host Windows 11 workstation | | profile_server | configurazione server | | dotfiles_common | distribuzione dotfiles comuni | | dotfiles | distribuzione configurazioni utente | @@ -290,25 +262,22 @@ I principali ruoli attualmente presenti sono: # Stato attuale del playbook principale -Il playbook `ansible/site.yml` e attualmente composto da sette blocchi: +Il playbook `ansible/site.yml` e attualmente composto da sei blocchi: ```text -all:!workstation_host_windows -> dotfiles_common +all -> dotfiles_common void -> packages_void + services_runit + profile_desktop_common + profile_desktop_i3 + profile_desktop_sway + profile_desktop_hyprland + profile_desktop_host -workstation_dev_ubuntu -> packages_ubuntu + services_systemd + profile_workstation_dev_common workstation_dev_fedora -> packages_fedora + services_systemd + profile_workstation_dev_common workstation_host_linux -> profile_workstation_gnome workstation_dev_wsl -> packages_ubuntu + services_systemd + profile_workstation_dev_common + profile_workstation_dev_wsl -workstation_host_windows -> profile_workstation_host_windows ubuntu_server -> packages_ubuntu + services_systemd + profile_server ``` Questo significa che, allo stato attuale: - i desktop Void (`ikaros`, `nymph`) restano il target operativo piu completo -- la workstation Ubuntu (`deadalus-ubuntu`) e gestita separando ambiente dev e layer host GNOME -- la workstation Fedora (`deadalus-fedora`) usa lo stesso principio di composizione a gruppi con il ramo Fedora dedicato e con `gsettings` host-specifici dichiarati in inventory -- il ramo Windows + WSL e predisposto con bootstrap PowerShell e play Windows/WSL dedicati +- la workstation Fedora (`deadalus-fedora`) usa il principio di composizione a gruppi con il ramo Fedora dedicato e con `gsettings` host-specifici dichiarati in inventory +- il ramo WSL (`deadalus-wsl`) e predisposto con play dev dedicato - il server Ubuntu (`prometheus`) e gestito con pacchetti, servizi, dotfiles server e firewall - lo stack container server include `navidrome`, `postgres`, `gitea`, `nginx-proxy-manager` e `syncthing`, con GUI Syncthing raggiungibile tramite la rete Docker `web` @@ -366,7 +335,6 @@ Gestione segreti: - `secrets/vault.yml.example` funge da template/esempio - se `secrets/vault.yml` non e presente, il playbook continua comunque senza caricare variabili locali opzionali - se `secrets/.vault_pass.gpg` esiste viene usato automaticamente per sbloccare i vault tramite `gpg`; in alternativa resta supportato `secrets/.vault_pass` come fallback legacy locale; se nessuno dei due file esiste Ansible richiede la password in modo interattivo -- per il ramo Windows puoi anche definire `vault_windows_package_backend`, con valori supportati `winget_psrp` e `winget_wsl_local`; il default e `winget_psrp` --- @@ -382,11 +350,9 @@ Allo stato attuale questo comando: - distribuisce i dotfiles comuni a tutti gli host - per gli host Void applica bootstrap desktop condiviso, sessione i3 e override specifici per host -- per `workstation_dev_ubuntu` applica pacchetti Ubuntu, servizi systemd e profilo dev comune - per `workstation_dev_fedora` applica pacchetti Fedora, servizi systemd e profilo dev comune - per `workstation_host_linux` applica il layer host Linux GNOME - per `workstation_dev_wsl` applica pacchetti Ubuntu, servizi systemd, profilo dev comune e tweak WSL dedicati -- per `workstation_host_windows` applica il layer host Windows 11 via PSRP, con installazione pacchetti Windows eseguita di default tramite `winget_psrp` - per gli host `ubuntu_server` applica pacchetti Ubuntu, servizi systemd, profilo server, UFW, dotfiles e template dedicati - non riavvia automaticamente `emptty`; le modifiche al display manager vanno applicate manualmente da SSH o da una TTY separata - carica `secrets/vault.yml` solo se presente @@ -398,7 +364,6 @@ Per validare prima di applicare: ansible-playbook ansible/site.yml --syntax-check ansible-playbook ansible/site.yml --limit ikaros --check --diff ansible-playbook ansible/site.yml --limit nymph --check --diff -ansible-playbook ansible/site.yml --limit deadalus-ubuntu --check --diff ansible-playbook ansible/site.yml --limit deadalus-fedora --check --diff ansible-playbook ansible/site.yml --limit deadalus-wsl --check --diff ansible-playbook ansible/site.yml --limit prometheus --check --diff @@ -435,7 +400,7 @@ Allo stato attuale `ansible/site.yml` espone questi tag: | Tag | Scopo | Ambito principale | | --- | --- | --- | -| `always` | pre-task sempre eseguiti, inclusi caricamento vault e validazioni preliminari | common, Windows | +| `always` | pre-task sempre eseguiti, inclusi caricamento vault e validazioni preliminari | common | | `dotfiles` | distribuzione/configurazione dotfiles | tutti i profili | | `dotfiles:common` | dotfiles comuni condivisi | common, workstation, server | | `dotfiles:desktop` | dotfiles desktop | desktop Void | @@ -450,9 +415,9 @@ Allo stato attuale `ansible/site.yml` espone questi tag: | `npm` | installazione pacchetti npm globali | desktop Void, workstation Linux, WSL | | `nvidia` | componenti NVIDIA desktop | desktop Void | | `packages` | installazione e aggiornamento pacchetti | tutti i profili | -| `services` | gestione servizi runit/systemd/Windows | tutti i profili | -| `vscode` | installazione/configurazione VS Code | Fedora, host Linux, Windows | -| `wsl` | bootstrap e configurazione WSL | WSL, Windows | +| `services` | gestione servizi runit/systemd | tutti i profili | +| `vscode` | installazione/configurazione VS Code | Fedora, host Linux | +| `wsl` | bootstrap e configurazione WSL | WSL | Esempi pratici: diff --git a/ansible/collections/requirements.yml b/ansible/collections/requirements.yml index 6c949bf..92a0244 100644 --- a/ansible/collections/requirements.yml +++ b/ansible/collections/requirements.yml @@ -1,6 +1,4 @@ --- collections: - name: ansible.posix - - name: ansible.windows - name: community.general - - name: community.windows diff --git a/ansible/inventory/group_vars/workstation_dev_wsl.yml b/ansible/inventory/group_vars/workstation_dev_wsl.yml index d45e9ca..2a50925 100644 --- a/ansible/inventory/group_vars/workstation_dev_wsl.yml +++ b/ansible/inventory/group_vars/workstation_dev_wsl.yml @@ -19,9 +19,7 @@ workstation_removed_snap_packages: [] workstation_snap_packages: - name: glab classic: true -workstation_dev_wsl_python_packages: - - pypsrp - - pyspnego +workstation_dev_wsl_python_packages: [] workstation_wsl_systemd_enabled: true workstation_dev_wsl_dotfiles: - src: .gnupg/gpg-agent.conf diff --git a/ansible/inventory/group_vars/workstation_host_windows.yml b/ansible/inventory/group_vars/workstation_host_windows.yml deleted file mode 100644 index d3f6856..0000000 --- a/ansible/inventory/group_vars/workstation_host_windows.yml +++ /dev/null @@ -1,71 +0,0 @@ ---- -ansible_connection: psrp -ansible_psrp_auth: negotiate -ansible_psrp_cert_validation: ignore -ansible_psrp_protocol: https -ansible_port: 5986 -ansible_shell_type: powershell - -windows_enable_dark_theme: true -windows_hide_taskbar_search: true -windows_hide_taskbar_widgets: true -windows_terminal_default_profile_name: Ubuntu -windows_taskbar_layout_directory: 'C:\ProgramData\Infra\Windows' -windows_taskbar_layout_path: '{{ windows_taskbar_layout_directory }}\taskbar-layout.xml' -windows_taskbar_reapply_every_logon: false - -windows_taskbar_pins: - - type: desktop_application_id - id: Chrome - - type: desktop_application_id - id: Microsoft.Windows.Explorer - - type: app_user_model_id - id: Microsoft.OutlookForWindows_8wekyb3d8bbwe!Microsoft.OutlookforWindows - - type: app_user_model_id - id: MSTeams_8wekyb3d8bbwe!MSTeams - - type: app_user_model_id - id: 5319275A.WhatsAppDesktop_cv1g1gvanyjgm!App - - type: desktop_application_id - id: Telegram.TelegramDesktop - - type: desktop_application_id - id: Microsoft.VisualStudioCode - - type: desktop_application_link_path - path: '%APPDATA%\Microsoft\Windows\Start Menu\Programs\JetBrains Toolbox\IntelliJ IDEA Ultimate.lnk' - - type: desktop_application_id - id: com.squirrel.Postman.Postman - - type: app_user_model_id - id: Microsoft.WindowsTerminal_8wekyb3d8bbwe!App - - type: desktop_application_link_path - path: '%APPDATA%\Microsoft\Windows\Start Menu\Programs\DBeaver Community\DBeaver.lnk' - -windows_winget_packages: - - id: 7zip.7zip - name: 7-Zip - - id: Adobe.Acrobat.Reader.64-bit - name: Adobe Acrobat Reader - - id: DBeaver.DBeaver.Community - name: DBeaver Community - - id: Google.Chrome - name: Google Chrome - - id: JetBrains.IntelliJIDEA.Ultimate - name: IntelliJ IDEA Ultimate - - id: Logitech.OptionsPlus - name: Logitech Options+ - - id: Microsoft.VisualStudioCode - name: Visual Studio Code - - id: Microsoft.WindowsTerminal - name: Windows Terminal - - id: Postman.Postman - name: Postman - - id: Telegram.TelegramDesktop - name: Telegram Desktop - - id: 9NKSQGP7F2NH - name: WhatsApp - source: msstore - -windows_vscode_extensions: - - ms-vscode-remote.remote-containers - - ms-vscode-remote.remote-ssh - - ms-vscode-remote.remote-wsl - -windows_wsl_distribution_name: Ubuntu diff --git a/ansible/inventory/host_vars/deadalus-ubuntu.yml b/ansible/inventory/host_vars/deadalus-ubuntu.yml deleted file mode 100644 index 09b5e75..0000000 --- a/ansible/inventory/host_vars/deadalus-ubuntu.yml +++ /dev/null @@ -1,319 +0,0 @@ ---- -hostname: deadalus-ubuntu - -host_packages: [] -host_enabled_services: [] - -workstation_host_vscode_extensions: - - ms-vscode-remote.remote-containers - - ms-vscode-remote.remote-ssh - - ms-azuretools.vscode-docker - - redhat.vscode-yaml - - redhat.ansible - -workstation_gnome_managed_settings: - - schema: org.gnome.shell - key: favorite-apps - value: "['google-chrome.desktop', 'org.gnome.Nautilus.desktop', 'spotify_spotify.desktop', 'thunderbird_thunderbird.desktop', 'telegram-desktop_telegram-desktop.desktop', 'code_code.desktop', 'intellij-idea-ultimate_intellij-idea-ultimate.desktop', 'dbeaver-ce_dbeaver-ce.desktop', 'postman_postman.desktop', 'org.gnome.Ptyxis.desktop']" - - schema: org.gnome.shell - key: app-picker-layout - value: "[{'Utilities': <{'position': <0>}>, 'System': <{'position': <1>}>, 'a3b499f3-e2cc-40ac-9145-7db9c827dff2': <{'position': <2>}>, 'org.gnome.Calculator.desktop': <{'position': <3>}>, 'com.mattjakeman.ExtensionManager.desktop': <{'position': <4>}>, 'org.gnome.clocks.desktop': <{'position': <5>}>, 'htop.desktop': <{'position': <6>}>, 'org.gnome.Characters.desktop': <{'position': <7>}>, 'gnome-language-selector.desktop': <{'position': <8>}>, 'org.gnome.Meld.desktop': <{'position': <9>}>, 'net.nokyan.Resources.desktop': <{'position': <10>}>, 'org.gnome.TextEditor.desktop': <{'position': <11>}>, 'org.gnome.tweaks.desktop': <{'position': <12>}>, 'vim.desktop': <{'position': <13>}>, 'snap-store_snap-store.desktop': <{'position': <14>}>, 'org.gnome.Yelp.desktop': <{'position': <15>}>}]" - - schema: org.gnome.desktop.app-folders - key: folder-children - value: "['System', 'Utilities', 'YaST', 'Pardus', 'a3b499f3-e2cc-40ac-9145-7db9c827dff2']" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/System/ - key: name - value: "'X-GNOME-Shell-System.directory'" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/System/ - key: translate - value: "true" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/System/ - key: categories - value: "@as []" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/System/ - key: apps - value: "['nm-connection-editor.desktop', 'org.gnome.baobab.desktop', 'org.gnome.DiskUtility.desktop', 'im-config.desktop', 'org.gnome.Logs.desktop', 'org.gnome.Sysprof.desktop', 'gufw.desktop', 'firmware-updater_firmware-updater.desktop', 'org.gnome.Settings.desktop', 'update-manager.desktop', 'desktop-security-center_desktop-security-center.desktop']" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/Utilities/ - key: name - value: "'X-GNOME-Shell-Utilities.directory'" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/Utilities/ - key: translate - value: "true" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/Utilities/ - key: categories - value: "@as []" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/Utilities/ - key: apps - value: "['org.gnome.Papers.desktop', 'org.gnome.font-viewer.desktop', 'org.gnome.Loupe.desktop', 'org.gnome.seahorse.Application.desktop']" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/YaST/ - key: name - value: "'suse-yast.directory'" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/YaST/ - key: translate - value: "true" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/YaST/ - key: categories - value: "['X-SuSE-YaST']" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/YaST/ - key: apps - value: "@as []" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/Pardus/ - key: name - value: "'X-Pardus-Apps.directory'" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/Pardus/ - key: translate - value: "true" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/Pardus/ - key: categories - value: "['X-Pardus-Apps']" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/Pardus/ - key: apps - value: "@as []" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/a3b499f3-e2cc-40ac-9145-7db9c827dff2/ - key: name - value: "'Office'" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/a3b499f3-e2cc-40ac-9145-7db9c827dff2/ - key: translate - value: "false" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/a3b499f3-e2cc-40ac-9145-7db9c827dff2/ - key: categories - value: "@as []" - - schema: org.gnome.desktop.app-folders.folder - path: /org/gnome/desktop/app-folders/folders/a3b499f3-e2cc-40ac-9145-7db9c827dff2/ - key: apps - value: "['libreoffice-calc.desktop', 'libreoffice-base.desktop', 'libreoffice-draw.desktop', 'libreoffice-impress.desktop', 'libreoffice-math.desktop', 'libreoffice-writer.desktop', 'xournalpp_xournalpp.desktop', 'libreoffice-startcenter.desktop', 'pdfarranger_pdfarranger.desktop']" - - schema: org.gnome.desktop.input-sources - key: sources - value: "[('xkb', 'us')]" - - schema: org.gnome.desktop.interface - key: accent-color - value: "'orange'" - - schema: org.gnome.desktop.interface - key: clock-format - value: "'24h'" - - schema: org.gnome.desktop.interface - key: clock-show-date - value: "true" - - schema: org.gnome.desktop.interface - key: color-scheme - value: "'prefer-dark'" - - schema: org.gnome.desktop.interface - key: cursor-theme - value: "'Adwaita'" - - schema: org.gnome.desktop.interface - key: document-font-name - value: "'Adwaita Sans 12'" - - schema: org.gnome.desktop.interface - key: font-name - value: "'Adwaita Sans 11'" - - schema: org.gnome.desktop.interface - key: gtk-theme - value: "'Yaru-dark'" - - schema: org.gnome.desktop.interface - key: icon-theme - value: "'Yaru-dark'" - - schema: org.gnome.desktop.interface - key: monospace-font-name - value: "'Ubuntu Sans Mono 11'" - - schema: org.gnome.desktop.interface - key: show-battery-percentage - value: "false" - - schema: org.gnome.desktop.interface - key: text-scaling-factor - value: "1.0" - - schema: org.gnome.desktop.privacy - key: report-technical-problems - value: "false" - - schema: org.gnome.desktop.wm.preferences - key: button-layout - value: "'appmenu:close'" - - schema: org.gnome.desktop.wm.preferences - key: focus-mode - value: "'click'" - - schema: org.gnome.desktop.wm.preferences - key: focus-new-windows - value: "'smart'" - - schema: org.gnome.desktop.wm.preferences - key: num-workspaces - value: "4" - - schema: org.gnome.nautilus.preferences - key: click-policy - value: "'double'" - - schema: org.gnome.nautilus.preferences - key: date-time-format - value: "'simple'" - - schema: org.gnome.nautilus.preferences - key: default-folder-viewer - value: "'icon-view'" - - schema: org.gnome.nautilus.preferences - key: default-sort-order - value: "'name'" - - schema: org.gnome.nautilus.preferences - key: recursive-search - value: "'local-only'" - - schema: org.gnome.nautilus.preferences - key: show-create-link - value: "true" - - schema: org.gnome.nautilus.preferences - key: show-delete-permanently - value: "true" - - schema: org.gnome.nautilus.preferences - key: show-directory-item-counts - value: "'local-only'" - - schema: org.gnome.nautilus.preferences - key: show-hidden-files - value: "false" - - schema: org.gnome.nautilus.preferences - key: show-image-thumbnails - value: "'local-only'" - - schema: org.gnome.nautilus.preferences - key: thumbnail-limit - value: "uint64 50" - - schema: org.gnome.nautilus.icon-view - key: captions - value: "['none', 'none', 'none']" - - schema: org.gnome.nautilus.icon-view - key: default-zoom-level - value: "'medium'" - - schema: org.gtk.gtk4.Settings.FileChooser - key: clock-format - value: "'24h'" - - schema: org.gtk.gtk4.Settings.FileChooser - key: date-format - value: "'regular'" - - schema: org.gtk.gtk4.Settings.FileChooser - key: location-mode - value: "'path-bar'" - - schema: org.gtk.gtk4.Settings.FileChooser - key: show-hidden - value: "false" - - schema: org.gtk.gtk4.Settings.FileChooser - key: show-size-column - value: "true" - - schema: org.gtk.gtk4.Settings.FileChooser - key: show-type-column - value: "true" - - schema: org.gtk.gtk4.Settings.FileChooser - key: sort-column - value: "'name'" - - schema: org.gtk.gtk4.Settings.FileChooser - key: sort-directories-first - value: "true" - - schema: org.gtk.gtk4.Settings.FileChooser - key: sort-order - value: "'ascending'" - - schema: org.gtk.gtk4.Settings.FileChooser - key: startup-mode - value: "'recent'" - - schema: org.gtk.gtk4.Settings.FileChooser - key: type-format - value: "'category'" - - schema: org.gtk.gtk4.Settings.FileChooser - key: view-type - value: "'list'" - - schema: org.gnome.settings-daemon.plugins.color - key: night-light-schedule-automatic - value: "false" - - schema: org.gnome.settings-daemon.plugins.power - key: sleep-inactive-ac-timeout - value: "3600" - - schema: org.gnome.settings-daemon.plugins.power - key: sleep-inactive-ac-type - value: "'nothing'" - - schema: org.gnome.system.location - key: enabled - value: "false" - - schema: org.gnome.TextEditor - key: auto-indent - value: "true" - - schema: org.gnome.TextEditor - key: auto-save-delay - value: "uint32 3" - - schema: org.gnome.TextEditor - key: custom-font - value: "'Monospace 11'" - - schema: org.gnome.TextEditor - key: discover-settings - value: "true" - - schema: org.gnome.TextEditor - key: draw-spaces - value: "@as []" - - schema: org.gnome.TextEditor - key: enable-snippets - value: "false" - - schema: org.gnome.TextEditor - key: highlight-current-line - value: "false" - - schema: org.gnome.TextEditor - key: highlight-matching-brackets - value: "true" - - schema: org.gnome.TextEditor - key: indent-style - value: "'tab'" - - schema: org.gnome.TextEditor - key: indent-width - value: "-1" - - schema: org.gnome.TextEditor - key: keybindings - value: "'default'" - - schema: org.gnome.TextEditor - key: line-height - value: "1.2" - - schema: org.gnome.TextEditor - key: recolor-window - value: "true" - - schema: org.gnome.TextEditor - key: restore-session - value: "true" - - schema: org.gnome.TextEditor - key: right-margin-position - value: "uint32 80" - - schema: org.gnome.TextEditor - key: show-grid - value: "false" - - schema: org.gnome.TextEditor - key: show-line-numbers - value: "false" - - schema: org.gnome.TextEditor - key: show-map - value: "false" - - schema: org.gnome.TextEditor - key: show-right-margin - value: "false" - - schema: org.gnome.TextEditor - key: spellcheck - value: "true" - - schema: org.gnome.TextEditor - key: style-scheme - value: "'Adwaita'" - - schema: org.gnome.TextEditor - key: style-variant - value: "'follow'" - - schema: org.gnome.TextEditor - key: tab-width - value: "uint32 8" - - schema: org.gnome.TextEditor - key: use-system-font - value: "true" - - schema: org.gnome.TextEditor - key: wrap-text - value: "true" diff --git a/ansible/inventory/host_vars/deadalus-win.yml b/ansible/inventory/host_vars/deadalus-win.yml deleted file mode 100644 index dac9a95..0000000 --- a/ansible/inventory/host_vars/deadalus-win.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -hostname: deadalus-win diff --git a/ansible/inventory/hosts.yml b/ansible/inventory/hosts.yml index 253527b..f5e0ba1 100644 --- a/ansible/inventory/hosts.yml +++ b/ansible/inventory/hosts.yml @@ -17,7 +17,6 @@ all: ubuntu: children: - ubuntu_workstation: workstation_dev_wsl: ubuntu_server: @@ -33,11 +32,9 @@ all: workstation_host: children: workstation_host_linux: - workstation_host_windows: workstation_dev: children: - workstation_dev_ubuntu: workstation_dev_fedora: workstation_dev_wsl: @@ -45,11 +42,6 @@ all: children: ubuntu_server: - ubuntu_workstation: - hosts: - deadalus-ubuntu: - ansible_connection: local - fedora_workstation: hosts: deadalus-fedora: @@ -57,25 +49,14 @@ all: workstation_host_linux: hosts: - deadalus-ubuntu: - ansible_connection: local deadalus-fedora: ansible_connection: local - workstation_dev_ubuntu: - hosts: - deadalus-ubuntu: - ansible_connection: local - workstation_dev_fedora: hosts: deadalus-fedora: ansible_connection: local - workstation_host_windows: - hosts: - deadalus-win: - workstation_dev_wsl: hosts: deadalus-wsl: diff --git a/ansible/roles/profile_workstation_host_windows/tasks/main.yml b/ansible/roles/profile_workstation_host_windows/tasks/main.yml deleted file mode 100644 index e2c5359..0000000 --- a/ansible/roles/profile_workstation_host_windows/tasks/main.yml +++ /dev/null @@ -1,411 +0,0 @@ ---- -- name: Enable required Windows features for WSL - tags: [packages, services, wsl] - ansible.windows.win_optional_feature: - name: - - Microsoft-Windows-Subsystem-Linux - - VirtualMachinePlatform - state: present - include_parent: true - -- name: Gather Windows host version details - tags: [packages] - ansible.windows.win_powershell: - script: | - $os = Get-ComputerInfo - $buildNumber = [int]$os.OsBuildNumber - $Ansible.Result = @{ - product_name = $os.WindowsProductName - build_number = $buildNumber - is_windows_11 = $buildNumber -ge 22000 - } - $Ansible.Changed = $false - register: windows_host_version_state - -- name: Fail when Windows host is not Windows 11 - tags: [packages] - ansible.builtin.fail: - msg: >- - workstation_host_windows is supported only on Windows 11. Detected {{ windows_host_version_state.result.product_name }} - build {{ windows_host_version_state.result.build_number }}. - when: not (windows_host_version_state.result.is_windows_11 | default(false)) - -- name: Enable dark mode for Windows apps - tags: [packages] - ansible.windows.win_regedit: - path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize - name: AppsUseLightTheme - data: 0 - type: dword - register: windows_apps_dark_mode_state - when: windows_enable_dark_theme | default(false) - -- name: Enable dark mode for Windows system surfaces - tags: [packages] - ansible.windows.win_regedit: - path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize - name: SystemUsesLightTheme - data: 0 - type: dword - register: windows_system_dark_mode_state - when: windows_enable_dark_theme | default(false) - -- name: Hide Windows taskbar search box - tags: [packages] - ansible.windows.win_regedit: - path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Search - name: SearchboxTaskbarMode - data: 0 - type: dword - register: windows_taskbar_search_state - when: windows_hide_taskbar_search | default(false) - -- name: Hide Windows 11 taskbar widgets - tags: [packages] - ansible.windows.win_regedit: - path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced - name: TaskbarDa - data: 0 - type: dword - register: windows_11_widgets_state - when: windows_hide_taskbar_widgets | default(false) - -- name: Disable Windows 11 widgets via policy - tags: [packages] - ansible.windows.win_regedit: - path: HKLM:\SOFTWARE\Policies\Microsoft\Dsh - name: AllowNewsAndInterests - data: 0 - type: dword - register: windows_11_widgets_policy_state - when: windows_hide_taskbar_widgets | default(false) - -- name: Note when Windows shell settings may require sign out - tags: [packages] - ansible.builtin.debug: - msg: >- - Windows shell appearance settings changed. Sign out and back in, or restart explorer.exe, - if taskbar or theme updates do not appear immediately. Windows 11 widget policy changes can require - signing out before the widget button disappears from the taskbar. - changed_when: false - when: >- - (windows_apps_dark_mode_state is changed) - or (windows_system_dark_mode_state is changed) - or (windows_taskbar_search_state is changed) - or (windows_11_widgets_state is changed) - or (windows_11_widgets_policy_state is changed) - -- name: Ensure winget is executable on Windows host through PSRP - tags: [packages] - when: windows_package_backend == 'winget_psrp' - ansible.windows.win_powershell: - script: | - $winget = Get-Command winget.exe -ErrorAction SilentlyContinue - if ($null -eq $winget) { - throw 'winget.exe is not available on the Windows host. Install App Installer or rerun the bootstrap script.' - } - - & $winget.Source --info *> $null - if ($LASTEXITCODE -ne 0) { - throw 'winget.exe is not executable through the current PSRP session. Set windows_package_backend to winget_wsl_local on WSL-managed hosts.' - } - - $Ansible.Changed = $false - -- name: Ensure winget is executable through local Windows PowerShell from WSL - tags: [packages] - when: windows_package_backend == 'winget_wsl_local' - block: - - name: Ensure winget_wsl_local backend is running inside WSL - ansible.builtin.assert: - that: - - lookup('ansible.builtin.env', 'WSL_DISTRO_NAME') | length > 0 - fail_msg: >- - winget_wsl_local requires running the playbook from inside the - target machine's WSL environment. - - - name: Get local Windows host name through WSL interop - ansible.builtin.shell: | - powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command '$env:COMPUTERNAME' - args: - executable: /bin/bash - delegate_to: localhost - register: local_windows_host_name_state - changed_when: false - - - name: Get local Windows host IP addresses through WSL interop - ansible.builtin.shell: | - powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command ' - Get-NetIPAddress -AddressFamily IPv4, IPv6 -ErrorAction SilentlyContinue | - Where-Object { - $_.IPAddress -notin @("127.0.0.1", "::1") -and - $_.IPAddress -notlike "169.254.*" -and - $_.IPAddress -notlike "fe80:*" - } | - Select-Object -ExpandProperty IPAddress - ' - args: - executable: /bin/bash - delegate_to: localhost - register: local_windows_host_ip_state - changed_when: false - - - name: Ensure winget_wsl_local backend targets the local Windows host - ansible.builtin.assert: - that: - - >- - (ansible_host | lower) in ['localhost', '127.0.0.1', '::1'] - or (local_windows_host_name_state.stdout | trim | upper) - == ((ansible_host | regex_replace('\\..*$', '')) | upper) - or (ansible_host | lower) - in (local_windows_host_ip_state.stdout_lines | map('trim') | map('lower') | list) - fail_msg: >- - winget_wsl_local can only target the local Windows host reached - through WSL interop. Local Windows host '{{ local_windows_host_name_state.stdout | trim }}' - with addresses {{ local_windows_host_ip_state.stdout_lines | map('trim') | list }} - does not match ansible_host '{{ ansible_host }}'. - - - name: Ensure winget is executable through local Windows PowerShell - ansible.builtin.shell: | - powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command ' - $ErrorActionPreference = "Stop" - $winget = Get-Command winget.exe -ErrorAction SilentlyContinue - if ($null -eq $winget) { - throw "winget.exe is not available on the local Windows host. Install App Installer or rerun the bootstrap script." - } - - & $winget.Source --info *> $null - if ($LASTEXITCODE -ne 0) { - throw "winget.exe is not executable through local Windows PowerShell interop." - } - ' - args: - executable: /bin/bash - delegate_to: localhost - changed_when: false - -- name: Ensure WSL 2 is the default backend - tags: [packages, services, wsl] - ansible.windows.win_powershell: - script: | - $status = & wsl --status 2>$null - if ($LASTEXITCODE -eq 0 -and $status -match 'Default Version:\s*2') { - $Ansible.Changed = $false - return - } - - & wsl --set-default-version 2 - if ($LASTEXITCODE -ne 0) { - throw 'Failed to set WSL default version to 2.' - } - - $Ansible.Changed = $true - -- name: Install Windows workstation applications with winget through PSRP - tags: [packages] - when: windows_package_backend == 'winget_psrp' - ansible.windows.win_powershell: - script: | - $packageId = '{{ item.id }}' - $packageName = '{{ item.name | default(item.id) }}' - $packageSource = '{{ item.source | default('') }}' - $listArgs = @( - 'list' - '--id', $packageId - '--exact' - '--accept-source-agreements' - '--disable-interactivity' - ) - $installArgs = @( - 'install' - '--id', $packageId - '--exact' - '--silent' - '--accept-package-agreements' - '--accept-source-agreements' - '--disable-interactivity' - ) - - if (-not [string]::IsNullOrWhiteSpace($packageSource)) { - $listArgs += @('--source', $packageSource) - $installArgs += @('--source', $packageSource) - } - - $installed = & winget @listArgs 2>$null - if ($LASTEXITCODE -eq 0 -and $installed -match [regex]::Escape($packageId)) { - $Ansible.Changed = $false - return - } - - & winget @installArgs - if ($LASTEXITCODE -ne 0) { - throw "Failed to install $packageName with winget" - } - - $Ansible.Changed = $true - loop: "{{ windows_winget_packages | default([]) }}" - loop_control: - label: "{{ item.id }}" - -- name: Install Windows workstation applications with winget through WSL local backend - tags: [packages] - when: windows_package_backend == 'winget_wsl_local' - ansible.builtin.shell: | - powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command ' - $ErrorActionPreference = "Stop" - $packageId = "{{ item.id }}" - $packageName = "{{ item.name | default(item.id) }}" - $packageSource = "{{ item.source | default('') }}" - $winget = Get-Command winget.exe -ErrorAction Stop - $listArgs = @( - "list" - "--id", $packageId - "--exact" - "--accept-source-agreements" - "--disable-interactivity" - ) - $installArgs = @( - "install" - "--id", $packageId - "--exact" - "--silent" - "--accept-package-agreements" - "--accept-source-agreements" - "--disable-interactivity" - ) - - if (-not [string]::IsNullOrWhiteSpace($packageSource)) { - $listArgs += @("--source", $packageSource) - $installArgs += @("--source", $packageSource) - } - - $installed = & $winget.Source @listArgs 2>$null - if ($LASTEXITCODE -eq 0 -and $installed -match [regex]::Escape($packageId)) { - [Console]::Out.WriteLine("changed=false") - exit 0 - } - - & $winget.Source @installArgs - if ($LASTEXITCODE -ne 0) { - throw "Failed to install $packageName with winget" - } - - [Console]::Out.WriteLine("changed=true") - ' - args: - executable: /bin/bash - delegate_to: localhost - register: windows_wsl_local_winget_install_state - changed_when: "'changed=true' in windows_wsl_local_winget_install_state.stdout" - loop: "{{ windows_winget_packages | default([]) }}" - loop_control: - label: "{{ item.id }}" - -- name: Configure Windows taskbar pin layout - tags: [packages] - when: (windows_taskbar_pins | default([])) | length > 0 - block: - - name: Ensure Windows taskbar layout directory exists - ansible.windows.win_file: - path: "{{ windows_taskbar_layout_directory }}" - state: directory - - - name: Render Windows taskbar layout policy file - ansible.windows.win_template: - src: taskbar-layout.xml.j2 - dest: "{{ windows_taskbar_layout_path }}" - register: windows_taskbar_layout_file_state - - - name: Enable Windows taskbar layout policy - ansible.windows.win_regedit: - path: HKCU:\Software\Policies\Microsoft\Windows\Explorer - name: LockedStartLayout - data: 1 - type: dword - register: windows_taskbar_layout_policy_state - - - name: Set Windows taskbar layout policy file path - ansible.windows.win_regedit: - path: HKCU:\Software\Policies\Microsoft\Windows\Explorer - name: StartLayoutFile - data: "{{ windows_taskbar_layout_path }}" - type: expandstring - register: windows_taskbar_layout_policy_path_state - - - name: Set Windows taskbar layout policy refresh behavior - ansible.windows.win_regedit: - path: HKCU:\Software\Policies\Microsoft\Windows\Explorer - name: ReapplyStartLayoutEveryLogon - data: "{{ (windows_taskbar_reapply_every_logon | default(false)) | ternary(1, 0) }}" - type: dword - register: windows_taskbar_layout_policy_reapply_state - - - name: Note when Windows taskbar pin layout may require sign out - ansible.builtin.debug: - msg: >- - Windows taskbar pin policy changed. Sign out and back in if the updated pin order does not appear immediately. - changed_when: false - when: >- - (windows_taskbar_layout_file_state is changed) - or (windows_taskbar_layout_policy_state is changed) - or (windows_taskbar_layout_policy_path_state is changed) - or (windows_taskbar_layout_policy_reapply_state is changed) - -- name: Install VS Code WSL extensions on Windows host - tags: [packages, vscode] - ansible.windows.win_powershell: - script: | - $extensionId = '{{ item }}' - $code = Get-Command code.cmd -ErrorAction SilentlyContinue - if ($null -eq $code) { - throw 'code.cmd is not available. Ensure Visual Studio Code is installed before managing extensions.' - } - - $installedExtensions = & $code.Source --list-extensions - if ($installedExtensions -contains $extensionId) { - $Ansible.Changed = $false - return - } - - & $code.Source --install-extension $extensionId --force - if ($LASTEXITCODE -ne 0) { - throw "Failed to install VS Code extension $extensionId" - } - - $Ansible.Changed = $true - loop: "{{ windows_vscode_extensions | default([]) }}" - loop_control: - label: "{{ item }}" - -- name: Set Windows Terminal default profile to Ubuntu - tags: [packages, wsl] - ansible.windows.win_powershell: - script: | - $terminalSettingsPath = Join-Path $env:LOCALAPPDATA 'Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json' - if (-not (Test-Path $terminalSettingsPath)) { - throw 'Windows Terminal settings.json was not found. Launch Windows Terminal once before applying the default profile configuration.' - } - - $settings = Get-Content -Path $terminalSettingsPath -Raw | ConvertFrom-Json - if ($null -eq $settings.profiles -or $null -eq $settings.profiles.list) { - throw 'Windows Terminal settings.json does not contain a profiles.list section.' - } - - $targetProfile = $settings.profiles.list | - Where-Object { - $_.name -eq '{{ windows_terminal_default_profile_name }}' -and -not ($_.PSObject.Properties.Name -contains 'hidden' -and $_.hidden) - } | - Select-Object -First 1 - - if ($null -eq $targetProfile) { - throw "Windows Terminal visible profile '{{ windows_terminal_default_profile_name }}' was not found. Ensure the Ubuntu WSL profile exists and is not hidden in Windows Terminal first." - } - - if ($settings.defaultProfile -eq $targetProfile.guid) { - $Ansible.Changed = $false - return - } - - $settings.defaultProfile = $targetProfile.guid - $settings | ConvertTo-Json -Depth 100 | Set-Content -Path $terminalSettingsPath -Encoding utf8 - $Ansible.Changed = $true diff --git a/ansible/roles/profile_workstation_host_windows/templates/taskbar-layout.xml.j2 b/ansible/roles/profile_workstation_host_windows/templates/taskbar-layout.xml.j2 deleted file mode 100644 index c2c20a7..0000000 --- a/ansible/roles/profile_workstation_host_windows/templates/taskbar-layout.xml.j2 +++ /dev/null @@ -1,23 +0,0 @@ - - - - - -{% for pin in windows_taskbar_pins %} -{% if pin.type == 'desktop_application_id' %} - -{% elif pin.type == 'desktop_application_link_path' %} - -{% elif pin.type == 'app_user_model_id' %} - -{% endif %} -{% endfor %} - - - - diff --git a/ansible/site.yml b/ansible/site.yml index 627dfbf..bc27c85 100644 --- a/ansible/site.yml +++ b/ansible/site.yml @@ -1,5 +1,5 @@ --- -- hosts: all:!workstation_host_windows +- hosts: all become: true pre_tasks: - name: Load local vault variables when available @@ -29,14 +29,6 @@ - profile_desktop_hyprland - profile_desktop_host -- hosts: workstation_dev_ubuntu - become: true - - roles: - - packages_ubuntu - - services_systemd - - profile_workstation_dev_common - - hosts: workstation_dev_fedora become: true @@ -60,53 +52,6 @@ - profile_workstation_dev_common - profile_workstation_dev_wsl -- hosts: workstation_host_windows - gather_facts: false - - pre_tasks: - - name: Load local vault variables when available - tags: [always] - ansible.builtin.include_vars: - file: "{{ playbook_dir }}/../secrets/vault.yml" - when: lookup('ansible.builtin.fileglob', playbook_dir + '/../secrets/vault.yml', errors='ignore', wantlist=True) | length > 0 - - - name: Load machine-local vault variables when available - tags: [always] - ansible.builtin.include_vars: - file: "{{ playbook_dir }}/../secrets/vault.local.yml" - when: lookup('ansible.builtin.fileglob', playbook_dir + '/../secrets/vault.local.yml', errors='ignore', wantlist=True) | length > 0 - - - name: Resolve Windows PSRP connection settings - tags: [always] - ansible.builtin.set_fact: - ansible_host: "{{ windows_psrp_host | default(vault_windows_psrp_host | default('')) }}" - ansible_user: "{{ windows_psrp_user | default(vault_windows_psrp_user | default('')) }}" - ansible_password: "{{ windows_psrp_password | default(vault_windows_psrp_password | default('')) }}" - windows_package_backend: "{{ windows_package_backend | default(vault_windows_package_backend | default('winget_psrp')) }}" - - - name: Ensure Windows PSRP connection settings are defined - tags: [always] - ansible.builtin.assert: - that: - - (ansible_host | default('') | length) > 0 - - (ansible_user | default('') | length) > 0 - fail_msg: >- - Define windows_psrp_host and windows_psrp_user via extra vars, secrets/vault.yml, - or secrets/vault.local.yml - before running the workstation_host_windows play. - - - name: Ensure Windows package backend is supported - tags: [always] - ansible.builtin.assert: - that: - - windows_package_backend in ['winget_psrp', 'winget_wsl_local'] - fail_msg: >- - Unsupported windows_package_backend '{{ windows_package_backend }}'. - Supported values are winget_psrp and winget_wsl_local. - - roles: - - profile_workstation_host_windows - - hosts: ubuntu_server become: true diff --git a/scripts/bootstrap_windows_workstation.ps1 b/scripts/bootstrap_windows_workstation.ps1 deleted file mode 100644 index 896ea04..0000000 --- a/scripts/bootstrap_windows_workstation.ps1 +++ /dev/null @@ -1,163 +0,0 @@ -#requires -RunAsAdministrator -param( - [string]$Distribution = 'Ubuntu', - [switch]$SkipUbuntuInstall -) - -Set-StrictMode -Version Latest -$ErrorActionPreference = 'Stop' - -function Get-OrCreate-WinRMHttpsCertificate { - $dnsName = $env:COMPUTERNAME - $existingCertificate = Get-ChildItem -Path Cert:\LocalMachine\My | - Where-Object { $_.Subject -eq "CN=$dnsName" } | - Sort-Object NotAfter -Descending | - Select-Object -First 1 - - if ($null -ne $existingCertificate) { - return $existingCertificate - } - - return New-SelfSignedCertificate ` - -DnsName $dnsName ` - -CertStoreLocation 'Cert:\LocalMachine\My' ` - -FriendlyName 'WinRM HTTPS Listener' ` - -KeyAlgorithm RSA ` - -KeyLength 2048 ` - -HashAlgorithm SHA256 ` - -NotAfter (Get-Date).AddYears(5) -} - -function Ensure-WinRMHttpsListener { - param( - [Parameter(Mandatory = $true)] - [string]$CertificateThumbprint - ) - - $listener = Get-ChildItem -Path WSMan:\localhost\Listener | - Where-Object { - $_.Keys -match 'Transport=HTTPS' - } | - Select-Object -First 1 - - if ($null -eq $listener) { - try { - New-WSManInstance -ResourceURI winrm/config/Listener ` - -SelectorSet @{ Transport = 'HTTPS'; Address = '*' } ` - -ValueSet @{ Hostname = $env:COMPUTERNAME; CertificateThumbprint = $CertificateThumbprint } | Out-Null - return $true - } - catch { - $existingHttpsListener = Get-ChildItem -Path WSMan:\localhost\Listener | - Where-Object { - $_.Keys -match 'Transport=HTTPS' - } | - Select-Object -First 1 - - if ($null -ne $existingHttpsListener) { - return $false - } - - throw - } - } - - return $false -} - -function Test-WinRMHttpsListener { - $listener = Get-ChildItem -Path WSMan:\localhost\Listener | - Where-Object { - $_.Keys -match 'Transport=HTTPS' - } | - Select-Object -First 1 - - return $null -ne $listener -} - -function Ensure-LocalAccountTokenFilterPolicy { - $registryPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System' - $propertyName = 'LocalAccountTokenFilterPolicy' - $currentValue = Get-ItemProperty -Path $registryPath -Name $propertyName -ErrorAction SilentlyContinue | Select-Object -ExpandProperty $propertyName -ErrorAction SilentlyContinue - - if ($currentValue -ne 1) { - New-ItemProperty -Path $registryPath -Name $propertyName -Value 1 -PropertyType DWord -Force | Out-Null - return $true - } - - return $false -} - -function Ensure-CurrentUserInRemoteManagementGroup { - $groupName = 'Utenti gestione remota' - $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name - $members = @(Get-LocalGroupMember -Name $groupName -ErrorAction Stop | Select-Object -ExpandProperty Name) - - if ($members -contains $currentUser) { - return @{ Changed = $false; User = $currentUser; Group = $groupName } - } - - Add-LocalGroupMember -Group $groupName -Member $currentUser -ErrorAction Stop - return @{ Changed = $true; User = $currentUser; Group = $groupName } -} - -function Enable-FeatureIfNeeded { - param( - [Parameter(Mandatory = $true)] - [string]$FeatureName - ) - - $feature = Get-WindowsOptionalFeature -Online -FeatureName $FeatureName - if ($feature.State -ne 'Enabled') { - Enable-WindowsOptionalFeature -Online -FeatureName $FeatureName -All -NoRestart | Out-Null - return $true - } - - return $false -} - -$rebootRequired = $false -$rebootRequired = (Enable-FeatureIfNeeded -FeatureName 'Microsoft-Windows-Subsystem-Linux') -or $rebootRequired -$rebootRequired = (Enable-FeatureIfNeeded -FeatureName 'VirtualMachinePlatform') -or $rebootRequired - -wsl --set-default-version 2 - -$installedDistributions = @(wsl --list --quiet) | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' } -$installedUbuntuDistribution = $installedDistributions | Where-Object { $_ -like 'Ubuntu*' } | Select-Object -First 1 - -if (-not $SkipUbuntuInstall -and $null -eq $installedUbuntuDistribution) { - wsl --install --distribution $Distribution --no-launch - $rebootRequired = $true -} - -Enable-PSRemoting -SkipNetworkProfileCheck -Force -Set-Service -Name WinRM -StartupType Automatic - -$winrmCertificate = Get-OrCreate-WinRMHttpsCertificate -$httpsListenerChanged = Ensure-WinRMHttpsListener -CertificateThumbprint $winrmCertificate.Thumbprint -$rebootRequired = (Ensure-LocalAccountTokenFilterPolicy) -or $rebootRequired -$remoteManagementGroupState = Ensure-CurrentUserInRemoteManagementGroup - -$httpsFirewallRule = Get-NetFirewallRule -DisplayName 'WinRM HTTPS (5986)' -ErrorAction SilentlyContinue -if ($null -eq $httpsFirewallRule) { - New-NetFirewallRule -DisplayName 'WinRM HTTPS (5986)' -Direction Inbound -Action Allow -Protocol TCP -LocalPort 5986 | Out-Null -} - -if (-not (Test-WinRMHttpsListener)) { - throw 'WinRM HTTPS listener was not created successfully. Verify certificate creation and WSMan listener configuration.' -} - -Write-Host '' -Write-Host 'Bootstrap completato.' -Write-Host 'Passi successivi:' -Write-Host '1. Riavvia Windows se richiesto dalle feature WSL.' -Write-Host '2. Avvia la distro Ubuntu almeno una volta e completa la creazione dell''utente Linux.' -Write-Host '3. Installa Ansible dentro WSL Ubuntu e lancia il playbook da li.' -Write-Host '4. Le applicazioni Windows saranno installate dal playbook Ansible; il backend predefinito e winget_psrp.' -Write-Host '' -Write-Host ('WSL distro Ubuntu rilevata: {0}' -f $(if ($null -ne $installedUbuntuDistribution) { $installedUbuntuDistribution } else { 'nessuna, verra installata ' + $Distribution })) -Write-Host ('PSRP transport consigliato: https://{0}:5986/wsman' -f $env:COMPUTERNAME) -Write-Host ('Certificato WinRM HTTPS: {0}' -f $winrmCertificate.Thumbprint) -Write-Host ('Utente aggiunto a Utenti gestione remota: {0}' -f $remoteManagementGroupState.User) -Write-Host ('Listener HTTPS creato in questo run: {0}' -f $(if ($httpsListenerChanged) { 'yes' } else { 'no' })) -Write-Host ('Riavvio consigliato: {0}' -f $(if ($rebootRequired) { 'yes' } else { 'no' })) diff --git a/secrets/vault.yml.example b/secrets/vault.yml.example index 5f43d8a..e48db25 100644 --- a/secrets/vault.yml.example +++ b/secrets/vault.yml.example @@ -8,10 +8,6 @@ vault_icloud_mail_password: "REPLACE_ME" vault_git_work_email: "REPLACE_ME" vault_git_work_gpg: "REPLACE_ME" vault_openai_api_key: "REPLACE_ME" -vault_windows_psrp_host: "REPLACE_ME" -vault_windows_psrp_user: 'MicrosoftAccount\user@example.com' -vault_windows_psrp_password: "REPLACE_ME" -vault_windows_package_backend: "winget_psrp" vault_navidrome_db_password: "REPLACE_ME" vault_postgres_root_password: "REPLACE_ME" vault_ikaros_authorized_ssh_keys: