--- - 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_rust_target_root: "{{ lookup('env', 'CARGO_TARGET_DIR') | default('/tmp/detmir-adk-rust-target', true) }}" aw_windows_telemetry_exe_source: "{{ aw_windows_rust_target_root }}/x86_64-pc-windows-gnu/release/aw-windows-telemetry.exe" aw_windows_telemetry_exe_path: "{{ aw_windows_deploy_root }}\\windows\\aw-windows-telemetry.exe" aw_windows_file_1c_target_user: "igor" aw_windows_file_1c_auto_upload_interval_minutes: 15 aw_windows_file_1c_auto_upload_task_name: "ActivityWatch File1C Upload" aw_windows_file_1c_auto_upload_run_as_user: "HOST-EXAMPLE\\Администратор" 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: Загрузить Rust telemetry binary в toolkit ansible.windows.win_copy: src: "{{ aw_windows_telemetry_exe_source }}" dest: "{{ aw_windows_telemetry_exe_path }}" - 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.paths.PSObject.Properties.Name -contains 'file1cTelemetryExecutable') { $config.paths.file1cTelemetryExecutable = "{{ aw_windows_telemetry_exe_path }}" } else { $config.paths | Add-Member -NotePropertyName 'file1cTelemetryExecutable' -NotePropertyValue "{{ aw_windows_telemetry_exe_path }}" } if ($config.PSObject.Properties.Name -notcontains 'analytics') { $config | Add-Member -NotePropertyName 'analytics' -NotePropertyValue ([pscustomobject]@{}) } $automation = [pscustomobject]@{ enabled = $true intervalMinutes = {{ aw_windows_file_1c_auto_upload_interval_minutes | 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 }}" runAsUser = "{{ aw_windows_file_1c_auto_upload_run_as_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 }}" $telemetryExe = "{{ aw_windows_telemetry_exe_path }}" $runAsUser = "{{ aw_windows_file_1c_auto_upload_run_as_user }}" $taskArgs = "file1c-upload --config-path `"{{ aw_windows_state_root }}\deployment-config.json`"" $action = New-ScheduledTaskAction -Execute $telemetryExe -Argument $taskArgs $trigger = New-ScheduledTaskTrigger -Once -At ((Get-Date).Date) -RepetitionInterval (New-TimeSpan -Minutes {{ aw_windows_file_1c_auto_upload_interval_minutes | int }}) -RepetitionDuration (New-TimeSpan -Days 3650) if ([string]::IsNullOrWhiteSpace($runAsUser)) { $principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest } else { $principal = New-ScheduledTaskPrincipal -UserId $runAsUser -LogonType Interactive -RunLevel Highest } $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -StartWhenAvailable -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Minutes 10) $existingTask = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue if ($existingTask) { Set-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -ErrorAction Stop | Out-Null } else { Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings | Out-Null }