Source code for openquake.commands.webui
# -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (C) 2016-2026 GEM Foundation
#
# OpenQuake is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# OpenQuake is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with OpenQuake. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import subprocess
import webbrowser
import psutil
from openquake.baselib import config, general
from openquake.commonlib import dbapi
from openquake.commonlib.auth import API_KEY
from openquake.server.db import actions
from openquake.server.utils import check_webserver_running
commands = ['start', 'status', 'stop']
def _find_webui_process(hostport):
"""Find the Uvicorn process listening on the requested port."""
_host, port = hostport.rsplit(':', 1)
for connection in psutil.net_connections(kind='tcp'):
if (connection.status == psutil.CONN_LISTEN and
connection.laddr.port == int(port)):
try:
return psutil.Process(connection.pid)
except psutil.NoSuchProcess:
return None
return None
def _status(hostport):
"""Print whether the WebUI responds on the requested address."""
url = 'http://' + hostport
running = check_webserver_running(url, max_retries=1, warn=False)
print('running' if running else 'stopped')
return running
def _stop(hostport):
"""Stop the Uvicorn process serving the requested WebUI port."""
process = _find_webui_process(hostport)
if process is None:
print('WebUI is not running')
return
process.terminate()
try:
process.wait(timeout=10)
except psutil.TimeoutExpired:
process.kill()
process.wait()
print('stopped')
[docs]def runserver(hostport=None, skip_browser=False):
"""Start Uvicorn and serve the combined WebUI application."""
url = 'http://' + hostport
if check_webserver_running(url, max_retries=1, warn=False):
if not skip_browser:
webbrowser.open(url)
return
host, port = hostport.rsplit(':', 1)
api_host = '127.0.0.1' if host == '0.0.0.0' else host
env = os.environ.copy()
env.update(
OQ_API_KEY=API_KEY,
OQ_WEBAPI_SERVER='http://%s:%s' % (api_host, port))
process = subprocess.Popen([
sys.executable, '-m', 'uvicorn',
'openquake.server.asgi:app',
'--host', host,
'--port', port,
], env=env)
if not skip_browser and check_webserver_running(url):
webbrowser.open(url)
try:
process.wait()
except KeyboardInterrupt:
process.terminate()
process.wait()
if process.returncode not in (0, -15):
sys.exit(process.returncode)
[docs]def main(cmd, hostport='127.0.0.1:8800', skip_browser: bool = False):
"""
Start the webui server in foreground. Other webui commands can be launched
after activating the openquake virtual environment, using Django’s
command-line utility for administrative tasks, e.g.:
manage.py <command> [options]
"""
if cmd == 'status':
_status(hostport)
return
if cmd == 'stop':
_stop(hostport)
return
os.environ.setdefault('OQ_API_KEY', API_KEY)
api_host, api_port = hostport.rsplit(':', 1)
if api_host == '0.0.0.0':
api_host = '127.0.0.1'
os.environ.setdefault(
'OQ_WEBAPI_SERVER', 'http://%s:%s' % (api_host, api_port))
dbpath = os.path.realpath(os.path.expanduser(config.dbserver.file))
if os.path.isfile(dbpath) and not os.access(dbpath, os.W_OK):
sys.exit('This command must be run by the proper user: '
'see the documentation for details')
actions.upgrade_db(dbapi.db)
print('Starting, using version %s' % general.engine_version())
runserver(hostport, skip_browser)
main.cmd = dict(help='webui command', choices=commands)
main.hostport = 'a string of the form <hostname:port>'
main.skip_browser = 'do not automatically open the browser'