mirror of
https://github.com/Steffo99/sophon.git
synced 2024-12-22 23:04:21 +00:00
* ✨ Create Dockerfile for the backend * 🔧 Limit the allowed slug values * ✨ Create docker image for the proxy * ✨ Add serve script (and serve dependency) * ✨ Add .dockerignore symlinks to .gitignore * ✨ Create docker image for the frontend * 🔧 Proxy the frontend * 🔧 Configure the proxy.dbm directory * 🚧 WIP * 💥 Improve settings handling * 💥 Prepare backend for docker deployment * 🔧 Reserve `static` notebook slug * ✨ Make static work * 🐛 Set a default value for reduce * 💥 Things * 💥 Everything works!
This commit is contained in:
parent
418b863cf9
commit
ba53064ce2
34 changed files with 1731 additions and 312 deletions
|
@ -6,14 +6,14 @@
|
||||||
<envs>
|
<envs>
|
||||||
<env name="PYTHONUNBUFFERED" value="1" />
|
<env name="PYTHONUNBUFFERED" value="1" />
|
||||||
<env name="DJANGO_SETTINGS_MODULE" value="sophon.settings" />
|
<env name="DJANGO_SETTINGS_MODULE" value="sophon.settings" />
|
||||||
<env name="DJANGO_SECRET_KEY" value="change-me-in-production" />
|
<env name="DJANGO_SECRET_KEY" value="DJANGONE" />
|
||||||
<env name="DJANGO_DEBUG" value="1" />
|
<env name="DJANGO_DEBUG" value="1" />
|
||||||
<env name="DJANGO_TIME_ZONE" value="CET" />
|
<env name="DJANGO_TIME_ZONE" value="CET" />
|
||||||
<env name="APACHE_PROXY_BASE_DOMAIN" value="dev.sophon.steffo.eu" />
|
<env name="DJANGO_PROXY_BASE_DOMAIN" value="dev.sophon.steffo.eu" />
|
||||||
<env name="APACHE_PROXY_HTTP_PROTOCOL" value="http" />
|
<env name="DJANGO_PROXY_PROTOCOL" value="http" />
|
||||||
<env name="DJANGO_CORS_ALLOWED_ORIGINS" value="http://localhost:3000" />
|
<env name="DJANGO_ALLOWED_ORIGINS" value="http://localhost:3000" />
|
||||||
</envs>
|
</envs>
|
||||||
<option name="SDK_HOME" value="" />
|
<option name="SDK_HOME" value="$USER_HOME$/.cache/pypoetry/virtualenvs/sophon-rpVYiJ6v-py3.9/bin/python" />
|
||||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
<option name="IS_MODULE_SDK" value="true" />
|
<option name="IS_MODULE_SDK" value="true" />
|
||||||
<option name="ADD_CONTENT_ROOTS" value="false" />
|
<option name="ADD_CONTENT_ROOTS" value="false" />
|
||||||
|
|
1
backend/.dockerignore
Symbolic link
1
backend/.dockerignore
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
.gitignore
|
36
backend/Dockerfile
Normal file
36
backend/Dockerfile
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
FROM python:3.9.7-bullseye
|
||||||
|
LABEL maintainer="Stefano Pigozzi <me@steffo.eu>"
|
||||||
|
|
||||||
|
# Set the base workdir as seen in https://hub.docker.com/_/python/
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
# Install Poetry
|
||||||
|
RUN pip install 'poetry==1.1.11'
|
||||||
|
|
||||||
|
# Copy the environment requirements into the docker image
|
||||||
|
COPY pyproject.toml ./pyproject.toml
|
||||||
|
COPY poetry.lock ./poetry.lock
|
||||||
|
|
||||||
|
# Install the dependencies using Poetry
|
||||||
|
RUN poetry install --no-root
|
||||||
|
|
||||||
|
# Copy the rest of the project into the container
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Install the project using Poetry
|
||||||
|
RUN poetry install
|
||||||
|
|
||||||
|
# Disable buffering as it may cause problems in logs
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
# Tell Django where the settings module is
|
||||||
|
ENV DJANGO_SETTINGS_MODULE="sophon.settings"
|
||||||
|
|
||||||
|
# Store the DBM file in a nice place
|
||||||
|
ENV DJANGO_PROXY_FILE="/run/sophon/proxy/proxy.dbm"
|
||||||
|
|
||||||
|
# Set the static files directory
|
||||||
|
ENV DJANGO_STATIC_ROOT="/run/sophon/static"
|
||||||
|
|
||||||
|
# Start the uvicorn server
|
||||||
|
ENTRYPOINT ["bash", "./docker_start.sh"]
|
6
backend/docker_start.sh
Normal file
6
backend/docker_start.sh
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
poetry run python -O ./manage.py migrate --no-input
|
||||||
|
poetry run python -O ./manage.py collectstatic --no-input
|
||||||
|
poetry run python -O ./manage.py initsuperuser
|
||||||
|
poetry run python -O -m gunicorn sophon.asgi:application -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000
|
115
backend/poetry.lock
generated
115
backend/poetry.lock
generated
|
@ -47,6 +47,20 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "coloredlogs"
|
||||||
|
version = "15.0.1"
|
||||||
|
description = "Colored terminal output for Python's logging module"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
humanfriendly = ">=9.1"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
cron = ["capturer (>=2.4)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deprecation"
|
name = "deprecation"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -97,18 +111,6 @@ python-versions = ">=3.5"
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
Django = ">=2.2"
|
Django = ">=2.2"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "django-pam"
|
|
||||||
version = "2.0.1"
|
|
||||||
description = "Django PAM authentication backend implementation."
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
python-pam = "*"
|
|
||||||
six = "*"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "djangorestframework"
|
name = "djangorestframework"
|
||||||
version = "3.12.4"
|
version = "3.12.4"
|
||||||
|
@ -159,6 +161,17 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humanfriendly"
|
||||||
|
version = "10.0"
|
||||||
|
description = "Human friendly output for text interfaces using Python"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
pyreadline3 = { version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\"" }
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "3.2"
|
version = "3.2"
|
||||||
|
@ -167,6 +180,14 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.5"
|
python-versions = ">=3.5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy-object-proxy"
|
||||||
|
version = "1.6.0"
|
||||||
|
description = "A fast and thorough lazy object proxy."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markdown"
|
name = "markdown"
|
||||||
version = "3.3.4"
|
version = "3.3.4"
|
||||||
|
@ -219,9 +240,9 @@ optional = false
|
||||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-pam"
|
name = "pyreadline3"
|
||||||
version = "1.8.4"
|
version = "3.3"
|
||||||
description = "Python PAM module using ctypes, py3/py2"
|
description = "A python implementation of GNU readline."
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
|
@ -260,14 +281,6 @@ urllib3 = ">=1.21.1,<1.27"
|
||||||
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
||||||
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
|
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "six"
|
|
||||||
version = "1.16.0"
|
|
||||||
description = "Python 2 and 3 compatibility utilities"
|
|
||||||
category = "main"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlparse"
|
name = "sqlparse"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
@ -320,7 +333,7 @@ test = ["websockets"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.9"
|
python-versions = "^3.9"
|
||||||
content-hash = "13e8ed6ddfe56e2e389508a531dea9997cd5bbf2da8170a685770c148472a9e0"
|
content-hash = "aed43668a7f9bc2d3703264168f93ce5f2a4a3836c8619e2fb385906765f74b4"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
asgiref = [
|
asgiref = [
|
||||||
|
@ -343,6 +356,10 @@ colorama = [
|
||||||
{ file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" },
|
{ file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" },
|
||||||
{ file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b" },
|
{ file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b" },
|
||||||
]
|
]
|
||||||
|
coloredlogs = [
|
||||||
|
{ file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934" },
|
||||||
|
{ file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0" },
|
||||||
|
]
|
||||||
deprecation = [
|
deprecation = [
|
||||||
{ file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a" },
|
{ file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a" },
|
||||||
{ file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff" },
|
{ file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff" },
|
||||||
|
@ -359,10 +376,6 @@ django-filter = [
|
||||||
{file = "django-filter-2.4.0.tar.gz", hash = "sha256:84e9d5bb93f237e451db814ed422a3a625751cbc9968b484ecc74964a8696b06"},
|
{file = "django-filter-2.4.0.tar.gz", hash = "sha256:84e9d5bb93f237e451db814ed422a3a625751cbc9968b484ecc74964a8696b06"},
|
||||||
{file = "django_filter-2.4.0-py3-none-any.whl", hash = "sha256:e00d32cebdb3d54273c48f4f878f898dced8d5dfaad009438fe61ebdf535ace1"},
|
{file = "django_filter-2.4.0-py3-none-any.whl", hash = "sha256:e00d32cebdb3d54273c48f4f878f898dced8d5dfaad009438fe61ebdf535ace1"},
|
||||||
]
|
]
|
||||||
django-pam = [
|
|
||||||
{ file = "django-pam-2.0.1.tar.gz", hash = "sha256:1c0e670589188e80b800ac5e93ac6599fc1bf5d850bb0f752dab6619efe7875c" },
|
|
||||||
{ file = "django_pam-2.0.1-py2.py3-none-any.whl", hash = "sha256:c34d2f42e9e92791ca313a1a9a3c2c5e1cd1370ceb706aae34de03f093e17414" },
|
|
||||||
]
|
|
||||||
djangorestframework = [
|
djangorestframework = [
|
||||||
{ file = "djangorestframework-3.12.4-py3-none-any.whl", hash = "sha256:6d1d59f623a5ad0509fe0d6bfe93cbdfe17b8116ebc8eda86d45f6e16e819aaf" },
|
{ file = "djangorestframework-3.12.4-py3-none-any.whl", hash = "sha256:6d1d59f623a5ad0509fe0d6bfe93cbdfe17b8116ebc8eda86d45f6e16e819aaf" },
|
||||||
{ file = "djangorestframework-3.12.4.tar.gz", hash = "sha256:f747949a8ddac876e879190df194b925c177cdeb725a099db1460872f7c0a7f2" },
|
{ file = "djangorestframework-3.12.4.tar.gz", hash = "sha256:f747949a8ddac876e879190df194b925c177cdeb725a099db1460872f7c0a7f2" },
|
||||||
|
@ -379,10 +392,38 @@ h11 = [
|
||||||
{ file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6" },
|
{ file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6" },
|
||||||
{ file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042" },
|
{ file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042" },
|
||||||
]
|
]
|
||||||
|
humanfriendly = [
|
||||||
|
{ file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477" },
|
||||||
|
{ file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc" },
|
||||||
|
]
|
||||||
idna = [
|
idna = [
|
||||||
{ file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a" },
|
{ file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a" },
|
||||||
{ file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" },
|
{ file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" },
|
||||||
]
|
]
|
||||||
|
lazy-object-proxy = [
|
||||||
|
{ file = "lazy-object-proxy-1.6.0.tar.gz", hash = "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp27-cp27m-win32.whl", hash = "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp36-cp36m-win32.whl", hash = "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp38-cp38-win32.whl", hash = "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp39-cp39-win32.whl", hash = "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61" },
|
||||||
|
{ file = "lazy_object_proxy-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b" },
|
||||||
|
]
|
||||||
markdown = [
|
markdown = [
|
||||||
{ file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c" },
|
{ file = "Markdown-3.3.4-py3-none-any.whl", hash = "sha256:96c3ba1261de2f7547b46a00ea8463832c921d3f9d6aba3f255a6f71386db20c" },
|
||||||
{ file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49" },
|
{ file = "Markdown-3.3.4.tar.gz", hash = "sha256:31b5b491868dcc87d6c24b7e3d19a0d730d59d3e46f4eea6430a321bed387a49" },
|
||||||
|
@ -427,16 +468,16 @@ pydantic = [
|
||||||
{file = "pydantic-1.7.4.tar.gz", hash = "sha256:0a1abcbd525fbb52da58c813d54c2ec706c31a91afdb75411a73dd1dec036595"},
|
{file = "pydantic-1.7.4.tar.gz", hash = "sha256:0a1abcbd525fbb52da58c813d54c2ec706c31a91afdb75411a73dd1dec036595"},
|
||||||
]
|
]
|
||||||
pyparsing = [
|
pyparsing = [
|
||||||
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
|
{ file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" },
|
||||||
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
{ file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1" },
|
||||||
]
|
]
|
||||||
python-pam = [
|
pyreadline3 = [
|
||||||
{file = "python-pam-1.8.4.tar.gz", hash = "sha256:c856d9c89fedb33951dd8a95727ae57c6887b02d065bbdffd2fd9dbc0183909b"},
|
{ file = "pyreadline3-3.3-py3-none-any.whl", hash = "sha256:0003fd0079d152ecbd8111202c5a7dfa6a5569ffd65b235e45f3c2ecbee337b4" },
|
||||||
{file = "python_pam-1.8.4-py2.py3-none-any.whl", hash = "sha256:8439b470b564ac558585b5a3ffce0fce48d1eeebdff19add48279c33de7da0e0"},
|
{ file = "pyreadline3-3.3.tar.gz", hash = "sha256:ff3b5a1ac0010d0967869f723e687d42cabc7dccf33b14934c92aa5168d260b3" },
|
||||||
]
|
]
|
||||||
pytz = [
|
pytz = [
|
||||||
{file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"},
|
{ file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798" },
|
||||||
{file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"},
|
{ file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da" },
|
||||||
]
|
]
|
||||||
pywin32 = [
|
pywin32 = [
|
||||||
{file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"},
|
{file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"},
|
||||||
|
@ -456,10 +497,6 @@ requests = [
|
||||||
{file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"},
|
{file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"},
|
||||||
{file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"},
|
{file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"},
|
||||||
]
|
]
|
||||||
six = [
|
|
||||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
|
||||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
|
||||||
]
|
|
||||||
sqlparse = [
|
sqlparse = [
|
||||||
{file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"},
|
{file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"},
|
||||||
{file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"},
|
{file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"},
|
||||||
|
|
|
@ -12,12 +12,13 @@ djangorestframework = "^3.12.4"
|
||||||
Markdown = "^3.3.4"
|
Markdown = "^3.3.4"
|
||||||
django-filter = "^2.4.0"
|
django-filter = "^2.4.0"
|
||||||
pydantic = "~1.7.3"
|
pydantic = "~1.7.3"
|
||||||
django-pam = "^2.0.0"
|
|
||||||
deprecation = "^2.1.0"
|
deprecation = "^2.1.0"
|
||||||
docker = "^5.0.2"
|
docker = "^5.0.2"
|
||||||
django-cors-headers = "^3.8.0"
|
django-cors-headers = "^3.8.0"
|
||||||
uvicorn = "^0.15.0"
|
uvicorn = "^0.15.0"
|
||||||
gunicorn = "^20.1.0"
|
gunicorn = "^20.1.0"
|
||||||
|
coloredlogs = "^15.0.1"
|
||||||
|
lazy-object-proxy = "^1.6.0"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
|
|
||||||
|
|
0
backend/sophon/core/management/__init__.py
Normal file
0
backend/sophon/core/management/__init__.py
Normal file
0
backend/sophon/core/management/commands/__init__.py
Normal file
0
backend/sophon/core/management/commands/__init__.py
Normal file
25
backend/sophon/core/management/commands/initsuperuser.py
Normal file
25
backend/sophon/core/management/commands/initsuperuser.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import logging
|
||||||
|
from os import environ
|
||||||
|
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# Based on https://stackoverflow.com/a/39745576/4334568
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Creates the superuser non-interactively if it doesn't exist"
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
User = get_user_model()
|
||||||
|
log.debug("Checking if an user already exists...")
|
||||||
|
if not User.objects.exists():
|
||||||
|
log.info("Creating superuser...")
|
||||||
|
User.objects.create_superuser(
|
||||||
|
username=environ["DJANGO_SU_USERNAME"],
|
||||||
|
email=environ["DJANGO_SU_EMAIL"],
|
||||||
|
password=environ["DJANGO_SU_PASSWORD"],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
log.info("An user already exists, not creating superuser.")
|
|
@ -8,13 +8,6 @@ It depends on the following :mod:`django` apps:
|
||||||
|
|
||||||
It can be configured with the following :data:`os.environ` keys:
|
It can be configured with the following :data:`os.environ` keys:
|
||||||
|
|
||||||
- ``DOCKER_HOST``: The URL to the Docker host.
|
|
||||||
- ``DOCKER_TLS_VERIFY``: Verify the host against a CA certificate.
|
|
||||||
- ``DOCKER_CERT_PATH``: A path to a directory containing TLS certificates to use when connecting to the Docker host.
|
|
||||||
- ``APACHE_PROXY_EXPRESS_DBM``: The filename of the ``proxy_express`` DBM file to write to.
|
|
||||||
- ``APACHE_PROXY_BASE_DOMAIN``: The base domain for virtualhost reverse proxying.
|
|
||||||
- ``APACHE_PROXY_HTTP_PROTOCOL``: The http_protocol that Apache uses to make the containers available to the public.
|
|
||||||
- ``APACHE_PROXY_WS_PROTOCOL``: The http_protocol that Apache uses to make the Jupyter websocket available to the public.
|
|
||||||
- ``SOPHON_CONTAINER_PREFIX``: The prefix added to the names of notebooks' containers will have.
|
- ``SOPHON_CONTAINER_PREFIX``: The prefix added to the names of notebooks' containers will have.
|
||||||
- ``SOPHON_VOLUME_PREFIX``: The prefix added to the names of notebooks' volumes will have.
|
- ``SOPHON_VOLUME_PREFIX``: The prefix added to the names of notebooks' volumes will have.
|
||||||
- ``SOPHON_NETWORK_PREFIX``: The prefix added to the names of notebooks' volumes will have.
|
- ``SOPHON_NETWORK_PREFIX``: The prefix added to the names of notebooks' volumes will have.
|
||||||
|
|
|
@ -13,7 +13,6 @@ class NotebookAdmin(SophonAdmin):
|
||||||
"locked_by",
|
"locked_by",
|
||||||
"container_image",
|
"container_image",
|
||||||
"container_id",
|
"container_id",
|
||||||
"port",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
list_filter = (
|
list_filter = (
|
||||||
|
@ -40,7 +39,6 @@ class NotebookAdmin(SophonAdmin):
|
||||||
"fields": (
|
"fields": (
|
||||||
"container_image",
|
"container_image",
|
||||||
"container_id",
|
"container_id",
|
||||||
"internet_access",
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -48,6 +46,7 @@ class NotebookAdmin(SophonAdmin):
|
||||||
"Proxy", {
|
"Proxy", {
|
||||||
"fields": (
|
"fields": (
|
||||||
"port",
|
"port",
|
||||||
|
"internal_url",
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
# Log rewrite at the maximum level
|
|
||||||
# DO NOT ENABLE THIS IN PRODUCTION OR YOUR LOGS WILL BE FLOODED!
|
|
||||||
# LogLevel "rewrite:trace8"
|
|
||||||
|
|
||||||
# Enable rewriting
|
|
||||||
RewriteEngine on
|
|
||||||
RewriteMap "sophonproxy" "dbm=gdbm:/mnt/tebi/ext4/workspace/sophon/proxy.dbm"
|
|
||||||
|
|
||||||
# Preserve host
|
|
||||||
ProxyPreserveHost on
|
|
||||||
|
|
||||||
# Proxy websockets
|
|
||||||
RewriteCond "%{HTTP_HOST}" ".dev.sophon.steffo.eu$" [NC]
|
|
||||||
RewriteCond "%{HTTP:Connection}" "Upgrade" [NC]
|
|
||||||
RewriteCond "%{HTTP:Upgrade}" "websocket" [NC]
|
|
||||||
RewriteRule "/(.*)" "ws://${sophonproxy:%{HTTP_HOST}}/$1" [P,L]
|
|
||||||
|
|
||||||
# Proxy regular requests
|
|
||||||
RewriteCond "%{HTTP_HOST}" ".dev.sophon.steffo.eu$" [NC]
|
|
||||||
RewriteRule "/(.*)" "http://${sophonproxy:%{HTTP_HOST}}/$1" [P,L]
|
|
|
@ -1,21 +1,28 @@
|
||||||
import dbm.gnu
|
import dbm.gnu
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import pathlib
|
||||||
import socket
|
import socket
|
||||||
import typing as t
|
import typing as t
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
db_name = os.environ.get("APACHE_PROXY_EXPRESS_DBM", "proxy.dbm")
|
|
||||||
base_domain = os.environ["APACHE_PROXY_BASE_DOMAIN"]
|
|
||||||
http_protocol = os.environ.get("APACHE_PROXY_HTTP_PROTOCOL", "https")
|
|
||||||
|
|
||||||
|
|
||||||
class ApacheDB:
|
class ApacheDB:
|
||||||
def __init__(self, filename: str):
|
def __init__(self, path: t.Union[str, pathlib.Path]):
|
||||||
self.filename: str = filename
|
self.path: pathlib.Path
|
||||||
log.debug(f"{self.filename}: Initializing...")
|
if isinstance(path, str):
|
||||||
with dbm.open(self.filename, "c"):
|
self.path = pathlib.Path(path)
|
||||||
|
else:
|
||||||
|
self.path = path
|
||||||
|
log.debug(f"Initializing directories...")
|
||||||
|
os.makedirs(self.path.parent, exist_ok=True)
|
||||||
|
log.debug(f"Initializing database...")
|
||||||
|
with dbm.open(str(self.path), "c"):
|
||||||
pass
|
pass
|
||||||
|
log.debug("Done!")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def convert_to_bytes(item: t.Union[str, bytes]) -> bytes:
|
def convert_to_bytes(item: t.Union[str, bytes]) -> bytes:
|
||||||
|
@ -26,27 +33,25 @@ class ApacheDB:
|
||||||
|
|
||||||
def __getitem__(self, key: t.Union[str, bytes]) -> bytes:
|
def __getitem__(self, key: t.Union[str, bytes]) -> bytes:
|
||||||
key = self.convert_to_bytes(key)
|
key = self.convert_to_bytes(key)
|
||||||
log.debug(f"{self.filename}: Getting {key!r}...")
|
log.debug(f"{self.path}: Getting {key!r}...")
|
||||||
with dbm.open(self.filename, "r") as adb:
|
with dbm.open(str(self.path), "r") as adb:
|
||||||
return adb[key]
|
return adb[key]
|
||||||
|
|
||||||
def __setitem__(self, key: bytes, value: bytes) -> None:
|
def __setitem__(self, key: bytes, value: bytes) -> None:
|
||||||
key = self.convert_to_bytes(key)
|
key = self.convert_to_bytes(key)
|
||||||
value = self.convert_to_bytes(value)
|
value = self.convert_to_bytes(value)
|
||||||
log.debug(f"{self.filename}: Setting {key!r} → {value!r}...")
|
log.debug(f"{self.path}: Setting {key!r} → {value!r}...")
|
||||||
with dbm.open(self.filename, "w") as adb:
|
with dbm.open(str(self.path), "w") as adb:
|
||||||
adb[key] = value
|
adb[key] = value
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
key = self.convert_to_bytes(key)
|
key = self.convert_to_bytes(key)
|
||||||
log.debug(f"{self.filename}: Deleting {key!r}...")
|
log.debug(f"{self.path}: Deleting {key!r}...")
|
||||||
with dbm.open(self.filename, "w") as adb:
|
with dbm.open(str(self.path), "w") as adb:
|
||||||
del adb[key]
|
del adb[key]
|
||||||
|
|
||||||
|
|
||||||
log.info(f"Creating proxy_express database: {db_name}")
|
db: ApacheDB = ApacheDB(settings.PROXY_FILE)
|
||||||
db = ApacheDB(db_name)
|
|
||||||
log.info(f"Created proxy_express database!")
|
|
||||||
|
|
||||||
|
|
||||||
def get_ephemeral_port() -> int:
|
def get_ephemeral_port() -> int:
|
||||||
|
|
|
@ -4,17 +4,24 @@ import time
|
||||||
|
|
||||||
import docker.errors
|
import docker.errors
|
||||||
import docker.models.containers
|
import docker.models.containers
|
||||||
|
import lazy_object_proxy
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
log.info("Connecting to Docker daemon...")
|
|
||||||
try:
|
def get_docker_client() -> docker.DockerClient:
|
||||||
client: docker.DockerClient = docker.from_env()
|
log.info("Connecting to Docker daemon...")
|
||||||
except docker.errors.DockerException as e:
|
try:
|
||||||
|
result = docker.from_env(environment=settings.__dict__)
|
||||||
|
except docker.errors.DockerException as e:
|
||||||
log.fatal("Could not connect to the Docker daemon!")
|
log.fatal("Could not connect to the Docker daemon!")
|
||||||
raise
|
else:
|
||||||
else:
|
|
||||||
log.info("Connection to Docker daemon successful!")
|
log.info("Connection to Docker daemon successful!")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
client: docker.DockerClient = lazy_object_proxy.Proxy(get_docker_client)
|
||||||
|
|
||||||
|
|
||||||
class HealthState(enum.IntEnum):
|
class HealthState(enum.IntEnum):
|
||||||
|
@ -49,6 +56,13 @@ def get_health(container: docker.models.containers.Container) -> HealthState:
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
|
||||||
|
def get_proxy_container() -> docker.models.containers.Container:
|
||||||
|
"""
|
||||||
|
:return: The container of the proxy, having the name specified in `settings.PROXY_CONTAINER_NAME`.
|
||||||
|
"""
|
||||||
|
return client.containers.get(settings.PROXY_CONTAINER_NAME)
|
||||||
|
|
||||||
|
|
||||||
def sleep_until_container_has_started(container: docker.models.containers.Container) -> HealthState:
|
def sleep_until_container_has_started(container: docker.models.containers.Container) -> HealthState:
|
||||||
"""
|
"""
|
||||||
Sleep until the specified container is not anymore in the ``starting`` state.
|
Sleep until the specified container is not anymore in the ``starting`` state.
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Generated by Django 3.2.7 on 2021-10-18 18:02
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import sophon.notebooks.validators
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('notebooks', '0008_alter_notebook_container_image'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='notebook',
|
||||||
|
name='slug',
|
||||||
|
field=models.SlugField(
|
||||||
|
help_text='Unique alphanumeric string which identifies the project. Changing this once the container has been created <strong>will break Docker</strong>!',
|
||||||
|
max_length=64, primary_key=True, serialize=False,
|
||||||
|
validators=[sophon.notebooks.validators.DisallowedValuesValidator(['api', 'proxy', 'backend', 'frontend', 'src'])], verbose_name='Slug'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Generated by Django 3.2.7 on 2021-10-19 17:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('notebooks', '0009_alter_notebook_slug'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='notebook',
|
||||||
|
name='internet_access',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='notebook',
|
||||||
|
name='internal_url',
|
||||||
|
field=models.IntegerField(blank=True,
|
||||||
|
help_text='The URL reachable from the proxy where the container is available. Can be null if the notebook is not running.',
|
||||||
|
null=True, verbose_name='Internal URL'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='notebook',
|
||||||
|
name='port',
|
||||||
|
field=models.IntegerField(blank=True,
|
||||||
|
help_text='The port number of the local machine at which the container is available. Can be null if the notebook is not running, or if the proxy itself is running in a Docker container.',
|
||||||
|
null=True, verbose_name='Local port number'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Generated by Django 3.2.7 on 2021-10-19 17:45
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import sophon.notebooks.validators
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('notebooks', '0010_auto_20211019_1738'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='notebook',
|
||||||
|
name='container_image',
|
||||||
|
field=models.CharField(choices=[('steffo45/jupyterlab-docker-sophon', 'Python (Sophonic)')], default='steffo45/jupyterlab-docker-sophon',
|
||||||
|
help_text='The Docker image to run for this notebook.', max_length=256, verbose_name='Docker image'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='notebook',
|
||||||
|
name='slug',
|
||||||
|
field=models.SlugField(
|
||||||
|
help_text='Unique alphanumeric string which identifies the project. Changing this once the container has been created <strong>will break Docker</strong>!',
|
||||||
|
max_length=64, primary_key=True, serialize=False,
|
||||||
|
validators=[sophon.notebooks.validators.DisallowedValuesValidator(['api', 'static', 'proxy', 'backend', 'frontend', 'src'])],
|
||||||
|
verbose_name='Slug'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.2.7 on 2021-10-19 19:46
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('notebooks', '0011_auto_20211019_1745'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='notebook',
|
||||||
|
name='internal_url',
|
||||||
|
field=models.CharField(blank=True,
|
||||||
|
help_text='The URL reachable from the proxy where the container is available. Can be null if the notebook is not running.',
|
||||||
|
max_length=512, null=True, verbose_name='Internal URL'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,7 +1,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
|
||||||
import typing as t
|
import typing as t
|
||||||
|
|
||||||
import docker.errors
|
import docker.errors
|
||||||
|
@ -9,15 +8,17 @@ import docker.models.containers
|
||||||
import docker.models.images
|
import docker.models.images
|
||||||
import docker.models.networks
|
import docker.models.networks
|
||||||
import docker.models.volumes
|
import docker.models.volumes
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from sophon.core.models import SophonGroupModel, ResearchGroup
|
from sophon.core.models import SophonGroupModel, ResearchGroup
|
||||||
from sophon.notebooks.apache import db as apache_db
|
from sophon.notebooks.apache import db as apache_db
|
||||||
from sophon.notebooks.apache import get_ephemeral_port, base_domain, http_protocol
|
from sophon.notebooks.apache import get_ephemeral_port
|
||||||
from sophon.notebooks.docker import client as docker_client
|
from sophon.notebooks.docker import client as docker_client
|
||||||
from sophon.notebooks.docker import sleep_until_container_has_started
|
from sophon.notebooks.docker import sleep_until_container_has_started, get_proxy_container
|
||||||
from sophon.notebooks.jupyter import generate_secure_token
|
from sophon.notebooks.jupyter import generate_secure_token
|
||||||
|
from sophon.notebooks.validators import DisallowedValuesValidator
|
||||||
from sophon.projects.models import ResearchProject
|
from sophon.projects.models import ResearchProject
|
||||||
|
|
||||||
module_name = __name__
|
module_name = __name__
|
||||||
|
@ -42,6 +43,16 @@ class Notebook(SophonGroupModel):
|
||||||
help_text="Unique alphanumeric string which identifies the project. Changing this once the container has been created <strong>will break Docker</strong>!",
|
help_text="Unique alphanumeric string which identifies the project. Changing this once the container has been created <strong>will break Docker</strong>!",
|
||||||
max_length=64,
|
max_length=64,
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
|
validators=[
|
||||||
|
DisallowedValuesValidator([
|
||||||
|
"api", # reserved for docker deployment
|
||||||
|
"static", # reserved for production deployment
|
||||||
|
"proxy", # reserved for future use
|
||||||
|
"backend", # reserved for future use
|
||||||
|
"frontend", # reserved for future use
|
||||||
|
"src", # reserved for future use
|
||||||
|
])
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
project = models.ForeignKey(
|
project = models.ForeignKey(
|
||||||
|
@ -65,13 +76,13 @@ class Notebook(SophonGroupModel):
|
||||||
|
|
||||||
# Remember to make a migration when changing this!
|
# Remember to make a migration when changing this!
|
||||||
IMAGE_CHOICES = (
|
IMAGE_CHOICES = (
|
||||||
("jupyter/base-notebook", "Base"),
|
# ("jupyter/base-notebook", "Base"),
|
||||||
("jupyter/minimal-notebook", "Python"),
|
# ("jupyter/minimal-notebook", "Python"),
|
||||||
("jupyter/scipy-notebook", "Python (Scientific)"),
|
# ("jupyter/scipy-notebook", "Python (Scientific)"),
|
||||||
("jupyter/tensorflow-notebook", "Python (Tensorflow)"),
|
# ("jupyter/tensorflow-notebook", "Python (Tensorflow)"),
|
||||||
("jupyter/r-notebook", "Python + R"),
|
# ("jupyter/r-notebook", "Python + R"),
|
||||||
("jupyter/pyspark-notebook", "Python (Scientific) + Apache Spark"),
|
# ("jupyter/pyspark-notebook", "Python (Scientific) + Apache Spark"),
|
||||||
("jupyter/all-spark-notebook", "Python (Scientific) + Scala + R + Apache Spark"),
|
# ("jupyter/all-spark-notebook", "Python (Scientific) + Scala + R + Apache Spark"),
|
||||||
("steffo45/jupyterlab-docker-sophon", "Python (Sophonic)"),
|
("steffo45/jupyterlab-docker-sophon", "Python (Sophonic)"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -83,14 +94,6 @@ class Notebook(SophonGroupModel):
|
||||||
default="steffo45/jupyterlab-docker-sophon",
|
default="steffo45/jupyterlab-docker-sophon",
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: Find a way to prevent Internet access without using the --internal flag, as it doesn't allow to expose ports
|
|
||||||
internet_access = models.BooleanField(
|
|
||||||
"Allow internet access",
|
|
||||||
help_text="If true, the notebook will be able to access the Internet as the host machine. Can only be set by a superuser via the admin interface. "
|
|
||||||
"<em>Does not currently do anything.</em>",
|
|
||||||
default=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
jupyter_token = models.CharField(
|
jupyter_token = models.CharField(
|
||||||
"Jupyter Access Token",
|
"Jupyter Access Token",
|
||||||
help_text="The token to allow access to the JupyterLab editor.",
|
help_text="The token to allow access to the JupyterLab editor.",
|
||||||
|
@ -107,10 +110,17 @@ class Notebook(SophonGroupModel):
|
||||||
|
|
||||||
port = models.IntegerField(
|
port = models.IntegerField(
|
||||||
"Local port number",
|
"Local port number",
|
||||||
help_text="The port number of the local machine at which the container is available. Can be null if the notebook is not running.",
|
help_text="The port number of the local machine at which the container is available. Can be null if the notebook is not running, or if the proxy itself is running in a Docker container.",
|
||||||
blank=True, null=True,
|
blank=True, null=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal_url = models.CharField(
|
||||||
|
"Internal URL",
|
||||||
|
help_text="The URL reachable from the proxy where the container is available. Can be null if the notebook is not running.",
|
||||||
|
blank=True, null=True,
|
||||||
|
max_length=512,
|
||||||
|
)
|
||||||
|
|
||||||
def get_group(self) -> ResearchGroup:
|
def get_group(self) -> ResearchGroup:
|
||||||
return self.project.group
|
return self.project.group
|
||||||
|
|
||||||
|
@ -122,7 +132,6 @@ class Notebook(SophonGroupModel):
|
||||||
"name",
|
"name",
|
||||||
"locked_by",
|
"locked_by",
|
||||||
"container_image",
|
"container_image",
|
||||||
"internet_access",
|
|
||||||
"is_running",
|
"is_running",
|
||||||
"lab_url",
|
"lab_url",
|
||||||
"legacy_notebook_url",
|
"legacy_notebook_url",
|
||||||
|
@ -165,28 +174,28 @@ class Notebook(SophonGroupModel):
|
||||||
"""
|
"""
|
||||||
:return: The name given to the container associated with this :class:`Notebook`.
|
:return: The name given to the container associated with this :class:`Notebook`.
|
||||||
"""
|
"""
|
||||||
return f"{os.environ.get('SOPHON_CONTAINER_PREFIX', 'sophon-container')}-{self.slug}"
|
return f"{settings.DOCKER_CONTAINER_PREFIX}-{self.slug}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def volume_name(self) -> str:
|
def volume_name(self) -> str:
|
||||||
"""
|
"""
|
||||||
:return: The name given to the volume associated with this :class:`Notebook`.
|
:return: The name given to the volume associated with this :class:`Notebook`.
|
||||||
"""
|
"""
|
||||||
return f"{os.environ.get('SOPHON_VOLUME_PREFIX', 'sophon-volume')}-{self.slug}"
|
return f"{settings.DOCKER_VOLUME_PREFIX}-{self.slug}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def network_name(self) -> str:
|
def network_name(self) -> str:
|
||||||
"""
|
"""
|
||||||
:return: The name given to the network associated with this :class:`Notebook`.
|
:return: The name given to the network associated with this :class:`Notebook`.
|
||||||
"""
|
"""
|
||||||
return f"{os.environ.get('SOPHON_NETWORK_PREFIX', 'sophon-network')}-{self.slug}"
|
return f"{settings.DOCKER_NETWORK_PREFIX}-{self.slug}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def external_domain(self) -> str:
|
def external_domain(self) -> str:
|
||||||
"""
|
"""
|
||||||
:return: The domain name where this :class:`Notebook` will be accessible on the Internet after its container is started.
|
:return: The domain name where this :class:`Notebook` will be accessible on the Internet after its container is started.
|
||||||
"""
|
"""
|
||||||
return f"{self.slug}.{base_domain}"
|
return f"{self.slug}.{settings.PROXY_BASE_DOMAIN}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lab_url(self) -> t.Optional[str]:
|
def lab_url(self) -> t.Optional[str]:
|
||||||
|
@ -197,7 +206,7 @@ class Notebook(SophonGroupModel):
|
||||||
"""
|
"""
|
||||||
if not self.is_running:
|
if not self.is_running:
|
||||||
return None
|
return None
|
||||||
return f"{http_protocol}://{self.external_domain}/lab?token={self.jupyter_token}"
|
return f"{settings.PROXY_PROTOCOL}://{self.external_domain}/lab?token={self.jupyter_token}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def legacy_notebook_url(self) -> t.Optional[str]:
|
def legacy_notebook_url(self) -> t.Optional[str]:
|
||||||
|
@ -208,13 +217,13 @@ class Notebook(SophonGroupModel):
|
||||||
"""
|
"""
|
||||||
if not self.is_running:
|
if not self.is_running:
|
||||||
return None
|
return None
|
||||||
return f"{http_protocol}://{self.external_domain}/tree?token={self.jupyter_token}"
|
return f"{settings.PROXY_PROTOCOL}://{self.external_domain}/tree?token={self.jupyter_token}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def internal_domain(self) -> t.Optional[str]:
|
def local_domain(self) -> t.Optional[str]:
|
||||||
"""
|
"""
|
||||||
:return: The domain name where this :class:`Notebook` is accessible on the local machine, or :data:`None` if no port has been assigned to this
|
:return: The domain name where this :class:`Notebook` is accessible on the local machine, or :data:`None` if no port has been assigned to this
|
||||||
container yet.
|
container yet or if the proxy itself is running in a container.
|
||||||
"""
|
"""
|
||||||
if self.port is None:
|
if self.port is None:
|
||||||
return None
|
return None
|
||||||
|
@ -296,7 +305,7 @@ class Notebook(SophonGroupModel):
|
||||||
self.log.debug(f"Network does not exist, creating it now...")
|
self.log.debug(f"Network does not exist, creating it now...")
|
||||||
network = docker_client.networks.create(
|
network = docker_client.networks.create(
|
||||||
name=self.network_name,
|
name=self.network_name,
|
||||||
internal=not self.internet_access,
|
internal=True,
|
||||||
)
|
)
|
||||||
self.log.info(f"Created {network!r}")
|
self.log.info(f"Created {network!r}")
|
||||||
return network
|
return network
|
||||||
|
@ -305,7 +314,20 @@ class Notebook(SophonGroupModel):
|
||||||
"""
|
"""
|
||||||
Disable the proxying of this :class:`Notebook` by removing its URLs from the :data:`apache_db` and its port from :attr:`.port`.
|
Disable the proxying of this :class:`Notebook` by removing its URLs from the :data:`apache_db` and its port from :attr:`.port`.
|
||||||
"""
|
"""
|
||||||
|
if settings.PROXY_CONTAINER_NAME:
|
||||||
|
self.log.debug("Getting the notebook network...")
|
||||||
|
network = self.get_network()
|
||||||
|
|
||||||
|
self.log.debug("Getting proxy container...")
|
||||||
|
proxy = get_proxy_container()
|
||||||
|
|
||||||
|
self.log.debug("Disconnecting proxy container from the network...")
|
||||||
|
try:
|
||||||
|
network.disconnect(proxy)
|
||||||
|
except docker.errors.APIError:
|
||||||
|
self.log.debug("Container was already disconnected.")
|
||||||
|
|
||||||
|
else:
|
||||||
self.log.debug("Unassigning port...")
|
self.log.debug("Unassigning port...")
|
||||||
self.port = None
|
self.port = None
|
||||||
|
|
||||||
|
@ -315,7 +337,7 @@ class Notebook(SophonGroupModel):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.log.debug("Clearing port from the SQL database...")
|
self.log.debug("Clearing proxy data from the SQL database...")
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def enable_proxying(self) -> None:
|
def enable_proxying(self) -> None:
|
||||||
|
@ -323,13 +345,30 @@ class Notebook(SophonGroupModel):
|
||||||
Enable the proxying of this :class:`Notebook` by adding its URLs to the :data:`apache_db` and its port to :attr:`.port`.
|
Enable the proxying of this :class:`Notebook` by adding its URLs to the :data:`apache_db` and its port to :attr:`.port`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if settings.PROXY_CONTAINER_NAME:
|
||||||
|
self.log.debug("Getting the notebook network...")
|
||||||
|
network = self.get_network()
|
||||||
|
|
||||||
|
self.log.debug("Getting proxy container...")
|
||||||
|
proxy = get_proxy_container()
|
||||||
|
|
||||||
|
self.log.debug("Connecting proxy container to the network...")
|
||||||
|
network.connect(proxy)
|
||||||
|
|
||||||
|
self.log.debug("Setting internal_url...")
|
||||||
|
self.internal_url = f"{self.container_name}:8888"
|
||||||
|
|
||||||
|
self.log.debug("Adding entry to the apache_db...")
|
||||||
|
apache_db[bytes(self.external_domain, encoding="ascii")] = bytes(self.internal_url, encoding="ascii")
|
||||||
|
|
||||||
|
else:
|
||||||
self.log.debug("Getting free port...")
|
self.log.debug("Getting free port...")
|
||||||
self.port: int = get_ephemeral_port()
|
self.port: int = get_ephemeral_port()
|
||||||
|
|
||||||
self.log.debug("Adding entry to the apache_db...")
|
self.log.debug("Adding entry to the apache_db...")
|
||||||
apache_db[self.external_domain] = f"{self.internal_domain}"
|
apache_db[bytes(self.external_domain, encoding="ascii")] = bytes(f"{self.local_domain}", encoding="ascii")
|
||||||
|
|
||||||
self.log.debug("Saving port to the SQL database...")
|
self.log.debug("Saving proxy data to the SQL database...")
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def get_container(self) -> t.Optional[docker.models.containers.Container]:
|
def get_container(self) -> t.Optional[docker.models.containers.Container]:
|
||||||
|
@ -449,7 +488,7 @@ class Notebook(SophonGroupModel):
|
||||||
name=self.container_name,
|
name=self.container_name,
|
||||||
ports={
|
ports={
|
||||||
"8888/tcp": (f"127.0.0.1", f"{self.port}/tcp")
|
"8888/tcp": (f"127.0.0.1", f"{self.port}/tcp")
|
||||||
},
|
} if self.port else {},
|
||||||
environment={
|
environment={
|
||||||
"JUPYTER_ENABLE_LAB": "yes",
|
"JUPYTER_ENABLE_LAB": "yes",
|
||||||
"RESTARTABLE": "yes",
|
"RESTARTABLE": "yes",
|
||||||
|
@ -462,6 +501,7 @@ class Notebook(SophonGroupModel):
|
||||||
"mode": "rw",
|
"mode": "rw",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
network=network.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.log.debug("Storing container_id in the SQL database...")
|
self.log.debug("Storing container_id in the SQL database...")
|
||||||
|
|
16
backend/sophon/notebooks/validators.py
Normal file
16
backend/sophon/notebooks/validators.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
from django.core.validators import ValidationError
|
||||||
|
from django.utils.deconstruct import deconstructible
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@deconstructible
|
||||||
|
class DisallowedValuesValidator:
|
||||||
|
def __init__(self, values):
|
||||||
|
self.values = values
|
||||||
|
|
||||||
|
def __call__(self, value):
|
||||||
|
if value in self.values:
|
||||||
|
raise ValidationError(
|
||||||
|
_("%(value)s is a disallowed value."),
|
||||||
|
params={"value": value},
|
||||||
|
)
|
|
@ -10,176 +10,36 @@ For the full list of settings and their values, see
|
||||||
https://docs.djangoproject.com/en/3.1/ref/settings/
|
https://docs.djangoproject.com/en/3.1/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import logging.config
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
import pathlib
|
||||||
|
import platform
|
||||||
|
import secrets
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
import coloredlogs
|
||||||
import rest_framework.authentication
|
import rest_framework.authentication
|
||||||
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
# <editor-fold desc="[Logging]">
|
||||||
|
|
||||||
|
# This must be the first thing set, or logging won't work properly.
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
log = logging.getLogger(__name__)
|
||||||
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
|
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
|
||||||
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY", "change-me-in-production")
|
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
|
||||||
DEBUG = bool(os.environ.get("DJANGO_DEBUG"))
|
|
||||||
|
|
||||||
ALLOWED_HOSTS = []
|
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
|
||||||
'django.contrib.admin',
|
|
||||||
'django.contrib.auth',
|
|
||||||
'django.contrib.contenttypes',
|
|
||||||
'django.contrib.sessions',
|
|
||||||
'django.contrib.messages',
|
|
||||||
'django.contrib.staticfiles',
|
|
||||||
'django.contrib.postgres',
|
|
||||||
'corsheaders',
|
|
||||||
'rest_framework',
|
|
||||||
'rest_framework.authtoken',
|
|
||||||
'sophon.core',
|
|
||||||
'sophon.projects',
|
|
||||||
'sophon.notebooks',
|
|
||||||
]
|
|
||||||
|
|
||||||
MIDDLEWARE = [
|
|
||||||
'corsheaders.middleware.CorsMiddleware',
|
|
||||||
'django.middleware.security.SecurityMiddleware',
|
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
||||||
'django.middleware.common.CommonMiddleware',
|
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
|
||||||
]
|
|
||||||
|
|
||||||
ROOT_URLCONF = 'sophon.urls'
|
|
||||||
|
|
||||||
TEMPLATES = [
|
|
||||||
{
|
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
|
||||||
'DIRS': [],
|
|
||||||
'APP_DIRS': True,
|
|
||||||
'OPTIONS': {
|
|
||||||
'context_processors': [
|
|
||||||
'django.template.context_processors.debug',
|
|
||||||
'django.template.context_processors.request',
|
|
||||||
'django.contrib.auth.context_processors.auth',
|
|
||||||
'django.contrib.messages.context_processors.messages',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
WSGI_APPLICATION = 'sophon.wsgi.application'
|
|
||||||
|
|
||||||
|
|
||||||
# Database
|
|
||||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
|
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
|
||||||
'ENGINE': 'django.db.backends.postgresql',
|
|
||||||
'HOST': os.environ.get("DJANGO_DATABASE_HOST", ""), # Connect via UNIX socket (does not work on Windows)
|
|
||||||
'NAME': os.environ.get("DJANGO_DATABASE_NAME", "sophon"),
|
|
||||||
'USER': os.environ.get("DJANGO_DATABASE_USER", "sophon"), # Connect using its own user, isolating sophon from the rest of the server
|
|
||||||
'PASSWORD': os.environ.get("DJANGO_DATABASE_PASSWORD", ""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Remember to run the following commands on a new installation:
|
|
||||||
# sudo -iu postgres
|
|
||||||
# createuser sophon
|
|
||||||
# createdb --owner=sophon sophon
|
|
||||||
#
|
|
||||||
# If you need to run tests, also ensure `sophon` is a superuser, or it won't be able to create and drop the testing database!
|
|
||||||
|
|
||||||
|
|
||||||
# Password validation
|
|
||||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
|
|
||||||
|
|
||||||
AUTH_PASSWORD_VALIDATORS = [
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
|
||||||
'django_pam.auth.backends.PAMBackend',
|
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
|
||||||
# https://docs.djangoproject.com/en/3.1/topics/i18n/
|
|
||||||
|
|
||||||
LANGUAGE_CODE = os.environ.get("DJANGO_LANGUAGE_CODE", "en-us")
|
|
||||||
|
|
||||||
TIME_ZONE = os.environ.get("DJANGO_TIME_ZONE", "UTC")
|
|
||||||
|
|
||||||
USE_I18N = True
|
|
||||||
|
|
||||||
USE_L10N = True
|
|
||||||
|
|
||||||
USE_TZ = True
|
|
||||||
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
|
||||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
|
||||||
|
|
||||||
|
|
||||||
# Django REST framework
|
|
||||||
# https://www.django-rest-framework.org/#example
|
|
||||||
|
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
|
||||||
# Use Django's standard `django.contrib.auth` permissions,
|
|
||||||
# or allow read-only access for unauthenticated users.
|
|
||||||
'DEFAULT_PERMISSION_CLASSES': [
|
|
||||||
'rest_framework.permissions.AllowAny'
|
|
||||||
],
|
|
||||||
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
|
||||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
|
||||||
'rest_framework.authentication.BasicAuthentication',
|
|
||||||
'rest_framework.authentication.SessionAuthentication',
|
|
||||||
'sophon.auth1.BearerTokenAuthentication',
|
|
||||||
],
|
|
||||||
'PAGE_SIZE': 100,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Logging
|
|
||||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#std:setting-LOGGING
|
|
||||||
|
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"formatters": {
|
"formatters": {
|
||||||
"detail": {
|
"detail": {
|
||||||
"format": "{asctime}\t| {levelname}\t| {name}\t| {message}",
|
"()": coloredlogs.ColoredFormatter,
|
||||||
|
"format": "{asctime:>19} | {name:<24} | {levelname:>8} | {message}",
|
||||||
"style": "{",
|
"style": "{",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"handlers": {
|
"handlers": {
|
||||||
"console": {
|
"console": {
|
||||||
|
# Log to console
|
||||||
"class": "logging.StreamHandler",
|
"class": "logging.StreamHandler",
|
||||||
"level": "DEBUG",
|
"level": os.environ.get("LOGGING_LEVEL", "INFO"),
|
||||||
"stream": "ext://sys.stdout",
|
"stream": "ext://sys.stdout",
|
||||||
"formatter": "detail",
|
"formatter": "detail",
|
||||||
},
|
},
|
||||||
|
@ -199,8 +59,330 @@ LOGGING = {
|
||||||
"handlers": ["console"],
|
"handlers": ["console"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logging.config.dictConfig(LOGGING)
|
||||||
|
|
||||||
# CORS
|
# </editor-fold>
|
||||||
|
|
||||||
CORS_ALLOWED_ORIGINS = os.environ["DJANGO_CORS_ALLOWED_ORIGINS"].split("|")
|
# <editor-fold desc="[Dynamic settings]">
|
||||||
|
|
||||||
|
# Set the cookie secret key
|
||||||
|
try:
|
||||||
|
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_SECRET_KEY wasn't changed from the default value, cookies will be invalidated at every launch")
|
||||||
|
SECRET_KEY = secrets.token_urlsafe(24)
|
||||||
|
log.debug(f"SECRET_KEY = {'*' * len(SECRET_KEY)}")
|
||||||
|
|
||||||
|
|
||||||
|
# Set debug mode
|
||||||
|
DEBUG = __debug__
|
||||||
|
if DEBUG:
|
||||||
|
log.warning("DEBUG mode is on, run the Python interpreter with the -O option to disable.")
|
||||||
|
log.debug(f"{DEBUG = }")
|
||||||
|
|
||||||
|
|
||||||
|
# Set the hosts from which the admin page can be accessed, separated by pipes
|
||||||
|
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "").split("|") if "DJANGO_ALLOWED_HOSTS" in os.environ else []
|
||||||
|
if len(ALLOWED_HOSTS) == 0:
|
||||||
|
log.warning(f"No DJANGO_ALLOWED_HOSTS are set, the admin page may not be accessible.")
|
||||||
|
log.debug(f"{ALLOWED_HOSTS = }")
|
||||||
|
|
||||||
|
# Set the origins from which the API can be called, separated by pipes
|
||||||
|
CORS_ALLOWED_ORIGINS = os.environ.get("DJANGO_ALLOWED_ORIGINS", "").split("|") if "DJANGO_ALLOWED_ORIGINS" in os.environ else []
|
||||||
|
if len(CORS_ALLOWED_ORIGINS) == 0:
|
||||||
|
log.warning(f"No DJANGO_ALLOWED_ORIGINS are set, the API may not be usable.")
|
||||||
|
log.debug(f"{CORS_ALLOWED_ORIGINS = }")
|
||||||
|
|
||||||
|
# Set the database engine to use with Sophon
|
||||||
|
try:
|
||||||
|
DATABASE_ENGINE = os.environ["DJANGO_DATABASE_ENGINE"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_DATABASE_ENGINE was not set, defaulting to PostgreSQL")
|
||||||
|
DATABASE_ENGINE = "django.db.backends.postgresql"
|
||||||
|
log.debug(f"{DATABASE_ENGINE = }")
|
||||||
|
|
||||||
|
# Set the dbms to use with Sophon
|
||||||
|
try:
|
||||||
|
DATABASE_HOST = os.environ["DJANGO_DATABASE_HOST"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_DATABASE_HOST was not set, defaulting to the local PostgreSQL UNIX socket")
|
||||||
|
DATABASE_HOST = ""
|
||||||
|
log.debug(f"{DATABASE_HOST = }")
|
||||||
|
|
||||||
|
# Set the database name to use with Sophon
|
||||||
|
try:
|
||||||
|
DATABASE_NAME = os.environ["DJANGO_DATABASE_NAME"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_DATABASE_NAME was not set, defaulting to `sophon`")
|
||||||
|
DATABASE_NAME = "sophon"
|
||||||
|
log.debug(f"{DATABASE_NAME = }")
|
||||||
|
|
||||||
|
# Set the database user to login to the database as
|
||||||
|
try:
|
||||||
|
DATABASE_USER = os.environ["DJANGO_DATABASE_USER"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_DATABASE_USER was not set, defaulting to `sophon`")
|
||||||
|
DATABASE_USER = "sophon"
|
||||||
|
log.debug(f"{DATABASE_USER = }")
|
||||||
|
|
||||||
|
# Set the database password to login to the database with
|
||||||
|
try:
|
||||||
|
DATABASE_PASSWORD = os.environ["DJANGO_DATABASE_PASSWORD"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_DATABASE_PASSWORD was not set, defaulting to none")
|
||||||
|
DATABASE_PASSWORD = ""
|
||||||
|
log.debug(f"DATABASE_PASSWORD = {'*' * len(DATABASE_PASSWORD)}")
|
||||||
|
|
||||||
|
# Set the authentication backend to use to authenticate users
|
||||||
|
try:
|
||||||
|
AUTHENTICATION_BACKEND = os.environ["DJANGO_AUTHENTICATION_BACKEND"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_AUTHENTICATION_BACKEND was not set, defaulting to the standard Django model authentication")
|
||||||
|
AUTHENTICATION_BACKEND = "django.contrib.auth.backends.ModelBackend"
|
||||||
|
log.debug(f"{AUTHENTICATION_BACKEND = }")
|
||||||
|
|
||||||
|
# Set the language to use in the admin page
|
||||||
|
try:
|
||||||
|
LANGUAGE_CODE = os.environ["DJANGO_LANGUAGE_CODE"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_LANGUAGE_CODE was not set, defaulting to American English")
|
||||||
|
LANGUAGE_CODE = "en-us"
|
||||||
|
log.debug(f"{LANGUAGE_CODE = }")
|
||||||
|
|
||||||
|
# Set the time zone to use
|
||||||
|
try:
|
||||||
|
TIME_ZONE = os.environ["DJANGO_TIME_ZONE"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_TIME_ZONE was not set, defaulting to UTC")
|
||||||
|
TIME_ZONE = "UTC"
|
||||||
|
log.debug(f"{TIME_ZONE = }")
|
||||||
|
|
||||||
|
# Set the directory to create static files at
|
||||||
|
try:
|
||||||
|
STATIC_ROOT = os.environ["DJANGO_STATIC_ROOT"]
|
||||||
|
except KeyError:
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
log.warning("DJANGO_STATIC_ROOT was not set, defaulting to `.\\static`")
|
||||||
|
# I have no idea of why IDEA is trying to resolve this
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
|
STATIC_ROOT = ".\\static"
|
||||||
|
else:
|
||||||
|
log.warning("DJANGO_STATIC_ROOT was not set, defaulting to `/run/sophon/static`")
|
||||||
|
# I have no idea of why IDEA is trying to resolve this
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
|
STATIC_ROOT = "/run/sophon/static"
|
||||||
|
log.debug(f"{STATIC_ROOT = }")
|
||||||
|
|
||||||
|
# Set the URL where static files are served at
|
||||||
|
try:
|
||||||
|
STATIC_URL = os.environ["DJANGO_STATIC_URL"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_STATIC_URL was not set, defaulting to `/static/`")
|
||||||
|
STATIC_URL = "/static/"
|
||||||
|
log.debug(f"{STATIC_URL = }")
|
||||||
|
|
||||||
|
# Set the directory where the apache proxy file will be created
|
||||||
|
try:
|
||||||
|
PROXY_FILE = os.environ["DJANGO_PROXY_FILE"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_PROXY_FILE was not set, defaulting to `./proxy.dbm`")
|
||||||
|
PROXY_FILE = "./proxy.dbm"
|
||||||
|
log.debug(f"{PROXY_FILE = }")
|
||||||
|
|
||||||
|
# Set the protocol that the proxy will use
|
||||||
|
try:
|
||||||
|
PROXY_PROTOCOL = os.environ["DJANGO_PROXY_PROTOCOL"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_PROXY_PROTOCOL was not set, defaulting to HTTPS")
|
||||||
|
PROXY_PROTOCOL = "https"
|
||||||
|
if PROXY_PROTOCOL not in ["http", "https"]:
|
||||||
|
log.warning("Unrecognized DJANGO_PROXY_PROTOCOL, acceptable values are `http` and `https`.")
|
||||||
|
log.debug(f"{PROXY_PROTOCOL = }")
|
||||||
|
|
||||||
|
# Set the base domain that the proxy will use
|
||||||
|
try:
|
||||||
|
PROXY_BASE_DOMAIN = os.environ["DJANGO_PROXY_BASE_DOMAIN"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_PROXY_BASE_DOMAIN was not set, defaulting to `dev.sophon.steffo.eu`")
|
||||||
|
PROXY_BASE_DOMAIN = "dev.sophon.steffo.eu"
|
||||||
|
log.debug(f"{PROXY_BASE_DOMAIN = }")
|
||||||
|
|
||||||
|
# Set the name of the proxy docker container
|
||||||
|
PROXY_CONTAINER_NAME = os.environ.get("DJANGO_PROXY_CONTAINER_NAME")
|
||||||
|
log.debug(f"{PROXY_CONTAINER_NAME =}")
|
||||||
|
|
||||||
|
# Set the prefix to add to all instantiated notebook container names
|
||||||
|
try:
|
||||||
|
DOCKER_CONTAINER_PREFIX = os.environ["DJANGO_DOCKER_CONTAINER_PREFIX"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DOCKER_CONTAINER_PREFIX was not set, defaulting to `sophon-container`")
|
||||||
|
DOCKER_CONTAINER_PREFIX = "sophon-container"
|
||||||
|
log.debug(f"{DOCKER_CONTAINER_PREFIX = }")
|
||||||
|
|
||||||
|
# Set the prefix to add to all instantiated notebook volume names
|
||||||
|
try:
|
||||||
|
DOCKER_VOLUME_PREFIX = os.environ["DJANGO_DOCKER_VOLUME_PREFIX"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DOCKER_VOLUME_PREFIX was not set, defaulting to `sophon-volume`")
|
||||||
|
DOCKER_VOLUME_PREFIX = "sophon-volume"
|
||||||
|
log.debug(f"{DOCKER_VOLUME_PREFIX = }")
|
||||||
|
|
||||||
|
# Set the prefix to add to all instantiated notebook network names
|
||||||
|
try:
|
||||||
|
DOCKER_NETWORK_PREFIX = os.environ["DJANGO_DOCKER_NETWORK_PREFIX"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DOCKER_VOLUME_PREFIX was not set, defaulting to `sophon-network`")
|
||||||
|
DOCKER_NETWORK_PREFIX = "sophon-network"
|
||||||
|
log.debug(f"{DOCKER_NETWORK_PREFIX = }")
|
||||||
|
|
||||||
|
try:
|
||||||
|
DOCKER_HOST = os.environ["DJANGO_DOCKER_HOST"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_DOCKER_HOST was not set, defaulting to none (may cause problems)")
|
||||||
|
DOCKER_HOST = None
|
||||||
|
log.debug(f"{DOCKER_HOST = }")
|
||||||
|
|
||||||
|
try:
|
||||||
|
DOCKER_TLS_VERIFY = os.environ["DJANGO_DOCKER_TLS_VERIFY"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_DOCKER_TLS_VERIFY was not set, defaulting to none (may cause problems)")
|
||||||
|
DOCKER_TLS_VERIFY = None
|
||||||
|
log.debug(f"{DOCKER_TLS_VERIFY = }")
|
||||||
|
|
||||||
|
try:
|
||||||
|
DOCKER_CERT_PATH = os.environ["DJANGO_DOCKER_CERT_PATH"]
|
||||||
|
except KeyError:
|
||||||
|
log.warning("DJANGO_DOCKER_CERT_PATH was not set, defaulting to none (may cause problems)")
|
||||||
|
DOCKER_CERT_PATH = None
|
||||||
|
log.debug(f"{DOCKER_CERT_PATH = }")
|
||||||
|
|
||||||
|
# </editor-fold>
|
||||||
|
|
||||||
|
# <editor-fold desc="[Static settings]">
|
||||||
|
|
||||||
|
# Set the base project directory
|
||||||
|
BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
# Define the installed django apps
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
'django.contrib.postgres',
|
||||||
|
'corsheaders',
|
||||||
|
'rest_framework',
|
||||||
|
'rest_framework.authtoken',
|
||||||
|
'sophon.core',
|
||||||
|
'sophon.projects', # Can be removed safely!
|
||||||
|
'sophon.notebooks', # Can be removed safely!
|
||||||
|
]
|
||||||
|
|
||||||
|
# Define the installed middleware
|
||||||
|
MIDDLEWARE = [
|
||||||
|
'corsheaders.middleware.CorsMiddleware',
|
||||||
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Define the root urlconf of the project
|
||||||
|
ROOT_URLCONF = 'sophon.urls'
|
||||||
|
|
||||||
|
# Define the installed template engines
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
|
'DIRS': [],
|
||||||
|
'APP_DIRS': True,
|
||||||
|
'OPTIONS': {
|
||||||
|
'context_processors': [
|
||||||
|
'django.template.context_processors.debug',
|
||||||
|
'django.template.context_processors.request',
|
||||||
|
'django.contrib.auth.context_processors.auth',
|
||||||
|
'django.contrib.messages.context_processors.messages',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Define the path to the project wsgi application
|
||||||
|
WSGI_APPLICATION = 'sophon.wsgi.application'
|
||||||
|
|
||||||
|
# Configure the database
|
||||||
|
#
|
||||||
|
# Remember to run the following commands on a new installation:
|
||||||
|
# sudo -iu postgres
|
||||||
|
# createuser sophon
|
||||||
|
# createdb --owner=sophon sophon
|
||||||
|
#
|
||||||
|
# If you need to run tests, also ensure `sophon` is a superuser, or it won't be able to create and drop the testing database!
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': DATABASE_ENGINE,
|
||||||
|
'HOST': DATABASE_HOST, # Connect via UNIX socket (does not work on Windows)
|
||||||
|
'NAME': DATABASE_NAME,
|
||||||
|
'USER': DATABASE_USER, # Connect using its own user, isolating sophon from the rest of the server
|
||||||
|
'PASSWORD': DATABASE_PASSWORD,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Define the Django model password validators
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Define the Django authentication backends
|
||||||
|
AUTHENTICATION_BACKENDS = [
|
||||||
|
AUTHENTICATION_BACKEND,
|
||||||
|
]
|
||||||
|
|
||||||
|
# Enable translation
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
# Enable formatting
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
# Enable timezones
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
# Configure Django Rest Framework for the Sophon API
|
||||||
|
REST_FRAMEWORK = {
|
||||||
|
'DEFAULT_PERMISSION_CLASSES': [
|
||||||
|
# Allow requests from all kinds of users
|
||||||
|
'rest_framework.permissions.AllowAny'
|
||||||
|
],
|
||||||
|
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||||
|
# Allow basic authentication
|
||||||
|
'rest_framework.authentication.BasicAuthentication',
|
||||||
|
# Allow session authentication
|
||||||
|
'rest_framework.authentication.SessionAuthentication',
|
||||||
|
# Allow bearer authentication
|
||||||
|
'sophon.auth1.BearerTokenAuthentication',
|
||||||
|
],
|
||||||
|
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
|
||||||
|
# Paginate in groups of 100 resources
|
||||||
|
'PAGE_SIZE': 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Specify the URLs where the CORS middleware should be applied to
|
||||||
CORS_URLS_REGEX = r"^/api/"
|
CORS_URLS_REGEX = r"^/api/"
|
||||||
|
|
||||||
|
# </editor-fold>
|
||||||
|
|
98
docker-compose.yml
Normal file
98
docker-compose.yml
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
proxy-data:
|
||||||
|
django-static:
|
||||||
|
react-static:
|
||||||
|
db-data:
|
||||||
|
|
||||||
|
|
||||||
|
networks:
|
||||||
|
bone:
|
||||||
|
|
||||||
|
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres
|
||||||
|
volumes:
|
||||||
|
- db-data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
# Don't change these.
|
||||||
|
- POSTGRES_USER=sophon
|
||||||
|
- POSTGRES_PASSWORD=sophonity
|
||||||
|
- POSTGRES_DB=sophon
|
||||||
|
networks:
|
||||||
|
- bone
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image: steffo45/sophon-frontend
|
||||||
|
environment:
|
||||||
|
- REACT_APP_DEFAULT_INSTANCE=http://api.dev.sophon.steffo.eu
|
||||||
|
networks:
|
||||||
|
- bone
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image: steffo45/sophon-backend
|
||||||
|
environment:
|
||||||
|
# TODO: Set a random secret key!
|
||||||
|
- DJANGO_SECRET_KEY=change-me!!!
|
||||||
|
# TODO: Configure your allowed hosts!
|
||||||
|
- DJANGO_ALLOWED_HOSTS=api.dev.sophon.steffo.eu
|
||||||
|
# TODO: Configure your allowed origins! (* doesn't work)
|
||||||
|
- DJANGO_ALLOWED_ORIGINS=http://dev.sophon.steffo.eu
|
||||||
|
# TODO: Configure your proxy details!
|
||||||
|
- DJANGO_PROXY_BASE_DOMAIN=dev.sophon.steffo.eu
|
||||||
|
- DJANGO_PROXY_PROTOCOL=http
|
||||||
|
- DJANGO_PROXY_CONTAINER_NAME=sophon2-proxy-1 # The correct name probably is $DIRECTORYNAME-proxy-1
|
||||||
|
# TODO: Configure your static url!
|
||||||
|
- DJANGO_STATIC_URL=http://static.dev.sophon.steffo.eu/django-static/
|
||||||
|
# TODO: Set your language!
|
||||||
|
- DJANGO_LANGUAGE_CODE=en-us
|
||||||
|
# TODO: Set your timezone!
|
||||||
|
- DJANGO_TIME_ZONE=CET
|
||||||
|
# TODO: Set the superuser login details!
|
||||||
|
- DJANGO_SU_USERNAME=root
|
||||||
|
- DJANGO_SU_EMAIL=root@example.org
|
||||||
|
- DJANGO_SU_PASSWORD=square
|
||||||
|
# Don't change these.
|
||||||
|
- DJANGO_DATABASE_ENGINE=django.db.backends.postgresql
|
||||||
|
- DJANGO_DATABASE_HOST=db
|
||||||
|
- DJANGO_DATABASE_USER=sophon
|
||||||
|
- DJANGO_DATABASE_PASSWORD=sophonity
|
||||||
|
- DJANGO_DATABASE_NAME=sophon
|
||||||
|
- DJANGO_AUTHENTICATION_BACKEND=django.contrib.auth.backends.ModelBackend
|
||||||
|
- DJANGO_DOCKER_CONTAINER_PREFIX=sophon-container
|
||||||
|
- DJANGO_DOCKER_VOLUME_PREFIX=sophon-volume
|
||||||
|
- DJANGO_DOCKER_NETWORK_PREFIX=sophon-network
|
||||||
|
- DJANGO_DOCKER_HOST=/var/run/docker.sock
|
||||||
|
- DJANGO_DOCKER_TLS_VERIFY=
|
||||||
|
- DJANGO_DOCKER_CERT_PATH=
|
||||||
|
volumes:
|
||||||
|
- proxy-data:/run/sophon/proxy
|
||||||
|
- django-static:/run/sophon/static
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
networks:
|
||||||
|
- bone
|
||||||
|
|
||||||
|
proxy:
|
||||||
|
image: steffo45/sophon-proxy
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
environment:
|
||||||
|
# TODO: Configure your proxy details!
|
||||||
|
- APACHE_PROXY_BASE_DOMAIN=dev.sophon.steffo.eu
|
||||||
|
#`Don't change these.
|
||||||
|
- SOPHON_BACKEND_NAME=backend:8000
|
||||||
|
- SOPHON_FRONTEND_NAME=frontend:5000
|
||||||
|
volumes:
|
||||||
|
- proxy-data:/run/sophon/proxy
|
||||||
|
- django-static:/usr/local/apache2/htdocs/django-static
|
||||||
|
- react-static:/usr/local/apache2/htdocs/react-static
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
- frontend
|
||||||
|
networks:
|
||||||
|
- bone
|
1
frontend/.dockerignore
Symbolic link
1
frontend/.dockerignore
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
.gitignore
|
19
frontend/Dockerfile
Normal file
19
frontend/Dockerfile
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
FROM node:16.11.1-bullseye
|
||||||
|
LABEL maintainer="Stefano Pigozzi <me@steffo.eu>"
|
||||||
|
|
||||||
|
# Set the base workdir
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
# Copy the yarn files
|
||||||
|
COPY package.json ./package.json
|
||||||
|
COPY yarn.lock ./yarn.lock
|
||||||
|
|
||||||
|
# Install the package
|
||||||
|
RUN yarn install
|
||||||
|
|
||||||
|
# Copy the rest of the project into the container
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Start the serve server
|
||||||
|
ENTRYPOINT ["yarn", "run"]
|
||||||
|
CMD ["serve"]
|
|
@ -5,6 +5,7 @@
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/src/components/legacy" />
|
<excludeFolder url="file://$MODULE_DIR$/src/components/legacy" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Poetry (frontend)" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Poetry (frontend)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"react-markdown": "^7.0.1",
|
"react-markdown": "^7.0.1",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"react-storage-hooks": "^4.0.1",
|
"react-storage-hooks": "^4.0.1",
|
||||||
|
"serve": "^12.0.1",
|
||||||
"typescript": "^4.1.2",
|
"typescript": "^4.1.2",
|
||||||
"web-vitals": "^1.0.1"
|
"web-vitals": "^1.0.1"
|
||||||
},
|
},
|
||||||
|
@ -29,7 +30,8 @@
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject",
|
||||||
|
"serve": "react-scripts build && serve -s build"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
|
|
|
@ -3,12 +3,13 @@ import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"
|
||||||
import {Box, Heading, Idiomatic} from "@steffo/bluelib-react"
|
import {Box, Heading, Idiomatic} from "@steffo/bluelib-react"
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import ReactMarkdown from "react-markdown"
|
import ReactMarkdown from "react-markdown"
|
||||||
|
import {Empty} from "./Empty"
|
||||||
|
|
||||||
|
|
||||||
export interface DescriptionBoxProps {
|
export interface DescriptionBoxProps {
|
||||||
icon: IconDefinition,
|
icon: IconDefinition,
|
||||||
name: string,
|
name: string,
|
||||||
description: string,
|
description?: string | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,9 +20,16 @@ export function DescriptionBox({icon, name, description}: DescriptionBoxProps):
|
||||||
<Heading level={3}>
|
<Heading level={3}>
|
||||||
<FontAwesomeIcon icon={icon}/> About <Idiomatic>{name}</Idiomatic>
|
<FontAwesomeIcon icon={icon}/> About <Idiomatic>{name}</Idiomatic>
|
||||||
</Heading>
|
</Heading>
|
||||||
|
{
|
||||||
|
description ?
|
||||||
<ReactMarkdown>
|
<ReactMarkdown>
|
||||||
{description}
|
{description}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
|
:
|
||||||
|
<Empty>
|
||||||
|
This resource has no about text.
|
||||||
|
</Empty>
|
||||||
|
}
|
||||||
</Box>
|
</Box>
|
||||||
),
|
),
|
||||||
[icon, name, description],
|
[icon, name, description],
|
||||||
|
|
|
@ -93,7 +93,7 @@ export function GroupCreateBox({viewSet, resource}: GroupCreateBoxProps): JSX.El
|
||||||
return obj
|
return obj
|
||||||
}).reduce((a, b) => {
|
}).reduce((a, b) => {
|
||||||
return {...a, ...b}
|
return {...a, ...b}
|
||||||
}),
|
}, {}),
|
||||||
[authorization, cache],
|
[authorization, cache],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,6 @@ export function InstanceDescriptionBox(): JSX.Element | null {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!instance.state.details.description) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DescriptionBox
|
<DescriptionBox
|
||||||
icon={faUniversity}
|
icon={faUniversity}
|
||||||
|
|
|
@ -45,7 +45,7 @@ export function CacheProvider({children}: WithChildren): JSX.Element {
|
||||||
return obj
|
return obj
|
||||||
}).reduce((a, b) => {
|
}).reduce((a, b) => {
|
||||||
return {...a, ...b}
|
return {...a, ...b}
|
||||||
})
|
}, {})
|
||||||
},
|
},
|
||||||
[users],
|
[users],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {DjangoResource, DjangoSlug} from "./DjangoTypes";
|
import {DjangoResource, DjangoSlug} from "./DjangoTypes"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,9 +64,8 @@ export interface SophonNotebook extends DjangoResource {
|
||||||
locked_by: number,
|
locked_by: number,
|
||||||
slug: DjangoSlug,
|
slug: DjangoSlug,
|
||||||
legacy_notebook_url: string | null,
|
legacy_notebook_url: string | null,
|
||||||
jupyter_token: string,
|
jupyter_token?: string,
|
||||||
is_running: boolean,
|
is_running: boolean,
|
||||||
internet_access: true,
|
|
||||||
container_image: string,
|
container_image: string,
|
||||||
project: DjangoSlug,
|
project: DjangoSlug,
|
||||||
name: string,
|
name: string,
|
||||||
|
|
|
@ -2350,6 +2350,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
|
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
|
||||||
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
|
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
|
||||||
|
|
||||||
|
"@zeit/schemas@2.6.0":
|
||||||
|
version "2.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.6.0.tgz#004e8e553b4cd53d538bd38eac7bcbf58a867fe3"
|
||||||
|
integrity sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==
|
||||||
|
|
||||||
abab@^2.0.3, abab@^2.0.5:
|
abab@^2.0.3, abab@^2.0.5:
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
|
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
|
||||||
|
@ -2434,7 +2439,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2:
|
||||||
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
|
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
|
||||||
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
|
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
|
||||||
|
|
||||||
ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4, ajv@^6.12.5:
|
ajv@6.12.6, ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4, ajv@^6.12.5:
|
||||||
version "6.12.6"
|
version "6.12.6"
|
||||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||||
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
||||||
|
@ -2459,6 +2464,13 @@ alphanum-sort@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
|
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
|
||||||
integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
|
integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
|
||||||
|
|
||||||
|
ansi-align@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
|
||||||
|
integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
|
||||||
|
dependencies:
|
||||||
|
string-width "^2.0.0"
|
||||||
|
|
||||||
ansi-colors@^3.0.0:
|
ansi-colors@^3.0.0:
|
||||||
version "3.2.4"
|
version "3.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
|
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
|
||||||
|
@ -2486,6 +2498,11 @@ ansi-regex@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||||
integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
|
integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
|
||||||
|
|
||||||
|
ansi-regex@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
|
||||||
|
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
|
||||||
|
|
||||||
ansi-regex@^4.1.0:
|
ansi-regex@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
|
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
|
||||||
|
@ -2536,6 +2553,16 @@ aproba@^1.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
|
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
|
||||||
integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
|
integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
|
||||||
|
|
||||||
|
arch@^2.1.1:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
|
||||||
|
integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
|
||||||
|
|
||||||
|
arg@2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/arg/-/arg-2.0.0.tgz#c06e7ff69ab05b3a4a03ebe0407fac4cba657545"
|
||||||
|
integrity sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==
|
||||||
|
|
||||||
argparse@^1.0.7:
|
argparse@^1.0.7:
|
||||||
version "1.0.10"
|
version "1.0.10"
|
||||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
||||||
|
@ -3037,6 +3064,19 @@ boolbase@^1.0.0, boolbase@~1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||||
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
|
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
|
||||||
|
|
||||||
|
boxen@1.3.0:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
|
||||||
|
integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
|
||||||
|
dependencies:
|
||||||
|
ansi-align "^2.0.0"
|
||||||
|
camelcase "^4.0.0"
|
||||||
|
chalk "^2.0.1"
|
||||||
|
cli-boxes "^1.0.0"
|
||||||
|
string-width "^2.0.0"
|
||||||
|
term-size "^1.2.0"
|
||||||
|
widest-line "^2.0.0"
|
||||||
|
|
||||||
brace-expansion@^1.1.7:
|
brace-expansion@^1.1.7:
|
||||||
version "1.1.11"
|
version "1.1.11"
|
||||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||||
|
@ -3316,6 +3356,11 @@ camelcase@5.3.1, camelcase@^5.0.0, camelcase@^5.3.1:
|
||||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
|
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
|
||||||
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
|
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
|
||||||
|
|
||||||
|
camelcase@^4.0.0:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
|
||||||
|
integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
|
||||||
|
|
||||||
camelcase@^6.0.0, camelcase@^6.1.0, camelcase@^6.2.0:
|
camelcase@^6.0.0, camelcase@^6.1.0, camelcase@^6.2.0:
|
||||||
version "6.2.0"
|
version "6.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
|
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
|
||||||
|
@ -3348,7 +3393,16 @@ case-sensitive-paths-webpack-plugin@2.3.0:
|
||||||
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz#23ac613cc9a856e4f88ff8bb73bbb5e989825cf7"
|
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz#23ac613cc9a856e4f88ff8bb73bbb5e989825cf7"
|
||||||
integrity sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==
|
integrity sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ==
|
||||||
|
|
||||||
chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
|
chalk@2.4.1:
|
||||||
|
version "2.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
|
||||||
|
integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==
|
||||||
|
dependencies:
|
||||||
|
ansi-styles "^3.2.1"
|
||||||
|
escape-string-regexp "^1.0.5"
|
||||||
|
supports-color "^5.3.0"
|
||||||
|
|
||||||
|
chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2:
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||||
|
@ -3492,6 +3546,20 @@ clean-stack@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
|
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
|
||||||
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
|
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
|
||||||
|
|
||||||
|
cli-boxes@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
|
||||||
|
integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
|
||||||
|
|
||||||
|
clipboardy@2.3.0:
|
||||||
|
version "2.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-2.3.0.tgz#3c2903650c68e46a91b388985bc2774287dba290"
|
||||||
|
integrity sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==
|
||||||
|
dependencies:
|
||||||
|
arch "^2.1.1"
|
||||||
|
execa "^1.0.0"
|
||||||
|
is-wsl "^2.1.1"
|
||||||
|
|
||||||
cliui@^5.0.0:
|
cliui@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
|
resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
|
||||||
|
@ -3628,13 +3696,26 @@ compose-function@3.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
arity-n "^1.0.4"
|
arity-n "^1.0.4"
|
||||||
|
|
||||||
compressible@~2.0.16:
|
compressible@~2.0.14, compressible@~2.0.16:
|
||||||
version "2.0.18"
|
version "2.0.18"
|
||||||
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
|
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
|
||||||
integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
|
integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
|
||||||
dependencies:
|
dependencies:
|
||||||
mime-db ">= 1.43.0 < 2"
|
mime-db ">= 1.43.0 < 2"
|
||||||
|
|
||||||
|
compression@1.7.3:
|
||||||
|
version "1.7.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db"
|
||||||
|
integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==
|
||||||
|
dependencies:
|
||||||
|
accepts "~1.3.5"
|
||||||
|
bytes "3.0.0"
|
||||||
|
compressible "~2.0.14"
|
||||||
|
debug "2.6.9"
|
||||||
|
on-headers "~1.0.1"
|
||||||
|
safe-buffer "5.1.2"
|
||||||
|
vary "~1.1.2"
|
||||||
|
|
||||||
compression@^1.7.4:
|
compression@^1.7.4:
|
||||||
version "1.7.4"
|
version "1.7.4"
|
||||||
resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
|
resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
|
||||||
|
@ -3683,6 +3764,11 @@ constants-browserify@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
|
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
|
||||||
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
|
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
|
||||||
|
|
||||||
|
content-disposition@0.5.2:
|
||||||
|
version "0.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
|
||||||
|
integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ=
|
||||||
|
|
||||||
content-disposition@0.5.3:
|
content-disposition@0.5.3:
|
||||||
version "0.5.3"
|
version "0.5.3"
|
||||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
|
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
|
||||||
|
@ -3849,6 +3935,15 @@ cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2:
|
||||||
shebang-command "^2.0.0"
|
shebang-command "^2.0.0"
|
||||||
which "^2.0.1"
|
which "^2.0.1"
|
||||||
|
|
||||||
|
cross-spawn@^5.0.1:
|
||||||
|
version "5.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
|
||||||
|
integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
|
||||||
|
dependencies:
|
||||||
|
lru-cache "^4.0.1"
|
||||||
|
shebang-command "^1.2.0"
|
||||||
|
which "^1.2.9"
|
||||||
|
|
||||||
cross-spawn@^6.0.0:
|
cross-spawn@^6.0.0:
|
||||||
version "6.0.5"
|
version "6.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||||
|
@ -4203,6 +4298,11 @@ deep-equal@^1.0.1:
|
||||||
object-keys "^1.1.1"
|
object-keys "^1.1.1"
|
||||||
regexp.prototype.flags "^1.2.0"
|
regexp.prototype.flags "^1.2.0"
|
||||||
|
|
||||||
|
deep-extend@^0.6.0:
|
||||||
|
version "0.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||||
|
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||||
|
|
||||||
deep-is@^0.1.3, deep-is@~0.1.3:
|
deep-is@^0.1.3, deep-is@~0.1.3:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
|
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
|
||||||
|
@ -4993,6 +5093,19 @@ exec-sh@^0.3.2:
|
||||||
resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc"
|
resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc"
|
||||||
integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==
|
integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==
|
||||||
|
|
||||||
|
execa@^0.7.0:
|
||||||
|
version "0.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
|
||||||
|
integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
|
||||||
|
dependencies:
|
||||||
|
cross-spawn "^5.0.1"
|
||||||
|
get-stream "^3.0.0"
|
||||||
|
is-stream "^1.1.0"
|
||||||
|
npm-run-path "^2.0.0"
|
||||||
|
p-finally "^1.0.0"
|
||||||
|
signal-exit "^3.0.0"
|
||||||
|
strip-eof "^1.0.0"
|
||||||
|
|
||||||
execa@^1.0.0:
|
execa@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
|
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
|
||||||
|
@ -5154,6 +5267,13 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
|
||||||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||||
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
||||||
|
|
||||||
|
fast-url-parser@1.1.3:
|
||||||
|
version "1.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d"
|
||||||
|
integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=
|
||||||
|
dependencies:
|
||||||
|
punycode "^1.3.2"
|
||||||
|
|
||||||
fastq@^1.6.0:
|
fastq@^1.6.0:
|
||||||
version "1.13.0"
|
version "1.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
|
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
|
||||||
|
@ -5460,6 +5580,11 @@ get-package-type@^0.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
|
resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
|
||||||
integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
|
integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
|
||||||
|
|
||||||
|
get-stream@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||||
|
integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
|
||||||
|
|
||||||
get-stream@^4.0.0:
|
get-stream@^4.0.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
|
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
|
||||||
|
@ -6019,7 +6144,7 @@ inherits@2.0.3:
|
||||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||||
|
|
||||||
ini@^1.3.5:
|
ini@^1.3.5, ini@~1.3.0:
|
||||||
version "1.3.8"
|
version "1.3.8"
|
||||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
|
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
|
||||||
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
|
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
|
||||||
|
@ -7325,6 +7450,14 @@ lower-case@^2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.0.3"
|
tslib "^2.0.3"
|
||||||
|
|
||||||
|
lru-cache@^4.0.1:
|
||||||
|
version "4.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
|
||||||
|
integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
|
||||||
|
dependencies:
|
||||||
|
pseudomap "^1.0.2"
|
||||||
|
yallist "^2.1.2"
|
||||||
|
|
||||||
lru-cache@^5.1.1:
|
lru-cache@^5.1.1:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
||||||
|
@ -7737,6 +7870,18 @@ mime-db@1.50.0, "mime-db@>= 1.43.0 < 2":
|
||||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f"
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f"
|
||||||
integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==
|
integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==
|
||||||
|
|
||||||
|
mime-db@~1.33.0:
|
||||||
|
version "1.33.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
|
||||||
|
integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==
|
||||||
|
|
||||||
|
mime-types@2.1.18:
|
||||||
|
version "2.1.18"
|
||||||
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
|
||||||
|
integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==
|
||||||
|
dependencies:
|
||||||
|
mime-db "~1.33.0"
|
||||||
|
|
||||||
mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.24:
|
mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.24:
|
||||||
version "2.1.33"
|
version "2.1.33"
|
||||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb"
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb"
|
||||||
|
@ -8238,7 +8383,7 @@ on-finished@~2.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
ee-first "1.1.1"
|
ee-first "1.1.1"
|
||||||
|
|
||||||
on-headers@~1.0.2:
|
on-headers@~1.0.1, on-headers@~1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
|
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
|
||||||
integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
|
integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
|
||||||
|
@ -8515,7 +8660,7 @@ path-is-absolute@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||||
|
|
||||||
path-is-inside@^1.0.2:
|
path-is-inside@1.0.2, path-is-inside@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
|
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
|
||||||
integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
|
integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
|
||||||
|
@ -8540,6 +8685,11 @@ path-to-regexp@0.1.7:
|
||||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
|
||||||
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
|
||||||
|
|
||||||
|
path-to-regexp@2.2.1:
|
||||||
|
version "2.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45"
|
||||||
|
integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==
|
||||||
|
|
||||||
path-type@^3.0.0:
|
path-type@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
|
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
|
||||||
|
@ -9452,6 +9602,11 @@ prr@~1.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
|
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
|
||||||
integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
|
integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
|
||||||
|
|
||||||
|
pseudomap@^1.0.2:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||||
|
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
|
||||||
|
|
||||||
psl@^1.1.33:
|
psl@^1.1.33:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
|
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
|
||||||
|
@ -9499,7 +9654,7 @@ punycode@1.3.2:
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
||||||
integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
|
integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
|
||||||
|
|
||||||
punycode@^1.2.4:
|
punycode@^1.2.4, punycode@^1.3.2:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||||
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
|
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
|
||||||
|
@ -9574,6 +9729,11 @@ randomfill@^1.0.3:
|
||||||
randombytes "^2.0.5"
|
randombytes "^2.0.5"
|
||||||
safe-buffer "^5.1.0"
|
safe-buffer "^5.1.0"
|
||||||
|
|
||||||
|
range-parser@1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
|
||||||
|
integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
|
||||||
|
|
||||||
range-parser@^1.2.1, range-parser@~1.2.1:
|
range-parser@^1.2.1, range-parser@~1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
|
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
|
||||||
|
@ -9589,6 +9749,16 @@ raw-body@2.4.0:
|
||||||
iconv-lite "0.4.24"
|
iconv-lite "0.4.24"
|
||||||
unpipe "1.0.0"
|
unpipe "1.0.0"
|
||||||
|
|
||||||
|
rc@^1.0.1, rc@^1.1.6:
|
||||||
|
version "1.2.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
|
||||||
|
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
|
||||||
|
dependencies:
|
||||||
|
deep-extend "^0.6.0"
|
||||||
|
ini "~1.3.0"
|
||||||
|
minimist "^1.2.0"
|
||||||
|
strip-json-comments "~2.0.1"
|
||||||
|
|
||||||
react-app-polyfill@^2.0.0:
|
react-app-polyfill@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz#a0bea50f078b8a082970a9d853dc34b6dcc6a3cf"
|
resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz#a0bea50f078b8a082970a9d853dc34b6dcc6a3cf"
|
||||||
|
@ -9919,6 +10089,21 @@ regexpu-core@^4.7.1:
|
||||||
unicode-match-property-ecmascript "^2.0.0"
|
unicode-match-property-ecmascript "^2.0.0"
|
||||||
unicode-match-property-value-ecmascript "^2.0.0"
|
unicode-match-property-value-ecmascript "^2.0.0"
|
||||||
|
|
||||||
|
registry-auth-token@3.3.2:
|
||||||
|
version "3.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20"
|
||||||
|
integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==
|
||||||
|
dependencies:
|
||||||
|
rc "^1.1.6"
|
||||||
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
|
registry-url@3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
|
||||||
|
integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
|
||||||
|
dependencies:
|
||||||
|
rc "^1.0.1"
|
||||||
|
|
||||||
regjsgen@^0.5.2:
|
regjsgen@^0.5.2:
|
||||||
version "0.5.2"
|
version "0.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733"
|
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733"
|
||||||
|
@ -10368,6 +10553,20 @@ serialize-javascript@^5.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
randombytes "^2.1.0"
|
randombytes "^2.1.0"
|
||||||
|
|
||||||
|
serve-handler@6.1.3:
|
||||||
|
version "6.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8"
|
||||||
|
integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==
|
||||||
|
dependencies:
|
||||||
|
bytes "3.0.0"
|
||||||
|
content-disposition "0.5.2"
|
||||||
|
fast-url-parser "1.1.3"
|
||||||
|
mime-types "2.1.18"
|
||||||
|
minimatch "3.0.4"
|
||||||
|
path-is-inside "1.0.2"
|
||||||
|
path-to-regexp "2.2.1"
|
||||||
|
range-parser "1.2.0"
|
||||||
|
|
||||||
serve-index@^1.9.1:
|
serve-index@^1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
|
resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
|
||||||
|
@ -10391,6 +10590,21 @@ serve-static@1.14.1:
|
||||||
parseurl "~1.3.3"
|
parseurl "~1.3.3"
|
||||||
send "0.17.1"
|
send "0.17.1"
|
||||||
|
|
||||||
|
serve@^12.0.1:
|
||||||
|
version "12.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/serve/-/serve-12.0.1.tgz#5b0e05849f5ed9b8aab0f30a298c3664bba052bb"
|
||||||
|
integrity sha512-CQ4ikLpxg/wmNM7yivulpS6fhjRiFG6OjmP8ty3/c1SBnSk23fpKmLAV4HboTA2KrZhkUPlDfjDhnRmAjQ5Phw==
|
||||||
|
dependencies:
|
||||||
|
"@zeit/schemas" "2.6.0"
|
||||||
|
ajv "6.12.6"
|
||||||
|
arg "2.0.0"
|
||||||
|
boxen "1.3.0"
|
||||||
|
chalk "2.4.1"
|
||||||
|
clipboardy "2.3.0"
|
||||||
|
compression "1.7.3"
|
||||||
|
serve-handler "6.1.3"
|
||||||
|
update-check "1.5.2"
|
||||||
|
|
||||||
set-blocking@^2.0.0:
|
set-blocking@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
|
||||||
|
@ -10783,6 +10997,14 @@ string-natural-compare@^3.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
|
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
|
||||||
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
|
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
|
||||||
|
|
||||||
|
string-width@^2.0.0, string-width@^2.1.1:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
|
||||||
|
integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
|
||||||
|
dependencies:
|
||||||
|
is-fullwidth-code-point "^2.0.0"
|
||||||
|
strip-ansi "^4.0.0"
|
||||||
|
|
||||||
string-width@^3.0.0, string-width@^3.1.0:
|
string-width@^3.0.0, string-width@^3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
|
||||||
|
@ -10868,6 +11090,13 @@ strip-ansi@^3.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-regex "^2.0.0"
|
ansi-regex "^2.0.0"
|
||||||
|
|
||||||
|
strip-ansi@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
|
||||||
|
integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
|
||||||
|
dependencies:
|
||||||
|
ansi-regex "^3.0.0"
|
||||||
|
|
||||||
strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
|
strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
|
||||||
version "5.2.0"
|
version "5.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
|
||||||
|
@ -10922,6 +11151,11 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
||||||
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
||||||
|
|
||||||
|
strip-json-comments@~2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||||
|
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
|
||||||
|
|
||||||
style-loader@1.3.0:
|
style-loader@1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e"
|
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e"
|
||||||
|
@ -11047,6 +11281,13 @@ tempy@^0.3.0:
|
||||||
type-fest "^0.3.1"
|
type-fest "^0.3.1"
|
||||||
unique-string "^1.0.0"
|
unique-string "^1.0.0"
|
||||||
|
|
||||||
|
term-size@^1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
|
||||||
|
integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=
|
||||||
|
dependencies:
|
||||||
|
execa "^0.7.0"
|
||||||
|
|
||||||
terminal-link@^2.0.0:
|
terminal-link@^2.0.0:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994"
|
resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994"
|
||||||
|
@ -11529,6 +11770,14 @@ upath@^1.1.1, upath@^1.1.2, upath@^1.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
|
resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
|
||||||
integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
|
integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
|
||||||
|
|
||||||
|
update-check@1.5.2:
|
||||||
|
version "1.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.2.tgz#2fe09f725c543440b3d7dabe8971f2d5caaedc28"
|
||||||
|
integrity sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==
|
||||||
|
dependencies:
|
||||||
|
registry-auth-token "3.3.2"
|
||||||
|
registry-url "3.1.0"
|
||||||
|
|
||||||
uri-js@^4.2.2:
|
uri-js@^4.2.2:
|
||||||
version "4.4.1"
|
version "4.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
||||||
|
@ -11937,6 +12186,13 @@ which@^2.0.1, which@^2.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
isexe "^2.0.0"
|
isexe "^2.0.0"
|
||||||
|
|
||||||
|
widest-line@^2.0.0:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc"
|
||||||
|
integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==
|
||||||
|
dependencies:
|
||||||
|
string-width "^2.1.1"
|
||||||
|
|
||||||
word-wrap@^1.2.3, word-wrap@~1.2.3:
|
word-wrap@^1.2.3, word-wrap@~1.2.3:
|
||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
|
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
|
||||||
|
@ -12174,6 +12430,11 @@ y18n@^4.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
|
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
|
||||||
integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
|
integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
|
||||||
|
|
||||||
|
yallist@^2.1.2:
|
||||||
|
version "2.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||||
|
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
|
||||||
|
|
||||||
yallist@^3.0.2:
|
yallist@^3.0.2:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
|
||||||
|
|
4
proxy/Dockerfile
Normal file
4
proxy/Dockerfile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
FROM httpd:2.4
|
||||||
|
LABEL maintainer="Stefano Pigozzi <me@steffo.eu>"
|
||||||
|
|
||||||
|
COPY ./httpd.conf /usr/local/apache2/conf/httpd.conf
|
595
proxy/httpd.conf
Normal file
595
proxy/httpd.conf
Normal file
|
@ -0,0 +1,595 @@
|
||||||
|
#
|
||||||
|
# This is the main Apache HTTP server configuration file. It contains the
|
||||||
|
# configuration directives that give the server its instructions.
|
||||||
|
# See <URL:http://httpd.apache.org/docs/2.4/> for detailed information.
|
||||||
|
# In particular, see
|
||||||
|
# <URL:http://httpd.apache.org/docs/2.4/mod/directives.html>
|
||||||
|
# for a discussion of each configuration directive.
|
||||||
|
#
|
||||||
|
# Do NOT simply read the instructions in here without understanding
|
||||||
|
# what they do. They're here only as hints or reminders. If you are unsure
|
||||||
|
# consult the online docs. You have been warned.
|
||||||
|
#
|
||||||
|
# Configuration and logfile names: If the filenames you specify for many
|
||||||
|
# of the server's control files begin with "/" (or "drive:/" for Win32), the
|
||||||
|
# server will use that explicit path. If the filenames do *not* begin
|
||||||
|
# with "/", the value of ServerRoot is prepended -- so "logs/access_log"
|
||||||
|
# with ServerRoot set to "/usr/local/apache2" will be interpreted by the
|
||||||
|
# server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log"
|
||||||
|
# will be interpreted as '/logs/access_log'.
|
||||||
|
|
||||||
|
#
|
||||||
|
# ServerRoot: The top of the directory tree under which the server's
|
||||||
|
# configuration, error, and log files are kept.
|
||||||
|
#
|
||||||
|
# Do not add a slash at the end of the directory path. If you point
|
||||||
|
# ServerRoot at a non-local disk, be sure to specify a local disk on the
|
||||||
|
# Mutex directive, if file-based mutexes are used. If you wish to share the
|
||||||
|
# same ServerRoot for multiple httpd daemons, you will need to change at
|
||||||
|
# least PidFile.
|
||||||
|
#
|
||||||
|
ServerRoot "/usr/local/apache2"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Mutex: Allows you to set the mutex mechanism and mutex file directory
|
||||||
|
# for individual mutexes, or change the global defaults
|
||||||
|
#
|
||||||
|
# Uncomment and change the directory if mutexes are file-based and the default
|
||||||
|
# mutex file directory is not on a local disk or is not appropriate for some
|
||||||
|
# other reason.
|
||||||
|
#
|
||||||
|
# Mutex default:logs
|
||||||
|
|
||||||
|
#
|
||||||
|
# Listen: Allows you to bind Apache to specific IP addresses and/or
|
||||||
|
# ports, instead of the default. See also the <VirtualHost>
|
||||||
|
# directive.
|
||||||
|
#
|
||||||
|
# Change this to Listen on specific IP addresses as shown below to
|
||||||
|
# prevent Apache from glomming onto all bound IP addresses.
|
||||||
|
#
|
||||||
|
#Listen 12.34.56.78:80
|
||||||
|
Listen 80
|
||||||
|
|
||||||
|
#
|
||||||
|
# Dynamic Shared Object (DSO) Support
|
||||||
|
#
|
||||||
|
# To be able to use the functionality of a module which was built as a DSO you
|
||||||
|
# have to place corresponding `LoadModule' lines at this location so the
|
||||||
|
# directives contained in it are actually available _before_ they are used.
|
||||||
|
# Statically compiled modules (those listed by `httpd -l') do not need
|
||||||
|
# to be loaded here.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# LoadModule foo_module modules/mod_foo.so
|
||||||
|
#
|
||||||
|
LoadModule mpm_event_module modules/mod_mpm_event.so
|
||||||
|
#LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
|
||||||
|
#LoadModule mpm_worker_module modules/mod_mpm_worker.so
|
||||||
|
LoadModule authn_file_module modules/mod_authn_file.so
|
||||||
|
#LoadModule authn_dbm_module modules/mod_authn_dbm.so
|
||||||
|
#LoadModule authn_anon_module modules/mod_authn_anon.so
|
||||||
|
#LoadModule authn_dbd_module modules/mod_authn_dbd.so
|
||||||
|
#LoadModule authn_socache_module modules/mod_authn_socache.so
|
||||||
|
LoadModule authn_core_module modules/mod_authn_core.so
|
||||||
|
LoadModule authz_host_module modules/mod_authz_host.so
|
||||||
|
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
||||||
|
LoadModule authz_user_module modules/mod_authz_user.so
|
||||||
|
#LoadModule authz_dbm_module modules/mod_authz_dbm.so
|
||||||
|
#LoadModule authz_owner_module modules/mod_authz_owner.so
|
||||||
|
#LoadModule authz_dbd_module modules/mod_authz_dbd.so
|
||||||
|
LoadModule authz_core_module modules/mod_authz_core.so
|
||||||
|
#LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
|
||||||
|
#LoadModule authnz_fcgi_module modules/mod_authnz_fcgi.so
|
||||||
|
LoadModule access_compat_module modules/mod_access_compat.so
|
||||||
|
LoadModule auth_basic_module modules/mod_auth_basic.so
|
||||||
|
#LoadModule auth_form_module modules/mod_auth_form.so
|
||||||
|
#LoadModule auth_digest_module modules/mod_auth_digest.so
|
||||||
|
#LoadModule allowmethods_module modules/mod_allowmethods.so
|
||||||
|
#LoadModule isapi_module modules/mod_isapi.so
|
||||||
|
#LoadModule file_cache_module modules/mod_file_cache.so
|
||||||
|
#LoadModule cache_module modules/mod_cache.so
|
||||||
|
#LoadModule cache_disk_module modules/mod_cache_disk.so
|
||||||
|
#LoadModule cache_socache_module modules/mod_cache_socache.so
|
||||||
|
#LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
|
||||||
|
#LoadModule socache_dbm_module modules/mod_socache_dbm.so
|
||||||
|
#LoadModule socache_memcache_module modules/mod_socache_memcache.so
|
||||||
|
#LoadModule socache_redis_module modules/mod_socache_redis.so
|
||||||
|
#LoadModule watchdog_module modules/mod_watchdog.so
|
||||||
|
#LoadModule macro_module modules/mod_macro.so
|
||||||
|
#LoadModule dbd_module modules/mod_dbd.so
|
||||||
|
#LoadModule bucketeer_module modules/mod_bucketeer.so
|
||||||
|
#LoadModule dumpio_module modules/mod_dumpio.so
|
||||||
|
#LoadModule echo_module modules/mod_echo.so
|
||||||
|
#LoadModule example_hooks_module modules/mod_example_hooks.so
|
||||||
|
#LoadModule case_filter_module modules/mod_case_filter.so
|
||||||
|
#LoadModule case_filter_in_module modules/mod_case_filter_in.so
|
||||||
|
#LoadModule example_ipc_module modules/mod_example_ipc.so
|
||||||
|
#LoadModule buffer_module modules/mod_buffer.so
|
||||||
|
#LoadModule data_module modules/mod_data.so
|
||||||
|
#LoadModule ratelimit_module modules/mod_ratelimit.so
|
||||||
|
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
||||||
|
#LoadModule ext_filter_module modules/mod_ext_filter.so
|
||||||
|
#LoadModule request_module modules/mod_request.so
|
||||||
|
#LoadModule include_module modules/mod_include.so
|
||||||
|
LoadModule filter_module modules/mod_filter.so
|
||||||
|
#LoadModule reflector_module modules/mod_reflector.so
|
||||||
|
#LoadModule substitute_module modules/mod_substitute.so
|
||||||
|
#LoadModule sed_module modules/mod_sed.so
|
||||||
|
#LoadModule charset_lite_module modules/mod_charset_lite.so
|
||||||
|
#LoadModule deflate_module modules/mod_deflate.so
|
||||||
|
#LoadModule xml2enc_module modules/mod_xml2enc.so
|
||||||
|
#LoadModule proxy_html_module modules/mod_proxy_html.so
|
||||||
|
#LoadModule brotli_module modules/mod_brotli.so
|
||||||
|
LoadModule mime_module modules/mod_mime.so
|
||||||
|
#LoadModule ldap_module modules/mod_ldap.so
|
||||||
|
LoadModule log_config_module modules/mod_log_config.so
|
||||||
|
#LoadModule log_debug_module modules/mod_log_debug.so
|
||||||
|
#LoadModule log_forensic_module modules/mod_log_forensic.so
|
||||||
|
#LoadModule logio_module modules/mod_logio.so
|
||||||
|
#LoadModule lua_module modules/mod_lua.so
|
||||||
|
LoadModule env_module modules/mod_env.so
|
||||||
|
#LoadModule mime_magic_module modules/mod_mime_magic.so
|
||||||
|
#LoadModule cern_meta_module modules/mod_cern_meta.so
|
||||||
|
#LoadModule expires_module modules/mod_expires.so
|
||||||
|
LoadModule headers_module modules/mod_headers.so
|
||||||
|
#LoadModule ident_module modules/mod_ident.so
|
||||||
|
#LoadModule usertrack_module modules/mod_usertrack.so
|
||||||
|
#LoadModule unique_id_module modules/mod_unique_id.so
|
||||||
|
LoadModule setenvif_module modules/mod_setenvif.so
|
||||||
|
LoadModule version_module modules/mod_version.so
|
||||||
|
#LoadModule remoteip_module modules/mod_remoteip.so
|
||||||
|
LoadModule proxy_module modules/mod_proxy.so
|
||||||
|
#LoadModule proxy_connect_module modules/mod_proxy_connect.so
|
||||||
|
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
|
||||||
|
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||||
|
#LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
|
||||||
|
#LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
|
||||||
|
#LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so
|
||||||
|
#LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so
|
||||||
|
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
|
||||||
|
#LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
|
||||||
|
#LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
|
||||||
|
#LoadModule proxy_express_module modules/mod_proxy_express.so
|
||||||
|
#LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so
|
||||||
|
#LoadModule session_module modules/mod_session.so
|
||||||
|
#LoadModule session_cookie_module modules/mod_session_cookie.so
|
||||||
|
#LoadModule session_crypto_module modules/mod_session_crypto.so
|
||||||
|
#LoadModule session_dbd_module modules/mod_session_dbd.so
|
||||||
|
#LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
|
||||||
|
#LoadModule slotmem_plain_module modules/mod_slotmem_plain.so
|
||||||
|
#LoadModule ssl_module modules/mod_ssl.so
|
||||||
|
#LoadModule optional_hook_export_module modules/mod_optional_hook_export.so
|
||||||
|
#LoadModule optional_hook_import_module modules/mod_optional_hook_import.so
|
||||||
|
#LoadModule optional_fn_import_module modules/mod_optional_fn_import.so
|
||||||
|
#LoadModule optional_fn_export_module modules/mod_optional_fn_export.so
|
||||||
|
#LoadModule dialup_module modules/mod_dialup.so
|
||||||
|
#LoadModule http2_module modules/mod_http2.so
|
||||||
|
#LoadModule proxy_http2_module modules/mod_proxy_http2.so
|
||||||
|
#LoadModule md_module modules/mod_md.so
|
||||||
|
#LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
|
||||||
|
#LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
|
||||||
|
#LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
|
||||||
|
#LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
|
||||||
|
LoadModule unixd_module modules/mod_unixd.so
|
||||||
|
#LoadModule heartbeat_module modules/mod_heartbeat.so
|
||||||
|
#LoadModule heartmonitor_module modules/mod_heartmonitor.so
|
||||||
|
#LoadModule dav_module modules/mod_dav.so
|
||||||
|
LoadModule status_module modules/mod_status.so
|
||||||
|
LoadModule autoindex_module modules/mod_autoindex.so
|
||||||
|
#LoadModule asis_module modules/mod_asis.so
|
||||||
|
#LoadModule info_module modules/mod_info.so
|
||||||
|
#LoadModule suexec_module modules/mod_suexec.so
|
||||||
|
<IfModule !mpm_prefork_module>
|
||||||
|
#LoadModule cgid_module modules/mod_cgid.so
|
||||||
|
</IfModule>
|
||||||
|
<IfModule mpm_prefork_module>
|
||||||
|
#LoadModule cgi_module modules/mod_cgi.so
|
||||||
|
</IfModule>
|
||||||
|
#LoadModule dav_fs_module modules/mod_dav_fs.so
|
||||||
|
#LoadModule dav_lock_module modules/mod_dav_lock.so
|
||||||
|
#LoadModule vhost_alias_module modules/mod_vhost_alias.so
|
||||||
|
#LoadModule negotiation_module modules/mod_negotiation.so
|
||||||
|
LoadModule dir_module modules/mod_dir.so
|
||||||
|
#LoadModule imagemap_module modules/mod_imagemap.so
|
||||||
|
#LoadModule actions_module modules/mod_actions.so
|
||||||
|
#LoadModule speling_module modules/mod_speling.so
|
||||||
|
#LoadModule userdir_module modules/mod_userdir.so
|
||||||
|
LoadModule alias_module modules/mod_alias.so
|
||||||
|
LoadModule rewrite_module modules/mod_rewrite.so
|
||||||
|
|
||||||
|
<IfModule unixd_module>
|
||||||
|
#
|
||||||
|
# If you wish httpd to run as a different user or group, you must run
|
||||||
|
# httpd as root initially and it will switch.
|
||||||
|
#
|
||||||
|
# User/Group: The name (or #number) of the user/group to run httpd as.
|
||||||
|
# It is usually good practice to create a dedicated user and group for
|
||||||
|
# running httpd, as with most system services.
|
||||||
|
#
|
||||||
|
User daemon
|
||||||
|
Group daemon
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# 'Main' server configuration
|
||||||
|
#
|
||||||
|
# The directives in this section set up the values used by the 'main'
|
||||||
|
# server, which responds to any requests that aren't handled by a
|
||||||
|
# <VirtualHost> definition. These values also provide defaults for
|
||||||
|
# any <VirtualHost> containers you may define later in the file.
|
||||||
|
#
|
||||||
|
# All of these directives may appear inside <VirtualHost> containers,
|
||||||
|
# in which case these default settings will be overridden for the
|
||||||
|
# virtual host being defined.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# ServerAdmin: Your address, where problems with the server should be
|
||||||
|
# e-mailed. This address appears on some server-generated pages, such
|
||||||
|
# as error documents. e.g. admin@your-domain.com
|
||||||
|
#
|
||||||
|
ServerAdmin nobody@example.org
|
||||||
|
|
||||||
|
#
|
||||||
|
# ServerName gives the name and port that the server uses to identify itself.
|
||||||
|
# This can often be determined automatically, but we recommend you specify
|
||||||
|
# it explicitly to prevent problems during startup.
|
||||||
|
#
|
||||||
|
# If your host doesn't have a registered DNS name, enter its IP address here.
|
||||||
|
#
|
||||||
|
#ServerName www.example.com:80
|
||||||
|
|
||||||
|
#
|
||||||
|
# Deny access to the entirety of your server's filesystem. You must
|
||||||
|
# explicitly permit access to web content directories in other
|
||||||
|
# <Directory> blocks below.
|
||||||
|
#
|
||||||
|
<Directory />
|
||||||
|
AllowOverride none
|
||||||
|
Require all denied
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
#
|
||||||
|
# Note that from this point forward you must specifically allow
|
||||||
|
# particular features to be enabled - so if something's not working as
|
||||||
|
# you might expect, make sure that you have specifically enabled it
|
||||||
|
# below.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# DocumentRoot: The directory out of which you will serve your
|
||||||
|
# documents. By default, all requests are taken from this directory, but
|
||||||
|
# symbolic links and aliases may be used to point to other locations.
|
||||||
|
#
|
||||||
|
DocumentRoot "/usr/local/apache2/htdocs"
|
||||||
|
<Directory "/usr/local/apache2/htdocs">
|
||||||
|
#
|
||||||
|
# Possible values for the Options directive are "None", "All",
|
||||||
|
# or any combination of:
|
||||||
|
# Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
|
||||||
|
#
|
||||||
|
# Note that "MultiViews" must be named *explicitly* --- "Options All"
|
||||||
|
# doesn't give it to you.
|
||||||
|
#
|
||||||
|
# The Options directive is both complicated and important. Please see
|
||||||
|
# http://httpd.apache.org/docs/2.4/mod/core.html#options
|
||||||
|
# for more information.
|
||||||
|
#
|
||||||
|
Options Indexes FollowSymLinks
|
||||||
|
|
||||||
|
#
|
||||||
|
# AllowOverride controls what directives may be placed in .htaccess files.
|
||||||
|
# It can be "All", "None", or any combination of the keywords:
|
||||||
|
# AllowOverride FileInfo AuthConfig Limit
|
||||||
|
#
|
||||||
|
AllowOverride None
|
||||||
|
|
||||||
|
#
|
||||||
|
# Controls who can get stuff from this server.
|
||||||
|
#
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
#
|
||||||
|
# DirectoryIndex: sets the file that Apache will serve if a directory
|
||||||
|
# is requested.
|
||||||
|
#
|
||||||
|
<IfModule dir_module>
|
||||||
|
DirectoryIndex index.html
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#
|
||||||
|
# The following lines prevent .htaccess and .htpasswd files from being
|
||||||
|
# viewed by Web clients.
|
||||||
|
#
|
||||||
|
<Files ".ht*">
|
||||||
|
Require all denied
|
||||||
|
</Files>
|
||||||
|
|
||||||
|
#
|
||||||
|
# ErrorLog: The location of the error log file.
|
||||||
|
# If you do not specify an ErrorLog directive within a <VirtualHost>
|
||||||
|
# container, error messages relating to that virtual host will be
|
||||||
|
# logged here. If you *do* define an error logfile for a <VirtualHost>
|
||||||
|
# container, that host's errors will be logged there and not here.
|
||||||
|
#
|
||||||
|
ErrorLog /proc/self/fd/2
|
||||||
|
|
||||||
|
#
|
||||||
|
# LogLevel: Control the number of messages logged to the error_log.
|
||||||
|
# Possible values include: debug, info, notice, warn, error, crit,
|
||||||
|
# alert, emerg.
|
||||||
|
#
|
||||||
|
LogLevel warn
|
||||||
|
|
||||||
|
<IfModule log_config_module>
|
||||||
|
#
|
||||||
|
# The following directives define some format nicknames for use with
|
||||||
|
# a CustomLog directive (see below).
|
||||||
|
#
|
||||||
|
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
|
||||||
|
LogFormat "%h %l %u %t \"%r\" %>s %b" common
|
||||||
|
|
||||||
|
<IfModule logio_module>
|
||||||
|
# You need to enable mod_logio.c to use %I and %O
|
||||||
|
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#
|
||||||
|
# The location and format of the access logfile (Common Logfile Format).
|
||||||
|
# If you do not define any access logfiles within a <VirtualHost>
|
||||||
|
# container, they will be logged here. Contrariwise, if you *do*
|
||||||
|
# define per-<VirtualHost> access logfiles, transactions will be
|
||||||
|
# logged therein and *not* in this file.
|
||||||
|
#
|
||||||
|
CustomLog /proc/self/fd/1 common
|
||||||
|
|
||||||
|
#
|
||||||
|
# If you prefer a logfile with access, agent, and referer information
|
||||||
|
# (Combined Logfile Format) you can use the following directive.
|
||||||
|
#
|
||||||
|
#CustomLog "logs/access_log" combined
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule alias_module>
|
||||||
|
#
|
||||||
|
# Redirect: Allows you to tell clients about documents that used to
|
||||||
|
# exist in your server's namespace, but do not anymore. The client
|
||||||
|
# will make a new request for the document at its new location.
|
||||||
|
# Example:
|
||||||
|
# Redirect permanent /foo http://www.example.com/bar
|
||||||
|
|
||||||
|
#
|
||||||
|
# Alias: Maps web paths into filesystem paths and is used to
|
||||||
|
# access content that does not live under the DocumentRoot.
|
||||||
|
# Example:
|
||||||
|
# Alias /webpath /full/filesystem/path
|
||||||
|
#
|
||||||
|
# If you include a trailing / on /webpath then the server will
|
||||||
|
# require it to be present in the URL. You will also likely
|
||||||
|
# need to provide a <Directory> section to allow access to
|
||||||
|
# the filesystem path.
|
||||||
|
|
||||||
|
#
|
||||||
|
# ScriptAlias: This controls which directories contain server scripts.
|
||||||
|
# ScriptAliases are essentially the same as Aliases, except that
|
||||||
|
# documents in the target directory are treated as applications and
|
||||||
|
# run by the server when requested rather than as documents sent to the
|
||||||
|
# client. The same rules about trailing "/" apply to ScriptAlias
|
||||||
|
# directives as to Alias.
|
||||||
|
#
|
||||||
|
ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule cgid_module>
|
||||||
|
#
|
||||||
|
# ScriptSock: On threaded servers, designate the path to the UNIX
|
||||||
|
# socket used to communicate with the CGI daemon of mod_cgid.
|
||||||
|
#
|
||||||
|
#Scriptsock cgisock
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#
|
||||||
|
# "/usr/local/apache2/cgi-bin" should be changed to whatever your ScriptAliased
|
||||||
|
# CGI directory exists, if you have that configured.
|
||||||
|
#
|
||||||
|
<Directory "/usr/local/apache2/cgi-bin">
|
||||||
|
AllowOverride None
|
||||||
|
Options None
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
<IfModule headers_module>
|
||||||
|
#
|
||||||
|
# Avoid passing HTTP_PROXY environment to CGI's on this or any proxied
|
||||||
|
# backend servers which have lingering "httpoxy" defects.
|
||||||
|
# 'Proxy' request header is undefined by the IETF, not listed by IANA
|
||||||
|
#
|
||||||
|
RequestHeader unset Proxy early
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule mime_module>
|
||||||
|
#
|
||||||
|
# TypesConfig points to the file containing the list of mappings from
|
||||||
|
# filename extension to MIME-type.
|
||||||
|
#
|
||||||
|
TypesConfig conf/mime.types
|
||||||
|
|
||||||
|
#
|
||||||
|
# AddType allows you to add to or override the MIME configuration
|
||||||
|
# file specified in TypesConfig for specific file types.
|
||||||
|
#
|
||||||
|
#AddType application/x-gzip .tgz
|
||||||
|
#
|
||||||
|
# AddEncoding allows you to have certain browsers uncompress
|
||||||
|
# information on the fly. Note: Not all browsers support this.
|
||||||
|
#
|
||||||
|
#AddEncoding x-compress .Z
|
||||||
|
#AddEncoding x-gzip .gz .tgz
|
||||||
|
#
|
||||||
|
# If the AddEncoding directives above are commented-out, then you
|
||||||
|
# probably should define those extensions to indicate media types:
|
||||||
|
#
|
||||||
|
AddType application/x-compress .Z
|
||||||
|
AddType application/x-gzip .gz .tgz
|
||||||
|
|
||||||
|
#
|
||||||
|
# AddHandler allows you to map certain file extensions to "handlers":
|
||||||
|
# actions unrelated to filetype. These can be either built into the server
|
||||||
|
# or added with the Action directive (see below)
|
||||||
|
#
|
||||||
|
# To use CGI scripts outside of ScriptAliased directories:
|
||||||
|
# (You will also need to add "ExecCGI" to the "Options" directive.)
|
||||||
|
#
|
||||||
|
#AddHandler cgi-script .cgi
|
||||||
|
|
||||||
|
# For type maps (negotiated resources):
|
||||||
|
#AddHandler type-map var
|
||||||
|
|
||||||
|
#
|
||||||
|
# Filters allow you to process content before it is sent to the client.
|
||||||
|
#
|
||||||
|
# To parse .shtml files for server-side includes (SSI):
|
||||||
|
# (You will also need to add "Includes" to the "Options" directive.)
|
||||||
|
#
|
||||||
|
#AddType text/html .shtml
|
||||||
|
#AddOutputFilter INCLUDES .shtml
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#
|
||||||
|
# The mod_mime_magic module allows the server to use various hints from the
|
||||||
|
# contents of the file itself to determine its type. The MIMEMagicFile
|
||||||
|
# directive tells the module where the hint definitions are located.
|
||||||
|
#
|
||||||
|
#MIMEMagicFile conf/magic
|
||||||
|
|
||||||
|
#
|
||||||
|
# Customizable error responses come in three flavors:
|
||||||
|
# 1) plain text 2) local redirects 3) external redirects
|
||||||
|
#
|
||||||
|
# Some examples:
|
||||||
|
#ErrorDocument 500 "The server made a boo boo."
|
||||||
|
#ErrorDocument 404 /missing.html
|
||||||
|
#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
|
||||||
|
#ErrorDocument 402 http://www.example.com/subscription_info.html
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# MaxRanges: Maximum number of Ranges in a request before
|
||||||
|
# returning the entire resource, or one of the special
|
||||||
|
# values 'default', 'none' or 'unlimited'.
|
||||||
|
# Default setting is to accept 200 Ranges.
|
||||||
|
#MaxRanges unlimited
|
||||||
|
|
||||||
|
#
|
||||||
|
# EnableMMAP and EnableSendfile: On systems that support it,
|
||||||
|
# memory-mapping or the sendfile syscall may be used to deliver
|
||||||
|
# files. This usually improves server performance, but must
|
||||||
|
# be turned off when serving from networked-mounted
|
||||||
|
# filesystems or if support for these functions is otherwise
|
||||||
|
# broken on your system.
|
||||||
|
# Defaults: EnableMMAP On, EnableSendfile Off
|
||||||
|
#
|
||||||
|
#EnableMMAP off
|
||||||
|
#EnableSendfile on
|
||||||
|
|
||||||
|
# Supplemental configuration
|
||||||
|
#
|
||||||
|
# The configuration files in the conf/extra/ directory can be
|
||||||
|
# included to add extra features or to modify the default configuration of
|
||||||
|
# the server, or you may simply copy their contents here and change as
|
||||||
|
# necessary.
|
||||||
|
|
||||||
|
# Server-pool management (MPM specific)
|
||||||
|
#Include conf/extra/httpd-mpm.conf
|
||||||
|
|
||||||
|
# Multi-language error messages
|
||||||
|
#Include conf/extra/httpd-multilang-errordoc.conf
|
||||||
|
|
||||||
|
# Fancy directory listings
|
||||||
|
#Include conf/extra/httpd-autoindex.conf
|
||||||
|
|
||||||
|
# Language settings
|
||||||
|
#Include conf/extra/httpd-languages.conf
|
||||||
|
|
||||||
|
# User home directories
|
||||||
|
#Include conf/extra/httpd-userdir.conf
|
||||||
|
|
||||||
|
# Real-time info on requests and configuration
|
||||||
|
#Include conf/extra/httpd-info.conf
|
||||||
|
|
||||||
|
# Virtual hosts
|
||||||
|
#Include conf/extra/httpd-vhosts.conf
|
||||||
|
|
||||||
|
# Local access to the Apache HTTP Server Manual
|
||||||
|
#Include conf/extra/httpd-manual.conf
|
||||||
|
|
||||||
|
# Distributed authoring and versioning (WebDAV)
|
||||||
|
#Include conf/extra/httpd-dav.conf
|
||||||
|
|
||||||
|
# Various default settings
|
||||||
|
#Include conf/extra/httpd-default.conf
|
||||||
|
|
||||||
|
# Configure mod_proxy_html to understand HTML4/XHTML1
|
||||||
|
<IfModule proxy_html_module>
|
||||||
|
Include conf/extra/proxy-html.conf
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# Secure (SSL/TLS) connections
|
||||||
|
#Include conf/extra/httpd-ssl.conf
|
||||||
|
#
|
||||||
|
# Note: The following must must be present to support
|
||||||
|
# starting without SSL on platforms with no /dev/random equivalent
|
||||||
|
# but a statically compiled-in mod_ssl.
|
||||||
|
#
|
||||||
|
<IfModule ssl_module>
|
||||||
|
SSLRandomSeed startup builtin
|
||||||
|
SSLRandomSeed connect builtin
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
|
||||||
|
# === Sophon specific settings ===
|
||||||
|
# --- DARK SORCERY AHEAD ---
|
||||||
|
# Regexes used as string comparisions lie beyond this line.
|
||||||
|
|
||||||
|
LogLevel rewrite:trace6
|
||||||
|
|
||||||
|
# Enable rewriting (proxying)
|
||||||
|
RewriteEngine on
|
||||||
|
|
||||||
|
# Preserve host
|
||||||
|
ProxyPreserveHost on
|
||||||
|
|
||||||
|
|
||||||
|
# Proxy regular requests to the frontend
|
||||||
|
# sophon.steffo.eu → frontend
|
||||||
|
RewriteCond "%{ENV:matched}" "! -eq 1" [NC] # If the url hasn't been matched by the previous rules
|
||||||
|
RewriteCond "%{ENV:APACHE_PROXY_BASE_DOMAIN} %{HTTP_HOST}" "^([^ ]+) \1$" [NC] # If ENV:APACHE_PROXY_BASE_DOMAIN equals HTTP_HOST
|
||||||
|
RewriteCond "%{ENV:SOPHON_FRONTEND_NAME}" "^(.+)$" [NC] # Capture ENV:SOPHON_FRONTEND_NAME for substitution in the rewriterule
|
||||||
|
RewriteRule "/(.*)" "http://%1/$1" [P,L,E=matched:1] # Rewrite as a SPA and set the matched flag
|
||||||
|
|
||||||
|
# Proxy api requests to the backend
|
||||||
|
# api.sophon.steffo.eu → backend
|
||||||
|
RewriteCond "%{ENV:matched}" "! -eq 1" [NC] # If the url hasn't been matched by the previous rules
|
||||||
|
RewriteCond "api.%{ENV:APACHE_PROXY_BASE_DOMAIN} %{HTTP_HOST}" "^([^ ]+) \1$" [NC] # If api. prefixed to ENV:APACHE_PROXY_BASE_DOMAIN equals HTTP_HOST
|
||||||
|
RewriteCond "%{ENV:SOPHON_BACKEND_NAME}" "^(.+)$" [NC] # Capture ENV:SOPHON_BACKEND_NAME for substitution in the rewriterule
|
||||||
|
RewriteRule "/(.*)" "http://%1/$1" [P,L,E=matched:1] # Rewrite and set the matched flag
|
||||||
|
|
||||||
|
# Create a map between the proxy file generated by Sophon and Apache
|
||||||
|
RewriteMap "sophonproxy" "dbm=gdbm:/run/sophon/proxy/proxy.dbm"
|
||||||
|
|
||||||
|
# Proxy websockets to the notebooks
|
||||||
|
# *.sophon.steffo.eu → notebook
|
||||||
|
RewriteCond "%{ENV:matched}" "! -eq 1" [NC] # If the url hasn't been matched by the previous rules
|
||||||
|
RewriteCond ".%{ENV:APACHE_PROXY_BASE_DOMAIN} %{HTTP_HOST}" "^([^ ]+) [^ ]+\1$" [NC] # If this is any other subdomain of ENV:APACHE_PROXY_BASE_DOMAIN
|
||||||
|
RewriteCond "%{HTTP:Connection}" "Upgrade" [NC] # If this is a websocket connection
|
||||||
|
RewriteCond "%{HTTP:Upgrade}" "websocket" [NC] # If this is a websocket connection
|
||||||
|
RewriteRule "/(.*)" "ws://${sophonproxy:%{HTTP_HOST}}/$1" [P,L,E=matched:1] # Rewrite and set the matched flag
|
||||||
|
|
||||||
|
# Proxy regular requests to the notebooks
|
||||||
|
# *.sophon.steffo.eu → notebook
|
||||||
|
RewriteCond "%{ENV:matched}" "! -eq 1" [NC] # If the url hasn't been matched by the previous rules
|
||||||
|
RewriteCond ".%{ENV:APACHE_PROXY_BASE_DOMAIN} %{HTTP_HOST}" "^([^ ]+) [^ ]+\1$" [NC] # If this is any other subdomain of ENV:APACHE_PROXY_BASE_DOMAIN
|
||||||
|
RewriteRule "/(.*)" "http://${sophonproxy:%{HTTP_HOST}}/$1" [P,L,E=matched:1]
|
Loading…
Reference in a new issue