127 lines
3.9 KiB
Markdown
127 lines
3.9 KiB
Markdown
# Python cron function template
|
|
|
|
Эту функцию можно создать вручную в console UI и привязать к `TimeTrigger`.
|
|
|
|
Она собирает базовые метрики системы, отдает JSON и сразу отправляет snapshot в страницу cron dashboard.
|
|
|
|
## Что нужно задать в UI
|
|
|
|
- `Route`: например `/system-metrics`
|
|
- `Methods`: `GET,POST`
|
|
- `Cron`: например `*/5 * * * *`
|
|
- `Entrypoint`: `main.main`
|
|
|
|
## Код
|
|
|
|
```python
|
|
import json
|
|
import os
|
|
import socket
|
|
import urllib.request
|
|
from datetime import datetime, timezone
|
|
|
|
|
|
def read_meminfo():
|
|
mem = {}
|
|
try:
|
|
with open('/proc/meminfo', 'r', encoding='utf-8') as fh:
|
|
for line in fh:
|
|
if ':' not in line:
|
|
continue
|
|
key, value = line.split(':', 1)
|
|
parts = value.strip().split()
|
|
if not parts:
|
|
continue
|
|
try:
|
|
mem[key] = float(parts[0]) / 1024.0 # kB -> MB
|
|
except ValueError:
|
|
continue
|
|
except OSError:
|
|
pass
|
|
return mem
|
|
|
|
|
|
def read_uptime_sec():
|
|
try:
|
|
with open('/proc/uptime', 'r', encoding='utf-8') as fh:
|
|
return float(fh.read().split()[0])
|
|
except Exception:
|
|
return 0.0
|
|
|
|
|
|
def read_disk_gb(path='/'):
|
|
st = os.statvfs(path)
|
|
total = (st.f_blocks * st.f_frsize) / (1024 ** 3)
|
|
free = (st.f_bavail * st.f_frsize) / (1024 ** 3)
|
|
used = total - free
|
|
return total, free, used
|
|
|
|
|
|
def payload():
|
|
mem = read_meminfo()
|
|
total = mem.get('MemTotal', 0.0)
|
|
free = mem.get('MemFree', 0.0)
|
|
available = mem.get('MemAvailable', free)
|
|
used = max(0.0, total - free) if total else 0.0
|
|
mem_percent = (used / total) * 100.0 if total else 0.0
|
|
|
|
try:
|
|
load1, load5, load15 = os.getloadavg()
|
|
except (AttributeError, OSError):
|
|
load1 = load5 = load15 = 0.0
|
|
|
|
disk_total, disk_free, disk_used = read_disk_gb('/')
|
|
return {
|
|
'timestamp': datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z'),
|
|
'source': os.getenv('CRON_SOURCE', 'python-cron'),
|
|
'hostname': socket.gethostname(),
|
|
'status': 'ok',
|
|
'memory_total_mb': round(total, 2),
|
|
'memory_free_mb': round(free, 2),
|
|
'memory_available_mb': round(available, 2),
|
|
'memory_used_mb': round(used, 2),
|
|
'memory_percent': round(mem_percent, 2),
|
|
'cpu_load_1m': round(load1, 2),
|
|
'cpu_load_5m': round(load5, 2),
|
|
'cpu_load_15m': round(load15, 2),
|
|
'disk_total_gb': round(disk_total, 2),
|
|
'disk_free_gb': round(disk_free, 2),
|
|
'disk_used_gb': round(disk_used, 2),
|
|
'uptime_sec': round(read_uptime_sec(), 2),
|
|
}
|
|
|
|
|
|
def push_snapshot(data):
|
|
target = os.getenv('CRON_TARGET_URL', 'http://fission-console.fission.svc.cluster.local/cron/api/metrics')
|
|
req = urllib.request.Request(
|
|
target,
|
|
data=json.dumps(data).encode('utf-8'),
|
|
method='POST',
|
|
headers={'Content-Type': 'application/json'},
|
|
)
|
|
token = os.getenv('CRON_TOKEN', '').strip()
|
|
if token:
|
|
req.add_header('X-Cron-Token', token)
|
|
with urllib.request.urlopen(req, timeout=10) as resp:
|
|
return resp.read().decode('utf-8', errors='ignore')
|
|
|
|
|
|
def main():
|
|
data = payload()
|
|
try:
|
|
push_snapshot(data)
|
|
except Exception as exc:
|
|
data['push_error'] = str(exc)
|
|
return {
|
|
'status': 200,
|
|
'headers': {'Content-Type': 'application/json'},
|
|
'body': json.dumps(data, ensure_ascii=False),
|
|
}
|
|
```
|
|
|
|
## Что важно
|
|
|
|
- `CRON_TARGET_URL` можно оставить по умолчанию, если console доступна по публичному URL.
|
|
- Если захочешь защитить ingest, задай `CRON_TOKEN` в функции и такой же `X-Cron-Token` на стороне console.
|
|
- Функция не требует внешних библиотек.
|