mirror of
https://github.com/neondatabase/neon.git
synced 2025-12-22 21:59:59 +00:00
## Problem ``` Could not resolve host: console.stage.neon.tech ``` ## Summary of changes - replace `console.stage.neon.tech` with `console-stage.neon.build`
133 lines
3.8 KiB
Python
133 lines
3.8 KiB
Python
import argparse
|
|
import logging
|
|
import os
|
|
import shutil
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import requests
|
|
|
|
level = logging.INFO
|
|
logging.basicConfig(
|
|
format="%(asctime)s,%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s",
|
|
datefmt="%Y-%m-%d:%H:%M:%S",
|
|
level=level,
|
|
)
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--trash-dir", required=True, type=Path)
|
|
parser.add_argument("--dry-run", action="store_true")
|
|
parser.add_argument("--safekeeper-id", required=True, type=int)
|
|
parser.add_argument("--safekeeper-host", required=True, type=str)
|
|
args = parser.parse_args()
|
|
|
|
access_key = os.getenv("CONSOLE_API_TOKEN")
|
|
endpoint: str = "https://console-stage.neon.build/api"
|
|
|
|
trash_dir: Path = args.trash_dir
|
|
dry_run: bool = args.dry_run
|
|
logging.info(f"dry_run={dry_run}")
|
|
sk_id: int = args.safekeeper_id
|
|
sk_host: str = args.safekeeper_host
|
|
|
|
assert trash_dir.is_dir()
|
|
|
|
###
|
|
|
|
|
|
def console_get(rel_url):
|
|
r = requests.get(
|
|
f"{endpoint}{rel_url}",
|
|
headers={
|
|
"Authorization": f"Bearer {access_key}",
|
|
"Content-Type": "application/json",
|
|
"Accept": "application/json",
|
|
},
|
|
)
|
|
r.raise_for_status()
|
|
return r
|
|
|
|
|
|
def tenant_is_deleted_in_console(tenant_id):
|
|
r = console_get(f"/v1/admin/projects?search={tenant_id}&show_deleted=true")
|
|
r = r.json()
|
|
results = r["data"]
|
|
assert len(results) == 1, f"unexpected results len: {results}"
|
|
r = results[0]
|
|
assert r["tenant"] == tenant_id, f"tenant id doesn't match: {r}"
|
|
assert r["safekeepers"] is not None, f"safekeepers is None: {r}"
|
|
assert any(sk["id"] == sk_id for sk in r["safekeepers"]), f"safekeeper id not found: {r}"
|
|
assert "deleted" in r, f"{r}"
|
|
return r["deleted"] is True
|
|
|
|
|
|
def call_delete_tenant_api(tenant_id):
|
|
r = requests.delete(f"http://{sk_host}:7676/v1/tenant/{tenant_id}")
|
|
r.raise_for_status()
|
|
return r
|
|
|
|
|
|
def cleanup_tenant(tenant_id):
|
|
tenant_dir = Path(f"/storage/safekeeper/data/{tenant_id}")
|
|
|
|
if not tenant_dir.exists():
|
|
logging.info("tenant directory doesn't exist, assuming it has been cleaned already")
|
|
return
|
|
|
|
if not tenant_is_deleted_in_console(tenant_id):
|
|
logging.info("tenant is not deleted in console, skipping")
|
|
return
|
|
|
|
logging.info("assertions passed")
|
|
|
|
if dry_run:
|
|
return
|
|
|
|
logging.info("deleting tenant")
|
|
|
|
tenant_dir_in_trash = trash_dir / tenant_dir.relative_to("/")
|
|
tenant_dir_in_trash.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
assert not tenant_dir_in_trash.exists(), f"{tenant_dir_in_trash}"
|
|
assert tenant_dir_in_trash.parent.exists(), f"{tenant_dir_in_trash}"
|
|
# double-check
|
|
assert tenant_dir.exists(), f"{tenant_dir}"
|
|
assert tenant_dir.is_dir(), f"{tenant_dir}"
|
|
|
|
logging.info(f"copying {tenant_dir} to {tenant_dir_in_trash}")
|
|
shutil.copytree(src=tenant_dir, dst=tenant_dir_in_trash, symlinks=False, dirs_exist_ok=False)
|
|
|
|
logging.info(f"deleting {tenant_dir}")
|
|
call_delete_tenant_api(tenant_id)
|
|
|
|
logging.info("tenant is now deleted, checking that it's gone")
|
|
assert not tenant_dir.exists(), f"{tenant_dir}"
|
|
|
|
|
|
if os.path.exists("script.pid"):
|
|
logging.info(
|
|
f"script is already running, with pid={Path('script.pid').read_text()}. Terminate it first."
|
|
)
|
|
exit(1)
|
|
|
|
with open("script.pid", "w", encoding="utf-8") as f:
|
|
f.write(str(os.getpid()))
|
|
|
|
logging.info(f"started script.py, pid={os.getpid()}")
|
|
|
|
for line in sys.stdin:
|
|
tenant_id = line.strip()
|
|
try:
|
|
logging.info(f"start tenant {tenant_id}")
|
|
cleanup_tenant(tenant_id)
|
|
logging.info(f"done tenant {tenant_id}")
|
|
except KeyboardInterrupt:
|
|
print("KeyboardInterrupt exception is caught")
|
|
break
|
|
except: # noqa: E722
|
|
logging.exception(f"failed to clean up tenant {tenant_id}")
|
|
|
|
logging.info(f"finished script.py, pid={os.getpid()}")
|
|
|
|
os.remove("script.pid")
|