Skip to content

Commit af6952b

Browse files
committed
Merge branch 'v2.0' into dev
2 parents dbad8c1 + d7680a3 commit af6952b

30 files changed

+221455
-239
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,5 +144,8 @@ src/api_service/experiments/venv
144144
docker-compose.yml
145145
/secretkey.txt
146146
/modulector/database_versions/
147-
/modulector/files/
147+
modulector/files/EPIC-8v2-0_A1.csv
148+
modulector/files/mirDIP_Unidirectional_search_v.5.txt
148149
*.sql.gz
150+
docker-compose.mauri_dev.yml
151+
modulector/files/tmp_db.csv

CONTRIBUTING.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ The entire contributing process consists in the following steps:
2929
1. `python3 -m venv venv`
3030
1. `source venv/bin/activate` (this command must be run every time you want to start the Django server, otherwise we won't have the dependencies available)
3131
1. `pip install -r config/requirements.txt`
32+
1. Database download:
33+
For reasons of size there are 2 databases that are not in the Modulector repository and you have to download them manually. The following databases must be downloaded:
34+
1. mirDIP version 5.2. Download [mirDIP_Unidirectional_search_v.5.txt](https://ophid.utoronto.ca//mirDIPweb/mirDIP_Unidirectional_search_v_5_2.zip) file.
35+
1. [EPIC-8v2-0_A1.csv](https://support.illumina.com/content/dam/illumina-support/documents/downloads/productfiles/methylationepic/MethylationEPIC_v2%20Files.zip) file of the Infinium MethylationEPIC array version 2.0.
36+
Once the two files are downloaded, unzip and move them into the `modulector/files/` directory.
37+
Note: there may be more than one file inside the ZIP. Be sure to move only the two files mentioned above.
3238
1. Apply migrations and create super user:
3339
1. `python3 manage.py makemigrations`
3440
1. `python3 manage.py migrate`

DEPLOYING.md

Lines changed: 91 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,26 @@ Below are the steps to perform a production deploy.
1616
1. Set the environment variables that are empty with data. They are listed below by category:
1717
- Django:
1818
- `DJANGO_SETTINGS_MODULE`: indicates the `settings.py` file to read. In production we set in `docker-compose_dist.yml` the value `ModulectorBackend.settings_prod` which contains several production properties.
19+
- `ALLOWED_HOSTS`: list of allowed host separated by commas. Default `['web', '.localhost', '127.0.0.1', '[::1]']`.
20+
- `ENABLE_SECURITY`: set the string `true` to enable Django's security mechanisms. In addition to this parameter, to have a secure site you must configure the HTTPS server, for more information on the latter see the section [Enable SSL/HTTPS](#enable-sslhttps). Default `false`.
21+
- `CSRF_TRUSTED_ORIGINS`: in Django >= 4.x, it's mandatory to define this in production when you are using Daphne through NGINX. The value is a single host or list of hosts separated by commas. 'http://', 'https://' prefixes are mandatory. Examples of values: 'http://127.0.0.1', 'http://127.0.0.1,https://127.0.0.1:8000', etc. You can read more [here](#csrf-trusted-issue).
1922
- `SECRET_KEY`: Django's secret key. If not specified, one is generated with [generate-secret-key application](https://github.com/MickaelBergem/django-generate-secret-key) automatically.
2023
- `MEDIA_ROOT`: absolute path where will be stored the uploaded files. By default `<project root>/uploads`.
2124
- `MEDIA_URL`: URL of the `MEDIA_ROOT` folder. By default `<url>/media/`.
2225
- `CUSTOM_ALLOWED_HOSTS`: list of allowed hosts (separated by commas) to access to Modulector (
2326
ex. `192.168.11.1,10.10.10.2,localhost`). If it is not defined, `web` (which is the alias of the Modulector host running in Docker) is used.
24-
- Healthchecks and alerts:
25-
- `HEALTH_URL` : indicates the url that will be requested on Docker healthchecks. By default it is http://localhost:8000/drugs/. The healthcheck makes a GET request on it. Any HTTP code value greatear or equals than 400 is considered an error.
26-
- `HEALTH_ALERT_URL` : if you want to receive an alert when healthchecks failed, you can set this variable to a webhook endpoint that will receive a POST request and a JSON body with the field **content** that contains the fail message.
27-
1. Set the environment variables for the database connection if the default values don't match your `db` service scenario:
27+
- Postgres:
2828
- `POSTGRES_USERNAME` : Database username. By default the docker image uses `modulector`.
2929
- `POSTGRES_PASSWORD` : Database username's password. By default the docker image uses `modulector`.
3030
- `POSTGRES_PORT` : Database server listen port. By default the docker image uses `5432`.
3131
- `POSTGRES_DB` : Database name to be used. By default the docker image uses `modulector`.
32+
- Healthchecks and alerts:
33+
- `HEALTH_URL` : indicates the url that will be requested on Docker healthchecks. By default it is http://localhost:8000/drugs/. The healthcheck makes a GET request on it. Any HTTP code value greatear or equals than 400 is considered an error.
34+
- `HEALTH_ALERT_URL` : if you want to receive an alert when healthchecks failed, you can set this variable to a webhook endpoint that will receive a POST request and a JSON body with the field **content** that contains the fail message.
3235
1. Go back to the project's root folder and run the following commands:
3336
- Docker Compose:
34-
- Start: `docker-compose up -d`. The service will available in `127.0.0.1`.
35-
- Stop: `docker-compose down`
37+
- Start: `docker compose up -d`. The service will available in `127.0.0.1`.
38+
- Stop: `docker compose down`
3639
- [Docker Swarm](https://docs.docker.com/engine/swarm/):
3740
- Start: `docker stack deploy --compose-file docker-compose.yml modulector`
3841
- Stop: `docker stack rm modulector`
@@ -44,8 +47,35 @@ Below are the steps to perform a production deploy.
4447

4548
### Start delays
4649

47-
Due the database restoration in the first start, the container modulectordb may take a while to be up an ready. We can follow the status of the startup process in the logs by doing: `docker-compose logs --follow`.
48-
Sometimes this delay makes django server throws database connection errors. If it is still down and not automatically fixed when database finally's up, we can restart the services by doing: `docker-compose up -d`.
50+
Due to the database restoration in the first start, the container modulectordb may take a while to be up an ready. We can follow the status of the startup process in the logs by doing: `docker compose logs --follow`.
51+
Sometimes this delay makes django server throws database connection errors. If it is still down and not automatically fixed when database is finally up, we can restart the services by doing: `docker compose up -d`.
52+
53+
54+
## Enable SSL/HTTPS
55+
56+
To enable HTTPS, follow the steps below:
57+
58+
1. Set the `ENABLE_SECURITY` parameter to `true` as explained in the [Instructions](#instructions) section.
59+
1. Copy the file `config/nginx/multiomics_intermediate_safe_dist.conf` and paste it into `config/nginx/conf.d/` with the name `multiomics_intermediate.conf`.
60+
1. Get the `.crt` and `.pem` files for both the certificate and the private key and put them in the `config/nginx/certificates` folder.
61+
1. Edit the `multiomics_intermediate.conf` file that we pasted in point 2. Uncomment the lines where both `.crt` and `.pem` files must be specified.
62+
1. Edit the `docker-compose.yml` file so that the `nginx` service exposes both port 8000 and 443. Also you need to add `certificates` folder to `volumes` section. It should look something like this:
63+
64+
```yaml
65+
...
66+
nginx:
67+
image: nginx:1.19.3
68+
ports:
69+
- 80:8000
70+
- 443:443
71+
# ...
72+
volumes:
73+
...
74+
- ./config/nginx/certificates:/etc/nginx/certificates
75+
...
76+
```
77+
78+
6. Redo the deployment with Docker.
4979

5080

5181
## Perform security checks
@@ -65,16 +95,16 @@ python3 manage.py check --deploy --settings ModulectorBackend.settings_prod
6595

6696
## Restart/stop the services
6797

68-
If the configuration of the `docker-compose.yml` file has been changed, you can apply the changes without stopping the services, just running the `docker-compose restart` command.
98+
If the configuration of the `docker-compose.yml` file has been changed, you can apply the changes without stopping the services, just running the `docker compose restart` command.
6999

70-
If you want to stop all services, you can execute the command `docker-compose down`.
100+
If you want to stop all services, you can execute the command `docker compose down`.
71101

72102

73103
## See container status
74104

75105
To check the different services' status you can run:
76106

77-
`docker-compose logs <service's name>`
107+
`docker service logs <service's name>`
78108

79109
Where *\<service's name\>* could be `nginx`, `web` or `db`.
80110

@@ -85,52 +115,69 @@ Where *\<service's name\>* could be `nginx`, `web` or `db`.
85115

86116
In order to create a database dump you can execute the following command:
87117

88-
`docker exec -t [name of DB container] pg_dump [db name] --data-only | gzip > modulector.sql.gz`
118+
`docker exec -t [name of DB container] pg_dump [db name] --no-owner -U modulector | gzip > modulector.sql.gz`
89119

90-
That command will create a compressed file with the database dump inside. **Note** that `--data-only` flag is present as DB structure is managed by Django Migrations so they are not necessary.
120+
That command will create a compressed file with the database dump inside.
91121

92122

93123
### Import
94124

95-
Use the followings steps if you manually set your postgres environment. Otherwise, you can just use the `modulector-db:<version>` and avoid all this steps. If you move between release versions it's very probable that the db image exists with the previous name mentioned.
125+
You can use set Modulector DB in three ways.
96126

97-
1. **Optional but recommended**: due to major changes, it's probably that an import thrown several errors when importing. To prevent that you could do the following steps before doing the importation:
98-
1. Drop all the tables from the DB:
99-
1. Log into docker container: `docker container exec -it [name of DB container] bash`
100-
1. Log into Postgres: `psql -U [username] -d [database]`
101-
1. Run to generate a `DELETE CASCADE` query for all
102-
tables: `select 'drop table if exists "' || tablename || '" cascade;' from pg_tables where schemaname = 'public';`
103-
1. (**Danger, will drop tables**) Run the generated query in previous step to drop all tables
104-
1. Run the Django migrations to create the empty tables with the correct structure: `docker exec -i [name of django container] python3 manage.py migrate`
105-
1. Download `.sql.gz` from [Modulector releases pages](https://github.com/multiomics-datascience/modulector-backend/releases) or use your own export file
106-
1. Restore the db running:
107127

108-
`zcat modulector.sql.gz | docker exec -i [name of DB container] psql [db name]`
128+
### Using official Docker image (recommended)
129+
130+
You can just use the [modulector-db][modulector-db-docker] and avoid all kind of importations steps. This is the default setting in `docker-compose_dist.yml`.
131+
109132

110-
That command will restore the database using a compressed dump as source
133+
### Importing an existing database dump
134+
135+
1. Comment the service in your `docker-compose.yml` that uses the `omicsdatascience/modulector-db` image.
136+
1. Start up a PostgreSQL service. You can use the same service listed in the `docker-compose.dev.yml` file.
137+
1. **Optional but recommended (You can omit these steps if it's the first time you are deploying Modulector)**: due to major changes, it's probably that an import thrown several errors when importing. To prevent that you could do the following steps before doing the importation:
138+
1. Drop all the tables from the DB:
139+
1. Log into docker container: `docker container exec -it [name of the DB container] bash`
140+
1. Log into Postgres: `psql -U [username]`
141+
1. (**Danger, will drop all the data**) Remove the `modulector` database: `DROP DATABASE modulector;`
142+
1. Create an empty database: `CREATE DATABASE modulector;`
143+
1. Download `.sql.gz` from [Modulector releases pages](https://github.com/multiomics-datascience/modulector-backend/releases) or use your own export file.
144+
1. Restore the db: `zcat modulector.sql.gz | docker exec -i [name of the DB container] psql modulector -U modulector`
145+
146+
That command will restore the database using a compressed dump as source.
111147

112148

113-
### Regenerate data
149+
### Regenerating the data manually
114150

115-
Use the followings steps if you manually set your postgres environment. Otherwise, you can just regenerate all the db data deleting or stoping the db container and bring it up. It's because the image has all the data you need. But if you are deploying your custom postgres the next steps are valid.
151+
1. Download the files for the mirDIP database (version 5.2) and the Illumina 'Infinium MethylationEPIC 2.0' array. The files can be freely downloaded from their respective web pages.
152+
**For the mirDIP database**:
153+
- Go to the [MirDIP download web page](https://ophid.utoronto.ca/mirDIP/download.jsp) and download the file called *"mirDIPweb/mirDIP Unidirectional search ver. 5.2"*.
154+
- Unzip the file.
155+
- Find the file called *"mirDIP_Unidirectional_search_v.5.txt"* and move it into the **"modulector/files/"** directory.
116156

117-
**If you need to regenerate all, or some of the data**
157+
**For the EPIC Methylation array**:
158+
- Go to the [Illumina product files web page](https://support.illumina.com/downloads/infinium-methylationepic-v2-0-product-files.html) and download the ZIP file called "*Infinium MethylationEPIC v2.0 Product Files (ZIP Format)*".
159+
- Unzip the file.
160+
- Within the unzipped files you will find one called "*EPIC-8v2-0_A1.csv*". Move this file to the directory **"modulor/files/"**.
161+
162+
**NOTE:** The total weight of both files is about 5 GB.
163+
1. Start up a PostgreSQL service. You can use the same service listed in the docker-compose.dev.yml file.
164+
1. Run the migrations. Use `python3 manage.py migrate` to run all the migrations (**NOTE:** this can take a long time to finish)
118165

119-
1. Download `files.zip` from [Modulector releases pages](https://github.com/multiomics-datascience/modulector-backend/releases) and place it inside the files folder **(this folder is ignored by git)**
120-
2. http://127.0.0.1:8000/process/?commands=
121-
3. If you don't sent the query param all the commands will be executed
122-
4. If you want a specific set you can combine the following `drugs, mature_mirna, diseases, ref_seq, gene, sequence, mirDIP`
123166

167+
## Update databases
124168

125-
## If you are using your own postgres server
169+
Modulector currently works with the mirDIP (version 5.2) and miRBase (version 22.1) databases for miRNA data, and with information from the Illumina 'Infinium MethylationEPIC 2.0' array for information about methylation sites.
170+
If new versions are released for these databases and you want to update them, follow these steps:
126171

127-
It's important that if you are using another postgres server, and not the modulector-db image for getting up the services, you must provide the next parameters on db and web services to assure their communication.
172+
- For **mirDIP** and **Illumina EPIC array** you must follow the same steps described in the [Regenerating the data manually](#regenerating-the-data-manually) section, replacing the named files with the most recent versions that have been published on their sites .
173+
- For **miRBase**, follow the instructions below:
174+
1. Go to the [_Download_ section on the website][mirbase-download-page].
175+
1. Download the files named _hairpin.fa_ and _mature.fa_ from the latest version of the database.
176+
1. Replace the files inside the _modulector/files/_ directory with the ones downloaded in the previous step.
177+
1. Start up a PostgreSQL service. You can use the same service listed in the _docker-compose.dev.yml_ file.
178+
1. Run the command `python3 manage.py migrate` to apply all the migrations (**NOTE:** this can take a long time to finish).
128179

129-
- `POSTGRES_USERNAME`: DB username. **Must be equal to** `POSTGRES_USER` in `db` service.
130-
- `POSTGRES_PASSWORD`: DB user's password. **Must be equal to** `POSTGRES_PASSWORD` in `db` service.
131-
- `POSTGRES_HOST`: DB host.
132-
- `POSTGRES_PORT`: DB host's port.
133-
- `POSTGRES_DB`: DB's name. **Must be equal to** `POSTGRES_DB` in in `db` service.
180+
**Note:** These updates will work correctly as long as they maintain the format of the data in the source files.
134181

135182

136183
## Configure your API key
@@ -140,3 +187,7 @@ When we notify user about updates of pubmeds they are subscribed to we interact
140187

141188
## Cron job configuration
142189
For cron jobs we use the following [library](https://github.com/kraiz/django-crontab). In our settings file we configured our cron jobs inside the `CRONJOBS = []`
190+
191+
192+
[modulector-db-docker]: https://hub.docker.com/r/omicsdatascience/modulector-db
193+
[mirbase-download-page]: https://www.mirbase.org/ftp.shtml

Dockerfile

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM python:3.8-buster
1+
FROM python:3.11-bullseye
22

33
# Default value for deploying with modulector-db image
44
ENV POSTGRES_USERNAME "modulector"
@@ -11,16 +11,17 @@ RUN mkdir /src
1111
WORKDIR /src/
1212
ENV BASEDIR=/src
1313

14+
# Install app python requirements
15+
ADD config/requirements.txt /config/
16+
RUN pip3 install -r /config/requirements.txt
17+
1418
# Copy all source data
1519
COPY . .
1620

17-
# Install app python requirements
18-
RUN pip3 install -r config/requirements.txt
19-
2021
RUN echo 0 > tools/healthcheck/tries.txt
2122
HEALTHCHECK CMD python tools/healthcheck/check.py
2223
CMD ["/bin/bash","-c","tools/run.sh"]
2324

24-
# modulector port
25+
# Modulector port
2526
EXPOSE 8000
2627

ModulectorBackend/settings.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
# Modulector version
1616
VERSION: str = '1.4.4'
1717

18+
# Default primary key field type
19+
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
20+
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
21+
1822
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
1923
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
2024

@@ -27,7 +31,7 @@
2731
# SECURITY WARNING: don't run with debug turned on in production!
2832
DEBUG = True
2933

30-
ALLOWED_HOSTS = ['.localhost', '127.0.0.1', '[::1]','*']
34+
ALLOWED_HOSTS = ['web', '.localhost', '127.0.0.1', '[::1]']
3135

3236
# Modulector unsubscribe endpoint
3337
UNSUBSCRIBE_URL = 'http://localhost:8000/unsubscribe-pubmeds/?token='

ModulectorBackend/settings_ci.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
# SECURITY WARNING: don't run with debug turned on in production!
2828
DEBUG = True
2929

30-
ALLOWED_HOSTS = ['.localhost', '127.0.0.1', '[::1]','*']
30+
ALLOWED_HOSTS = ['.localhost', '127.0.0.1', '[::1]', '*']
3131

3232
# Modulector unsubscribe endpoint
3333
UNSUBSCRIBE_URL = 'http://localhost:8000/unsubscribe-pubmeds/?token='
@@ -101,8 +101,7 @@
101101
DATABASES = {
102102
'default': {
103103
'ENGINE': 'django.db.backends.sqlite3',
104-
'TEST':
105-
{
104+
'TEST': {
106105
'MIGRATE': False
107106
}
108107
},

ModulectorBackend/settings_prod.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,25 @@
2727
# 'web' is the name of the docker-compose service which serves Django
2828
custom_allowed_hosts: Optional[str] = os.getenv('CUSTOM_ALLOWED_HOSTS')
2929
if custom_allowed_hosts is None:
30-
ALLOWED_HOSTS = ['web','.localhost', '127.0.0.1', '[::1]']
30+
ALLOWED_HOSTS = ['web', '.localhost', '127.0.0.1', '[::1]']
3131
else:
3232
# Gets all the hosts declared by the user (separated by commas)
3333
allowed_host_list = custom_allowed_hosts.split(',')
3434
allowed_host_list_stripped = [x.strip() for x in allowed_host_list]
3535
ALLOWED_HOSTS = allowed_host_list_stripped
3636

37+
# From Django 4 this needs to be set to prevent issue with NGINX
38+
csrf_trusted_origins_env = os.getenv('CSRF_TRUSTED_ORIGINS', '')
39+
CSRF_TRUSTED_ORIGINS = csrf_trusted_origins_env.split(',')
40+
3741
# Security settings
38-
# SESSION_COOKIE_SECURE = True # TODO: set when configured a SSL Cert.
39-
# CSRF_COOKIE_SECURE = True # TODO: set when configured a SSL Cert.
42+
ENABLE_SECURITY: bool = os.getenv('ENABLE_SECURITY', 'false') == 'true'
43+
SESSION_COOKIE_SECURE = ENABLE_SECURITY
44+
CSRF_COOKIE_SECURE = ENABLE_SECURITY
4045
SECURE_REFERRER_POLICY = 'same-origin'
4146

47+
# This prevents issues with FileField/ImageField URLs
48+
if ENABLE_SECURITY:
49+
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
50+
51+

0 commit comments

Comments
 (0)