runv-server

server tooling for runv.club
Log | Files | Refs | README

inspect_postfix_mysql_aliases.py (3159B)


      1 #!/usr/bin/env python3
      2 """
      3 Lê mysql-virtual-alias-maps.cf e mostra estrutura da tabela (read-only).
      4 
      5 Ajuda a preencher /etc/runv-member-mail.json para backend postfix-mysql.
      6 """
      7 
      8 from __future__ import annotations
      9 
     10 import argparse
     11 import re
     12 import subprocess
     13 import sys
     14 from pathlib import Path
     15 
     16 _SCRIPT_DIR = Path(__file__).resolve().parent
     17 _REPO_TOOLS_LIB = _SCRIPT_DIR.parent.parent / "tools" / "lib"
     18 if str(_REPO_TOOLS_LIB) not in sys.path:
     19     sys.path.insert(0, str(_REPO_TOOLS_LIB))
     20 
     21 import runv_mail_sync as ms  # noqa: E402
     22 
     23 QUERY_HINT = re.compile(
     24     r"SELECT\s+[`']?(\w+)[`']?\s+FROM\s+[`']?(\w+)[`']?\s+WHERE\s+[`']?(\w+)[`']?\s*=",
     25     re.IGNORECASE,
     26 )
     27 
     28 
     29 def main() -> int:
     30     p = argparse.ArgumentParser(description="Inspecionar mapa MySQL de aliases Postfix")
     31     p.add_argument(
     32         "--map-file",
     33         default="/etc/postfix/mysql-virtual-alias-maps.cf",
     34         help="ficheiro .cf do Postfix",
     35     )
     36     p.add_argument("--table", default="", help="forçar nome da tabela")
     37     args = p.parse_args()
     38 
     39     if sys.platform == "win32":
     40         print("Execute na VPS Linux.", file=sys.stderr)
     41         return 2
     42 
     43     map_path = Path(args.map_file)
     44     if not map_path.is_file():
     45         print(f"ausente: {map_path}", file=sys.stderr)
     46         return 1
     47 
     48     parsed = ms.parse_postfix_mysql_cf(map_path)
     49     print(f"=== {map_path} ===")
     50     for key in ("hosts", "user", "dbname", "query"):
     51         val = parsed.get(key, "")
     52         if key == "password":
     53             continue
     54         print(f"{key} = {val}")
     55     print("password = ***")
     56 
     57     query = parsed.get("query", "")
     58     table = args.table.strip()
     59     dest_col = ""
     60     addr_col = ""
     61     m = QUERY_HINT.search(query.replace("\n", " "))
     62     if m:
     63         dest_col, table, addr_col = m.group(1), m.group(2), m.group(3)
     64         print(f"\ninferido da query: tabela={table!r} col_destino={dest_col!r} col_endereco={addr_col!r}")
     65 
     66     if not table:
     67         print("\nNão foi possível inferir a tabela; use --table NOME", file=sys.stderr)
     68         return 1
     69 
     70     sql = f"DESCRIBE `{table}`;"
     71     print(f"\n=== {sql} ===")
     72     try:
     73         out = ms.mysql_exec(parsed, sql, dry_run=False)
     74         print(out or "(sem saída)")
     75     except SystemExit as e:
     76         print(e, file=sys.stderr)
     77         return 1
     78 
     79     sample = f"SELECT * FROM `{table}` LIMIT 5;"
     80     print(f"\n=== {sample} ===")
     81     try:
     82         print(ms.mysql_exec(parsed, sample, dry_run=False) or "(vazio)")
     83     except SystemExit:
     84         print("(amostra indisponível)", file=sys.stderr)
     85 
     86     print(
     87         "\nSugestão /etc/runv-member-mail.json:\n"
     88         "{\n"
     89         '  "enabled": true,\n'
     90         '  "backend": "postfix-mysql",\n'
     91         f'  "mysql_map_file": "{map_path}",\n'
     92         "  \"mysql\": {\n"
     93         f'    "table": "{table}",\n'
     94         f'    "address_column": "{addr_col or "address"}",\n'
     95         f'    "goto_column": "{dest_col or "goto"}",\n'
     96         '    "active_column": "active",\n'
     97         '    "active_value": "1"\n'
     98         "  },\n"
     99         '  "reload_postfix": true,\n'
    100         '  "auto_sync_on_approve": true\n'
    101         "}"
    102     )
    103     return 0
    104 
    105 
    106 if __name__ == "__main__":
    107     raise SystemExit(main())