--- - name: Развернуть file-1C telemetry uploader на Windows hosts: aw_windows gather_facts: false vars: aw_windows_repo_root: "{{ playbook_dir | dirname }}" aw_windows_state_root: "C:\\ProgramData\\AWatch-rus" aw_windows_deploy_root: "C:\\Program Files\\AWatch-rus" aw_windows_file_1c_target_user: "igor" aw_windows_file_1c_auto_upload_interval_hours: 6 aw_windows_file_1c_auto_upload_task_name: "ActivityWatch File1C Upload" aw_windows_file_1c_remote_root: "/opt/activitywatch/clickhouse-1c/landing" aw_windows_file_1c_remote_key_path: "" aw_windows_file_1c_registry_workbook_path: "E:\\USER1\\СПИСОК ПРЕДПРИЯТИЙ И ИХ РАСПРЕДЕЛЕНИЕ.xlsx" aw_windows_upload_key_private_path: /tmp/awops_ed25519 aw_windows_upload_key_public_path: /tmp/awops_ed25519.pub tasks: - name: Вычислить inventory host analytics node по умолчанию ansible.builtin.set_fact: aw_analytics_inventory_host_effective: "{{ (groups['proxmox'] | default([]) | first) | default('', true) }}" - name: Вычислить effective host для file-1C analytics ansible.builtin.set_fact: aw_windows_file_1c_target_host_effective: >- {{ aw_windows_file_1c_target_host | default( ( hostvars[aw_analytics_inventory_host_effective].ansible_host | default(aw_analytics_inventory_host_effective, true) ) if (aw_analytics_inventory_host_effective | length) > 0 else '', true ) }} - name: Проверить обязательные переменные file-1C telemetry ansible.builtin.assert: that: - aw_windows_file_1c_target_host_effective | length > 0 fail_msg: "Не удалось вычислить host file-1C analytics для Windows uploader." - name: Создать каталоги file-1C telemetry на Windows ansible.windows.win_file: path: "{{ item }}" state: directory loop: - "{{ aw_windows_state_root }}" - "{{ aw_windows_deploy_root }}\\windows" - "{{ aw_windows_state_root }}\\ssh" - name: Установить private key для Windows file-1C uploader ansible.windows.win_copy: src: "{{ aw_windows_upload_key_private_path }}" dest: "{{ aw_windows_state_root }}\\ssh\\awops_ed25519" - name: Установить public key для Windows file-1C uploader ansible.windows.win_copy: src: "{{ aw_windows_upload_key_public_path }}" dest: "{{ aw_windows_state_root }}\\ssh\\awops_ed25519.pub" - name: Загрузить file-1C telemetry script в toolkit ansible.windows.win_copy: src: "{{ aw_windows_repo_root }}/windows/export-upload-file-1c-telemetry.ps1" dest: "{{ aw_windows_deploy_root }}\\windows\\export-upload-file-1c-telemetry.ps1" - name: Загрузить file-1C telemetry script в state root ansible.windows.win_copy: src: "{{ aw_windows_repo_root }}/windows/export-upload-file-1c-telemetry.ps1" dest: "{{ aw_windows_state_root }}\\export-upload-file-1c-telemetry.ps1" - name: Обновить deployment-config.json блоком analytics.file1cAutomation ansible.windows.win_powershell: script: | $ErrorActionPreference = 'Stop' $configPath = "{{ aw_windows_state_root }}\deployment-config.json" $config = Get-Content -Raw -LiteralPath $configPath | ConvertFrom-Json if ($config.PSObject.Properties.Name -notcontains 'paths') { $config | Add-Member -NotePropertyName 'paths' -NotePropertyValue ([pscustomobject]@{}) } if ($config.paths.PSObject.Properties.Name -contains 'file1cTelemetryScript') { $config.paths.file1cTelemetryScript = "{{ aw_windows_state_root }}\export-upload-file-1c-telemetry.ps1" } else { $config.paths | Add-Member -NotePropertyName 'file1cTelemetryScript' -NotePropertyValue "{{ aw_windows_state_root }}\export-upload-file-1c-telemetry.ps1" } if ($config.PSObject.Properties.Name -notcontains 'analytics') { $config | Add-Member -NotePropertyName 'analytics' -NotePropertyValue ([pscustomobject]@{}) } $automation = [pscustomobject]@{ enabled = $true intervalHours = {{ aw_windows_file_1c_auto_upload_interval_hours | int }} taskName = "{{ aw_windows_file_1c_auto_upload_task_name }}" targetHost = "{{ aw_windows_file_1c_target_host_effective }}" targetUser = "{{ aw_windows_file_1c_target_user }}" remoteRoot = "{{ aw_windows_file_1c_remote_root }}" registryWorkbookPath = "{{ aw_windows_file_1c_registry_workbook_path }}" remoteKeyPath = "{{ aw_windows_file_1c_remote_key_path }}" } if ($config.analytics.PSObject.Properties.Name -contains 'file1cAutomation') { $config.analytics.file1cAutomation = $automation } else { $config.analytics | Add-Member -NotePropertyName 'file1cAutomation' -NotePropertyValue $automation } $json = $config | ConvertTo-Json -Depth 12 Set-Content -LiteralPath $configPath -Value $json -Encoding UTF8 - name: Разложить file-1C upload key по локальным пользовательским профилям ansible.windows.win_powershell: script: | $ErrorActionPreference = 'Stop' $src = "{{ aw_windows_state_root }}\ssh\awops_ed25519" if (-not (Test-Path -LiteralPath $src)) { throw "Не найден private key uploader: $src" } $statePath = "{{ aw_windows_state_root }}\file1c-telemetry-state.json" if (-not (Test-Path -LiteralPath $statePath)) { '{}' | Set-Content -LiteralPath $statePath -Encoding UTF8 } $profiles = Get-CimInstance Win32_UserProfile | Where-Object { -not $_.Special -and $_.LocalPath -like 'C:\Users\*' } | Sort-Object LocalPath foreach ($profile in $profiles) { $user = Split-Path $profile.LocalPath -Leaf $sshDir = Join-Path $profile.LocalPath '.ssh' $dst = Join-Path $sshDir 'awops_ed25519' $grantDir = 'HOST-EXAMPLE\' + $user + ':(OI)(CI)(F)' $grantRead = 'HOST-EXAMPLE\' + $user + ':(R)' $grantModify = 'HOST-EXAMPLE\' + $user + ':(M)' New-Item -ItemType Directory -Path $sshDir -Force | Out-Null & icacls.exe $sshDir /grant $grantDir | Out-Null & icacls.exe $statePath /grant $grantModify | Out-Null if (-not (Test-Path -LiteralPath $dst)) { Copy-Item -LiteralPath $src -Destination $dst -Force } & icacls.exe $dst /inheritance:r /grant:r $grantRead '*S-1-5-18:(R)' '*S-1-5-32-544:(R)' | Out-Null } - name: Создать scheduled task file-1C upload ansible.windows.win_powershell: script: | $ErrorActionPreference = 'Stop' $taskName = "{{ aw_windows_file_1c_auto_upload_task_name }}" $powerShellExe = Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe' $taskCommand = "`"$powerShellExe`" -NoProfile -ExecutionPolicy Bypass -File `"{{ aw_windows_state_root }}\export-upload-file-1c-telemetry.ps1`" -ConfigPath `"{{ aw_windows_state_root }}\deployment-config.json`"" $existingTask = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue if ($existingTask) { $action = New-ScheduledTaskAction -Execute $powerShellExe -Argument "-NoProfile -ExecutionPolicy Bypass -File `"{{ aw_windows_state_root }}\export-upload-file-1c-telemetry.ps1`" -ConfigPath `"{{ aw_windows_state_root }}\deployment-config.json`"" try { Set-ScheduledTask -TaskName $taskName -Action $action -ErrorAction Stop | Out-Null } catch { Write-Host "skip task action update for $taskName because the existing principal requires stored credentials: $($_.Exception.Message)" } } else { & schtasks.exe /Create /TN $taskName /TR $taskCommand /SC HOURLY /MO {{ aw_windows_file_1c_auto_upload_interval_hours | int }} /ST 00:00 /RU SYSTEM /RL HIGHEST /F | Out-Null if ($LASTEXITCODE -ne 0) { throw "Не удалось создать scheduled task $taskName" } }