alyx-local 3.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- alyx_local-3.1.2/.gitignore +27 -0
- alyx_local-3.1.2/PKG-INFO +47 -0
- alyx_local-3.1.2/pyproject.toml +121 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/celery_server/Dockerfile +12 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/celery_server/celery.env +4 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/compose.yaml +115 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/django_server/Dockerfile +113 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/django_server/custom_settings.py +17 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/django_server/entrypoint.sh +19 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/django_server/gunicorn.conf.py +7 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/nginx_server/502.html +79 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/nginx_server/nginx.conf +95 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/pgadmin/pgadmin.env +2 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/pgadmin/servers.json +13 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/postgres_db/db-secure-password +1 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/rabbitmq/Dockerfile +15 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/rabbitmq/entrypoint.sh +11 -0
- alyx_local-3.1.2/src/alyx/ressources/docker/rabbitmq/rabbitmq.conf +4 -0
- alyx_local-3.1.2/src/alyx/ressources/pyproject.toml +121 -0
- alyx_local-3.1.2/src/alyx/ressources/uv.lock +1801 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
*.pyc
|
|
2
|
+
*__pycache__*
|
|
3
|
+
*.asv
|
|
4
|
+
*.pkl
|
|
5
|
+
*.patch
|
|
6
|
+
*.sql
|
|
7
|
+
*.html.py
|
|
8
|
+
*.orig
|
|
9
|
+
.venv*
|
|
10
|
+
.idea/*
|
|
11
|
+
.vscode/
|
|
12
|
+
.DS_Store
|
|
13
|
+
.pdm-python
|
|
14
|
+
.pdm-build/
|
|
15
|
+
.python-version
|
|
16
|
+
/compose.yaml
|
|
17
|
+
__pypackages__*
|
|
18
|
+
/src/alyx/data/management/commands/*ibl*
|
|
19
|
+
/src/alyx/templates/ibl_reports
|
|
20
|
+
/src/alyx/alyx/settings_secret.py
|
|
21
|
+
/src/alyx/alyx/settings_lab.py
|
|
22
|
+
|
|
23
|
+
/config
|
|
24
|
+
/data
|
|
25
|
+
/legacy
|
|
26
|
+
|
|
27
|
+
*secrets*
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: alyx-local
|
|
3
|
+
Version: 3.1.2
|
|
4
|
+
Summary: Local database for experimental neuroscience laboratories
|
|
5
|
+
Project-URL: source, https://github.com/JostTim/alyx-local
|
|
6
|
+
Project-URL: documentation, https://josttim.github.io/alyx-local/
|
|
7
|
+
Author-email: JostTim <timothe.jost-mousseau@pasteur.fr>
|
|
8
|
+
License: MIT
|
|
9
|
+
Requires-Python: <3.13,>=3.12
|
|
10
|
+
Requires-Dist: alyx-connector>=2.1.10
|
|
11
|
+
Requires-Dist: colorlog>=6.9.0
|
|
12
|
+
Requires-Dist: django-admin-list-filter-dropdown>=1.0.3
|
|
13
|
+
Requires-Dist: django-admin-rangefilter>=0.13.2
|
|
14
|
+
Requires-Dist: django-autocomplete-light>=3.11.0
|
|
15
|
+
Requires-Dist: django-cleanup>=9.0.0
|
|
16
|
+
Requires-Dist: django-crispy-forms>=2.3
|
|
17
|
+
Requires-Dist: django-dbbackup>=4.2.1
|
|
18
|
+
Requires-Dist: django-debug-toolbar>=6.0.0
|
|
19
|
+
Requires-Dist: django-filter>=24.3
|
|
20
|
+
Requires-Dist: django-jsoneditor>=0.2.4
|
|
21
|
+
Requires-Dist: django-markdownx>=4.0.7
|
|
22
|
+
Requires-Dist: django-mptt>=0.16.0
|
|
23
|
+
Requires-Dist: django-password-eye>=1.1.4
|
|
24
|
+
Requires-Dist: django-polymorphic>=3.1.0
|
|
25
|
+
Requires-Dist: django-reversion>=5.1.0
|
|
26
|
+
Requires-Dist: django-storages>=1.14.4
|
|
27
|
+
Requires-Dist: django-structlog>=8.1.0
|
|
28
|
+
Requires-Dist: django-stubs>=5.2.8
|
|
29
|
+
Requires-Dist: django-test-without-migrations>=0.6
|
|
30
|
+
Requires-Dist: django>=5.1.3
|
|
31
|
+
Requires-Dist: djangorestframework>=3.15.2
|
|
32
|
+
Requires-Dist: docutils>=0.21.2
|
|
33
|
+
Requires-Dist: drf-spectacular[sidecar]>=0.27.2
|
|
34
|
+
Requires-Dist: gunicorn>=23.0.0
|
|
35
|
+
Requires-Dist: inotify>=0.2.10
|
|
36
|
+
Requires-Dist: matplotlib>=3.9.2
|
|
37
|
+
Requires-Dist: platformdirs>=4.3.8
|
|
38
|
+
Requires-Dist: processing-pypelines[celery]>=0.0.66
|
|
39
|
+
Requires-Dist: psycopg2-binary>=2.9.10
|
|
40
|
+
Requires-Dist: pynwb>=3.1.2
|
|
41
|
+
Requires-Dist: rich-click>=1.8.9
|
|
42
|
+
Requires-Dist: structlog>=24.4.0
|
|
43
|
+
Requires-Dist: tzlocal>=5.2
|
|
44
|
+
Provides-Extra: celery
|
|
45
|
+
Requires-Dist: celery>=5.4.0; extra == 'celery'
|
|
46
|
+
Provides-Extra: docs
|
|
47
|
+
Requires-Dist: mkdocs-material>=9.6.11; extra == 'docs'
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "alyx-local"
|
|
3
|
+
description = "Local database for experimental neuroscience laboratories"
|
|
4
|
+
requires-python = ">=3.12,<3.13"
|
|
5
|
+
dependencies = [
|
|
6
|
+
"django>=5.1.3",
|
|
7
|
+
"django-admin-list-filter-dropdown>=1.0.3",
|
|
8
|
+
"django-admin-rangefilter>=0.13.2",
|
|
9
|
+
"django-autocomplete-light>=3.11.0",
|
|
10
|
+
"django-cleanup>=9.0.0",
|
|
11
|
+
"django-filter>=24.3",
|
|
12
|
+
"django-jsoneditor>=0.2.4",
|
|
13
|
+
"django-markdownx>=4.0.7",
|
|
14
|
+
"django-password-eye>=1.1.4",
|
|
15
|
+
"django-mptt>=0.16.0",
|
|
16
|
+
"django-polymorphic>=3.1.0",
|
|
17
|
+
"django-reversion>=5.1.0",
|
|
18
|
+
"django-storages>=1.14.4",
|
|
19
|
+
"django-structlog>=8.1.0",
|
|
20
|
+
"django-test-without-migrations>=0.6",
|
|
21
|
+
"djangorestframework>=3.15.2",
|
|
22
|
+
"drf-spectacular[sidecar]>=0.27.2",
|
|
23
|
+
"django-dbbackup>=4.2.1",
|
|
24
|
+
"django-crispy-forms>=2.3",
|
|
25
|
+
"docutils>=0.21.2",
|
|
26
|
+
"gunicorn>=23.0.0",
|
|
27
|
+
"inotify>=0.2.10",
|
|
28
|
+
"tzlocal>=5.2",
|
|
29
|
+
"colorlog>=6.9.0",
|
|
30
|
+
"processing-pypelines[celery]>=0.0.66",
|
|
31
|
+
"structlog>=24.4.0",
|
|
32
|
+
"psycopg2-binary>=2.9.10",
|
|
33
|
+
"matplotlib>=3.9.2",
|
|
34
|
+
"alyx-connector>=2.1.10",
|
|
35
|
+
"rich-click>=1.8.9",
|
|
36
|
+
"platformdirs>=4.3.8",
|
|
37
|
+
"django-debug-toolbar>=6.0.0",
|
|
38
|
+
"pynwb>=3.1.2",
|
|
39
|
+
"django-stubs>=5.2.8",
|
|
40
|
+
]
|
|
41
|
+
dynamic = ["version"]
|
|
42
|
+
|
|
43
|
+
[project.urls]
|
|
44
|
+
"source" = "https://github.com/JostTim/alyx-local"
|
|
45
|
+
"documentation" = "https://josttim.github.io/alyx-local/"
|
|
46
|
+
|
|
47
|
+
[project.license]
|
|
48
|
+
text = "MIT"
|
|
49
|
+
|
|
50
|
+
[[project.authors]]
|
|
51
|
+
name = "JostTim"
|
|
52
|
+
email = "timothe.jost-mousseau@pasteur.fr"
|
|
53
|
+
|
|
54
|
+
[project.optional-dependencies] # For actual installations
|
|
55
|
+
celery = ["celery>=5.4.0"]
|
|
56
|
+
docs = ["mkdocs-material>=9.6.11"]
|
|
57
|
+
|
|
58
|
+
[dependency-groups] # to use with CLI tools (for dev/CI only) https://packaging.python.org/en/latest/specifications/dependency-groups/
|
|
59
|
+
docs = ["mkdocs-material>=9.6.11"]
|
|
60
|
+
celery = ["celery>=5.4.0"]
|
|
61
|
+
|
|
62
|
+
[build-system]
|
|
63
|
+
requires = ["hatchling"]
|
|
64
|
+
build-backend = "hatchling.build"
|
|
65
|
+
|
|
66
|
+
[tool.hatch.version]
|
|
67
|
+
path = "src/alyx/__init__.py"
|
|
68
|
+
variable = "__version__"
|
|
69
|
+
|
|
70
|
+
[tool.hatch.build.targets.wheel]
|
|
71
|
+
packages = ["src/alyx"]
|
|
72
|
+
|
|
73
|
+
[tool.hatch.build]
|
|
74
|
+
include = ["src/alyx/ressources/*"]
|
|
75
|
+
|
|
76
|
+
[tool.wheel]
|
|
77
|
+
universal = true
|
|
78
|
+
|
|
79
|
+
[tool.flake8]
|
|
80
|
+
ignore = [
|
|
81
|
+
"E203",
|
|
82
|
+
"E117",
|
|
83
|
+
"E265",
|
|
84
|
+
"E266",
|
|
85
|
+
"E401",
|
|
86
|
+
"E704",
|
|
87
|
+
"E712",
|
|
88
|
+
"E731",
|
|
89
|
+
"E741",
|
|
90
|
+
"E722",
|
|
91
|
+
"F401",
|
|
92
|
+
"F403",
|
|
93
|
+
"F841",
|
|
94
|
+
"W504",
|
|
95
|
+
"W503",
|
|
96
|
+
"W605",
|
|
97
|
+
]
|
|
98
|
+
max-line-length = 99
|
|
99
|
+
exclude = ["migrations"]
|
|
100
|
+
|
|
101
|
+
[tool.black]
|
|
102
|
+
preview = true
|
|
103
|
+
line-length = 99
|
|
104
|
+
|
|
105
|
+
[tool.coverage.run]
|
|
106
|
+
branch = false
|
|
107
|
+
source = ["src/alyx"]
|
|
108
|
+
omit = []
|
|
109
|
+
|
|
110
|
+
[tool.coverage.report]
|
|
111
|
+
exclude_lines = [
|
|
112
|
+
"pragma: no cover",
|
|
113
|
+
"raise AssertionError",
|
|
114
|
+
"raise NotImplementedError",
|
|
115
|
+
"pass",
|
|
116
|
+
"return$",
|
|
117
|
+
]
|
|
118
|
+
show_missing = true
|
|
119
|
+
|
|
120
|
+
[project.scripts]
|
|
121
|
+
alyx = "alyx.installation.cli:alyx"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
FROM python:3.12-slim AS base
|
|
2
|
+
|
|
3
|
+
# install uv for installing other python packages faster
|
|
4
|
+
RUN pip install uv
|
|
5
|
+
|
|
6
|
+
# Install flower and celery with uv (faster than pip) at system level (no venv)
|
|
7
|
+
RUN uv pip install flower pyamqp --system
|
|
8
|
+
|
|
9
|
+
CMD ["sh", \
|
|
10
|
+
"-c", \
|
|
11
|
+
"celery --broker=pyamqp://${RABBITMQ_USER}:${RABBITMQ_PASSWORD}@rabbitmq:5672// \
|
|
12
|
+
flower --port=5001 --address=0.0.0.0 --basic_auth=${FLOWER_USER}:${FLOWER_PASSWORD} --url_prefix=services/celery"]
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
services:
|
|
2
|
+
|
|
3
|
+
django_server:
|
|
4
|
+
restart: on-failure:5
|
|
5
|
+
build:
|
|
6
|
+
context: .
|
|
7
|
+
dockerfile: ./django_server/Dockerfile
|
|
8
|
+
image: alyx_django_server:latest
|
|
9
|
+
container_name: django_server
|
|
10
|
+
hostname: 'django_server'
|
|
11
|
+
volumes :
|
|
12
|
+
- uploaded-data:/app/uploaded
|
|
13
|
+
- ./postgres_db/db-secure-password:/run/secrets/db-secure-password:ro
|
|
14
|
+
- "%%ALYX_SRC_PATH%%:/app/src/alyx:rw"
|
|
15
|
+
- "%%DJANGO_DATA_PATH%%:/app/data:rw"
|
|
16
|
+
environment :
|
|
17
|
+
- POSTGRES_PASSWORD_FILE=/run/secrets/db-secure-password
|
|
18
|
+
expose:
|
|
19
|
+
- 8000 # this is redirected through nginx, it is not directly exposed outside the docker network
|
|
20
|
+
cap_add:
|
|
21
|
+
- SYS_ADMIN
|
|
22
|
+
- DAC_READ_SEARCH
|
|
23
|
+
- CAP_DAC_READ_SEARCH
|
|
24
|
+
depends_on:
|
|
25
|
+
nginx_server:
|
|
26
|
+
condition: service_started
|
|
27
|
+
db:
|
|
28
|
+
condition: service_healthy
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
nginx_server:
|
|
32
|
+
image: nginx:latest
|
|
33
|
+
container_name: nginx_server
|
|
34
|
+
hostname: 'nginx_server'
|
|
35
|
+
ports:
|
|
36
|
+
- "0.0.0.0:%%NGINX_OUT_PORT%%:80"
|
|
37
|
+
volumes:
|
|
38
|
+
- uploaded-data:/app/uploaded
|
|
39
|
+
- ./nginx_server/nginx.conf:/etc/nginx/nginx.conf:ro
|
|
40
|
+
- ./nginx_server/502.html:/etc/nginx/errorpages/502.html:ro
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
db:
|
|
44
|
+
image: postgres:17
|
|
45
|
+
container_name: postgres_db
|
|
46
|
+
hostname: 'postgres_db'
|
|
47
|
+
restart: unless-stopped
|
|
48
|
+
user: postgres
|
|
49
|
+
volumes:
|
|
50
|
+
- db-data:/var/lib/postgresql/data
|
|
51
|
+
- ./postgres_db/db-secure-password:/run/secrets/db-secure-password:ro
|
|
52
|
+
environment:
|
|
53
|
+
- POSTGRES_DB=alyx
|
|
54
|
+
- POSTGRES_PASSWORD_FILE=/run/secrets/db-secure-password
|
|
55
|
+
expose:
|
|
56
|
+
- 5432 # this is for the access to postgres by django service, it is not exposed outside the docker network
|
|
57
|
+
healthcheck:
|
|
58
|
+
test: [ "CMD", "pg_isready" ]
|
|
59
|
+
interval: 10s
|
|
60
|
+
timeout: 5s
|
|
61
|
+
retries: 5
|
|
62
|
+
|
|
63
|
+
pgadmin:
|
|
64
|
+
image: dpage/pgadmin4
|
|
65
|
+
container_name: pgadmin
|
|
66
|
+
hostname: 'pgadmin'
|
|
67
|
+
environment:
|
|
68
|
+
- SCRIPT_NAME=/services/pgadmin
|
|
69
|
+
- PGADMIN_SERVER_JSON_FILE=/pgadmin4/servers.json
|
|
70
|
+
env_file:
|
|
71
|
+
- ./pgadmin/pgadmin.env
|
|
72
|
+
expose:
|
|
73
|
+
- 80 # this is for the management web interface of pgadmin to nginx, it is not exposed outside the docker network
|
|
74
|
+
volumes:
|
|
75
|
+
- pgadmin-data:/var/lib/pgadmin
|
|
76
|
+
- ./pgadmin/servers.json:/pgadmin4/servers.json:ro
|
|
77
|
+
depends_on:
|
|
78
|
+
db:
|
|
79
|
+
condition: service_healthy
|
|
80
|
+
|
|
81
|
+
rabbitmq:
|
|
82
|
+
image: rabbitmq:4-management
|
|
83
|
+
container_name: rabbitmq
|
|
84
|
+
hostname: 'rabbitmq'
|
|
85
|
+
ports:
|
|
86
|
+
- "0.0.0.0:%%RABBITMQ_OUT_PORT%%:5672"
|
|
87
|
+
expose :
|
|
88
|
+
- 15672 # this is for the management web interface of rabbitmq to nginx, it is not exposed outside the docker network
|
|
89
|
+
environment:
|
|
90
|
+
- RABBITMQ_MANAGEMENT_PATH_PREFIX=/services/rabbitmq
|
|
91
|
+
volumes:
|
|
92
|
+
- rabbitmq-data:/var/lib/rabbitmq
|
|
93
|
+
- ./rabbitmq/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
|
|
94
|
+
|
|
95
|
+
celery_server:
|
|
96
|
+
build:
|
|
97
|
+
context: .
|
|
98
|
+
dockerfile: ./celery_server/Dockerfile
|
|
99
|
+
image: celery_flower:latest
|
|
100
|
+
container_name: celery_server
|
|
101
|
+
hostname: 'celery_server'
|
|
102
|
+
expose:
|
|
103
|
+
- 5001 # this is for the management web interface of celery to nginx, it is not exposed outside the docker network
|
|
104
|
+
- 5555 # this is for the management web interface of flower to nginx, it is not exposed outside the docker network
|
|
105
|
+
env_file:
|
|
106
|
+
- ./celery_server/celery.env
|
|
107
|
+
depends_on:
|
|
108
|
+
- rabbitmq
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
volumes:
|
|
112
|
+
pgadmin-data:
|
|
113
|
+
db-data:
|
|
114
|
+
rabbitmq-data:
|
|
115
|
+
uploaded-data:
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
ARG PYTHON_VERSION=3.12.3
|
|
3
|
+
ARG DEGUG=0
|
|
4
|
+
FROM python:${PYTHON_VERSION}-slim AS base
|
|
5
|
+
|
|
6
|
+
ARG APP_USER=%%PERMISIONED_USERNAME%%
|
|
7
|
+
ARG UID=%%PERMISSIONED_UID%%
|
|
8
|
+
ARG GID=%%PERMISSIONED_GID%%
|
|
9
|
+
ARG APP_GROUP=%%PERMISSIONED_GROUPNAME%%
|
|
10
|
+
|
|
11
|
+
RUN echo "Building the Docker image..."
|
|
12
|
+
|
|
13
|
+
# Prevents Python from writing pyc files.
|
|
14
|
+
ENV PYTHONDONTWRITEBYTECODE=${DEBUG}
|
|
15
|
+
|
|
16
|
+
# Keeps Python from buffering stdout and stderr to avoid situations where
|
|
17
|
+
# the application crashes without emitting any logs due to buffering.
|
|
18
|
+
ENV PYTHONUNBUFFERED=1
|
|
19
|
+
|
|
20
|
+
#########################################
|
|
21
|
+
# Create a non-root user to run the app #
|
|
22
|
+
RUN if ! getent group "${APP_GROUP}"; then \
|
|
23
|
+
addgroup --gid "${GID}" "${APP_GROUP}"; fi
|
|
24
|
+
|
|
25
|
+
RUN adduser \
|
|
26
|
+
--disabled-password \
|
|
27
|
+
--gecos "" \
|
|
28
|
+
--shell "/sbin/nologin" \
|
|
29
|
+
--home "/${APP_USER}" \
|
|
30
|
+
--uid "${UID}" \
|
|
31
|
+
--ingroup "${APP_GROUP}" \
|
|
32
|
+
"${APP_USER}"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# get pg_restore and other database tools #
|
|
36
|
+
#
|
|
37
|
+
RUN apt-get update && \
|
|
38
|
+
apt-get install -y --no-install-recommends \
|
|
39
|
+
# The list of packages that we install here :
|
|
40
|
+
ca-certificates wget gnupg2 lsb-release sudo iputils-ping curl dos2unix cifs-utils && \
|
|
41
|
+
# End of the list of packages
|
|
42
|
+
apt-get clean && \
|
|
43
|
+
rm -rf /var/lib/apt/lists/*
|
|
44
|
+
|
|
45
|
+
# Add postgresql repos to the keyring (to be able to install postgresql client connector with the right stable version)
|
|
46
|
+
RUN install -d -m 0755 /etc/apt/keyrings
|
|
47
|
+
|
|
48
|
+
RUN cat /etc/os-release >&2
|
|
49
|
+
RUN set -eux; . /etc/os-release; echo "ID=$ID VERSION_CODENAME=$VERSION_CODENAME" >&2
|
|
50
|
+
|
|
51
|
+
RUN wget -qO /etc/apt/keyrings/postgresql.asc https://www.postgresql.org/media/keys/ACCC4CF8.asc; \
|
|
52
|
+
echo "deb [signed-by=/etc/apt/keyrings/postgresql.asc] https://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" \
|
|
53
|
+
> /etc/apt/sources.list.d/pgdg.list
|
|
54
|
+
|
|
55
|
+
RUN rm -rf /var/lib/apt/lists/* && apt-get update
|
|
56
|
+
|
|
57
|
+
RUN apt-get install -y --no-install-recommends \
|
|
58
|
+
postgresql-client-17 \
|
|
59
|
+
&& apt-get clean \
|
|
60
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
61
|
+
|
|
62
|
+
########################################################
|
|
63
|
+
# Install UV that will manage the python dependancies #
|
|
64
|
+
RUN pip install uv
|
|
65
|
+
|
|
66
|
+
#################################################################
|
|
67
|
+
## Copy the django application source code into the container. ##
|
|
68
|
+
RUN mkdir -p /app/uploaded/static && \
|
|
69
|
+
mkdir -p /app/uploaded/media && \
|
|
70
|
+
mkdir -p /mnt/external_data
|
|
71
|
+
|
|
72
|
+
COPY ./pyproject.toml /app/pyproject.toml
|
|
73
|
+
COPY ./uv.lock /app/uv.lock
|
|
74
|
+
# copying uv.lock is to ensure that while we install dependancies, they are not updated
|
|
75
|
+
# (if the version pinning is "loose") compared to the lockfile, to avoid potential code break
|
|
76
|
+
# when using these dependancies in alyx's implementation
|
|
77
|
+
|
|
78
|
+
################################################
|
|
79
|
+
## ENSURE WE ACCESS THE ENTRYPOINT CORRECTLY ##
|
|
80
|
+
COPY ./django_server/entrypoint.sh /app/entrypoint.sh
|
|
81
|
+
COPY ./django_server/gunicorn.conf.py /app/gunicorn.conf.py
|
|
82
|
+
|
|
83
|
+
#############################################################################
|
|
84
|
+
## ENSURE WE COPY CONFIG FILES GENERATED WITH INSTALL, IN PROPER LOCATIONS ##
|
|
85
|
+
COPY ./django_server/custom_settings.py /app/extra_configuration/custom_settings.py
|
|
86
|
+
|
|
87
|
+
##################################################################
|
|
88
|
+
## SET USER PERMISSIONS ON THE APP FOLDER AND ENTRYPOINT SCRIPT ##
|
|
89
|
+
RUN chown -R ${APP_USER}:${APP_GROUP} /app/
|
|
90
|
+
|
|
91
|
+
RUN dos2unix -o /app/entrypoint.sh
|
|
92
|
+
RUN chown ${APP_USER}:${APP_GROUP} /app/entrypoint.sh
|
|
93
|
+
RUN chmod +x /app/entrypoint.sh
|
|
94
|
+
|
|
95
|
+
##########################################################################
|
|
96
|
+
## Permissions to access the external_data folder on the mount location ##
|
|
97
|
+
RUN chown -R ${APP_USER}:${APP_GROUP} /mnt/external_data
|
|
98
|
+
RUN chmod -R 700 /mnt/external_data
|
|
99
|
+
|
|
100
|
+
#############################################################
|
|
101
|
+
RUN echo "${APP_USER} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
|
102
|
+
|
|
103
|
+
#############################################################
|
|
104
|
+
# Switch to the non-privileged user to run the application. #
|
|
105
|
+
USER ${APP_USER}
|
|
106
|
+
|
|
107
|
+
WORKDIR /app
|
|
108
|
+
|
|
109
|
+
# Expose the port that the application listens on.
|
|
110
|
+
EXPOSE 80
|
|
111
|
+
|
|
112
|
+
RUN echo "Launching the entrypoint script..."
|
|
113
|
+
CMD ["./entrypoint.sh"]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
ALLOWED_HOSTS = [%%MACHINE_ALLOWED_HOSTS%%]
|
|
2
|
+
|
|
3
|
+
CSRF_TRUSTED_ORIGINS = [%%MACHINE_CSRF_TRUSTED_ORIGINS%%]
|
|
4
|
+
|
|
5
|
+
DEFAULT_LAB_NAME = "defaultlab"
|
|
6
|
+
|
|
7
|
+
SECRET_KEY = "%%DJANGO_SECRET_KEY%%"
|
|
8
|
+
|
|
9
|
+
NARRATIVE_TEMPLATES = {}
|
|
10
|
+
|
|
11
|
+
DBBACKUP_HOSTNAME = "%%DB_BACKUP_HOSTNAME%%"
|
|
12
|
+
|
|
13
|
+
TIME_ZONE = "%%TIMEZONE%%"
|
|
14
|
+
|
|
15
|
+
DEBUG = %%DJANGO_DEBUG_MODE%%
|
|
16
|
+
|
|
17
|
+
AUTO_RESTORE_ON_STARTUP = %%AUTORESTORE_DJANGO_ON_STARTUP%%
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
echo -n "Django version: " && echo -n $(uv run python -m django --version) && echo " is installed"
|
|
3
|
+
|
|
4
|
+
# pdm install --prod --frozen-lockfile
|
|
5
|
+
uv sync --all-groups
|
|
6
|
+
|
|
7
|
+
# Collect static files
|
|
8
|
+
echo "Collecting static files..."
|
|
9
|
+
uv run alyx manage collectstatic --noinput --clear --verbosity 0
|
|
10
|
+
|
|
11
|
+
uv run alyx manage auto_restore --use_settings --migrate_new_db
|
|
12
|
+
|
|
13
|
+
# Restore mounts
|
|
14
|
+
echo "Restoring all mounts if any"
|
|
15
|
+
uv run alyx manage mounts
|
|
16
|
+
|
|
17
|
+
# Start Gunicorn
|
|
18
|
+
echo "Starting Gunicorn to serve django alyx..."
|
|
19
|
+
uv run gunicorn 'alyx.base.wsgi' --config '/app/gunicorn.conf.py'
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Service Unavailable</title>
|
|
5
|
+
<style>
|
|
6
|
+
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap');
|
|
7
|
+
*:focus {
|
|
8
|
+
outline: none;
|
|
9
|
+
}
|
|
10
|
+
h1 {
|
|
11
|
+
text-align: center;
|
|
12
|
+
font-family: 'Roboto', sans-serif;
|
|
13
|
+
color: rgb(0, 164, 109);
|
|
14
|
+
}
|
|
15
|
+
h2 {
|
|
16
|
+
text-align: center;
|
|
17
|
+
font-family: 'Roboto', sans-serif;
|
|
18
|
+
font-weight: 600;
|
|
19
|
+
}
|
|
20
|
+
p {
|
|
21
|
+
text-align: center;
|
|
22
|
+
font-family: 'Roboto', sans-serif;
|
|
23
|
+
}
|
|
24
|
+
.icon {
|
|
25
|
+
display: block;
|
|
26
|
+
margin: 0 auto;
|
|
27
|
+
width: 50px;
|
|
28
|
+
height: 50px;
|
|
29
|
+
animation: spin 2s linear infinite;
|
|
30
|
+
color:rgb(0, 164, 109);
|
|
31
|
+
margin-top: 50px;
|
|
32
|
+
}
|
|
33
|
+
.block {
|
|
34
|
+
max-width:50vw;
|
|
35
|
+
box-shadow: 0px 0px 5px 5px rgba(185, 185, 185, 0.422);
|
|
36
|
+
border-radius: 5px;
|
|
37
|
+
padding : 50px;
|
|
38
|
+
padding-top: 30px;
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
}
|
|
41
|
+
.block:active {
|
|
42
|
+
box-shadow: 0px 0px 4px 4px rgba(218, 218, 218, 0.422);
|
|
43
|
+
background-color: rgb(248, 248, 248);
|
|
44
|
+
}
|
|
45
|
+
body {
|
|
46
|
+
/* rest of your CSS */
|
|
47
|
+
display: flex;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
align-items: center;
|
|
50
|
+
min-height: 100vh;
|
|
51
|
+
margin: 0;
|
|
52
|
+
}
|
|
53
|
+
@keyframes spin {
|
|
54
|
+
0% { transform: rotate(0deg); }
|
|
55
|
+
100% { transform: rotate(360deg); }
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
58
|
+
</head>
|
|
59
|
+
<body>
|
|
60
|
+
<div class="block" onclick="location.reload();">
|
|
61
|
+
<h2 >Error 502</h2>
|
|
62
|
+
<h1 >Alyx's Django server container is not yet fully started</h1>
|
|
63
|
+
<p>Please wait a bit and refresh this page, or look at logs or console to see if an error is preventing django's correct launch.</p>
|
|
64
|
+
<svg class="icon" fill="#007850" height="200px" width="200px" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 235.319 235.319" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
65
|
+
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
|
66
|
+
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g>
|
|
67
|
+
<g id="SVGRepo_iconCarrier">
|
|
68
|
+
<g>
|
|
69
|
+
<path d="m201.094,29.997c2.649-0.623 4.623-2.996 4.623-5.835v-18.162c0-3.313-2.687-6-6-6h-164.114c-3.313,0-6,2.687-6,6v18.163c0,2.839 1.974,5.212 4.623,5.835 1.812,32.314 18.594,61.928 45.682,80.076l11.324,7.586-11.324,7.586c-27.089,18.147-43.871,47.762-45.682,80.076-2.649,0.623-4.623,2.996-4.623,5.835v18.163c0,3.313 2.687,6 6,6h164.114c3.313,0 6-2.687 6-6v-18.163c0-2.839-1.974-5.212-4.623-5.835-1.812-32.314-18.594-61.928-45.683-80.076l-11.324-7.586 11.324-7.586c27.089-18.148 43.871-47.763 45.683-80.077zm-159.491-17.997h152.114v6.163h-152.114v-6.163zm152.114,211.319h-152.114v-6.163h152.114v6.163zm-63.749-110.644c-1.663,1.114-2.661,2.983-2.661,4.985s0.998,3.871 2.661,4.985l18.765,12.571c23.71,15.883 38.49,41.705 40.333,69.941h-142.812c1.843-28.235 16.623-54.057 40.333-69.941l18.765-12.571c1.663-1.114 2.661-2.983 2.661-4.985s-0.998-3.871-2.661-4.985l-18.765-12.571c-23.71-15.884-38.49-41.706-40.333-69.941h142.812c-1.843,28.236-16.623,54.057-40.333,69.941l-18.765,12.571z"></path>
|
|
70
|
+
<path d="m133.307,82.66h-31.295c-2.487,0-4.717,1.535-5.605,3.858-0.888,2.324-0.25,4.955 1.604,6.613l15.647,14c1.139,1.019 2.57,1.528 4,1.528s2.862-0.509 4-1.528l15.647-14c1.854-1.659 2.492-4.29 1.604-6.613-0.885-2.323-3.115-3.858-5.602-3.858z"></path>
|
|
71
|
+
<path d="m117.414,140.581l-15.218,9.775c-13.306,8.914-21.292,23.876-21.292,39.892h76.511c0-16.016-7.986-30.978-21.292-39.892l-15.218-9.775c-1.074-0.644-2.416-0.644-3.491,0z"></path>
|
|
72
|
+
</g>
|
|
73
|
+
</g>
|
|
74
|
+
</svg>
|
|
75
|
+
</div>
|
|
76
|
+
</body>
|
|
77
|
+
</html>
|
|
78
|
+
|
|
79
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
events {
|
|
2
|
+
}
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
http {
|
|
6
|
+
include /etc/nginx/mime.types;
|
|
7
|
+
# include /etc/nginx/conf.d/default.conf;
|
|
8
|
+
default_type application/octet-stream;
|
|
9
|
+
|
|
10
|
+
resolver 127.0.0.11 valid=30s; # Docker's internal DNS server
|
|
11
|
+
|
|
12
|
+
server {
|
|
13
|
+
listen %%NGINX_OUT_PORT%%;
|
|
14
|
+
listen [::]:%%NGINX_OUT_PORT%%;
|
|
15
|
+
server_name nginx_server;
|
|
16
|
+
|
|
17
|
+
location /static/ {
|
|
18
|
+
alias /app/uploaded/static/;
|
|
19
|
+
expires 30d;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
location /media/ {
|
|
23
|
+
alias /app/uploaded/media/;
|
|
24
|
+
expires 30d;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
location / {
|
|
28
|
+
set $upstream_django http://django_server:8000;
|
|
29
|
+
proxy_pass $upstream_django;
|
|
30
|
+
proxy_set_header Host $host;
|
|
31
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
32
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
33
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
error_page 502 /502.html;
|
|
37
|
+
location = /502.html {
|
|
38
|
+
root /etc/nginx/errorpages;
|
|
39
|
+
internal;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
location /services/celery/ {
|
|
43
|
+
|
|
44
|
+
# using set variable allows this to make route to upstream_celery optional,
|
|
45
|
+
# and work even if it is not available at config time, but later on.
|
|
46
|
+
set $upstream_celery http://celery_server:5001/services/celery/;
|
|
47
|
+
rewrite ^/services/celery(.*) $1 break;
|
|
48
|
+
proxy_pass $upstream_celery;
|
|
49
|
+
proxy_set_header Host $host;
|
|
50
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
51
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
52
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
53
|
+
|
|
54
|
+
proxy_redirect / /services/celery/;
|
|
55
|
+
|
|
56
|
+
sub_filter_once off;
|
|
57
|
+
sub_filter_types text/html application/javascript;
|
|
58
|
+
sub_filter 'href="/' 'href="/services/celery/';
|
|
59
|
+
sub_filter 'src="/' 'src="/services/celery/';
|
|
60
|
+
sub_filter 'action="/' 'action="/services/celery/';
|
|
61
|
+
sub_filter 'url: "/' 'url: "/services/celery/';
|
|
62
|
+
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
location /services/rabbitmq/ {
|
|
66
|
+
set $upstream_rabbitmq http://rabbitmq:15672;
|
|
67
|
+
# rewrite ^/services/rabbitmq(.*) $1 break;
|
|
68
|
+
proxy_pass $upstream_rabbitmq;
|
|
69
|
+
proxy_set_header Host $host;
|
|
70
|
+
# proxy_set_header X-Forwarded-Prefix /services/rabbitmq;
|
|
71
|
+
# proxy_set_header X-Real-IP $remote_addr;
|
|
72
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
73
|
+
# proxy_set_header X-Script-Name /services/rabbitmq;
|
|
74
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
75
|
+
|
|
76
|
+
# proxy_redirect / /services/rabbitmq/;
|
|
77
|
+
|
|
78
|
+
# sub_filter_once off;
|
|
79
|
+
# sub_filter_types text/html application/javascript;
|
|
80
|
+
# sub_filter 'href="/' 'href="/services/rabbitmq/';
|
|
81
|
+
# sub_filter 'src="/' 'src="/services/rabbitmq/';
|
|
82
|
+
# sub_filter 'action="/' 'action="/services/rabbitmq/';
|
|
83
|
+
# sub_filter 'url: "/' 'url: "/services/rabbitmq/';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
location /services/pgadmin/ {
|
|
87
|
+
set $upstream_rabbitmq http://pgadmin:80;
|
|
88
|
+
proxy_set_header X-Script-Name /services/pgadmin;
|
|
89
|
+
proxy_set_header Host $host;
|
|
90
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
91
|
+
proxy_pass $upstream_rabbitmq;
|
|
92
|
+
proxy_redirect off;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|