Added new role misc/tg_monitor_cmd
parent
7f9980903f
commit
0a5b3fc26f
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
# monitor_name: "echo-output-check"
|
||||||
|
instance_name: "tg-monitor-cmd-{{ monitor_name }}"
|
||||||
|
description: "{{ monitor_name }}" # should be human fancy
|
||||||
|
|
||||||
|
# command: "/bin/echo Hello" # or command_str
|
||||||
|
command_str: "{{ command | map('quote') | join(' ') }}"
|
||||||
|
use_shell: no # read https://docs.python.org/3/library/subprocess.html#security-considerations before using use_shell=yes
|
||||||
|
|
||||||
|
system_user: tg-monitor-cmd
|
||||||
|
|
||||||
|
recipient_id: "{{ default_tg_monitor_recipient_id }}"
|
||||||
|
bot_key: "{{ global_telegram_server_bot_key }}"
|
||||||
|
telegram_timeout: 10
|
||||||
|
|
||||||
|
calendar_spec: "*:0:0" # once every hour
|
||||||
|
service_description: |
|
||||||
|
Telegram Monitor Command of {{ description }}
|
||||||
|
|
||||||
|
# paths
|
||||||
|
|
||||||
|
monitoring_directory: "{{ global_deployment_directory }}/tg-monitor-cmd"
|
||||||
|
instance_directory: "{{ monitoring_directory }}/{{ monitor_name }}"
|
||||||
|
script_path: "{{ instance_directory }}/script.py"
|
||||||
|
data_path: "{{ instance_directory }}/data"
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
allow_duplicates: yes
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- role: misc/system_user
|
||||||
|
# system_user
|
||||||
|
user_directory: "{{ monitoring_directory }}"
|
@ -0,0 +1,69 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- name: Create directory for monitoring scripts and data
|
||||||
|
file:
|
||||||
|
state: directory
|
||||||
|
path: "{{ instance_directory }}"
|
||||||
|
owner: root
|
||||||
|
group: "{{ system_user }}"
|
||||||
|
mode: u=rwx,g=rx,o=
|
||||||
|
|
||||||
|
- name: Deploy script
|
||||||
|
template:
|
||||||
|
src: monitor.py
|
||||||
|
dest: "{{ script_path }}"
|
||||||
|
owner: root
|
||||||
|
group: "{{ system_user }}"
|
||||||
|
mode: u=rwx,g=rx,o=
|
||||||
|
register: script_task
|
||||||
|
|
||||||
|
- name: Create empty data file
|
||||||
|
copy:
|
||||||
|
content: ""
|
||||||
|
dest: "{{ data_path }}"
|
||||||
|
force: no # do not overwrite
|
||||||
|
|
||||||
|
- name: Ensure permissions on data file
|
||||||
|
file:
|
||||||
|
state: file
|
||||||
|
path: "{{ data_path }}"
|
||||||
|
owner: root
|
||||||
|
group: "{{ system_user }}"
|
||||||
|
mode: u=rw,g=rw,o=
|
||||||
|
|
||||||
|
- name: Register service for monitor
|
||||||
|
template:
|
||||||
|
src: monitor.service
|
||||||
|
dest: "{{ global_systemd_configuration_directory }}/{{ instance_name }}.service"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: u=rw,g=r,o=
|
||||||
|
register: service_task
|
||||||
|
|
||||||
|
- name: Run service for initial test
|
||||||
|
systemd:
|
||||||
|
state: started
|
||||||
|
daemon_reload: yes
|
||||||
|
name: "{{ instance_name }}.service"
|
||||||
|
when: script_task.changed or service_task.changed
|
||||||
|
|
||||||
|
- name: Register timer for monitor service
|
||||||
|
template:
|
||||||
|
src: monitor.timer
|
||||||
|
dest: "{{ global_systemd_configuration_directory }}/{{ instance_name }}.timer"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: u=rw,g=r,o=
|
||||||
|
register: timer_task
|
||||||
|
|
||||||
|
- name: Restart timer for monitor
|
||||||
|
systemd:
|
||||||
|
state: restarted
|
||||||
|
daemon_reload: yes
|
||||||
|
name: "{{ instance_name }}.timer"
|
||||||
|
when: timer_task.changed
|
||||||
|
|
||||||
|
- name: Enable timer for monitor
|
||||||
|
systemd:
|
||||||
|
name: "{{ instance_name }}.timer"
|
||||||
|
enabled: yes
|
@ -0,0 +1,64 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# imports
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from hashlib import sha256
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
# config
|
||||||
|
|
||||||
|
MONITOR_DESC = """{{ description }}"""
|
||||||
|
MONITOR_COMMAND = """{{ command_str }}"""
|
||||||
|
USE_SHELL = {{ use_shell | ternary('True', 'False') }}
|
||||||
|
|
||||||
|
DATA_PATH = Path("""{{ data_path }}""")
|
||||||
|
|
||||||
|
TG_ENDPOINT = "https://api.telegram.org"
|
||||||
|
TG_KEY = """{{ bot_key }}"""
|
||||||
|
TG_RECIPIENT = """{{ recipient_id }}"""
|
||||||
|
|
||||||
|
# helpers
|
||||||
|
|
||||||
|
def print_error(*args, **kwargs):
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
def tg_msg(msg: str) -> None:
|
||||||
|
print(f"Sending message using telegram:\n{msg}")
|
||||||
|
ret = requests.post(f"{TG_ENDPOINT}/bot{TG_KEY}/sendMessage", data={
|
||||||
|
"chat_id": TG_RECIPIENT,
|
||||||
|
"disable_web_page_preview": 1,
|
||||||
|
"parse_mode": "Markdown",
|
||||||
|
"text": msg,
|
||||||
|
})
|
||||||
|
if 400 <= ret.status_code:
|
||||||
|
raise Exception(f"Sending telegram message failed: {ret.status_code} {ret.text}")
|
||||||
|
|
||||||
|
def run_cmd(cmd: list, **kwargs) -> str:
|
||||||
|
return subprocess.run(cmd, capture_output=True, check=True, text=True, **kwargs).stdout
|
||||||
|
|
||||||
|
def hash_data(data: str) -> bool:
|
||||||
|
return sha256(data.encode("utf-8")).hexdigest()
|
||||||
|
|
||||||
|
def check_cmd(cmd_str: str, use_shell: bool, data_file: Path) -> str:
|
||||||
|
cmd = shlex.split(cmd_str) if not use_shell else cmd_str
|
||||||
|
old_hash = data_file.read_text() if data_file.exists() else None
|
||||||
|
new_data = run_cmd(cmd, shell=use_shell)
|
||||||
|
new_hash = hash_data(new_data)
|
||||||
|
if old_hash == new_hash:
|
||||||
|
return None
|
||||||
|
data_file.write_text(new_hash)
|
||||||
|
return new_data
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
data = check_cmd(MONITOR_COMMAND, USE_SHELL, DATA_PATH)
|
||||||
|
if data:
|
||||||
|
tg_msg(f"{MONITOR_DESC} changed to:\n```\n{data}\n```")
|
||||||
|
except Exception as e:
|
||||||
|
tg_msg(f"Got exception while running command of {MONITOR_DESC}: {str(e)}")
|
||||||
|
raise e
|
@ -0,0 +1,23 @@
|
|||||||
|
[Unit]
|
||||||
|
Description={{ service_description }}
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart={{ script_path | quote }}
|
||||||
|
User={{ system_user }}
|
||||||
|
Group={{ system_user }}
|
||||||
|
|
||||||
|
UMask=007
|
||||||
|
PrivateTmp=yes
|
||||||
|
PrivateDevices=yes
|
||||||
|
ProtectHome=yes
|
||||||
|
ReadOnlyPaths=/
|
||||||
|
ReadWritePaths=-{{ data_path }}
|
||||||
|
|
||||||
|
ProtectKernelModules=true
|
||||||
|
ProtectKernelTunables=true
|
||||||
|
ProtectControlGroups=true
|
||||||
|
RestrictRealtime=true
|
||||||
|
RestrictNamespaces=true
|
||||||
|
|
||||||
|
ProtectSystem=full
|
@ -0,0 +1,8 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Timer of {{ service_description }}
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar={{ calendar_spec }}
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
Loading…
Reference in New Issue