#!/usr/bin/env python3 import datetime import subprocess import sys from pathlib import Path import click import requests from http_host_lib import DEFAULT_ASSETS_DIR, DEFAULT_RUNS_DIR, HOST_CONFIG, MNT_DIR from http_host_lib.download_assets import ( download_and_extract_asset_tar_gz, download_sprites, ) from http_host_lib.download_tileset import download_and_extract_tileset from http_host_lib.mount import clean_up_mounts, create_fstab from http_host_lib.nginx import write_nginx_config from http_host_lib.set_tileset_versions import set_tileset_versions from http_host_lib.utils import assert_linux, assert_sudo @click.group() def cli(): """ Manages OpenFreeMap HTTP hosts, including:\n - Downloading assets\n - Downloading tilesets\n - Mounting directories\n - Updating nginx config\n - Setting the latest versions of tilesets\n - Running the sync cron task (called every minute) """ @cli.command() @click.argument('area', required=False) @click.option('--version', default='latest', help='Version string, like "20231227_043106_pt"') @click.option( '--runs-dir', help='Specify runs directory', type=click.Path(dir_okay=True, file_okay=False, path_type=Path), ) @click.option('--list-versions', is_flag=True, help='List all versions in an area and terminate') def download_tileset(area: str, version: str, list_versions: bool, runs_dir: Path): """ Downloads and extracts the latest tiles.btrfs file from the public bucket. Version can also be specified. """ print('running download_tileset') if area not in {'planet', 'monaco'}: sys.exit(' please specify area: "planet" or "monaco"') r = requests.get(f'https://{area}.openfreemap.com/dirs.txt', timeout=30) r.raise_for_status() versions = sorted(r.text.splitlines()) all_versions_str = '\n'.join(versions) if list_versions: print(all_versions_str) return if version == 'latest': selected_version = versions[-1] else: if version not in versions: sys.exit(f'Requested version is not available. Available versions:\n{all_versions_str}') selected_version = version if not runs_dir: runs_dir = DEFAULT_RUNS_DIR if not runs_dir.parent.exists(): sys.exit("runs dir's parent doesn't exist") return download_and_extract_tileset(area, selected_version, runs_dir) @cli.command() @click.option( '--assets-dir', help='Specify assets directory', type=click.Path(dir_okay=True, file_okay=False, path_type=Path), ) def download_assets(assets_dir: Path): """ Downloads and extracts assets """ print('running download_assets') if not assets_dir: assets_dir = DEFAULT_ASSETS_DIR if not assets_dir.parent.exists(): sys.exit("asset dir's parent doesn't exist") download_and_extract_asset_tar_gz(assets_dir, 'fonts') download_and_extract_asset_tar_gz(assets_dir, 'styles') download_and_extract_asset_tar_gz(assets_dir, 'natural_earth') download_sprites(assets_dir) @cli.command() def mount(): """ Mounts/unmounts the btrfs images from /data/ofm/http_host/runs automatically. When finished, /mnt/ofm dir will have all the present tiles.btrfs files mounted in a read-only way. """ print('running mount') assert_linux() assert_sudo() if not DEFAULT_RUNS_DIR.exists(): sys.exit(' download_tileset needs to be run first') clean_up_mounts(MNT_DIR) create_fstab() print(' running mount -a') subprocess.run(['mount', '-a'], check=True) clean_up_mounts(MNT_DIR) @cli.command() def set_latest_versions(): """ Sets the latest version of the tilesets to the version specified by https://assets.openfreemap.com/versions/deployed_planet.txt 1. Checks if the given version is present on the disk and is mounted 2. Writes to a version file """ print('running set_latest_versions') assert_linux() assert_sudo() if not MNT_DIR.exists(): sys.exit(' mount needs to be run first') return set_tileset_versions() @cli.command() def nginx_sync(): """ Syncs the nginx config to the state of the system """ print('running nginx_sync') assert_linux() assert_sudo() if not MNT_DIR.exists(): sys.exit(' mount needs to be run first') write_nginx_config() @cli.command() @click.pass_context def sync(ctx): """ Runs the sync task, normally called by cron every minute On a new server this also takes care of everything, no need to run anything manually. """ print('---') print('running sync') print(datetime.datetime.now(tz=datetime.timezone.utc)) assert_linux() assert_sudo() download_done = False download_done += ctx.invoke(download_tileset, area='monaco') if not HOST_CONFIG.get('skip_planet'): download_done += ctx.invoke(download_tileset, area='planet') if download_done: ctx.invoke(mount) ctx.invoke(download_assets) deploy_done = ctx.invoke(set_latest_versions) if download_done or deploy_done: ctx.invoke(nginx_sync) if __name__ == '__main__': print(HOST_CONFIG) cli()