Files
AWatch-rus/ansible/deploy_aw_server.yml
T

1561 lines
65 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: Развернуть сервер AWatch-rus
hosts: aw_server
become: true
gather_facts: true
vars:
aw_release_root: "/opt/activitywatch/releases"
aw_release_dir: "{{ aw_release_root }}/{{ aw_server_version }}"
aw_archive_path: "/tmp/activitywatch-{{ aw_server_version }}.zip"
aw_bootstrap_dir: "/tmp/aw-rus-bootstrap"
aw_release_install_dir: "{{ aw_release_root }}/aw-server-rust-{{ aw_server_version }}"
aw_ru_patch_cache_bust: "{{ lookup('file', aw_repo_root + '/aw-server/aw-ru-patch.js') | hash('sha1') | truncate(12, true, '') }}"
aw_sw_cleanup_cache_bust: "{{ lookup('file', aw_repo_root + '/aw-server/aw-sw-cleanup.js') | hash('sha1') | truncate(12, true, '') }}"
aw_worktime_classes: "{{ lookup('file', aw_repo_root + '/aw-server/settings/classes-worktime.json') | from_json }}"
aw_default_views: "{{ lookup('file', aw_repo_root + '/aw-server/settings/views-default.json') | from_json }}"
tasks:
- name: Установить базовые пакеты
ansible.builtin.apt:
name:
- curl
- python3-venv
- python3-pip
- rsync
- tesseract-ocr
- tesseract-ocr-rus
- unzip
state: present
update_cache: true
- name: Создать системную группу сервиса
ansible.builtin.group:
name: "{{ aw_server_group }}"
system: true
state: present
- name: Создать системную учётную запись сервиса
ansible.builtin.user:
name: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
home: "{{ aw_server_data_dir }}"
shell: /usr/sbin/nologin
system: true
create_home: false
- name: Создать обязательные каталоги
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: "0755"
loop:
- "{{ aw_release_root }}"
- "{{ aw_release_dir }}"
- "{{ aw_release_install_dir }}"
- /opt/activitywatch
- /opt/activitywatch/bin
- "{{ aw_server_webui_dir }}"
- "{{ aw_server_webui_dir }}/js"
- "{{ aw_server_data_dir }}"
- "{{ aw_server_db_path | dirname }}"
- "{{ aw_server_data_dir }}/.config"
- "{{ aw_server_data_dir }}/.config/activitywatch"
- "{{ aw_server_data_dir }}/.config/activitywatch/aw-server-rust"
- "{{ aw_server_data_dir }}/backups"
- "{{ aw_server_log_dir }}"
- /etc/activitywatch
- "{{ aw_bootstrap_dir }}"
- name: Настроить каталоги ActivityWatch с владельцем сервиса
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
loop:
- /opt/activitywatch
- /opt/activitywatch/bin
- "{{ aw_release_root }}"
- "{{ aw_release_dir }}"
- "{{ aw_release_install_dir }}"
- "{{ aw_server_webui_dir }}"
- "{{ aw_server_webui_dir }}/js"
- "{{ aw_server_data_dir }}"
- "{{ aw_server_db_path | dirname }}"
- "{{ aw_server_data_dir }}/.config"
- "{{ aw_server_data_dir }}/.config/activitywatch"
- "{{ aw_server_data_dir }}/.config/activitywatch/aw-server-rust"
- "{{ aw_server_data_dir }}/backups"
- "{{ aw_server_log_dir }}"
- name: (Check mode) Пропустить установку релиза ActivityWatch
ansible.builtin.debug:
msg: "ansible_check_mode=true: download/unarchive/install of ActivityWatch release is skipped."
when: ansible_check_mode
- name: Установить релиз ActivityWatch (download/unarchive/install)
when: not ansible_check_mode
block:
- name: Скачать архив релиза ActivityWatch
ansible.builtin.get_url:
url: "{{ aw_server_download_url }}"
dest: "{{ aw_archive_path }}"
mode: "0644"
- name: Распаковать релиз ActivityWatch
ansible.builtin.unarchive:
src: "{{ aw_archive_path }}"
dest: "{{ aw_release_dir }}"
remote_src: true
extra_opts: ["-o"]
- name: Найти распакованный каталог ActivityWatch
ansible.builtin.find:
paths: "{{ aw_release_dir }}"
recurse: true
file_type: directory
patterns: "activitywatch*"
register: aw_release_find
- name: Найти бинарный файл AW server
ansible.builtin.find:
paths: "{{ aw_release_dir }}"
recurse: true
file_type: file
patterns:
- aw-server-rust
- aw-server
register: aw_server_binary_find
- name: Найти index.html WebUI
ansible.builtin.find:
paths: "{{ aw_release_dir }}"
recurse: true
file_type: file
patterns:
- index.html
register: aw_webui_index_find
- name: Сохранить пути распакованного релиза (binary + webui index)
ansible.builtin.set_fact:
aw_release_extracted: "{{ (aw_release_find.files | default([]) | sort(attribute='path') | map(attribute='path') | list | first) | default('') }}"
aw_server_binary_path: >-
{{
(
(
(aw_server_binary_find.files | default([]) | sort(attribute='path') | map(attribute='path') | list)
| select('match', '.*/aw-server-rust$') | list | first
)
| default(
(
(aw_server_binary_find.files | default([]) | sort(attribute='path') | map(attribute='path') | list | first)
),
true
)
) | default('')
}}
aw_webui_index_path: >-
{{
(
(
(aw_webui_index_find.files | default([]) | sort(attribute='path') | map(attribute='path') | list)
| select('search', '/static/index\\.html$') | list | first
)
| default(
(
(aw_webui_index_find.files | default([]) | sort(attribute='path') | map(attribute='path') | list | first)
),
true
)
) | default('')
}}
- name: Сохранить каталог WebUI (dirname index.html)
ansible.builtin.set_fact:
aw_webui_source_path: "{{ aw_webui_index_path | dirname }}"
- name: Проверить, что компоненты релиза найдены
ansible.builtin.assert:
that:
- aw_release_extracted is defined
- aw_release_extracted | length > 0
- aw_server_binary_path is defined
- aw_server_binary_path | length > 0
- aw_webui_source_path is defined
- aw_webui_source_path | length > 0
fail_msg: "Не удалось найти бинарный файл или WebUI в распакованном релизе ActivityWatch."
- name: Создать каталог установленного релиза
ansible.builtin.file:
path: "{{ aw_release_install_dir }}"
state: directory
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
- name: Установить бинарный файл AW server
ansible.builtin.copy:
remote_src: true
src: "{{ aw_server_binary_path }}"
dest: "{{ aw_release_install_dir }}/aw-server-rust"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
- name: Создать ссылку на активный бинарный файл AW server
ansible.builtin.file:
src: "{{ aw_release_install_dir }}/aw-server-rust"
dest: /opt/activitywatch/bin/aw-server-rust
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
state: link
force: true
- name: Синхронизировать WebUI в RU каталог
ansible.builtin.command:
cmd: "rsync -a {{ aw_webui_source_path }}/ {{ aw_server_webui_dir }}/"
- name: Настроить владельца файлов /opt/activitywatch
ansible.builtin.file:
path: /opt/activitywatch
state: directory
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
recurse: true
- name: Установить systemd service из шаблона репозитория
ansible.builtin.copy:
dest: /etc/systemd/system/activitywatch-server.service
mode: "0644"
content: >-
{{
lookup('file', aw_repo_root + '/aw-server/activitywatch-server.service')
| replace('__AW_SERVER_USER__', aw_server_user)
| replace('__AW_SERVER_GROUP__', aw_server_group)
| replace('__AW_SERVER_DATA_DIR__', aw_server_data_dir)
}}
notify:
- Перезагрузить systemd
- Перезапустить activitywatch
- name: (Check mode) Пропустить WebUI patch и запуск сервиса
ansible.builtin.debug:
msg: "ansible_check_mode=true: WebUI patch + service start + API checks are skipped."
when: ansible_check_mode
- name: Применить WebUI RU patch и запустить сервис
when: not ansible_check_mode
block:
- name: Скопировать RU patch файлы WebUI из репозитория
ansible.builtin.copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
loop:
- { src: "{{ aw_repo_root }}/aw-server/aw-ru-patch.js", dest: "{{ aw_server_webui_dir }}/js/ru-patch-v5.js", mode: "0644" }
- { src: "{{ aw_repo_root }}/aw-server/aw-sw-cleanup.js", dest: "{{ aw_server_webui_dir }}/js/sw-cleanup.js", mode: "0644" }
- { src: "{{ aw_repo_root }}/aw-server/aw-worktime-panel.js", dest: "{{ aw_server_webui_dir }}/js/aw-worktime-panel.js", mode: "0644" }
- { src: "{{ aw_repo_root }}/aw-server/aw-host-groups.json", dest: "{{ aw_server_webui_dir }}/js/aw-host-groups.json", mode: "0644" }
- name: Создать каталог /root/bootstrap для apply_webui_ru_patch.sh
ansible.builtin.file:
path: /root/bootstrap
state: directory
mode: "0755"
- name: Скопировать RU patch файлы для apply_webui_ru_patch.sh (хотфиксы compiled JS чанков)
ansible.builtin.copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
loop:
- { src: "{{ aw_repo_root }}/aw-server/aw-ru-patch.js", dest: "/root/bootstrap/aw-ru-patch.js", mode: "0644" }
- { src: "{{ aw_repo_root }}/aw-server/aw-sw-cleanup.js", dest: "/root/bootstrap/aw-sw-cleanup.js", mode: "0644" }
- { src: "{{ aw_repo_root }}/aw-server/aw-worktime-panel.js", dest: "/root/bootstrap/aw-worktime-panel.js", mode: "0644" }
- { src: "{{ aw_repo_root }}/aw-server/aw-host-groups.json", dest: "/root/bootstrap/aw-host-groups.json", mode: "0644" }
- name: Скопировать apply_webui_ru_patch.sh скрипт
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/apply_webui_ru_patch.sh"
dest: /opt/activitywatch/aw-server/apply_webui_ru_patch.sh
mode: "0755"
- name: Записать /etc/activitywatch/aw-server.env перед хотфиксами
ansible.builtin.copy:
dest: /etc/activitywatch/aw-server.env
mode: "0640"
owner: root
group: root
content: |
AW_SERVER_BIND_HOST={{ aw_server_bind_host }}
AW_SERVER_PORT={{ aw_server_port }}
AW_SERVER_DATA_DIR={{ aw_server_data_dir }}
AW_SERVER_DB_PATH={{ aw_server_db_path }}
AW_SERVER_LOG_DIR={{ aw_server_log_dir }}
AW_SERVER_WEBUI_DIR={{ aw_server_webui_dir }}
AW_SERVER_USER={{ aw_server_user }}
AW_SERVER_GROUP={{ aw_server_group }}
AW_WORKTIME_REPORT_BASE={{ aw_worktime_report_base }}
AW_WORKTIME_TZ={{ aw_worktime_timezone }}
AW_DLP_IOC_DIR={{ aw_dlp_ioc_workdir }}/output
AW_DLP_POLICY_ENGINE_BIND_HOST={{ aw_dlp_policy_engine_bind_host }}
AW_DLP_POLICY_ENGINE_PORT={{ aw_dlp_policy_engine_port }}
AW_DLP_POLICY_ENGINE_DB_PATH={{ aw_dlp_policy_engine_db_path }}
AW_DLP_CASE_BIND_HOST={{ aw_dlp_case_bind_host }}
AW_DLP_CASE_PORT={{ aw_dlp_case_port }}
AW_DLP_CASE_DB_PATH={{ aw_dlp_case_db_path }}
AW_DLP_COMPLIANCE_REPORT_DIR={{ aw_dlp_compliance_report_dir }}
AW_DLP_COMPLIANCE_TEMPLATE={{ aw_dlp_compliance_template_path }}
AW_SERVER_URL=http://127.0.0.1:5600
XDG_DATA_HOME={{ aw_server_data_dir }}/.local/share
XDG_CONFIG_HOME={{ aw_server_data_dir }}/.config
AW_WORKTIME_INFLUX_ENABLED={{ 'true' if (aw_worktime_influx_enabled | default(false) | bool) else 'false' }}
AW_WORKTIME_INFLUX_URL={{ aw_worktime_influx_url | default('') }}
AW_WORKTIME_INFLUX_ORG={{ aw_worktime_influx_org | default('proxmox') }}
AW_WORKTIME_INFLUX_BUCKET={{ aw_worktime_influx_bucket | default('aw_metrics') }}
AW_WORKTIME_INFLUX_HOSTS={{ aw_worktime_influx_hosts | default('SHARKON2025') }}
AW_WORKTIME_INFLUX_DAYS={{ aw_worktime_influx_days | default('today,yesterday') }}
AW_WORKTIME_INFLUX_TOKEN={{ aw_worktime_influx_token | default('') }}
AW_DLP_INFLUX_ENABLED={{ 'true' if (aw_dlp_influx_enabled | default(false) | bool) else 'false' }}
AW_DLP_INFLUX_URL={{ aw_dlp_influx_url | default('') }}
AW_DLP_INFLUX_ORG={{ aw_dlp_influx_org | default('proxmox') }}
AW_DLP_INFLUX_BUCKET={{ aw_dlp_influx_bucket | default('aw_metrics') }}
AW_DLP_INFLUX_HOSTS={{ aw_dlp_influx_hosts | default('SHARKON2025') }}
AW_DLP_INFLUX_LOOKBACK_DAYS={{ aw_dlp_influx_lookback_days | default(30) }}
AW_DLP_INFLUX_EVENT_LIMIT={{ aw_dlp_influx_event_limit | default(2000) }}
AW_DLP_INFLUX_TOKEN={{ aw_dlp_influx_token | default('') }}
AW_DLP_AW_API_BASE=http://127.0.0.1:5600/api/0
AW_DLP_CASE_API_BASE=http://127.0.0.1:5602/api/0/dlp/cases
AW_EXPECT_START_OF_DAY={{ aw_worktime_start_of_day | default('') }}
AW_EXPECT_ALWAYS_ACTIVE_PATTERN={{ aw_server_always_active_pattern | default('') }}
AW_EXPECT_LANDINGPAGE={{ aw_server_landingpage | default('') }}
AW_HEALTH_STRICT_FILEOPS={{ aw_health_strict_fileops | default(0) }}
- name: Создать каталог DLP policy engine
ansible.builtin.file:
path: /opt/activitywatch/dlp-policy-engine
state: directory
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
when: aw_dlp_policy_engine_enabled | default(false) | bool
- name: Скопировать файлы DLP policy engine
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-policy-engine/{{ item }}"
dest: "/opt/activitywatch/dlp-policy-engine/{{ item }}"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0644"
loop:
- policy_service.py
- policy_schema.py
- policy_storage.py
- policy_distributor.py
- requirements.txt
when: aw_dlp_policy_engine_enabled | default(false) | bool
- name: Создать virtualenv DLP policy engine
ansible.builtin.command:
cmd: python3 -m venv /opt/activitywatch/dlp-policy-engine/.venv
args:
creates: /opt/activitywatch/dlp-policy-engine/.venv/bin/python
when: aw_dlp_policy_engine_enabled | default(false) | bool
- name: Установить зависимости DLP policy engine
ansible.builtin.pip:
requirements: /opt/activitywatch/dlp-policy-engine/requirements.txt
virtualenv: /opt/activitywatch/dlp-policy-engine/.venv
when: aw_dlp_policy_engine_enabled | default(false) | bool
- name: Установить systemd unit DLP policy engine
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-policy-engine/dlp-policy-engine.service"
dest: /etc/systemd/system/aw-dlp-policy-engine.service
owner: root
group: root
mode: "0644"
when: aw_dlp_policy_engine_enabled | default(false) | bool
- name: Создать каталог DLP content analysis
ansible.builtin.file:
path: /opt/activitywatch/dlp-content-analysis
state: directory
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
when: aw_dlp_content_analysis_enabled | default(true) | bool
- name: Скопировать файлы DLP content analysis
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-content-analysis/"
dest: /opt/activitywatch/dlp-content-analysis/
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0644"
when: aw_dlp_content_analysis_enabled | default(true) | bool
- name: Установить wrapper запуска DLP content analysis через virtualenv
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-content-analysis/aw-dlp-content-analyzer.sh"
dest: /usr/local/bin/aw-dlp-content-analyzer
owner: root
group: root
mode: "0755"
when: aw_dlp_content_analysis_enabled | default(true) | bool
- name: Создать virtualenv DLP content analysis
ansible.builtin.command:
cmd: python3 -m venv /opt/activitywatch/dlp-content-analysis/.venv
args:
creates: /opt/activitywatch/dlp-content-analysis/.venv/bin/python
when: aw_dlp_content_analysis_enabled | default(true) | bool
- name: Установить зависимости DLP content analysis
ansible.builtin.pip:
requirements: /opt/activitywatch/dlp-content-analysis/requirements.txt
virtualenv: /opt/activitywatch/dlp-content-analysis/.venv
when: aw_dlp_content_analysis_enabled | default(true) | bool
- name: Создать каталог DLP integrations
ansible.builtin.file:
path: /opt/activitywatch/dlp-integrations
state: directory
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Скопировать файлы DLP integrations
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-integrations/{{ item }}"
dest: "/opt/activitywatch/dlp-integrations/{{ item }}"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0644"
loop:
- cef_exporter.py
- syslog_forwarder.py
- webhook_sender.py
- cef-config.yaml
- syslog-forwarder-config.yaml
- webhook-config.yaml
- requirements.txt
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Выставить executable для python scripts DLP integrations
ansible.builtin.file:
path: "/opt/activitywatch/dlp-integrations/{{ item }}"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
loop:
- cef_exporter.py
- syslog_forwarder.py
- webhook_sender.py
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Создать virtualenv DLP integrations
ansible.builtin.command:
cmd: python3 -m venv /opt/activitywatch/dlp-integrations/.venv
args:
creates: /opt/activitywatch/dlp-integrations/.venv/bin/python
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Установить зависимости DLP integrations
ansible.builtin.pip:
requirements: /opt/activitywatch/dlp-integrations/requirements.txt
virtualenv: /opt/activitywatch/dlp-integrations/.venv
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Создать state каталог DLP integrations
ansible.builtin.file:
path: /var/lib/activitywatch/dlp-integrations
state: directory
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Установить systemd unit CEF exporter
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-integrations/cef-exporter.service"
dest: /etc/systemd/system/aw-dlp-cef-exporter.service
owner: root
group: root
mode: "0644"
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Установить systemd timer CEF exporter
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-integrations/cef-exporter.timer"
dest: /etc/systemd/system/aw-dlp-cef-exporter.timer
owner: root
group: root
mode: "0644"
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Установить systemd unit syslog forwarder
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-integrations/syslog-forwarder.service"
dest: /etc/systemd/system/aw-dlp-syslog-forwarder.service
owner: root
group: root
mode: "0644"
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Установить systemd timer syslog forwarder
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-integrations/syslog-forwarder.timer"
dest: /etc/systemd/system/aw-dlp-syslog-forwarder.timer
owner: root
group: root
mode: "0644"
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Установить systemd unit webhook sender
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-integrations/webhook-sender.service"
dest: /etc/systemd/system/aw-dlp-webhook-sender.service
owner: root
group: root
mode: "0644"
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Установить systemd timer webhook sender
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-integrations/webhook-sender.timer"
dest: /etc/systemd/system/aw-dlp-webhook-sender.timer
owner: root
group: root
mode: "0644"
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Создать каталог DLP case management
ansible.builtin.file:
path: /opt/activitywatch/dlp-case-management
state: directory
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
when: aw_dlp_case_management_enabled | default(true) | bool
- name: Скопировать файлы DLP case management
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-case-management/{{ item }}"
dest: "/opt/activitywatch/dlp-case-management/{{ item }}"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0644"
loop:
- case_service.py
- case_rules.py
- case_schema.py
- case_storage.py
- evidence_chain.py
- requirements.txt
when: aw_dlp_case_management_enabled | default(true) | bool
- name: Выставить executable для case_service
ansible.builtin.file:
path: /opt/activitywatch/dlp-case-management/case_service.py
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
when: aw_dlp_case_management_enabled | default(true) | bool
- name: Создать virtualenv DLP case management
ansible.builtin.command:
cmd: python3 -m venv /opt/activitywatch/dlp-case-management/.venv
args:
creates: /opt/activitywatch/dlp-case-management/.venv/bin/python
when: aw_dlp_case_management_enabled | default(true) | bool
- name: Установить зависимости DLP case management
ansible.builtin.pip:
requirements: /opt/activitywatch/dlp-case-management/requirements.txt
virtualenv: /opt/activitywatch/dlp-case-management/.venv
when: aw_dlp_case_management_enabled | default(true) | bool
- name: Установить systemd unit DLP case management
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-case-management/case-service.service"
dest: /etc/systemd/system/aw-dlp-case-management.service
owner: root
group: root
mode: "0644"
when: aw_dlp_case_management_enabled | default(true) | bool
- name: Создать каталоги DLP compliance
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
loop:
- /opt/activitywatch/dlp-compliance
- /opt/activitywatch/dlp-compliance/templates
- "{{ aw_dlp_compliance_report_dir }}"
when: aw_dlp_compliance_enabled | default(true) | bool
- name: Скопировать файлы DLP compliance
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/dlp-compliance/{{ item.src }}"
dest: "{{ item.dest }}"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "{{ item.mode }}"
loop:
- { src: "report_generator.py", dest: "/opt/activitywatch/dlp-compliance/report_generator.py", mode: "0755" }
- { src: "compliance_scheduler.py", dest: "/opt/activitywatch/dlp-compliance/compliance_scheduler.py", mode: "0755" }
- { src: "requirements.txt", dest: "/opt/activitywatch/dlp-compliance/requirements.txt", mode: "0644" }
- { src: "templates/152-fz-report.html", dest: "/opt/activitywatch/dlp-compliance/templates/152-fz-report.html", mode: "0644" }
- { src: "templates/pci-dss-report.html", dest: "/opt/activitywatch/dlp-compliance/templates/pci-dss-report.html", mode: "0644" }
- { src: "report-scheduler.service", dest: "/etc/systemd/system/aw-dlp-report-scheduler.service", mode: "0644" }
- { src: "report-scheduler.timer", dest: "/etc/systemd/system/aw-dlp-report-scheduler.timer", mode: "0644" }
when: aw_dlp_compliance_enabled | default(true) | bool
- name: Создать virtualenv DLP compliance
ansible.builtin.command:
cmd: python3 -m venv /opt/activitywatch/dlp-compliance/.venv
args:
creates: /opt/activitywatch/dlp-compliance/.venv/bin/python
when: aw_dlp_compliance_enabled | default(true) | bool
- name: Установить зависимости DLP compliance
ansible.builtin.pip:
requirements: /opt/activitywatch/dlp-compliance/requirements.txt
virtualenv: /opt/activitywatch/dlp-compliance/.venv
when: aw_dlp_compliance_enabled | default(true) | bool
- name: Установить dlp-admin-cli
ansible.builtin.copy:
src: "{{ aw_repo_root }}/scripts/dlp-admin-cli.py"
dest: /usr/local/bin/dlp-admin-cli.py
owner: root
group: root
mode: "0755"
- name: Установить скрипт AW worktime API
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-worktime-api.py"
dest: /usr/local/bin/aw-worktime-api.py
owner: root
group: root
mode: "0755"
- name: Установить systemd unit AW worktime API
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-worktime-api.service"
dest: /etc/systemd/system/aw-worktime-api.service
owner: root
group: root
mode: "0644"
- name: Установить скрипт AW worktime UI bridge
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-worktime-ui-bridge.py"
dest: /usr/local/bin/aw-worktime-ui-bridge.py
owner: root
group: root
mode: "0755"
- name: Установить скрипт AW worktime autoheal
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-worktime-autoheal.sh"
dest: /usr/local/bin/aw-worktime-autoheal.sh
owner: root
group: root
mode: "0755"
- name: Установить скрипт AW worktime Influx exporter
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-worktime-influx-exporter.py"
dest: /usr/local/bin/aw-worktime-influx-exporter.py
owner: root
group: root
mode: "0755"
when: aw_worktime_influx_enabled | default(false) | bool
- name: Установить скрипт AW DLP Influx exporter
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-dlp-influx-exporter.py"
dest: /usr/local/bin/aw-dlp-influx-exporter.py
owner: root
group: root
mode: "0755"
when: aw_dlp_influx_enabled | default(false) | bool
- name: Установить скрипт aw-health-check
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/health-check.sh"
dest: /usr/local/bin/aw-health-check
owner: root
group: root
mode: "0755"
- name: Установить скрипт dlp-health-check
ansible.builtin.copy:
src: "{{ aw_repo_root }}/scripts/dlp-health-check.py"
dest: /usr/local/bin/dlp-health-check
owner: root
group: root
mode: "0755"
- name: Установить systemd unit AW worktime UI bridge
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-worktime-ui-bridge.service"
dest: /etc/systemd/system/aw-worktime-ui-bridge.service
owner: root
group: root
mode: "0644"
- name: Установить systemd timer AW worktime UI bridge
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-worktime-ui-bridge.timer"
dest: /etc/systemd/system/aw-worktime-ui-bridge.timer
owner: root
group: root
mode: "0644"
- name: Установить systemd unit AW worktime autoheal
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-worktime-autoheal.service"
dest: /etc/systemd/system/aw-worktime-autoheal.service
owner: root
group: root
mode: "0644"
- name: Установить systemd timer AW worktime autoheal
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-worktime-autoheal.timer"
dest: /etc/systemd/system/aw-worktime-autoheal.timer
owner: root
group: root
mode: "0644"
- name: Установить systemd unit AW worktime Influx exporter
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-worktime-influx-exporter.service"
dest: /etc/systemd/system/aw-worktime-influx-exporter.service
owner: root
group: root
mode: "0644"
when: aw_worktime_influx_enabled | default(false) | bool
- name: Установить systemd timer AW worktime Influx exporter
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-worktime-influx-exporter.timer"
dest: /etc/systemd/system/aw-worktime-influx-exporter.timer
owner: root
group: root
mode: "0644"
when: aw_worktime_influx_enabled | default(false) | bool
- name: Установить systemd unit AW DLP Influx exporter
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-dlp-influx-exporter.service"
dest: /etc/systemd/system/aw-dlp-influx-exporter.service
owner: root
group: root
mode: "0644"
when: aw_dlp_influx_enabled | default(false) | bool
- name: Установить systemd timer AW DLP Influx exporter
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/aw-dlp-influx-exporter.timer"
dest: /etc/systemd/system/aw-dlp-influx-exporter.timer
owner: root
group: root
mode: "0644"
when: aw_dlp_influx_enabled | default(false) | bool
- name: Перезагрузить systemd после установки AW worktime API
ansible.builtin.systemd:
daemon_reload: true
- name: Включить и перезапустить DLP policy engine
ansible.builtin.systemd:
name: aw-dlp-policy-engine.service
enabled: true
state: restarted
when: aw_dlp_policy_engine_enabled | default(false) | bool
- name: Включить и перезапустить timer CEF exporter
ansible.builtin.systemd:
name: aw-dlp-cef-exporter.timer
enabled: true
state: restarted
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Включить и перезапустить timer syslog forwarder
ansible.builtin.systemd:
name: aw-dlp-syslog-forwarder.timer
enabled: true
state: restarted
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Включить и перезапустить timer webhook sender
ansible.builtin.systemd:
name: aw-dlp-webhook-sender.timer
enabled: true
state: restarted
when: aw_dlp_integrations_enabled | default(true) | bool
- name: Включить и перезапустить DLP case management
ansible.builtin.systemd:
name: aw-dlp-case-management.service
enabled: true
state: restarted
when: aw_dlp_case_management_enabled | default(true) | bool
- name: Включить и перезапустить timer DLP compliance report
ansible.builtin.systemd:
name: aw-dlp-report-scheduler.timer
enabled: true
state: restarted
when: aw_dlp_compliance_enabled | default(true) | bool
- name: Выполнить разовый прогон DLP compliance report
ansible.builtin.systemd:
name: aw-dlp-report-scheduler.service
state: started
failed_when: false
when: aw_dlp_compliance_enabled | default(true) | bool
- name: Включить и перезапустить AW worktime API
ansible.builtin.systemd:
name: aw-worktime-api.service
enabled: true
state: restarted
- name: Отключить legacy timer aw-worktime-afk-bridge (если есть)
ansible.builtin.systemd:
name: aw-worktime-afk-bridge.timer
enabled: false
state: stopped
failed_when: false
- name: Включить и перезапустить AW worktime UI bridge timer
ansible.builtin.systemd:
name: aw-worktime-ui-bridge.timer
enabled: true
state: restarted
- name: Выполнить разовый прогон AW worktime UI bridge
ansible.builtin.systemd:
name: aw-worktime-ui-bridge.service
state: started
failed_when: false
- name: Включить и перезапустить AW worktime autoheal timer
ansible.builtin.systemd:
name: aw-worktime-autoheal.timer
enabled: true
state: restarted
- name: Выполнить разовый прогон AW worktime autoheal
ansible.builtin.systemd:
name: aw-worktime-autoheal.service
state: started
failed_when: false
- name: Включить и перезапустить AW worktime Influx exporter timer
ansible.builtin.systemd:
name: aw-worktime-influx-exporter.timer
enabled: true
state: restarted
when: aw_worktime_influx_enabled | default(false) | bool
- name: Выполнить разовый прогон AW worktime Influx exporter
ansible.builtin.systemd:
name: aw-worktime-influx-exporter.service
state: started
failed_when: false
when: aw_worktime_influx_enabled | default(false) | bool
- name: Включить и перезапустить AW DLP Influx exporter timer
ansible.builtin.systemd:
name: aw-dlp-influx-exporter.timer
enabled: true
state: restarted
when: aw_dlp_influx_enabled | default(false) | bool
- name: Выполнить разовый прогон AW DLP Influx exporter
ansible.builtin.systemd:
name: aw-dlp-influx-exporter.service
state: started
failed_when: false
when: aw_dlp_influx_enabled | default(false) | bool
- name: Применить хотфиксы compiled JS чанков (Trends, Timespiral, Category helper)
ansible.builtin.command:
cmd: "/opt/activitywatch/aw-server/apply_webui_ru_patch.sh"
register: apply_ru_patch_result
failed_when: false
- name: Вывести результат применения хотфиксов
ansible.builtin.debug:
msg: "apply_webui_ru_patch.sh: {{ apply_ru_patch_result.stdout }}"
- name: Проверить наличие index.html после копирования
ansible.builtin.stat:
path: "{{ aw_server_webui_dir }}/index.html"
register: aw_webui_ru_index
- name: Проверить, что index.html доступен для RU patch
ansible.builtin.assert:
that:
- aw_webui_ru_index.stat.exists
- (aw_webui_ru_index.stat.size | default(0) | int) > 0
fail_msg: "Не найден index.html WebUI для применения RU patch."
- name: Проверить, что index.html не опустел после применения RU patch
ansible.builtin.stat:
path: "{{ aw_server_webui_dir }}/index.html"
register: aw_webui_ru_index_after_patch
- name: Подтвердить, что index.html остался непустым
ansible.builtin.assert:
that:
- aw_webui_ru_index_after_patch.stat.exists
- (aw_webui_ru_index_after_patch.stat.size | default(0) | int) > 0
fail_msg: "index.html WebUI пуст после RU patch."
- name: Удалить старые теги RU patch из index.html
ansible.builtin.replace:
path: "{{ aw_server_webui_dir }}/index.html"
regexp: '<script[^>]+(?:ru-patch-v5\.js|sw-cleanup\.js|aw-ru-patch\.js|aw-sw-cleanup\.js)[^>]*></script>'
replace: ''
- name: Добавить cleanup script RU patch в index.html
ansible.builtin.replace:
path: "{{ aw_server_webui_dir }}/index.html"
regexp: '</head>'
replace: '<script src="/js/sw-cleanup.js?v={{ aw_sw_cleanup_cache_bust }}"></script></head>'
- name: Добавить загрузчик RU patch перед закрытием body
ansible.builtin.replace:
path: "{{ aw_server_webui_dir }}/index.html"
regexp: '</body>'
replace: '<script defer="defer" src="/js/ru-patch-v5.js?v={{ aw_ru_patch_cache_bust }}"></script></body>'
- name: Скопировать merge script AW DB на сервер
ansible.builtin.copy:
src: "{{ aw_repo_root }}/scripts/merge_aw_server_dbs.py"
dest: /usr/local/bin/merge_aw_server_dbs.py
owner: root
group: root
mode: "0755"
- name: Проверить наличие legacy root DB
ansible.builtin.stat:
path: /root/.local/share/activitywatch/aw-server-rust/sqlite.db
register: aw_legacy_root_db
- name: Проверить наличие target DB
ansible.builtin.stat:
path: "{{ aw_server_db_path }}"
register: aw_target_db
- name: Остановить сервис перед merge server DB
ansible.builtin.systemd:
name: activitywatch-server.service
state: stopped
when: aw_legacy_root_db.stat.exists | default(false)
- name: Создать backup каталоги server DB
ansible.builtin.file:
path: "{{ aw_server_data_dir }}/backups/db"
state: directory
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
when: aw_legacy_root_db.stat.exists | default(false)
- name: Backup target DB перед merge
ansible.builtin.copy:
remote_src: true
src: "{{ aw_server_db_path }}"
dest: "{{ aw_server_data_dir }}/backups/db/target-before-merge-{{ ansible_date_time.iso8601_basic_short }}.sqlite.db"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0644"
when:
- aw_legacy_root_db.stat.exists | default(false)
- aw_target_db.stat.exists | default(false)
- name: Backup legacy root DB перед merge
ansible.builtin.copy:
remote_src: true
src: /root/.local/share/activitywatch/aw-server-rust/sqlite.db
dest: "{{ aw_server_data_dir }}/backups/db/legacy-root-{{ ansible_date_time.iso8601_basic_short }}.sqlite.db"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0644"
when: aw_legacy_root_db.stat.exists | default(false)
- name: Merge legacy root DB в target DB
ansible.builtin.command:
argv:
- python3
- /usr/local/bin/merge_aw_server_dbs.py
- --base
- /root/.local/share/activitywatch/aw-server-rust/sqlite.db
- --overlay
- "{{ aw_server_db_path }}"
- --output
- "{{ aw_server_db_path }}.merged"
register: aw_merge_result
failed_when: false
when:
- aw_legacy_root_db.stat.exists | default(false)
- aw_target_db.stat.exists | default(false)
- name: Показать результат merge legacy root DB
ansible.builtin.debug:
msg: "{{ aw_merge_result.stdout | default(aw_merge_result.stderr | default('merge not executed')) }}"
when:
- aw_legacy_root_db.stat.exists | default(false)
- aw_target_db.stat.exists | default(false)
- name: Install merged DB as active target DB
ansible.builtin.copy:
remote_src: true
src: "{{ aw_server_db_path }}.merged"
dest: "{{ aw_server_db_path }}"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0644"
when:
- aw_legacy_root_db.stat.exists | default(false)
- aw_target_db.stat.exists | default(false)
- aw_merge_result is defined
- (aw_merge_result.rc | default(1) | int) == 0
- name: Скопировать legacy root DB в target DB если target ещё не существует
ansible.builtin.copy:
remote_src: true
src: /root/.local/share/activitywatch/aw-server-rust/sqlite.db
dest: "{{ aw_server_db_path }}"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0644"
when:
- aw_legacy_root_db.stat.exists | default(false)
- not (aw_target_db.stat.exists | default(false))
- name: Записать aw-server-rust config.toml с разрешёнными CORS origin
ansible.builtin.copy:
dest: "{{ aw_server_data_dir }}/.config/activitywatch/aw-server-rust/config.toml"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0644"
content: |
cors = [
{% for origin in aw_server_cors_origins | default([]) %}
"{{ origin }}"{% if not loop.last %},{% endif %}
{% endfor %}
]
- name: Включить и запустить сервис
ansible.builtin.systemd:
name: activitywatch-server.service
enabled: true
state: restarted
daemon_reload: true
- name: Дождаться ответа API
ansible.builtin.uri:
url: "http://127.0.0.1:{{ aw_server_port }}/api/0/info"
method: GET
status_code: 200
register: aw_api
retries: 10
delay: 3
until: aw_api.status == 200
- name: Считать текущие server-side settings
ansible.builtin.uri:
url: "http://127.0.0.1:{{ aw_server_port }}/api/0/settings/"
method: GET
status_code: 200
register: aw_settings_current
when: aw_apply_worktime_settings | default(false) | bool
- name: Считать текущие server-side views
ansible.builtin.uri:
url: "http://127.0.0.1:{{ aw_server_port }}/api/0/settings/views"
method: GET
status_code: 200
register: aw_views_current
when: aw_apply_worktime_settings | default(false) | bool
- name: Считать текущие server-side classes
ansible.builtin.uri:
url: "http://127.0.0.1:{{ aw_server_port }}/api/0/settings/classes"
method: GET
status_code: 200
register: aw_classes_current
when: aw_apply_worktime_settings | default(false) | bool
- name: Создать backup текущих server-side settings/views/classes
ansible.builtin.copy:
dest: "{{ aw_server_data_dir }}/backups/{{ item.name }}-{{ ansible_date_time.iso8601_basic_short }}.json"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0644"
content: "{{ item.payload | to_nice_json }}"
loop:
- name: settings
payload: "{{ aw_settings_current.json | default({}) }}"
- name: views
payload: "{{ aw_views_current.json | default(none) }}"
- name: classes
payload: "{{ aw_classes_current.json | default(none) }}"
when: aw_apply_worktime_settings | default(false) | bool
- name: Настроить DLP Aggregator (Phase 2)
block:
- name: Создать каталог для скриптов
ansible.builtin.file:
path: "/opt/activitywatch/scripts"
state: directory
owner: root
group: root
mode: "0755"
- name: Скопировать агрегатор событий DLP
ansible.builtin.copy:
src: "{{ aw_repo_root }}/scripts/aggregate_dlp_events.py"
dest: "/opt/activitywatch/scripts/aggregate_dlp_events.py"
owner: root
group: root
mode: "0755"
- name: Установить systemd unit для агрегатора
ansible.builtin.copy:
dest: /etc/systemd/system/activitywatch-dlp-aggregator.service
content: |
[Unit]
Description=ActivityWatch DLP Event Aggregator
After=activitywatch-server.service
[Service]
Type=oneshot
User={{ aw_server_user }}
WorkingDirectory={{ aw_server_data_dir }}
ExecStart=/usr/bin/python3 /opt/activitywatch/scripts/aggregate_dlp_events.py \
--aw-url http://127.0.0.1:{{ aw_server_port }}/api/0 \
--sqlite-path {{ aw_server_data_dir }}/dlp_warehouse.sqlite \
--state-path {{ aw_server_data_dir }}/dlp-aggregator-state.json
[Install]
WantedBy=multi-user.target
- name: Установить systemd timer для агрегатора
ansible.builtin.copy:
dest: /etc/systemd/system/activitywatch-dlp-aggregator.timer
content: |
[Unit]
Description=Run ActivityWatch DLP Aggregator every 5 minutes
[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
AccuracySec=1s
[Install]
WantedBy=timers.target
- name: Включить и запустить таймер агрегатора
ansible.builtin.systemd:
name: activitywatch-dlp-aggregator.timer
enabled: true
state: started
daemon_reload: true
- name: Настроить IOC enrichment из Hayabusa Sigma
when: aw_dlp_ioc_enabled | default(false) | bool
block:
- name: Установить зависимости IOC refresh
ansible.builtin.apt:
name:
- python3-yaml
state: present
update_cache: true
- name: Создать каталог IOC enrichment
ansible.builtin.file:
path: "{{ aw_dlp_ioc_workdir }}/{{ item }}"
state: directory
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
mode: "0755"
loop:
- ""
- output
- tmp
- name: Установить экстрактор IOC из Sigma
ansible.builtin.copy:
src: "{{ aw_repo_root }}/scripts/extract_ioc_from_sigma.py"
dest: /usr/local/bin/aw-extract-ioc-from-sigma.py
owner: root
group: root
mode: "0755"
- name: Установить wrapper refresh IOC
ansible.builtin.copy:
dest: /usr/local/bin/aw-dlp-ioc-refresh.sh
owner: root
group: root
mode: "0755"
content: |
#!/usr/bin/env bash
set -euo pipefail
WORKDIR="{{ aw_dlp_ioc_workdir }}"
OUTDIR="${WORKDIR}/output"
TMPDIR="${WORKDIR}/tmp"
RULES_DIR="${TMPDIR}/hayabusa-rules"
ZIP_PATH="${TMPDIR}/hayabusa-rules.zip"
mkdir -p "${OUTDIR}" "${TMPDIR}"
rm -rf "${RULES_DIR}"
curl -fsSL -o "${ZIP_PATH}" "{{ aw_dlp_ioc_rules_zip_url }}"
unzip -q -o "${ZIP_PATH}" -d "${TMPDIR}"
EXTRACTED_DIR=$(find "${TMPDIR}" -maxdepth 1 -type d -name 'hayabusa-rules-*' | head -n1)
if [ -z "${EXTRACTED_DIR}" ]; then
echo "ERROR: hayabusa-rules archive extraction failed" >&2
exit 1
fi
mv "${EXTRACTED_DIR}" "${RULES_DIR}"
/usr/bin/python3 /usr/local/bin/aw-extract-ioc-from-sigma.py \
--rules-root "${RULES_DIR}" \
--out-dir "${OUTDIR}"
ln -sfn "${OUTDIR}" "${WORKDIR}/latest"
- name: Установить systemd unit IOC refresh
ansible.builtin.copy:
dest: /etc/systemd/system/aw-dlp-ioc-refresh.service
owner: root
group: root
mode: "0644"
content: |
[Unit]
Description=Refresh DLP IOC blacklist from Hayabusa Sigma rules
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/aw-dlp-ioc-refresh.sh
- name: Установить systemd timer IOC refresh
ansible.builtin.copy:
dest: /etc/systemd/system/aw-dlp-ioc-refresh.timer
owner: root
group: root
mode: "0644"
content: |
[Unit]
Description=Run DLP IOC refresh from Hayabusa rules
[Timer]
OnBootSec={{ aw_dlp_ioc_refresh_on_boot_sec }}
OnUnitActiveSec={{ aw_dlp_ioc_refresh_interval }}
Persistent=true
Unit=aw-dlp-ioc-refresh.service
[Install]
WantedBy=timers.target
- name: Включить и запустить IOC refresh timer
ansible.builtin.systemd:
name: aw-dlp-ioc-refresh.timer
enabled: true
state: started
daemon_reload: true
- name: Выполнить принудительный refresh IOC
ansible.builtin.systemd:
name: aw-dlp-ioc-refresh.service
state: started
- name: Проверить наличие IOC артефактов после refresh
ansible.builtin.stat:
path: "{{ aw_dlp_ioc_workdir }}/output/{{ item }}"
register: aw_dlp_ioc_artifacts
loop:
- ioc_blacklist.json
- ioc_blacklist.csv
- ioc_blacklist.sql
- name: Assert по IOC артефактам
ansible.builtin.assert:
that:
- item.stat.exists
- (item.stat.size | int) > 100
fail_msg: "Не сгенерирован IOC артефакт: {{ item.stat.path | default('unknown') }}"
loop: "{{ aw_dlp_ioc_artifacts.results }}"
- name: Применить базовые worktime settings (classes)
ansible.builtin.uri:
url: "http://127.0.0.1:{{ aw_server_port }}/api/0/settings/classes"
method: POST
body: "{{ aw_worktime_classes }}"
body_format: json
status_code: [200, 201]
when: aw_apply_worktime_settings | default(false) | bool
- name: Применить базовые views для DLP и worktime
ansible.builtin.uri:
url: "http://127.0.0.1:{{ aw_server_port }}/api/0/settings/views"
method: POST
body: "{{ aw_default_views }}"
body_format: json
status_code: [200, 201]
when: aw_apply_worktime_settings | default(false) | bool
- name: Вычислить worktime durationDefault из aw_worktime_from/to
ansible.builtin.set_fact:
aw_worktime_duration_default_derived: >-
{{
(
(
(((aw_worktime_to | default('17:00')).split(':')[0] | int) * 60 + ((aw_worktime_to | default('17:00')).split(':')[1] | int)) -
(((aw_worktime_from | default('00:00')).split(':')[0] | int) * 60 + ((aw_worktime_from | default('00:00')).split(':')[1] | int))
) * 60
)
}}
when: aw_apply_worktime_settings | default(false) | bool
- name: Нормализовать durationDefault для ночных смен
ansible.builtin.set_fact:
aw_worktime_duration_default_effective: >-
{{
(aw_worktime_duration_default_derived | int)
if (aw_worktime_duration_default_derived | int) > 0
else ((aw_worktime_duration_default_derived | int) + 86400)
}}
when: aw_apply_worktime_settings | default(false) | bool
- name: Проверить корректность durationDefault
ansible.builtin.assert:
that:
- aw_worktime_duration_default_effective | int > 0
- aw_worktime_duration_default_effective | int <= 86400
fail_msg: "Некорректный интервал рабочего времени: {{ aw_worktime_from }}..{{ aw_worktime_to }}"
when: aw_apply_worktime_settings | default(false) | bool
- name: Применить базовый период worktime (startOfDay)
ansible.builtin.uri:
url: "http://127.0.0.1:{{ aw_server_port }}/api/0/settings/startOfDay"
method: POST
body: "\"{{ aw_worktime_start_of_day }}\""
headers:
Content-Type: application/json
status_code: [200, 201]
when: aw_apply_worktime_settings | default(false) | bool
- name: Применить базовый период worktime (durationDefault seconds)
ansible.builtin.uri:
url: "http://127.0.0.1:{{ aw_server_port }}/api/0/settings/durationDefault"
method: POST
body: "{{ aw_worktime_duration_default_effective | string }}"
headers:
Content-Type: application/json
status_code: [200, 201]
when: aw_apply_worktime_settings | default(false) | bool
- name: Применить always_active_pattern для fallback без AFK
ansible.builtin.uri:
url: "http://127.0.0.1:{{ aw_server_port }}/api/0/settings/always_active_pattern"
method: POST
body: "\"{{ aw_server_always_active_pattern }}\""
headers:
Content-Type: application/json
status_code: [200, 201]
when:
- aw_apply_worktime_settings | default(false) | bool
- (aw_server_always_active_pattern | default('') | string | length) > 0
- name: Применить landingpage профиля
ansible.builtin.uri:
url: "http://127.0.0.1:{{ aw_server_port }}/api/0/settings/landingpage"
method: POST
body: "\"{{ aw_server_landingpage }}\""
headers:
Content-Type: application/json
status_code: [200, 201]
when:
- aw_apply_worktime_settings | default(false) | bool
- (aw_server_landingpage | default('') | string | length) > 0
- name: Обновить IOC blacklist из hayabusa (если включено)
when:
- aw_hayabusa_ioc_refresh_enabled | default(false) | bool
- aw_hayabusa_rules_root is defined
- aw_hayabusa_ioc_output_dir is defined
block:
- name: Создать выходную директорию для IOC
ansible.builtin.file:
path: "{{ aw_hayabusa_ioc_output_dir }}"
state: directory
mode: "0755"
owner: "{{ aw_server_user }}"
group: "{{ aw_server_group }}"
- name: Обновить IOC blacklist из hayabusa правил
ansible.builtin.shell:
cmd: |
set -euo pipefail
{{ aw_repo_root }}/scripts/build_dlp_ioc_from_hayabusa.sh \
"{{ aw_hayabusa_rules_root }}" \
"{{ aw_hayabusa_ioc_output_dir }}"
args:
chdir: "{{ aw_repo_root }}"
register: aw_hayabusa_ioc_refresh_result
changed_when: "'IOC artifacts generated' in aw_hayabusa_ioc_refresh_result.stdout"
- name: Показать результат обновления IOC
ansible.builtin.debug:
msg: "{{ aw_hayabusa_ioc_refresh_result.stdout }}"
when: aw_hayabusa_ioc_refresh_result.stdout is defined
- name: Установить server-side Hayabusa runner
when: aw_hayabusa_runner_enabled | default(false) | bool
block:
- name: Создать каталоги Hayabusa
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: root
group: root
mode: "0755"
loop:
- "{{ aw_hayabusa_root }}"
- "{{ aw_hayabusa_root }}/releases"
- "{{ aw_hayabusa_release_dir }}"
- "{{ aw_hayabusa_reports_dir }}"
- "{{ aw_hayabusa_state_dir }}"
- "{{ aw_hayabusa_inbox_dir }}"
- "{{ aw_hayabusa_archive_dir }}"
- "{{ aw_hayabusa_incoming_dir }}"
- "{{ aw_hayabusa_staging_dir }}"
- "{{ aw_hayabusa_archive_packages_dir }}"
- "{{ aw_hayabusa_archive_extracted_dir }}"
- "{{ aw_hayabusa_logs_dir }}"
- name: Скачать архив Hayabusa
ansible.builtin.get_url:
url: "{{ aw_hayabusa_download_url }}"
dest: "{{ aw_hayabusa_archive_path }}"
mode: "0644"
- name: Распаковать pinned Hayabusa release
ansible.builtin.unarchive:
src: "{{ aw_hayabusa_archive_path }}"
dest: "{{ aw_hayabusa_release_dir }}"
remote_src: true
creates: "{{ aw_hayabusa_release_dir }}/{{ aw_hayabusa_binary_name }}"
- name: Нормализовать права release Hayabusa
ansible.builtin.file:
path: "{{ aw_hayabusa_release_dir }}"
state: directory
owner: root
group: root
mode: "0755"
recurse: true
- name: Сделать бинарь Hayabusa исполняемым
ansible.builtin.file:
path: "{{ aw_hayabusa_release_dir }}/{{ aw_hayabusa_binary_name }}"
owner: root
group: root
mode: "0755"
state: file
- name: Создать canonical symlink на текущий релиз Hayabusa
ansible.builtin.file:
src: "{{ aw_hayabusa_release_dir }}"
dest: "{{ aw_hayabusa_current_link }}"
state: link
force: true
- name: Создать canonical symlink на бинарь Hayabusa
ansible.builtin.file:
src: "{{ aw_hayabusa_binary_name }}"
dest: "{{ aw_hayabusa_release_dir }}/hayabusa"
state: link
force: true
- name: Установить wrapper aw-hayabusa
ansible.builtin.copy:
src: "{{ aw_repo_root }}/aw-server/hayabusa/aw-hayabusa.sh"
dest: /usr/local/bin/aw-hayabusa
owner: root
group: root
mode: "0755"
- name: Проверить server-side runner через doctor
ansible.builtin.command:
cmd: /usr/local/bin/aw-hayabusa doctor
changed_when: false
- name: Проверить загрузку profiles Hayabusa
ansible.builtin.shell: /usr/local/bin/aw-hayabusa profiles > /tmp/aw-hayabusa-profiles.txt
args:
executable: /bin/bash
changed_when: false
- name: Проверить наличие standard profile у Hayabusa
ansible.builtin.shell: "grep -q 'standard:' /tmp/aw-hayabusa-profiles.txt"
args:
executable: /bin/bash
changed_when: false
- name: Post-deploy health gate (aw-health-check)
when:
- not ansible_check_mode
- aw_server_post_deploy_health_check_enabled | default(true) | bool
block:
- name: Запустить /usr/local/bin/aw-health-check
ansible.builtin.command:
cmd: /usr/local/bin/aw-health-check
register: aw_post_deploy_health
changed_when: false
- name: Показать результат aw-health-check
ansible.builtin.debug:
msg: "{{ aw_post_deploy_health.stdout }}"
- name: Запустить /usr/local/bin/dlp-health-check --json
ansible.builtin.command:
cmd: /usr/local/bin/dlp-health-check --json
register: dlp_post_deploy_health
changed_when: false
- name: Показать результат dlp-health-check
ansible.builtin.debug:
msg: "{{ dlp_post_deploy_health.stdout }}"
handlers:
- name: Перезагрузить systemd
ansible.builtin.systemd:
daemon_reload: true
- name: Перезапустить activitywatch
ansible.builtin.systemd:
name: activitywatch-server.service
state: restarted