switch to gunicorn due to issues with uwsgi and reporting
This commit is contained in:
parent
0ac415ad83
commit
c851ca9328
|
@ -57,4 +57,5 @@ daphne.sock.lock
|
|||
coverage.xml
|
||||
setup_dev.yml
|
||||
11env/
|
||||
query_schema.json
|
||||
query_schema.json
|
||||
gunicorn_config.py
|
|
@ -0,0 +1,70 @@
|
|||
import multiprocessing
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Generate conf for gunicorn"
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
self.stdout.write("Creating gunicorn conf...")
|
||||
|
||||
cpu_count = multiprocessing.cpu_count()
|
||||
|
||||
# worker processes
|
||||
workers = getattr(settings, "TRMM_GUNICORN_WORKERS", cpu_count * 2 + 1)
|
||||
threads = getattr(settings, "TRMM_GUNICORN_THREADS", cpu_count * 2)
|
||||
worker_class = getattr(settings, "TRMM_GUNICORN_WORKER_CLASS", "gthread")
|
||||
max_requests = getattr(settings, "TRMM_GUNICORN_MAX_REQUESTS", 50)
|
||||
max_requests_jitter = getattr(settings, "TRMM_GUNICORN_MAX_REQUESTS_JITTER", 8)
|
||||
worker_connections = getattr(settings, "TRMM_GUNICORN_WORKER_CONNS", 1000)
|
||||
timeout = getattr(settings, "TRMM_GUNICORN_TIMEOUT", 300)
|
||||
graceful_timeout = getattr(settings, "TRMM_GUNICORN_GRACEFUL_TIMEOUT", 300)
|
||||
|
||||
# socket
|
||||
backlog = getattr(settings, "TRMM_GUNICORN_BACKLOG", 2048)
|
||||
if getattr(settings, "DOCKER_BUILD", False):
|
||||
bind = "0.0.0.0:8080"
|
||||
else:
|
||||
bind = f"unix:{settings.BASE_DIR / 'tacticalrmm.sock'}"
|
||||
|
||||
# security
|
||||
limit_request_line = getattr(settings, "TRMM_GUNICORN_LIMIT_REQUEST_LINE", 0)
|
||||
limit_request_fields = getattr(
|
||||
settings, "TRMM_GUNICORN_LIMIT_REQUEST_FIELDS", 500
|
||||
)
|
||||
limit_request_field_size = getattr(
|
||||
settings, "TRMM_GUNICORN_LIMIT_REQUEST_FIELD_SIZE", 0
|
||||
)
|
||||
|
||||
# server
|
||||
preload_app = getattr(settings, "TRMM_GUNICORN_PRELOAD_APP", True)
|
||||
|
||||
# log
|
||||
loglevel = getattr(settings, "TRMM_GUNICORN_LOGLEVEL", "info")
|
||||
|
||||
cfg = [
|
||||
f"bind = '{bind}'",
|
||||
f"workers = {workers}",
|
||||
f"threads = {threads}",
|
||||
f"worker_class = '{worker_class}'",
|
||||
f"backlog = {backlog}",
|
||||
f"worker_connections = {worker_connections}",
|
||||
f"timeout = {timeout}",
|
||||
f"graceful_timeout = {graceful_timeout}",
|
||||
f"limit_request_line = {limit_request_line}",
|
||||
f"limit_request_fields = {limit_request_fields}",
|
||||
f"limit_request_field_size = {limit_request_field_size}",
|
||||
f"max_requests = {max_requests}",
|
||||
f"max_requests_jitter = {max_requests_jitter}",
|
||||
f"loglevel = '{loglevel}'",
|
||||
f"chdir = '{settings.BASE_DIR}'",
|
||||
f"preload_app = {preload_app}",
|
||||
]
|
||||
|
||||
with open(settings.BASE_DIR / "gunicorn_config.py", "w") as fp:
|
||||
for line in cfg:
|
||||
fp.write(line + "\n")
|
||||
|
||||
self.stdout.write("Created gunicorn conf")
|
|
@ -14,6 +14,7 @@ django-ipware==5.0.0
|
|||
django-rest-knox==4.2.0
|
||||
djangorestframework==3.14.0
|
||||
drf-spectacular==0.26.5
|
||||
gunicorn==21.2.0
|
||||
hiredis==2.2.3
|
||||
meshctrl==0.1.15
|
||||
msgpack==1.0.7
|
||||
|
@ -33,12 +34,11 @@ six==1.16.0
|
|||
sqlparse==0.4.4
|
||||
twilio==8.10.0
|
||||
urllib3==2.0.7
|
||||
uWSGI==2.0.22
|
||||
validators==0.20.0
|
||||
vine==5.0.0
|
||||
websockets==11.0.3
|
||||
zipp==3.17.0
|
||||
pandas==2.1.1
|
||||
pandas==2.1.2
|
||||
kaleido==0.2.1
|
||||
jinja2==3.1.2
|
||||
markdown==3.3.6
|
||||
|
|
|
@ -53,13 +53,13 @@ if [ "$1" = 'tactical-init' ]; then
|
|||
mkdir -p ${TACTICAL_DIR}/api/tacticalrmm/private/exe
|
||||
mkdir -p ${TACTICAL_DIR}/api/tacticalrmm/private/log
|
||||
touch ${TACTICAL_DIR}/api/tacticalrmm/private/log/django_debug.log
|
||||
|
||||
until (echo > /dev/tcp/"${POSTGRES_HOST}"/"${POSTGRES_PORT}") &> /dev/null; do
|
||||
|
||||
until (echo >/dev/tcp/"${POSTGRES_HOST}"/"${POSTGRES_PORT}") &>/dev/null; do
|
||||
echo "waiting for postgresql container to be ready..."
|
||||
sleep 5
|
||||
done
|
||||
|
||||
until (echo > /dev/tcp/"${MESH_SERVICE}"/4443) &> /dev/null; do
|
||||
until (echo >/dev/tcp/"${MESH_SERVICE}"/4443) &>/dev/null; do
|
||||
echo "waiting for meshcentral container to be ready..."
|
||||
sleep 5
|
||||
done
|
||||
|
@ -68,8 +68,9 @@ if [ "$1" = 'tactical-init' ]; then
|
|||
MESH_TOKEN=$(cat ${TACTICAL_DIR}/tmp/mesh_token)
|
||||
ADMINURL=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 70 | head -n 1)
|
||||
DJANGO_SEKRET=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 80 | head -n 1)
|
||||
|
||||
localvars="$(cat << EOF
|
||||
|
||||
localvars="$(
|
||||
cat <<EOF
|
||||
SECRET_KEY = '${DJANGO_SEKRET}'
|
||||
|
||||
DEBUG = False
|
||||
|
@ -110,15 +111,15 @@ REDIS_HOST = '${REDIS_HOST}'
|
|||
MESH_WS_URL = '${MESH_WS_URL}'
|
||||
ADMIN_ENABLED = False
|
||||
EOF
|
||||
)"
|
||||
)"
|
||||
|
||||
echo "${localvars}" > ${TACTICAL_DIR}/api/tacticalrmm/local_settings.py
|
||||
echo "${localvars}" >${TACTICAL_DIR}/api/tacticalrmm/local_settings.py
|
||||
|
||||
# run migrations and init scripts
|
||||
python manage.py pre_update_tasks
|
||||
python manage.py migrate --no-input
|
||||
python manage.py generate_json_schemas
|
||||
python manage.py get_webtar_url > ${TACTICAL_DIR}/tmp/web_tar_url
|
||||
python manage.py get_webtar_url >${TACTICAL_DIR}/tmp/web_tar_url
|
||||
python manage.py collectstatic --no-input
|
||||
python manage.py initial_db_setup
|
||||
python manage.py initial_mesh_setup
|
||||
|
@ -126,12 +127,12 @@ EOF
|
|||
python manage.py load_community_scripts
|
||||
python manage.py reload_nats
|
||||
python manage.py create_natsapi_conf
|
||||
python manage.py create_uwsgi_conf
|
||||
python manage.py create_gunicorn_conf
|
||||
python manage.py create_installer_user
|
||||
python manage.py clear_redis_celery_locks
|
||||
python manage.py post_update_tasks
|
||||
|
||||
# create super user
|
||||
# create super user
|
||||
echo "Creating dashboard user if it doesn't exist"
|
||||
echo "from accounts.models import User; User.objects.create_superuser('${TRMM_USER}', 'admin@example.com', '${TRMM_PASS}') if not User.objects.filter(username='${TRMM_USER}').exists() else 0;" | python manage.py shell
|
||||
|
||||
|
@ -149,7 +150,7 @@ fi
|
|||
if [ "$1" = 'tactical-backend' ]; then
|
||||
check_tactical_ready
|
||||
|
||||
uwsgi ${TACTICAL_DIR}/api/app.ini
|
||||
gunicorn -c ${TACTICAL_DIR}/api/gunicorn_config.py tacticalrmm.wsgi:application
|
||||
fi
|
||||
|
||||
if [ "$1" = 'tactical-celery' ]; then
|
||||
|
|
22
install.sh
22
install.sh
|
@ -505,7 +505,7 @@ python manage.py migrate
|
|||
python manage.py generate_json_schemas
|
||||
python manage.py collectstatic --no-input
|
||||
python manage.py create_natsapi_conf
|
||||
python manage.py create_uwsgi_conf
|
||||
python manage.py create_gunicorn_conf
|
||||
python manage.py load_chocos
|
||||
python manage.py load_community_scripts
|
||||
WEB_VERSION=$(python manage.py get_config webversion)
|
||||
|
@ -528,7 +528,7 @@ read -n 1 -s -r -p "Press any key to continue..."
|
|||
rmmservice="$(
|
||||
cat <<EOF
|
||||
[Unit]
|
||||
Description=tacticalrmm uwsgi daemon
|
||||
Description=tacticalrmm gunicorn daemon v1
|
||||
After=network.target postgresql.service
|
||||
|
||||
[Service]
|
||||
|
@ -536,7 +536,10 @@ User=${USER}
|
|||
Group=www-data
|
||||
WorkingDirectory=/rmm/api/tacticalrmm
|
||||
Environment="PATH=/rmm/api/env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
ExecStart=/rmm/api/env/bin/uwsgi --ini app.ini
|
||||
ExecStart=/rmm/api/env/bin/gunicorn -c gunicorn_config.py tacticalrmm.wsgi:application
|
||||
ExecReload=/bin/kill -s HUP \$MAINPID
|
||||
ExecStartPre=rm -f /rmm/api/tacticalrmm/tacticalrmm.sock
|
||||
KillMode=mixed
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
|
||||
|
@ -617,8 +620,8 @@ nginxrmm="$(
|
|||
cat <<EOF
|
||||
server_tokens off;
|
||||
|
||||
upstream tacticalrmm {
|
||||
server unix:////rmm/api/tacticalrmm/tacticalrmm.sock;
|
||||
upstream tacticalgunicorn {
|
||||
server unix:/rmm/api/tacticalrmm/tacticalrmm.sock;
|
||||
}
|
||||
|
||||
map \$http_user_agent \$ignore_ua {
|
||||
|
@ -696,10 +699,11 @@ server {
|
|||
}
|
||||
|
||||
location / {
|
||||
uwsgi_pass tacticalrmm;
|
||||
include /etc/nginx/uwsgi_params;
|
||||
uwsgi_read_timeout 300s;
|
||||
uwsgi_ignore_client_abort on;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_set_header Host \$http_host;
|
||||
proxy_redirect off;
|
||||
proxy_pass http://tacticalgunicorn;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
|
47
restore.sh
47
restore.sh
|
@ -235,6 +235,36 @@ sudo chown ${USER}:${USER} -R /etc/conf.d
|
|||
print_green 'Restoring systemd services'
|
||||
|
||||
sudo cp $tmp_dir/systemd/* /etc/systemd/system/
|
||||
|
||||
# for older systems still on uwsgi, migrate to gunicorn
|
||||
if ! grep -q gunicorn /etc/systemd/system/rmm.service; then
|
||||
sudo rm -f /etc/systemd/system/rmm.service
|
||||
|
||||
gunicornsvc="$(
|
||||
cat <<EOF
|
||||
[Unit]
|
||||
Description=tacticalrmm gunicorn daemon v1
|
||||
After=network.target postgresql.service
|
||||
|
||||
[Service]
|
||||
User=${USER}
|
||||
Group=www-data
|
||||
WorkingDirectory=/rmm/api/tacticalrmm
|
||||
Environment="PATH=/rmm/api/env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
ExecStart=/rmm/api/env/bin/gunicorn -c gunicorn_config.py tacticalrmm.wsgi:application
|
||||
ExecReload=/bin/kill -s HUP \$MAINPID
|
||||
ExecStartPre=rm -f /rmm/api/tacticalrmm/tacticalrmm.sock
|
||||
KillMode=mixed
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
)"
|
||||
echo "${gunicornsvc}" | sudo tee /etc/systemd/system/rmm.service >/dev/null
|
||||
fi
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
print_green "Installing Python ${PYTHON_VER}"
|
||||
|
@ -428,7 +458,7 @@ python manage.py migrate
|
|||
python manage.py generate_json_schemas
|
||||
python manage.py collectstatic --no-input
|
||||
python manage.py create_natsapi_conf
|
||||
python manage.py create_uwsgi_conf
|
||||
python manage.py create_gunicorn_conf
|
||||
python manage.py reload_nats
|
||||
python manage.py post_update_tasks
|
||||
API=$(python manage.py get_config api)
|
||||
|
@ -456,7 +486,7 @@ for i in frontend meshcentral; do
|
|||
sudo ln -s /etc/nginx/sites-available/${i}.conf /etc/nginx/sites-enabled/${i}.conf
|
||||
done
|
||||
|
||||
if ! grep -q "location /assets/" $tmp_dir/nginx/rmm.conf; then
|
||||
if ! grep -q gunicorn $tmp_dir/nginx/rmm.conf; then
|
||||
if [ -d "${tmp_dir}/certs/selfsigned" ]; then
|
||||
CERT_PUB_KEY="${certdir}/cert.pem"
|
||||
CERT_PRIV_KEY="${certdir}/key.pem"
|
||||
|
@ -465,8 +495,8 @@ if ! grep -q "location /assets/" $tmp_dir/nginx/rmm.conf; then
|
|||
cat <<EOF
|
||||
server_tokens off;
|
||||
|
||||
upstream tacticalrmm {
|
||||
server unix:////rmm/api/tacticalrmm/tacticalrmm.sock;
|
||||
upstream tacticalgunicorn {
|
||||
server unix:/rmm/api/tacticalrmm/tacticalrmm.sock;
|
||||
}
|
||||
|
||||
map \$http_user_agent \$ignore_ua {
|
||||
|
@ -544,10 +574,11 @@ server {
|
|||
}
|
||||
|
||||
location / {
|
||||
uwsgi_pass tacticalrmm;
|
||||
include /etc/nginx/uwsgi_params;
|
||||
uwsgi_read_timeout 300s;
|
||||
uwsgi_ignore_client_abort on;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_set_header Host \$http_host;
|
||||
proxy_redirect off;
|
||||
proxy_pass http://tacticalgunicorn;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
|
44
update.sh
44
update.sh
|
@ -142,6 +142,35 @@ EOF
|
|||
sudo systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if ! grep -q gunicorn /etc/systemd/system/rmm.service; then
|
||||
sudo rm -f /etc/systemd/system/rmm.service
|
||||
|
||||
gunicornsvc="$(
|
||||
cat <<EOF
|
||||
[Unit]
|
||||
Description=tacticalrmm gunicorn daemon v1
|
||||
After=network.target postgresql.service
|
||||
|
||||
[Service]
|
||||
User=${USER}
|
||||
Group=www-data
|
||||
WorkingDirectory=/rmm/api/tacticalrmm
|
||||
Environment="PATH=/rmm/api/env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
ExecStart=/rmm/api/env/bin/gunicorn -c gunicorn_config.py tacticalrmm.wsgi:application
|
||||
ExecReload=/bin/kill -s HUP \$MAINPID
|
||||
ExecStartPre=rm -f /rmm/api/tacticalrmm/tacticalrmm.sock
|
||||
KillMode=mixed
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
)"
|
||||
echo "${gunicornsvc}" | sudo tee /etc/systemd/system/rmm.service >/dev/null
|
||||
sudo systemctl daemon-reload
|
||||
fi
|
||||
|
||||
if [ ! -f /etc/apt/sources.list.d/nginx.list ]; then
|
||||
osname=$(lsb_release -si)
|
||||
osname=${osname^}
|
||||
|
@ -342,7 +371,7 @@ python manage.py reload_nats
|
|||
python manage.py load_chocos
|
||||
python manage.py create_installer_user
|
||||
python manage.py create_natsapi_conf
|
||||
python manage.py create_uwsgi_conf
|
||||
python manage.py create_gunicorn_conf
|
||||
python manage.py clear_redis_celery_locks
|
||||
python manage.py post_update_tasks
|
||||
API=$(python manage.py get_config api)
|
||||
|
@ -375,8 +404,8 @@ if ! grep -q "location /assets/" $rmmconf; then
|
|||
cat <<EOF
|
||||
server_tokens off;
|
||||
|
||||
upstream tacticalrmm {
|
||||
server unix:////rmm/api/tacticalrmm/tacticalrmm.sock;
|
||||
upstream tacticalgunicorn {
|
||||
server unix:/rmm/api/tacticalrmm/tacticalrmm.sock;
|
||||
}
|
||||
|
||||
map \$http_user_agent \$ignore_ua {
|
||||
|
@ -454,10 +483,11 @@ server {
|
|||
}
|
||||
|
||||
location / {
|
||||
uwsgi_pass tacticalrmm;
|
||||
include /etc/nginx/uwsgi_params;
|
||||
uwsgi_read_timeout 300s;
|
||||
uwsgi_ignore_client_abort on;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
proxy_set_header Host \$http_host;
|
||||
proxy_redirect off;
|
||||
proxy_pass http://tacticalgunicorn;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
|
Loading…
Reference in New Issue