mirror of
https://github.com/fscotto/infra.git
synced 2026-05-30 15:39:58 +00:00
Simplify Windows role to Windows 11 only
This commit is contained in:
@@ -18,7 +18,7 @@ Project type: Ansible-driven infrastructure, workstation/server provisioning, an
|
|||||||
- Void desktops: `ikaros`, `nymph`
|
- Void desktops: `ikaros`, `nymph`
|
||||||
- Ubuntu workstation: `deadalus`
|
- Ubuntu workstation: `deadalus`
|
||||||
- Ubuntu server: `prometheus`
|
- Ubuntu server: `prometheus`
|
||||||
- Workstation topology now supports Linux host + Ubuntu dev and Windows host + Ubuntu WSL dev as separate layers
|
- Workstation topology now supports Linux host + Ubuntu dev and Windows 11 host + Ubuntu WSL dev as separate layers
|
||||||
- The WSL dev environment is intended to be managed by running Ansible locally from inside the distro, while the Windows host is managed remotely via PSRP
|
- The WSL dev environment is intended to be managed by running Ansible locally from inside the distro, while the Windows host is managed remotely via PSRP
|
||||||
- Most hosts use `ansible_connection: local`
|
- Most hosts use `ansible_connection: local`
|
||||||
- Current playbook layering: `all:!workstation_host_windows -> 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_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`
|
- Current playbook layering: `all:!workstation_host_windows -> 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_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`
|
||||||
@@ -156,7 +156,7 @@ Use the narrowest command matching the changed area.
|
|||||||
- `profile_workstation_dev_common` carries the Ubuntu dev layer shared by native workstation and WSL Ubuntu
|
- `profile_workstation_dev_common` carries the Ubuntu dev layer shared by native workstation and WSL Ubuntu
|
||||||
- `profile_workstation_gnome` carries Linux host-only GNOME setup, extensions, and UFW
|
- `profile_workstation_gnome` carries Linux host-only GNOME setup, extensions, and UFW
|
||||||
- `profile_workstation_dev_wsl` carries WSL-specific Ubuntu tweaks such as `systemd` and PSRP Python dependencies
|
- `profile_workstation_dev_wsl` carries WSL-specific Ubuntu tweaks such as `systemd` and PSRP Python dependencies
|
||||||
- `profile_workstation_host_windows` manages the Windows host via PSRP over HTTPS using `negotiate` by default and installs host applications via `winget`
|
- `profile_workstation_host_windows` manages the Windows 11 host via PSRP over HTTPS using `negotiate` by default and installs host applications via `winget`
|
||||||
- `deadalus-wsl` is modeled as a local inventory target intended to be run from inside the Ubuntu WSL distro
|
- `deadalus-wsl` is modeled as a local inventory target intended to be run from inside the Ubuntu WSL distro
|
||||||
- Future Windows taskbar pinning work should be done from a real Windows session after discovering installed app identifiers on that host, then applied via a Windows 11 taskbar layout policy with `PinListPlacement="Replace"`
|
- Future Windows taskbar pinning work should be done from a real Windows session after discovering installed app identifiers on that host, then applied via a Windows 11 taskbar layout policy with `PinListPlacement="Replace"`
|
||||||
- Do not auto-restart `emptty` during playbook runs on active desktop hosts; prefer a manual restart from SSH or another TTY after the run
|
- Do not auto-restart `emptty` during playbook runs on active desktop hosts; prefer a manual restart from SSH or another TTY after the run
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ Lo stato attuale del profilo desktop include, tra le altre cose:
|
|||||||
Sistemi operativi supportati:
|
Sistemi operativi supportati:
|
||||||
|
|
||||||
- Ubuntu LTS nativa
|
- Ubuntu LTS nativa
|
||||||
- Windows host + Ubuntu WSL
|
- Windows 11 host + Ubuntu WSL
|
||||||
|
|
||||||
Desktop environment host Linux:
|
Desktop environment host Linux:
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ 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 Ubuntu condiviso tra workstation Linux nativa e Ubuntu in WSL
|
||||||
- layer host Linux GNOME
|
- layer host Linux GNOME
|
||||||
- layer host Windows con bootstrap WSL, remoting `PSRP` su `HTTPS/5986`, gestione app via `winget` e VS Code lato Windows
|
- layer host Windows 11 con bootstrap WSL, remoting `PSRP` su `HTTPS/5986`, gestione app via `winget` e VS Code lato Windows
|
||||||
- layer WSL dedicato per sviluppo con `systemd`
|
- layer WSL dedicato per sviluppo con `systemd`
|
||||||
|
|
||||||
Lo stato attuale del profilo workstation include:
|
Lo stato attuale del profilo workstation include:
|
||||||
|
|||||||
@@ -16,14 +16,20 @@
|
|||||||
$buildNumber = [int]$os.OsBuildNumber
|
$buildNumber = [int]$os.OsBuildNumber
|
||||||
$Ansible.Result = @{
|
$Ansible.Result = @{
|
||||||
product_name = $os.WindowsProductName
|
product_name = $os.WindowsProductName
|
||||||
version = $os.WindowsVersion
|
|
||||||
build_number = $buildNumber
|
build_number = $buildNumber
|
||||||
is_windows_11 = ($os.WindowsProductName -like 'Windows 11*') -or ($buildNumber -ge 22000)
|
is_windows_11 = $buildNumber -ge 22000
|
||||||
is_windows_10 = ($os.WindowsProductName -like 'Windows 10*') -and ($buildNumber -lt 22000)
|
|
||||||
}
|
}
|
||||||
$Ansible.Changed = $false
|
$Ansible.Changed = $false
|
||||||
register: windows_host_version_state
|
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
|
- name: Enable dark mode for Windows apps
|
||||||
tags: [packages]
|
tags: [packages]
|
||||||
ansible.windows.win_regedit:
|
ansible.windows.win_regedit:
|
||||||
@@ -62,9 +68,7 @@
|
|||||||
data: 0
|
data: 0
|
||||||
type: dword
|
type: dword
|
||||||
register: windows_11_widgets_state
|
register: windows_11_widgets_state
|
||||||
when:
|
when: windows_hide_taskbar_widgets | default(false)
|
||||||
- windows_hide_taskbar_widgets | default(false)
|
|
||||||
- windows_host_version_state.result.is_windows_11 | default(false)
|
|
||||||
|
|
||||||
- name: Disable Windows 11 widgets via policy
|
- name: Disable Windows 11 widgets via policy
|
||||||
tags: [packages]
|
tags: [packages]
|
||||||
@@ -74,21 +78,7 @@
|
|||||||
data: 0
|
data: 0
|
||||||
type: dword
|
type: dword
|
||||||
register: windows_11_widgets_policy_state
|
register: windows_11_widgets_policy_state
|
||||||
when:
|
when: windows_hide_taskbar_widgets | default(false)
|
||||||
- windows_hide_taskbar_widgets | default(false)
|
|
||||||
- windows_host_version_state.result.is_windows_11 | default(false)
|
|
||||||
|
|
||||||
- name: Hide Windows 10 news and interests taskbar widget
|
|
||||||
tags: [packages]
|
|
||||||
ansible.windows.win_regedit:
|
|
||||||
path: HKCU:\Software\Microsoft\Windows\CurrentVersion\Feeds
|
|
||||||
name: ShellFeedsTaskbarViewMode
|
|
||||||
data: 2
|
|
||||||
type: dword
|
|
||||||
register: windows_10_widgets_state
|
|
||||||
when:
|
|
||||||
- windows_hide_taskbar_widgets | default(false)
|
|
||||||
- windows_host_version_state.result.is_windows_10 | default(false)
|
|
||||||
|
|
||||||
- name: Note when Windows shell settings may require sign out
|
- name: Note when Windows shell settings may require sign out
|
||||||
tags: [packages]
|
tags: [packages]
|
||||||
@@ -104,7 +94,6 @@
|
|||||||
or (windows_taskbar_search_state is changed)
|
or (windows_taskbar_search_state is changed)
|
||||||
or (windows_11_widgets_state is changed)
|
or (windows_11_widgets_state is changed)
|
||||||
or (windows_11_widgets_policy_state is changed)
|
or (windows_11_widgets_policy_state is changed)
|
||||||
or (windows_10_widgets_state is changed)
|
|
||||||
|
|
||||||
- name: Ensure winget is available on Windows host
|
- name: Ensure winget is available on Windows host
|
||||||
tags: [packages]
|
tags: [packages]
|
||||||
@@ -140,6 +129,7 @@
|
|||||||
$packageId = '{{ item.id }}'
|
$packageId = '{{ item.id }}'
|
||||||
$packageName = '{{ item.name | default(item.id) }}'
|
$packageName = '{{ item.name | default(item.id) }}'
|
||||||
$packageScope = '{{ item.scope | default('' ) }}'
|
$packageScope = '{{ item.scope | default('' ) }}'
|
||||||
|
$packageIdRegex = [regex]::Escape($packageId)
|
||||||
$installArgs = @(
|
$installArgs = @(
|
||||||
'install'
|
'install'
|
||||||
'--id', $packageId
|
'--id', $packageId
|
||||||
@@ -154,10 +144,12 @@
|
|||||||
$installArgs += @('--scope', $packageScope)
|
$installArgs += @('--scope', $packageScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
$installed = & winget list --id $packageId --exact --accept-source-agreements --disable-interactivity 2>$null
|
if ($packageScope -ne 'user') {
|
||||||
if ($LASTEXITCODE -eq 0 -and $installed -match [regex]::Escape($packageId)) {
|
$installed = & winget list --id $packageId --exact --accept-source-agreements --disable-interactivity 2>$null
|
||||||
$Ansible.Changed = $false
|
if ($LASTEXITCODE -eq 0 -and $installed -match $packageIdRegex) {
|
||||||
return
|
$Ansible.Changed = $false
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($packageScope -eq 'user') {
|
if ($packageScope -eq 'user') {
|
||||||
@@ -170,11 +162,31 @@
|
|||||||
$taskScriptPath = Join-Path $env:TEMP "$taskName.ps1"
|
$taskScriptPath = Join-Path $env:TEMP "$taskName.ps1"
|
||||||
$stdoutPath = Join-Path $env:TEMP "$taskName.stdout.log"
|
$stdoutPath = Join-Path $env:TEMP "$taskName.stdout.log"
|
||||||
$stderrPath = Join-Path $env:TEMP "$taskName.stderr.log"
|
$stderrPath = Join-Path $env:TEMP "$taskName.stderr.log"
|
||||||
|
$resultPath = Join-Path $env:TEMP "$taskName.result.json"
|
||||||
$quotedArgs = ($installArgs | ForEach-Object { '"' + ($_ -replace '"', '""') + '"' }) -join ', '
|
$quotedArgs = ($installArgs | ForEach-Object { '"' + ($_ -replace '"', '""') + '"' }) -join ', '
|
||||||
$taskScript = @(
|
$taskScript = @(
|
||||||
|
"`$ErrorActionPreference = 'Stop'",
|
||||||
|
"function Test-PackageInstalled {",
|
||||||
|
" `$installed = & winget.exe list --id '$packageId' --exact --accept-source-agreements --disable-interactivity 2>`$null",
|
||||||
|
" return (`$LASTEXITCODE -eq 0 -and `$installed -match '$packageIdRegex')",
|
||||||
|
"}",
|
||||||
|
"`$result = @{ changed = `$false; installed = `$false }",
|
||||||
|
"if (-not (Test-PackageInstalled)) {",
|
||||||
"`$installArgs = @($quotedArgs)",
|
"`$installArgs = @($quotedArgs)",
|
||||||
"`$process = Start-Process -FilePath 'winget.exe' -ArgumentList `$installArgs -Wait -PassThru -NoNewWindow -RedirectStandardOutput '$stdoutPath' -RedirectStandardError '$stderrPath'",
|
"`$process = Start-Process -FilePath 'winget.exe' -ArgumentList `$installArgs -Wait -PassThru -NoNewWindow -RedirectStandardOutput '$stdoutPath' -RedirectStandardError '$stderrPath'",
|
||||||
"exit `$process.ExitCode"
|
" if (`$process.ExitCode -ne 0) { exit `$process.ExitCode }",
|
||||||
|
" `$deadline = (Get-Date).AddMinutes(2)",
|
||||||
|
" do {",
|
||||||
|
" Start-Sleep -Seconds 2",
|
||||||
|
" `$result.installed = Test-PackageInstalled",
|
||||||
|
" } while ((Get-Date) -lt `$deadline -and -not `$result.installed)",
|
||||||
|
" if (-not `$result.installed) { throw 'Package was not detected after the user-scoped install completed.' }",
|
||||||
|
" `$result.changed = `$true",
|
||||||
|
"}",
|
||||||
|
"else {",
|
||||||
|
" `$result.installed = `$true",
|
||||||
|
"}",
|
||||||
|
"`$result | ConvertTo-Json -Compress | Set-Content -Path '$resultPath' -Encoding Ascii"
|
||||||
) -join [Environment]::NewLine
|
) -join [Environment]::NewLine
|
||||||
|
|
||||||
Set-Content -Path $taskScriptPath -Value $taskScript -Encoding Ascii
|
Set-Content -Path $taskScriptPath -Value $taskScript -Encoding Ascii
|
||||||
@@ -203,10 +215,22 @@
|
|||||||
$stdout = if (Test-Path $stdoutPath) { Get-Content -Path $stdoutPath -Raw } else { '' }
|
$stdout = if (Test-Path $stdoutPath) { Get-Content -Path $stdoutPath -Raw } else { '' }
|
||||||
throw "Failed to install $packageName with winget. Exit code: $($taskInfo.LastTaskResult). Stdout: $stdout Stderr: $stderr"
|
throw "Failed to install $packageName with winget. Exit code: $($taskInfo.LastTaskResult). Stdout: $stdout Stderr: $stderr"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path $resultPath)) {
|
||||||
|
throw "Failed to install $packageName with winget: no result file was produced by the user-scoped scheduled task."
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = Get-Content -Path $resultPath -Raw | ConvertFrom-Json
|
||||||
|
if (-not $result.installed) {
|
||||||
|
throw "Failed to install $packageName with winget: the package is still not detected after the user-scoped install task finished."
|
||||||
|
}
|
||||||
|
|
||||||
|
$Ansible.Changed = [bool]$result.changed
|
||||||
|
return
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||||
Remove-Item -Path $taskScriptPath, $stdoutPath, $stderrPath -Force -ErrorAction SilentlyContinue
|
Remove-Item -Path $taskScriptPath, $stdoutPath, $stderrPath, $resultPath -Force -ErrorAction SilentlyContinue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
Reference in New Issue
Block a user