mirror of
https://github.com/odoo/runbot.git
synced 2025-03-15 15:35:46 +07:00
95 lines
2.5 KiB
Python
Executable File
95 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
import contextlib
|
|
import random
|
|
import signal
|
|
import subprocess
|
|
import threading
|
|
import time
|
|
|
|
import requests
|
|
import sys
|
|
|
|
port = int(sys.argv[1])
|
|
|
|
NGROK_CLI = [
|
|
'ngrok', 'start', '--none', '--region', 'eu',
|
|
]
|
|
|
|
own = None
|
|
web_addr = 'http://localhost:4040/api'
|
|
addr = 'localhost:%d' % port
|
|
|
|
# FIXME: this is for xdist to avoid workers running ngrok at the
|
|
# exact same time, use lockfile instead
|
|
time.sleep(random.SystemRandom().randint(1, 10))
|
|
# try to find out if ngrok is running, and if it's not attempt
|
|
# to start it
|
|
try:
|
|
requests.get(web_addr)
|
|
except requests.exceptions.ConnectionError:
|
|
own = subprocess.Popen(NGROK_CLI, stdout=subprocess.DEVNULL)
|
|
for _ in range(5):
|
|
time.sleep(1)
|
|
with contextlib.suppress(requests.exceptions.ConnectionError):
|
|
requests.get(web_addr)
|
|
break
|
|
else:
|
|
sys.exit("Unable to connect to ngrok")
|
|
|
|
requests.post(f'{web_addr}/tunnels', json={
|
|
'name': str(port),
|
|
'proto': 'http',
|
|
'addr': addr,
|
|
'schemes': ['https'],
|
|
'inspect': True,
|
|
}).raise_for_status()
|
|
|
|
|
|
tunnel = f'{web_addr}/tunnels/{port}'
|
|
for _ in range(10):
|
|
time.sleep(2)
|
|
r = requests.get(tunnel)
|
|
# not created yet, wait and retry
|
|
if r.status_code == 404:
|
|
continue
|
|
# check for weird responses
|
|
r.raise_for_status()
|
|
|
|
print(r.json()['public_url'], flush=True)
|
|
sys.stdout.close()
|
|
break
|
|
else:
|
|
sys.exit("ngrok tunnel creation failed (?)")
|
|
|
|
shutdown = threading.Event()
|
|
def cleanup(_sig, _frame):
|
|
requests.delete(tunnel)
|
|
for _ in range(10):
|
|
time.sleep(1)
|
|
r = requests.get(tunnel)
|
|
# check if deletion is done
|
|
if r.status_code == 404:
|
|
break
|
|
r.raise_for_status()
|
|
else:
|
|
raise sys.exit("ngrok tunnel deletion failed")
|
|
|
|
r = requests.get(f'{web_addr}/tunnels')
|
|
if not r.ok:
|
|
sys.exit(f'{r.reason} {r.text}')
|
|
# FIXME: if we started ngrok, we should probably wait for all tunnels to be
|
|
# closed then terminate ngrok? This is likely a situation where the
|
|
# worker which created the ngrok instance finished early...
|
|
if own and not r.json()['tunnels']:
|
|
# no more tunnels and we started ngrok -> try to kill it
|
|
own.terminate()
|
|
own.wait(30)
|
|
shutdown.set()
|
|
|
|
# don't know why but signal.sigwait doesn't seem to take SIGTERM in account so
|
|
# we need the cursed version
|
|
signal.signal(signal.SIGTERM, cleanup)
|
|
signal.signal(signal.SIGINT, cleanup)
|
|
|
|
shutdown.wait()
|