340 lines
14 KiB
YAML
340 lines
14 KiB
YAML
---
|
|
- 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
|
|
- rsync
|
|
- 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_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_log_dir }}"
|
|
|
|
- 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 }}"
|
|
file_type: directory
|
|
patterns: "activitywatch*"
|
|
register: aw_release_find
|
|
|
|
- name: Найти бинарный файл AW server
|
|
ansible.builtin.find:
|
|
paths: "{{ aw_release_dir }}"
|
|
file_type: file
|
|
patterns:
|
|
- aw-server-rust
|
|
- aw-server
|
|
register: aw_server_binary_find
|
|
|
|
- name: Найти каталог WebUI
|
|
ansible.builtin.find:
|
|
paths: "{{ aw_release_dir }}"
|
|
file_type: directory
|
|
patterns:
|
|
- aw-webui
|
|
- webui
|
|
register: aw_webui_dir_find
|
|
|
|
- name: Сохранить пути распакованного релиза
|
|
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 | first) | default('') }}"
|
|
aw_webui_source_path: "{{ (aw_webui_dir_find.files | default([]) | sort(attribute='path') | map(attribute='path') | list | first) | default('') }}"
|
|
|
|
- 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: Скопировать 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-host-groups.json", dest: "{{ aw_server_webui_dir }}/js/aw-host-groups.json", mode: "0644" }
|
|
|
|
- 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
|
|
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: Записать /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_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 }}
|
|
|
|
- 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: Применить базовые 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_from_h: "{{ (aw_worktime_from | default('08:00')).split(':')[0] | int }}"
|
|
aw_worktime_from_m: "{{ (aw_worktime_from | default('08:00')).split(':')[1] | int }}"
|
|
aw_worktime_to_h: "{{ (aw_worktime_to | default('17:00')).split(':')[0] | int }}"
|
|
aw_worktime_to_m: "{{ (aw_worktime_to | default('17:00')).split(':')[1] | int }}"
|
|
aw_worktime_duration_default_derived: >-
|
|
{{
|
|
(
|
|
(
|
|
((aw_worktime_to_h | int) * 60 + (aw_worktime_to_m | int)) -
|
|
((aw_worktime_from_h | int) * 60 + (aw_worktime_from_m | 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 }}"
|
|
body_format: json
|
|
status_code: 200
|
|
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 }}"
|
|
body_format: json
|
|
status_code: 200
|
|
when: aw_apply_worktime_settings | default(false) | bool
|
|
|
|
handlers:
|
|
- name: Перезагрузить systemd
|
|
ansible.builtin.systemd:
|
|
daemon_reload: true
|
|
|
|
- name: Перезапустить activitywatch
|
|
ansible.builtin.systemd:
|
|
name: activitywatch-server.service
|
|
state: restarted
|