mirror of
https://github.com/hyperknot/openfreemap.git
synced 2026-05-21 22:12:15 +00:00
149 lines
3.9 KiB
Python
Executable File
149 lines
3.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import datetime
|
|
import json
|
|
|
|
import click
|
|
import requests
|
|
from dotenv import dotenv_values
|
|
from loadbalancer_lib.cloudflare import get_zone_id, set_records_round_robin
|
|
from loadbalancer_lib.curl import pycurl_get, pycurl_status
|
|
from loadbalancer_lib.telegram_ import telegram_send_message
|
|
|
|
|
|
AREAS = ['planet', 'monaco']
|
|
|
|
|
|
@click.group()
|
|
def cli():
|
|
"""
|
|
Manages load-balancing of Round-Robin DNS records
|
|
"""
|
|
|
|
|
|
@cli.command()
|
|
def check():
|
|
"""
|
|
Runs load-balancing check (triggered by cron every minute)
|
|
"""
|
|
|
|
print(f'starting loadbalancer check at: {datetime.datetime.now(tz=datetime.timezone.utc)}')
|
|
check_or_fix(fix=False)
|
|
|
|
|
|
@cli.command()
|
|
def fix():
|
|
"""
|
|
Fixes records based on check results
|
|
"""
|
|
|
|
print(f'starting loadbalancer fix at: {datetime.datetime.now(tz=datetime.timezone.utc)}')
|
|
check_or_fix(fix=True)
|
|
|
|
|
|
def check_or_fix(fix=False):
|
|
with open('/data/ofm/config/loadbalancer.json') as fp:
|
|
c = json.load(fp)
|
|
# print(c)
|
|
|
|
try:
|
|
results_by_ip = {}
|
|
working_hosts = set()
|
|
|
|
for area in AREAS:
|
|
for host_ip, host_is_ok in run_area(c, area).items():
|
|
results_by_ip.setdefault(host_ip, True)
|
|
results_by_ip[host_ip] &= host_is_ok
|
|
|
|
for host_ip, host_is_ok in results_by_ip.items():
|
|
if not host_is_ok:
|
|
message = f'OFM ERROR with host: {host_ip}'
|
|
print(message)
|
|
telegram_send_message(message, c['telegram_token'], c['telegram_chat_id'])
|
|
else:
|
|
working_hosts.add(host_ip)
|
|
|
|
except Exception as e:
|
|
message = f'OFM ERROR with loadbalancer: {e}'
|
|
print(message)
|
|
telegram_send_message(message, c['telegram_token'], c['telegram_chat_id'])
|
|
return
|
|
|
|
print(f'working hosts: {sorted(working_hosts)}')
|
|
|
|
if fix:
|
|
# if no hosts are detected working, probably a bug in this script
|
|
# fail-safe to include all hosts
|
|
if not working_hosts:
|
|
working_hosts = set(c['http_host_list'])
|
|
|
|
update_records(c, working_hosts)
|
|
|
|
|
|
def run_area(c, area):
|
|
target_version = get_target_version(area)
|
|
|
|
print(f'target version: {area}: {target_version}')
|
|
|
|
results = {}
|
|
|
|
for host_ip in c['http_host_list']:
|
|
try:
|
|
check_host(c['domain_ledns'], host_ip, area, target_version)
|
|
results[host_ip] = True
|
|
except Exception:
|
|
results[host_ip] = False
|
|
|
|
return results
|
|
|
|
|
|
def check_host(domain, host_ip, area, version):
|
|
# check TileJSON first
|
|
url = f'https://{domain}/{area}'
|
|
tilejson_str = pycurl_get(url, domain, host_ip)
|
|
tilejson = json.loads(tilejson_str)
|
|
tiles_url = tilejson['tiles'][0]
|
|
version_in_tilejson = tiles_url.split('/')[4]
|
|
assert version_in_tilejson == version
|
|
|
|
# check actual vector tile
|
|
url = f'https://{domain}/{area}/{version}/14/8529/5975.pbf'
|
|
assert pycurl_status(url, domain, host_ip) == 200
|
|
|
|
|
|
def get_target_version(area):
|
|
url = f'https://assets.openfreemap.com/versions/deployed_{area}.txt'
|
|
response = requests.get(url)
|
|
response.raise_for_status()
|
|
return response.text.strip()
|
|
|
|
|
|
def update_records(c, working_hosts):
|
|
config = dotenv_values('/data/ofm/config/cloudflare.ini')
|
|
cloudflare_api_token = config['dns_cloudflare_api_token']
|
|
|
|
domain = '.'.join(c['domain_ledns'].split('.')[-2:])
|
|
zone_id = get_zone_id(domain, cloudflare_api_token=cloudflare_api_token)
|
|
|
|
set_records_round_robin(
|
|
zone_id=zone_id,
|
|
name=c['domain_ledns'],
|
|
host_ip_set=working_hosts,
|
|
proxied=False,
|
|
ttl=300,
|
|
comment='domain_ledns',
|
|
cloudflare_api_token=cloudflare_api_token,
|
|
)
|
|
|
|
set_records_round_robin(
|
|
zone_id=zone_id,
|
|
name=c['domain_cf'],
|
|
host_ip_set=working_hosts,
|
|
proxied=True,
|
|
comment='domain_cf',
|
|
cloudflare_api_token=cloudflare_api_token,
|
|
)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
cli()
|