Files
AWatch-rus/ansible/deploy_aw_windows.yml
T

602 lines
30 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
- name: Развернуть Windows/RDP collector'ы AWatch-rus
hosts: aw_windows
gather_facts: false
vars:
ansible_winrm_operation_timeout_sec: 120
ansible_winrm_read_timeout_sec: 180
aw_windows_repo_root: "{{ playbook_dir | dirname }}"
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_candidates:
- "{{ aw_windows_repo_root }}/windows/aw-windows-telemetry.exe"
- "{{ aw_windows_rust_target_root }}/x86_64-pc-windows-gnu/release/aw-windows-telemetry.exe"
aw_windows_telemetry_exe_source: ""
aw_windows_server_scheme: "http"
aw_windows_server_port: 5600
aw_windows_package_version: "v0.13.2"
aw_windows_package_url: "https://github.com/ActivityWatch/activitywatch/releases/download/v0.13.2/activitywatch-v0.13.2-windows-x86_64.zip"
aw_windows_package_zip_path: ""
aw_windows_domain: "SHARKON2025"
aw_windows_builtin_administrator_name: "Администратор"
aw_windows_users:
- Администратор
- user1
- user2
- user3
- user4
- user5
aw_windows_extra_users: []
aw_windows_users_effective: "{{ (aw_windows_users + aw_windows_extra_users) | unique }}"
aw_windows_install_root: "C:\\Program Files\\AWatch-rus\\bin"
aw_windows_state_root: "C:\\ProgramData\\AWatch-rus"
aw_windows_policy_mode: "server"
aw_windows_policy_refresh_seconds: 300
aw_windows_policy_engine_enabled: true
aw_windows_policy_engine_port: 5601
aw_windows_policy_engine_scheme: "http"
aw_windows_hayabusa_auto_upload_enabled: true
aw_windows_hayabusa_auto_upload_interval_hours: 6
aw_windows_hayabusa_auto_upload_hours_back: 6
aw_windows_hayabusa_auto_upload_mode: "incident"
aw_windows_hayabusa_auto_upload_task_name: "ActivityWatch Hayabusa Upload"
aw_windows_hayabusa_auto_upload_run_as_user: ""
aw_windows_file_1c_auto_upload_enabled: true
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: "{{ aw_windows_domain }}\\{{ aw_windows_builtin_administrator_name }}"
aw_windows_file_1c_target_user: "igor"
aw_windows_file_1c_registry_workbook_path: "E:\\USER1\\СПИСОК ПРЕДПРИЯТИЙ И ИХ РАСПРЕДЕЛЕНИЕ.xlsx"
aw_windows_afk_enabled_default: true
aw_windows_window_enabled_default: true
aw_windows_file_ops_enabled: true
aw_windows_local_agent_logs_enabled: false
aw_windows_incident_capture_enabled: true
aw_windows_incident_screenshot_enabled: true
aw_windows_incident_artifacts_root: "{{ aw_windows_state_root }}\\incident-artifacts"
aw_windows_forensics_root: "{{ aw_windows_state_root }}\\forensics\\evtx-exports"
aw_windows_logon_marker_enabled: true
aw_windows_process_events_enabled: false
aw_windows_skip_hardening: false
aw_windows_rules_path: "{{ aw_windows_deploy_root }}\\windows\\web-category-rules.example.json"
aw_windows_policy_path: "{{ aw_windows_deploy_root }}\\windows\\dlp-policy.example.json"
aw_windows_validation_remote_path: "{{ aw_windows_state_root }}\\aw_validate_ansible.json"
aw_windows_validation_local_dir: "/tmp/aw-rus-validation-{{ lookup('env','USER') | default('ansible', true) }}"
aw_windows_launch_task_pattern: "ActivityWatch Launch *"
aw_windows_recovery_task_name: "ActivityWatch Recovery"
aw_windows_collector_guard_enabled: true
aw_windows_collector_guard_mode: "enforce"
aw_windows_collector_guard_service_name: "AWatchRusCollectorGuard"
aw_windows_collector_guard_loop_seconds: 60
aw_windows_force_task_restart: true
aw_windows_api_smoke_check_enabled: true
aw_windows_api_smoke_check_bucket: ""
aw_windows_api_smoke_check_limit: 10
aw_windows_api_smoke_check_window_enabled_default: true
aw_windows_api_smoke_check_window_bucket: ""
aw_windows_api_smoke_check_min_events: 1
aw_windows_fail_on_validation_error: true
aw_windows_migration_enabled: true
aw_windows_legacy_install_root: "C:\\Program Files\\ActivityWatch-Phase2"
aw_windows_legacy_state_root: "C:\\ProgramData\\ActivityWatch-Phase2"
aw_windows_migration_report_remote_path: "{{ aw_windows_state_root }}\\aw_migration_ansible.json"
tasks:
- name: Вычислить inventory host AW server по умолчанию
ansible.builtin.set_fact:
aw_server_inventory_host_effective: "{{ (groups['aw_server'] | default([]) | first) | default('', true) }}"
- name: Вычислить inventory host analytics node по умолчанию
ansible.builtin.set_fact:
aw_analytics_inventory_host_effective: "{{ (groups['proxmox'] | default([]) | first) | default('', true) }}"
- name: Вычислить effective host для AW server
ansible.builtin.set_fact:
aw_windows_server_host_effective: >-
{{
aw_windows_server_host
| default(
(
hostvars[aw_server_inventory_host_effective].ansible_host
| default(aw_server_inventory_host_effective, true)
)
if (aw_server_inventory_host_effective | length) > 0
else '',
true
)
}}
- name: Вычислить effective каталог health validation на AW server
ansible.builtin.set_fact:
aw_windows_health_validation_dir_effective: >-
{{
(
hostvars[aw_server_inventory_host_effective].aw_rus_health_validation_dir
| default('/var/lib/activitywatch/health/windows-validation', true)
)
if (aw_server_inventory_host_effective | length) > 0
else ''
}}
- name: Вычислить effective host для policy engine
ansible.builtin.set_fact:
aw_windows_policy_engine_host_effective: >-
{{
aw_windows_policy_engine_host
| default(aw_windows_server_host_effective, 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: Проверить обязательные переменные
ansible.builtin.assert:
that:
- aw_windows_server_host_effective | length > 0
- aw_windows_server_port is defined
- aw_windows_server_scheme is defined
- aw_windows_domain is defined
- aw_windows_builtin_administrator_name is defined
- aw_windows_builtin_administrator_name | length > 0
- aw_windows_users_effective | length > 0
- aw_windows_install_root is defined
- aw_windows_state_root is defined
- (not (aw_windows_file_1c_auto_upload_enabled | bool)) or (aw_windows_file_1c_target_host_effective | length > 0)
fail_msg: "Не заданы обязательные переменные Windows-развёртывания."
- name: Нормализовать effective флаги collector'ов и smoke-check
ansible.builtin.set_fact:
aw_windows_afk_enabled_effective: "{{ (aw_windows_afk_enabled | default(aw_windows_afk_enabled_default)) | bool }}"
aw_windows_window_enabled_effective: "{{ (aw_windows_window_enabled | default(aw_windows_window_enabled_default)) | bool }}"
aw_windows_api_smoke_check_window_enabled_effective: "{{ (aw_windows_api_smoke_check_window_enabled | default(aw_windows_api_smoke_check_window_enabled_default)) | bool }}"
- name: Создать каталоги развёртывания
ansible.windows.win_file:
path: "{{ item }}"
state: directory
loop:
- "{{ aw_windows_deploy_root }}"
- "{{ aw_windows_deploy_root }}\\windows"
- name: Загрузить Windows toolkit развёртывания (без PS-дубликатов — заменены Rust)
ansible.windows.win_copy:
src: "{{ aw_windows_repo_root }}/windows/{{ item }}"
dest: "{{ aw_windows_deploy_root }}\\windows\\{{ item }}"
loop:
- ActivityWatch.Windows.Common.psd1
- ActivityWatch.Windows.Common.psm1
- dlp-policy-client.ps1
- email-outbound-collector.ps1
- worktime-session-collector.ps1
- export-evtx-for-hayabusa.ps1
- export-upload-hayabusa-to-aw-server.ps1
- export-upload-file-1c-telemetry.ps1
- sync-dlp-evidence-artifacts.ps1
- migrate-awatch-rus-paths.ps1
- deploy-domain-users.ps1
- deploy-ensemble.ps1
- hardening-recovery.ps1
- AWatchRusCollectorGuardService.cs
- install-collector-guard-service.ps1
- rebuild-worktime-tasks.ps1
- audit-cryptopro.ps1
- validate-deployment.ps1
- web-category-rules.example.json
- dlp-policy.example.json
- name: Проверить кандидаты Rust Windows telemetry binary
ansible.builtin.stat:
path: "{{ item }}"
loop: "{{ aw_windows_telemetry_exe_source_candidates }}"
delegate_to: localhost
become: false
register: aw_windows_telemetry_exe_candidate_stats
- name: Выбрать Rust Windows telemetry binary
ansible.builtin.set_fact:
aw_windows_telemetry_exe_source_effective: >-
{{
aw_windows_telemetry_exe_source
if (aw_windows_telemetry_exe_source | string | length) > 0
else (
aw_windows_telemetry_exe_candidate_stats.results
| selectattr('stat.exists')
| map(attribute='item')
| list
| first
| default('')
)
}}
- name: Проверить наличие Rust Windows telemetry binary
ansible.builtin.fail:
msg: >-
Не найден aw-windows-telemetry.exe. Соберите его командой:
cargo build --release --target x86_64-pc-windows-gnu -p aw-windows-telemetry
или используйте актуальный install-kit с windows/aw-windows-telemetry.exe.
when: aw_windows_telemetry_exe_source_effective | length == 0
- name: Загрузить Rust Windows telemetry binary
ansible.windows.win_copy:
src: "{{ aw_windows_telemetry_exe_source_effective }}"
dest: "{{ aw_windows_deploy_root }}\\windows\\aw-windows-telemetry.exe"
- name: Нормализовать кодировку PowerShell файлов (UTF-8 BOM для Windows PowerShell)
ansible.windows.win_powershell:
script: |
$ErrorActionPreference = 'Stop'
$toolkitDir = "{{ aw_windows_deploy_root }}\windows"
$encIn = New-Object System.Text.UTF8Encoding($false)
$encOut = New-Object System.Text.UTF8Encoding($true)
Get-ChildItem -LiteralPath $toolkitDir -File -Include *.ps1,*.psm1,*.psd1 | ForEach-Object {
$text = [System.IO.File]::ReadAllText($_.FullName, $encIn)
[System.IO.File]::WriteAllText($_.FullName, $text, $encOut)
}
- name: Загрузить список пользователей для доменного развёртывания
ansible.windows.win_copy:
dest: "{{ aw_windows_deploy_root }}\\windows\\users.txt"
content: |
{% for user in aw_windows_users_effective -%}
{{ user }}
{% endfor -%}
- name: Проверить нужен ли migration с legacy ActivityWatch путей
when: aw_windows_migration_enabled | bool
ansible.windows.win_stat:
path: "{{ aw_windows_legacy_state_root }}\\deployment-config.json"
register: aw_windows_legacy_config
- name: Выполнить безопасную migration legacy prod в AWatch-rus
when:
- aw_windows_migration_enabled | bool
- aw_windows_legacy_config.stat.exists | default(false)
ansible.windows.win_powershell:
script: |
$ErrorActionPreference = 'Stop'
$result = & "{{ aw_windows_deploy_root }}\windows\migrate-awatch-rus-paths.ps1" `
-OldInstallRoot "{{ aw_windows_legacy_install_root }}" `
-OldStateRoot "{{ aw_windows_legacy_state_root }}" `
-NewInstallRoot "{{ aw_windows_install_root }}" `
-NewStateRoot "{{ aw_windows_state_root }}" `
-ToolkitRoot "{{ aw_windows_deploy_root }}\windows"
$result | ConvertTo-Json -Depth 8 | Out-File -FilePath "{{ aw_windows_migration_report_remote_path }}" -Encoding utf8
- name: Запустить Windows/RDP ensemble развёртывание
ansible.windows.win_powershell:
script: |
$ErrorActionPreference = 'Stop'
$env:AWATCH_RUS_BUILTIN_ADMINISTRATOR_NAME = "{{ aw_windows_builtin_administrator_name }}"
$params = @{
ServerScheme = "{{ aw_windows_server_scheme }}"
ServerHost = "{{ aw_windows_server_host_effective }}"
ServerPort = {{ aw_windows_server_port }}
Version = "{{ aw_windows_package_version }}"
Domain = "{{ aw_windows_domain }}"
UserListPath = "{{ aw_windows_deploy_root }}\windows\users.txt"
InstallRoot = "{{ aw_windows_install_root }}"
StateRoot = "{{ aw_windows_state_root }}"
AfkEnabled = {{ '$true' if (aw_windows_afk_enabled_effective | bool) else '$false' }}
WindowEnabled = {{ '$true' if (aw_windows_window_enabled_effective | bool) else '$false' }}
FileOpsEnabled = {{ '$true' if (aw_windows_file_ops_enabled | bool) else '$false' }}
LocalAgentLogsEnabled = {{ '$true' if (aw_windows_local_agent_logs_enabled | bool) else '$false' }}
IncidentCaptureEnabled = {{ '$true' if (aw_windows_incident_capture_enabled | bool) else '$false' }}
IncidentScreenshotEnabled = {{ '$true' if (aw_windows_incident_screenshot_enabled | bool) else '$false' }}
IncidentArtifactsRoot = "{{ aw_windows_incident_artifacts_root }}"
EvtxExportRoot = "{{ aw_windows_forensics_root }}"
EvtxRetentionDays = {{ aw_windows_evtx_retention_days | int }}
LogonMarkerEnabled = {{ '$true' if (aw_windows_logon_marker_enabled | bool) else '$false' }}
ProcessEventsEnabled = {{ '$true' if (aw_windows_process_events_enabled | bool) else '$false' }}
PolicyMode = "{{ aw_windows_policy_mode }}"
PolicyEngineEnabled = {{ '$true' if (aw_windows_policy_engine_enabled | bool) else '$false' }}
PolicyEngineHost = "{{ aw_windows_policy_engine_host_effective }}"
PolicyEnginePort = {{ aw_windows_policy_engine_port }}
PolicyEngineScheme = "{{ aw_windows_policy_engine_scheme }}"
PolicyRefreshSeconds = {{ aw_windows_policy_refresh_seconds }}
HayabusaAutoUploadEnabled = {{ '$true' if (aw_windows_hayabusa_auto_upload_enabled | bool) else '$false' }}
HayabusaAutoUploadIntervalHours = {{ aw_windows_hayabusa_auto_upload_interval_hours | int }}
HayabusaAutoUploadHoursBack = {{ aw_windows_hayabusa_auto_upload_hours_back | int }}
HayabusaAutoUploadMode = "{{ aw_windows_hayabusa_auto_upload_mode }}"
HayabusaAutoUploadTaskName = "{{ aw_windows_hayabusa_auto_upload_task_name }}"
HayabusaAutoUploadRunAsUser = "{{ aw_windows_hayabusa_auto_upload_run_as_user }}"
File1CAutoUploadEnabled = {{ '$true' if (aw_windows_file_1c_auto_upload_enabled | bool) else '$false' }}
File1CAutoUploadIntervalMinutes = {{ aw_windows_file_1c_auto_upload_interval_minutes | int }}
File1CAutoUploadTaskName = "{{ aw_windows_file_1c_auto_upload_task_name }}"
File1CAutoUploadRunAsUser = "{{ aw_windows_file_1c_auto_upload_run_as_user }}"
File1CTargetHost = "{{ aw_windows_file_1c_target_host_effective }}"
File1CTargetUser = "{{ aw_windows_file_1c_target_user }}"
File1CRegistryWorkbookPath = "{{ aw_windows_file_1c_registry_workbook_path }}"
CustomRulesPath = "{{ aw_windows_rules_path }}"
CustomPolicyPath = "{{ aw_windows_policy_path }}"
}
{% if (aw_windows_package_url | default('') | string | length) > 0 %}
$params.PackageUrl = "{{ aw_windows_package_url }}"
{% endif %}
{% if (aw_windows_package_zip_path | default('') | string | length) > 0 %}
$params.PackageZipPath = "{{ aw_windows_package_zip_path }}"
{% endif %}
{% if (aw_windows_evtx_channels | default([]) | length) > 0 %}
$params.EvtxChannels = @(
{% for channel in aw_windows_evtx_channels %}
"{{ channel }}"{% if not loop.last %},{% endif %}
{% endfor %}
)
{% endif %}
{% if (aw_windows_hostname_override | default('') | string | length) > 0 %}
$params.AwHostname = "{{ aw_windows_hostname_override }}"
{% endif %}
{% if aw_windows_skip_hardening | bool %}
$params.SkipHardening = $true
{% endif %}
{% if aw_windows_integration_test_enabled | bool %}
$params.IntegrationTestEnabled = $true
{% endif %}
& "{{ aw_windows_deploy_root }}\windows\deploy-ensemble.ps1" @params
- name: Удалить лишние ActivityWatch Launch tasks вне текущего deployment-config
ansible.windows.win_powershell:
script: |
$ErrorActionPreference = 'Stop'
$config = Get-Content -Raw -LiteralPath "{{ aw_windows_state_root }}\deployment-config.json" | ConvertFrom-Json
$desired = @($config.userTasks | ForEach-Object { [string]$_.LaunchTaskName })
foreach ($task in @(Get-ScheduledTask | Where-Object { $_.TaskName -like 'ActivityWatch Launch *' })) {
if ($desired -notcontains [string]$task.TaskName) {
Unregister-ScheduledTask -TaskName $task.TaskName -Confirm:$false -ErrorAction SilentlyContinue
& cmd.exe /c "schtasks /Delete /TN `"$($task.TaskName)`" /F >nul 2>&1" | Out-Null
}
}
- name: Принудительно запустить ActivityWatch recovery и launch tasks
when: aw_windows_force_task_restart | bool
ansible.windows.win_powershell:
script: |
$ErrorActionPreference = 'Stop'
function Get-CollectorKey {
param([string]$CommandLine)
if (-not $CommandLine) { return $null }
$cl = $CommandLine.ToLowerInvariant()
if ($cl -like '*browser-domains-native-collector.ps1*') { return 'browser' }
if ($cl -like '*file-operations-collector.ps1*') { return 'fileops' }
if ($cl -like '*dlp-endpoint-signals-collector.ps1*') { return 'endpoint' }
if ($cl -like '*email-outbound-collector.ps1*') { return 'email' }
if ($cl -like '*worktime-session-collector.ps1*') { return 'worktime' }
return $null
}
$collectorProcs = Get-CimInstance Win32_Process |
Where-Object { $_.Name -eq 'powershell.exe' -and $_.CommandLine } |
ForEach-Object {
$key = Get-CollectorKey -CommandLine $_.CommandLine
if ($key) {
$groupKey = if ($key -eq 'worktime') { 'worktime::global' } else { '{0}::{1}' -f $key, ([int]$_.SessionId) }
[pscustomobject]@{
ProcessId = [int]$_.ProcessId
SessionId = [int]$_.SessionId
CreationDate = $_.CreationDate
CollectorKey = $key
GroupKey = $groupKey
}
}
} |
Where-Object { $_ -ne $null }
# Keep only one process per collector scope: worktime collector is global, others stay per-session.
foreach ($group in ($collectorProcs | Group-Object GroupKey)) {
$ordered = @($group.Group | Sort-Object CreationDate -Descending)
if ($ordered.Count -le 1) { continue }
foreach ($dup in $ordered | Select-Object -Skip 1) {
Stop-Process -Id $dup.ProcessId -Force -ErrorAction SilentlyContinue
}
}
# Force managed collectors/watchers to reload the freshly deployed scripts.
Get-CimInstance Win32_Process -ErrorAction SilentlyContinue |
Where-Object {
(
($_.Name -ieq 'powershell.exe' -or $_.Name -ieq 'pwsh.exe') -and
$_.CommandLine -match 'C:\\ProgramData\\AWatch-rus\\' -and
$_.CommandLine -match '(collector|launch-watchers|recovery-loop)\.ps1'
) -or
($_.Name -ieq 'aw-watcher-afk.exe') -or
($_.Name -ieq 'aw-watcher-window.exe')
} |
ForEach-Object {
Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue
}
Start-Sleep -Seconds 2
$modulePath = "{{ aw_windows_deploy_root }}\windows\ActivityWatch.Windows.Common.psm1"
Import-Module $modulePath -Force
# Ensure tasks are enabled (some environments keep them disabled, causing "0s" in WebUI).
try {
Enable-ScheduledTask -TaskName "{{ aw_windows_recovery_task_name }}" -ErrorAction SilentlyContinue | Out-Null
} catch {}
$config = Get-Content -Raw -LiteralPath "{{ aw_windows_state_root }}\deployment-config.json" | ConvertFrom-Json
$configPaths = Get-ActivityWatchRecoveryConfigPaths -PrimaryConfigPath "{{ aw_windows_state_root }}\deployment-config.json"
$taskDefs = @(Get-ActivityWatchRecoveryTaskDefinitions -ConfigPaths $configPaths)
$sessionRecords = @(Get-ActivityWatchSessionRecords)
foreach ($taskDef in @($taskDefs)) {
try { Enable-ScheduledTask -TaskName ([string]$taskDef.taskName) -ErrorAction SilentlyContinue | Out-Null } catch {}
}
$recoveryTask = Get-ScheduledTask -TaskName "{{ aw_windows_recovery_task_name }}" -ErrorAction SilentlyContinue
if ($recoveryTask -and $recoveryTask.State -notin @('Running', 'Queued')) {
Start-ScheduledTask -TaskName "{{ aw_windows_recovery_task_name }}"
}
foreach ($taskDef in @($taskDefs)) {
if (-not (Test-ActivityWatchUserHasManagedSession -UserId ([string]$taskDef.userId) -SessionRecords $sessionRecords -IncludeLive -IncludeDisconnected)) {
continue
}
$launchTask = Get-ScheduledTask -TaskName ([string]$taskDef.taskName) -ErrorAction SilentlyContinue
if ($launchTask -and $launchTask.State -notin @('Running', 'Queued')) {
Start-ScheduledTask -TaskName ([string]$taskDef.taskName) -ErrorAction SilentlyContinue
}
}
- name: Установить session-aware AWatch-rus Collector Guard service
when: aw_windows_collector_guard_enabled | bool
ansible.windows.win_powershell:
script: |
$ErrorActionPreference = 'Stop'
$guardParams = @{
ConfigPath = "{{ aw_windows_state_root }}\deployment-config.json"
Mode = "{{ aw_windows_collector_guard_mode }}"
ServiceName = "{{ aw_windows_collector_guard_service_name }}"
LoopSeconds = {{ aw_windows_collector_guard_loop_seconds | int }}
}
& "{{ aw_windows_deploy_root }}\windows\install-collector-guard-service.ps1" @guardParams
- name: Получить Windows hostname для AW smoke-check bucket
when:
- aw_windows_api_smoke_check_enabled | bool
ansible.windows.win_command: powershell.exe -NoProfile -Command "$env:COMPUTERNAME"
register: aw_windows_hostname_result
changed_when: false
- name: Вычислить AW worktime smoke-check bucket
when:
- aw_windows_api_smoke_check_enabled | bool
- aw_windows_hostname_result.stdout is defined
ansible.builtin.set_fact:
aw_windows_api_smoke_check_bucket_effective: >-
{{
aw_windows_api_smoke_check_bucket
if (aw_windows_api_smoke_check_bucket | default('') | string | length) > 0
else 'aw-worktime-sessions_' ~ (aw_windows_hostname_result.stdout | trim)
}}
- name: Вычислить AW Window smoke-check bucket
when:
- aw_windows_api_smoke_check_enabled | bool
- aw_windows_api_smoke_check_window_enabled_effective | bool
- aw_windows_window_enabled_effective | bool
- aw_windows_hostname_result.stdout is defined
ansible.builtin.set_fact:
aw_windows_api_smoke_check_window_bucket_effective: >-
{{
aw_windows_api_smoke_check_window_bucket
if (aw_windows_api_smoke_check_window_bucket | default('') | string | length) > 0
else 'aw-watcher-window_' ~ (aw_windows_hostname_result.stdout | trim)
}}
- name: Выполнить AW API smoke-check (worktime bucket должен получать события)
when:
- aw_windows_api_smoke_check_enabled | bool
ansible.builtin.uri:
url: "{{ aw_windows_server_scheme }}://{{ aw_windows_server_host_effective }}:{{ aw_windows_server_port }}/api/0/buckets/{{ aw_windows_api_smoke_check_bucket_effective }}/events?limit={{ aw_windows_api_smoke_check_limit }}"
method: GET
status_code: 200
return_content: true
register: aw_windows_api_smoke_result
failed_when: false
until: >-
(aw_windows_api_smoke_result.status | default(0)) == 200
and ((aw_windows_api_smoke_result.json | default([])) | length) >= aw_windows_api_smoke_check_min_events
and (
(aw_windows_api_smoke_result.json | default([]))
| selectattr('data.source', 'equalto', 'worktime-session-collector')
| list
| length
) > 0
retries: 12
delay: 5
ignore_errors: "{{ (not aw_windows_fail_on_validation_error | bool) }}"
delegate_to: localhost
changed_when: false
- name: Выполнить AW API smoke-check (Window bucket должен получать события)
when:
- aw_windows_api_smoke_check_enabled | bool
- aw_windows_api_smoke_check_window_enabled_effective | bool
- aw_windows_window_enabled_effective | bool
ansible.builtin.uri:
url: "{{ aw_windows_server_scheme }}://{{ aw_windows_server_host_effective }}:{{ aw_windows_server_port }}/api/0/buckets/{{ aw_windows_api_smoke_check_window_bucket_effective }}/events?limit={{ aw_windows_api_smoke_check_limit }}"
method: GET
status_code: 200
return_content: true
register: aw_windows_api_smoke_window_result
failed_when: false
until: >-
(aw_windows_api_smoke_window_result.status | default(0)) == 200
and ((aw_windows_api_smoke_window_result.json | default([])) | length) >= aw_windows_api_smoke_check_min_events
retries: 12
delay: 5
ignore_errors: "{{ (not aw_windows_fail_on_validation_error | bool) }}"
delegate_to: localhost
changed_when: false
- name: Валидировать развёртывание на эндпоинте
ansible.windows.win_powershell:
script: |
$ErrorActionPreference = 'Stop'
$result = & "{{ aw_windows_deploy_root }}\windows\validate-deployment.ps1" `
-ConfigPath "{{ aw_windows_state_root }}\deployment-config.json"
$result | ConvertTo-Json -Depth 12 | Out-File -FilePath "{{ aw_windows_validation_remote_path }}" -Encoding utf8
return $result
- name: Создать локальную директорию для отчётов валидации
ansible.builtin.file:
path: "{{ aw_windows_validation_local_dir }}"
state: directory
mode: "0755"
delegate_to: localhost
- name: Стянуть отчёт валидации с эндпоинта
ansible.builtin.fetch:
src: "{{ aw_windows_validation_remote_path }}"
dest: "{{ aw_windows_validation_local_dir }}/{{ inventory_hostname }}-aw_validate_ansible.json"
flat: true
- name: Убедиться, что каталог Windows validation существует на AW server
when:
- aw_server_inventory_host_effective | length > 0
- aw_windows_health_validation_dir_effective | length > 0
ansible.builtin.file:
path: "{{ aw_windows_health_validation_dir_effective }}"
state: directory
mode: "0755"
delegate_to: "{{ aw_server_inventory_host_effective }}"
- name: Опубликовать validation report на AW server для aw-rus-healthd
when:
- aw_server_inventory_host_effective | length > 0
- aw_windows_health_validation_dir_effective | length > 0
ansible.builtin.copy:
src: "{{ aw_windows_validation_local_dir }}/{{ inventory_hostname }}-aw_validate_ansible.json"
dest: "{{ aw_windows_health_validation_dir_effective }}/{{ inventory_hostname }}-aw_validate_ansible.json"
mode: "0644"
delegate_to: "{{ aw_server_inventory_host_effective }}"
- name: Проверить статус валидации
ansible.builtin.shell: |
python3 - <<'PY'
import json, sys
with open('{{ aw_windows_validation_local_dir }}/{{ inventory_hostname }}-aw_validate_ansible.json', 'r', encoding='utf-8-sig') as f:
data = json.load(f)
if not data.get('overallOk', False):
failed = ", ".join(data.get("summary", {}).get("failedSections", [])) or "unknown"
print(f"Validation failed for {{ inventory_hostname }}: {failed}")
sys.exit(1)
PY
delegate_to: localhost
when: aw_windows_fail_on_validation_error | bool