How To’s#
Deployment#
Deployment using docker-compose#
In the repository there is a directory .docker
that contains a docker-compose
file. Starting a TaskManager is as simple as:
$ cd .docker
$ docker-compose build
$ docker-compose up
By default the TaskManager will be reachable at localhost:5000
and the account admin
, password admin
, will be available.
The configuration of the TaskManager can be done by setting environment variables
in the docker-compose
file. For the list of variables to are used see the Configuration section.
Deployment using kubernetes#
Setting up a TaskManager on you own computer in K8s is as simple as executing a helm install:
$ kubectl create namespace taskmanager
$ helm install registry.gitlab.com/radiology/infrastructure/task-manager:6.6.0
The Task Manager should now be running on localhost/taskmanager
and is ready to be setup.
Note
The repository contains helm charts for deployment using kubernetes. They can be
found in the charts
subdirectory.
Configuration values for kubernetes#
The following config values that map to environment variables are defined in
the values.yaml
:
Environment variable |
Config value in Helm Charts |
---|---|
TASKMANAGER_PORT |
taskmanager.port |
GUNICORN_WORKER_CLASS |
taskmanager.gunicorn.workerClass |
GUNICORN_WORKER_CONNECTIONS |
taskmanager.gunicorn.workerConnections |
GUNICORN_TIMEOUT |
taskmanager.gunicorn.timeout |
TASKMAN_INSTANCE_NAME |
taskmanager.instanceName |
TASKMAN_PROJECT_NAME |
taskmanager.projectName |
DB_SCHEMA |
taskmanager.db.schema |
DB_NAME |
taskmanager.db.name |
DB_USER |
taskmanager.db.user |
DB_PASS |
taskmanager.db.password |
DB_HOST |
taskmanager.db.host |
DB_PORT |
taskmanager.db.port |
SECURITY_REGISTERABLE |
taskmanager.security.registerable |
SECURITY_CHANGEABLE |
taskmanager.security.changable |
SECURITY_RECOVERABLE |
taskmanager.security.recoverable |
SECURITY_CONFIRMABLE |
taskmanager.security.confirmable |
SECRET_KEY |
taskmanager.security.secretKey |
SECURITY_PASSWORD_SALT |
taskmanager.security.passwordSalt |
PROJECT_REPO |
taskmanager.project.git.url |
PROJECT_BRANCH |
taskmanager.project.git.branch |
PROJECT_RELATIVE_PATH |
taskmanager.project.git.relativePath |
For the explanation of these environment variables please see the Configuration section.
Setting up a development environment for kubernetes#
You need a number of tools to start developing for the TaskManager on kubernetes locally.
Once you have docker, k3d, helm and Tilt installed a kubernetes cluster need to be created. There is a Makefile that will create a basic cluster using k3d:
$ make up
The a development environment
can be started by using the Tiltfile
in the repository root:
$ tilt up
The TaskManager will be available at localhost/taskmanager
by default. The admin account will be set to admin
, password supersecretpassword
.
To stop running the system use the following commands:
$ tilt down
$ make down
The first command stops all TaskManager containers and the second command clean up the kubernetes cluster.
Setting up a local development environment#
If you want to set up a local development environment for either developing or just testing the TaskManager, a database and rabbitmq need to be provided.
The database needs to be initialized, for example for MySQL/mariadb:
# Go the mysql command line (add the -p if you have set a root password).
$ sudo mysql (-p)
# Create user
mysql> CREATE USER '<username>'@'localhost' IDENTIFIED BY '<password>';
# Create database
mysql> CREATE DATABASE taskmanager;
# Grant all permissions of the database to the user.
mysql> GRANT ALL ON taskmanager.* TO '<username>'@'localhost'; ``
The <username> and <password> needs to be replaced with a username and password of your choice.
Then you can create a .env
in the directory from which you want to
run the TaskManager. A minimal example (matching the above database
creation) would be:
FLASK_APP="taskmanager"
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://<username>:<password>@localhost/taskmanager"
SECURITY_PASSWORD_SALT="<password salt>"
SECRET_KEY="<secret key>"
Note
This example uses mysql/mariadb in the SQLALCHEMY_DATABASE_URI
, not that
the correct drivers for the target database needs to be selected. For
Postgres we tested using psycopg2
.
The password salt and secret key are used for security purposes. The password salt is described in the FlaskSecurity documentation The secret key is described in the Flask documentation The TaskManager needs to be installed in your environment before you can run it, this can simply be done from pypi using pip or from sources in case you want to develop TaskManager. Installation from pypi using pip is as simples as:
pip install taskmanager
If you want to develop from source we assume that you know how to install a Python package yourself. Now everything is set up, starting the app can be done using Flask:
$ flask run
Manual installation#
Warning
The manual installation is STRONGLY discouraged, please consider using Kubernetes or docker-compose instead.
This section explains how to install the TaskManager manually without using containers. Note that this is somewhat outdated and uses MySQL as a database backend. It is possible to use Postgres, but this is not documented here.
Prerequisites#
The first step is to install all requirements to install the TaskManager
apt-get install -y build-essential python-dev python-pip mercurial mysql-server libmysqlclient-dev nginx
pip install virtualenv
adduser taskman
su taskman
(taskman)$ mkdir ~/taskmanager && cd ~/taskmanager
(taskman)$ git clone https://gitlab.com/radiology/infrastructure/task-manager.git
(taskman)$ virtualenv --prompt="(taskman)" venv
(taskman)$ ln -s venv/bin/activate
(taskman)$ source activate
(taskman)$ cd taskmanager
(taskman)$ pip install -e .
Mysql database initialization#
Create a database and a user, and grant permissions.
mysql -p #[use -p if you have set a root password, which you should done anyway]
mysql> CREATE USER 'taskmanager'@'localhost' IDENTIFIED BY 'blaat123';
mysql> CREATE DATABASE taskmanager;
mysql> GRANT ALL ON taskmanager.* TO 'taskmanager'@'localhost';
(taskman)$ python ./create_config.py -d taskmanager -u taskmanager -p blaat123
(taskman)$ taskmanager-db-init [migrations should be implemented]
Initialize TaskManager db#
(taskman)$ taskmanager-db-init
(taskman)$ taskmanager-config taskmanager/tests/config/test_config.json
(taskman)$ taskmanager-test-tasks
(taskman)$ taskmanager-test-taskgroup
Running a test instance of the TaskManger#
(taskman)$ flask run
Deploy on a production server#
(taskman)$ pip install -r requirements_production.txt
service nginx start
rm /etc/nginx/sites-enabled/default
cp resources/nginx/taskmanager /etc/nginx/sites-available/taskmanager
ln -s /etc/nginx/sites-available/taskmanager /etc/nginx/sites-enabled/taskmanager
Startup scripts#
Find out which process management system you are using: `stat /proc/1/exe`
. If this outputs something along the lines of ‘/lib/systemd/systemd’ skip to the systemd version otherwise you probably are running on an upstart system. See [this StackExchange post](http://unix.stackexchange.com/questions/196166/how-to-find-out-if-a-system-uses-sysv-upstart-or-systemd-initsystem) for more details.
Below are configurations for the upstart and systemd provided. (Make sure you should only follow 1 of those).
systemd#
There is script that is called from the systemd unit in `resources/systemd/taskmanager-run`
. If you have changed the install location in the first steps please make sure to update this file accordingly.
cp resources/systemd/taskmanager.service /etc/systemd/system/taskmanager.service
systemctl enable taskmanager.service
systemctl start taskmanager
systemctl restart nginx
upstart#
If you have changed the install location in the first steps please make sure to update the upstart file accordingly.
cp resources/upstart/taskmanager.conf /etc/systemd/system/taskmanager.conf
initctl reload-configuration
service taskmanager start
service nginx restart
You can now reach the TaskManager on port 80 from your network.
Add authentication to the TaskManager (optional)#
You can add Basic Authentication to the TaskManager by creating credentials and uncommenting 2 lines from the provided nginx config
apt install apache2-utils
htpasswd -c /etc/nginx/.htpasswd username
Uncomment auth_basic ...
and auth_basic_user_file ...
in the nginx config (/etc/nginx/sites-available/taskmanager
).
systemctl restart nginx
Add sentry.io to the TaskManager (optional)#
Install the dependencies in the TaskManager virtualenv:
(taskman)$ pip install raven[flask]
Create a drop-in configuration for the systemd unit:
mkdir /etc/systemd/system/taskmanager.service.d
touch /etc/systemd/system/taskmanager.service.d/environment.conf
vim /etc/systemd/system/taskmanager.service.d/environment.conf
Add the following to the file and close it:
[service]
Environment="SENTRY_DSN=YOUR_SENTRY_DSN"
systemctl daemon-reload
systemctl restart taskmanager
Developing and installing a task session#
Let’s consider a relatively simple application, as an example to give more insight in the workflow of the TaskManager. Suppose you want to assign the task to a group of users to carry out a few measurements in an MR sequence of the brain. And suppose that these measurements can be done by indicating a set of anatomical landmarks in the MR data. The 3D coordinates of these landmarks can then be used afterwards to calculate some anatomical distances in the brain. Let’s consider that these measurements should be carried out in a cohort of 1000 patients. This measurement application can be realized with (for example) the following steps:
1. Add the group of users to the selected TaskManager.#
This means that the group should be defined in the TaskManager (if it is not there already), the users should be defined (if they are not there already), and these specific users should be added to (become a member of) the group just created/defined.
Adding a new group and new users is done using the REST API.
To add a user, click on POST /users
. You will see an example of the
input object:
{
"username": "string",
"name": "string",
"active": true,
"email": "string",
"password": "string",
"assignment_weight": 0
}
Click on “Try it out”. After that you can edit the six fields shown above. Fill in the username, name (real name of the person, the email address, some password, and the assignment_weight. The assignement weight is an indication of how many tasks (of the total number available) will be shown to this user. If the assignment_weight is 0, no task will be assigned to that specific user. If the assignment_weight equals 1, all tasks will be assigned (shown) to that user. If the user is a group member and the tasks are assigned to the group, also other users can pick up the task. If the assignment_weight is for example 0.1, only 10 percent of the uploaded tasks (assigned to the group) will be shown to this specific user. If a user is inactive (active == false), he or she is currently not involved in carrying out tasks. After filling in all the desired in a correct way, click on ‘execute’. Repeat this procedure for every new user you want to add.
To define a new group, click on ‘POST group’. You will see the following example model:
{
"groupname": "string",
"name": "string"
}
Fill in (edit) the “groupname” (used as referring ‘id’) and also give a more descriptive “name” in the second field. The click on execute. Now you are at the fase of making the new users a member of the group. At the moment this is not yet possible with the REST API. It should be done from ipython or by executing python scripts directly on the database.
Note
Adding a user to a group (make him/her a group member) is currently not yet possible with the REST API. For now it should done directly from the ipython command line or by python scripts.
2. Write the task_template#
Writing a JSON file with the ‘description/definition’ of the TaskManager task_template, needed to give the ViewR the optimal appearance in which the desired measurements can be carried out.
Details on how to write a viewr task template can be found at ViewR template documentation.
3. Upload the task_template to the TaskManager#
This means adding the template, mentioned/written in step 2 to the collection of templates known by (stored in) the TaskManager. This can be done using the REST API, but it is more convenient to use another approach, namely the TaskManager command line scripts mentioned before. If you use the API you have to click on ‘POST /task_templates’. You will see a model like this:
{
"label": "string",
"content": {}
}
You have to fill in the label
. That’s just the name of the task_template
that will be used as a kind of referred name/id. The contents should be the
complete template (JSON) as shown in step 2. It is more convenient to put
this contents into a JSON file, and upload the file with command line scripts
(executables). For more details see the section
Task Manager commands from the command line.
4. Write the specific task needed#
This means writing a JSON file with the overall ‘description/definition’ of the task to be carried out by the users. This task has to be linked to the desired template. In general a ‘task’ is less complex than a ‘template’ to write. An important issue to pay attention to is that the task should be linked to a template. This doesn’t mean only that the name of the task_template that should be used for this task should be filled in to the model (JSON file), but also that specific field in the task and task_template should be coherent and consistently linked to each other. More details will follow using the next example.
In this (example) case, the task could look this:
{
"scan_sources": {
"T1":"http://10.20:30:40/data/experiments/E1234/scans/T1W/resources/NIFTI/files/T1W.nii.gz"
},
"_vars": {
"SYSTEM_URL": "http://10.20:3:4",
"EXPERIMENT_ID": "E1234",
"LABEL": "L100"
},
"name": "L100 pinealis",
"fields": {},
"template": "glandula_pinealis",
"fields_file": "http://10.20:3:4/data/experiments/E1234/resources/FIELDS/files/out{timestamp}.json",
"windowing": {
"width": 50.0,
"center": 100.0
}
}
Important in this task example is the definition of the scan_sources
. In
this example only one MR sequence will be used and shown in the ViewR during
execution of the task. The MR sequence is a T1-weighted scan. The URL after
T1
: points to the location on a specific XNAT host where the input data
(T1) for this task can be retrieved.
If you look at the template definition above, you will see that there is a
field scans
. Also there is only 1 sequence defined, a T1. The protocol
and modality
are additional info.
Note
Keep in mind the name(s) of the input scan(s), in this case T1
should be
equal (consistent) in both the task.json and the template.json! If not the
task will not run properly when loaded in the ViewR
5. Upload the tasks to the TaskManager#
This means that for every dataset, specific MR sequence present in the cohort of 1000 patients, a task should be defined and uploaded to the Task Manager. This can almost be done using the REST API. With the REST API you have to post all 1000 tasks (one measurement task per data set) one by one. It is therefore more convenient to use the Task Manager command line scripts.
6. Apply the measurements#
This means: start the ViewR (as one of the users) and connect it to the TaskManager containing the info generated in step 1 to 5. This will be described in more detail in the following section.
Items to be discussed#
Roles and privileges (at least user and admin)
Description of the model
Task
How to create a Task
How to assign a Task to a user
How to upload a Task to the TaskManager
How to link a Task with a Template
Status of a Task (queued, locked, done, etc)
Relation ViewR, Task Manager, XNAT
How to deal with Tasks in de ViewR
TaskGroups, TaskTemplates, TaskTags
Creating a group and/or adding a user to the group is still difficult.
Relation taskmodel with usermodel
Usergroups
Assignment weights
Installation of the TaskManager? With a VirtualEnv? Or is that not needed?
REST-API! … Flask … What can you post put get delete etc.
How to connect the viewer to a specific Task Manager
Callback to the Syncotron.
With PUT you can change particular contents of tasks
With status you can make a task
done
(REST API)Exploring the contents of the TaskManager
Roles! What can a user do … and what can admin do … and intermediate … superuser