These are the sources for the CbrnAlert application. This application first consists of a REST API for the computation and visualization of atmospheric dispersion simulations of CBRN agents. The documentation of this API should be available here. The access to this API is restricted, but it's possible to install your own instance of the application.
This repo also contains the sources for the Single Page Application developed with the Angular framework, which provides a GUI for calling the API.
The API is defined using the Open API specifications. The file with all the API definitions is availabe here. From these definitions, the API routes and data structures are generated in the Angular/Typescript world with ng-openapi-gen and in the Julia/Genie world with OpenAPI.jl and OpenAPI generator.
This section covers setting up the app for development and production. We provide two methods:
- Docker (Recommended): This is the easiest and most reproducible method. The only prerequisite is having Docker installed.
- Manual Setup: Follow platform-specific instructions to install dependencies directly on your system.
Both methods are further described below.
The application needs to retrieve weather forecasts from ECMWF. That means you'll need to have access to licensed datasets from ECMWF. To setup your credentials, you need to go on https://api.ecmwf.int/v1/key to get your API key, and write those lines on a file called .ecmwfapirc in your $HOME folder:
{
"url" : "https://api.ecmwf.int/v1",
"key" : "YOUR_API_KEY",
"email" : "YOUR_EMAIL"
}
The easiest way to develop is to use a VS Code devcontainer. Install the Dev Containers VS Code extension.
And then after opening a clone of this repository choose to open it in a dev container. From there, start a first bash terminal and run:
cd backend
./bin/replThis will start a CLI into the backend server. Once you get the julia prompt, enter:
up()Next, open a new terminal and enter:
cd frontend
npm run startYou can now connect to http://localhost:4200 and login with login test and password test.
To build and run the app in a production environment using Docker, follow these steps.
- Ensure Docker and Docker Compose are installed on your system.
-
Clone the repository and navigate to the
dockerfolder:cd docker -
Build the service:
docker compose build
-
Run the service:
docker compose up
The app will start and listen on the port specified by the
APP_PORTvariable in thedocker/.envfile (default:8080).
- Open a browser and go to
http://localhost:8080. - Log in using the default credentials:
- Email:
default - Password:
password
- Email:
Before deploying the app, you must delete the default user and create new, secure user accounts. Failure to do so will leave your application publicly accessible to anyone.
The installation is meant to be done on Rocky Linux v9 or Centos 7, but it should be easy to adapt on other Linux systems. The main softwares needed for the application is Julia, nodejs, Angular, java and eccodes. See the section Installation without Docker.
The application is currently setup to work with Julia v1.10 and above. To easily install the Julia version of choice, you can use Juliaup:
curl -fsSL https://install.julialang.org | shAccept the basic configuration, restart your shell session, and assuming we use v1.10, install the Julia v1.10 binary with:
juliaup add 1.10Now you should be able to run this julia version with:
julia +1.10The app needs at least nodejs v16.
On Rocky Linux v9
The registry version of nodejs is should be at least v16, so it can be installed globally:
sudo yum update nodejsOn CentOS 7
On CentOS 7, nodejs is limited to v14, so we'll need to install it locally with nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash- Uncomment NVM related lines in
~/.bashrc chmod +x ~/.nvm/nvm.shsource ~/.bashrcnvm install 16(v18 won't work because of glibc incompatibilities)
At the moment, Java is needed for the openapi-generator-cli to work properly:
sudo yum install java-11-openjdk-develUnfortunately, the python program for flex_extract is executing the grib_set command with subprocess.check_call(). I couldn't find a way to make this command available in the PATH when running the python script. So eccodes and the grib_* commands must be available in the path.
sudo yum install eccodesgit clone https://github.com/PrzPaul/CbrnAlertInstall the Angular command line interface:
npm install @angular/cliDownload and install the required javascript librairies for the frontend:
cd CbrnAlert/frontend
npm install
You might get compats error from npm, if so, retry with npm install --force
Go to the backend folder and open a Julia REPL:
cd CbrnAlert/backend
julia +1.10 --project
Download the required Julia packages. You will have to enter the Pkg REPL by pressing ] from the Julia REPL. Then, the following command will install all the required registered Julia packages:
(CbrnAlertApp) pkg> instantiateYou might get an error like that:
[ Info: Precompiling FlexExtract [5ad5ba56-8ec2-41bb-8b56-2065914898b5]
ERROR: LoadError: InitError: PyError (PyImport_ImportModule
The Python package ecmwfapi could not be imported by pyimport. Usually this means
that you did not install ecmwfapi in the Python version being used by PyCall.The simplest way to overcome this is to configure PyCall to use a Julia-specific Python distribution. To do that:
ENV["PYTHON"] = ""
using Pkg
Pkg.build("PyCall")Then restart julia, and you should be to import FlexExtract without error.
Still in the backend folder, run the repl scripts:
cd CbrnAlert/backend
./bin/replThis will open a Julia REPL and setup the Genie environment. This may take a few minutes. Once it's done and you can write in the Julia REPL, you need to set up the database with:
using SearchLight
using SearchLightSQLite
SearchLight.Migration.init()
SearchLight.Migration.status()
SearchLight.Migration.allup()Finally, due to a bug in the flex_extract software used to retrieve ECMWF data, run the following lines still in the Julia REPL:
using FlexExtract
faulty_script = joinpath(FlexExtract.PATH_FLEXEXTRACT, "Source", "Python", "Mods", "checks.py")
run(`sed -i "882s@'{:0>3}'.join(numbers)@'/'.join(numbers)@" $faulty_script`)This temporary patch can be ignored once the flex_extract source files have been fixed.
We need now to generate the keys for encoding and decoding the JSON Web Tokens authentication. Go to the backend folder and write:
openssl genrsa -out config/private.pem 2048
openssl rsa -in config/private.pem -out config/public.pem -outform PEM -puboutNote: These lines won't work with OpenSSL v1
To get the app up and ready for development, you'll need to follow those few steps.
Go to the backend folder, and run the repl scripts:
cd CbrnAlert/backend
./bin/replAnd finally start the server:
julia> up()
┌ Info: 2023-10-06 09:42:54
└ Web Server starting at http://127.0.0.1:8000
[ Info: 2023-10-06 09:42:54 Listening on: 127.0.0.1:8000, thread id: 1
Genie.Server.ServersCollection(Task (runnable) @0x00007f821a6e42f0, nothing)You should see those lines, meaning that a server is listening on localhost:8000.
If you want, you can also set up a tmux session like this (you will probably have to install tmux with sudo yum install tmux):
tmux new -s cbrnalert_backendand then follow the above steps.
If you need to start the server again, you just need to run repl script and run up() in the Julia REPL:
./bin/repl
julia> up()In case you're using tmux you can attach to your screen session with:
tmux a -t cbrnalert_backendGo to the frontend folder and run this command:
cd CbrnAlert/frontend
npm run generate:allThis will read the OpenAPI specifications file to generate all the files needed for both the frontend and the backend.
Finally, run the frontend server that will listen to localhost:4200:
npm run startAt this point you should be able to connect to localhost:4200 and start using the application. If you set everything up on a remote machine, you might need to use ssh tunnels to redirect the application ports. When using the VS code editor, this is done automatically.
When getting on the app landing page, you're asked for an email and a password. That's because you need to be authenticated to use the application API. To add a new user in the database, you need to get into the Genie environment in the interactive mode:
cd CbrnAlert/backend
./bin/replThen you need to use the Users.add function:
julia> using CbrnAlertApp.Users
julia> Users.add("USER_EMAIL", "USER_PW", username = "USERNAME")Now you should be able to log into the app by using USER_EMAIL and USER_PW.
We will deploy the app by using nginx to serve the Angular frontend static files and proxy the API traffic to the Genie backend.
Go to the frontend folder and run:
npm run buildThis should create a dist folder that will be served with nginx.
Go to the backend folder. You should install the tmux software and create a new tmux session for the backend. This will allow you to close the terminal while keeping the Julia server up.
tmux new -s genieThen start the Genie server in production mode:
export GENIE_ENV=prod
./bin/serverFirst install nginx and start it to see if it works (you'll need to do all of this in sudo mode):
yum install nginx
systemctl start nginx
systemctl enable nginxThe next step is to configure nginx to serve the static files and forward the API traffic to the Genie backend. After installing nginx, you should have the default configuration in the /etc/nginx directory. You can add the configuration for the application by creating a new configuration file:
touch /etc/nginx/conf.d/YOUR_DOMAIN.confwhere YOUR_DOMAIN is the domain name you want to deploy. Then writing the following configuration in this file should do the trick:
server {
server_name YOUR_DOMAIN;
root PATH_TO_APP/CbrnAlert/frontend/dist;
location /api {
proxy_pass http://localhost:8000;
}
location /api/docs {
proxy_pass http://localhost:8000/docs;
}
location / {
try_files $uri $uri/ /index.html;
}
}Now, for having a secured communication with HTTPS, we can use certbot and Let's Encrypt to get the certificates. First, you need to install certbot with:
sudo yum install certbot python3-certbot-apacheand to get the Let's Encrypt certificates:
sudo certbot --nginx -d YOUR_DOMAINcertbot should have modified your configuration file that should look like this now:
server {
server_name YOUR_DOMAIN;
root PATH_TO_APP/CbrnAlert/frontend/dist;
location /api {
proxy_pass http://localhost:8000;
}
location /api/docs {
proxy_pass http://localhost:8000/docs;
}
location / {
try_files $uri $uri/ /index.html;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/YOUR_DOMAIN/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/YOUR_DOMAIN/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = YOUR_DOMAIN) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 default_server;
listen [::]:80 default_server;
server_name YOUR_DOMAIN;
return 404; # managed by Certbot
}You'll also need to open the port of the server machine to the world:
sudo firewall-cmd --add-port=80/tcp --permanent
sudo firewall-cmd --zone=public --permanent --add-service=https
sudo firewall-cmd --reloadIf the machine uses SELinux, you might have a problem with connecting to the backend API. This can be solved with:
setsebool -P httpd_can_network_connect 1Now, you should get the application landing page when you connect to your domain with a browser. However, it's possible that SELinux blocks the access of nginx to the PATH_TO_APP/CbrnAlert/frontend/dist folder. This can be solved by changing the context of this folder:
sudo find PATH_TO_APP/CbrnAlert/frontend/dist/ -exec chcon -t httpd_sys_content_t {} \;
After all that, your instance of the application should be accessible on the Internet! Please open an issue if it's not the case. Don't forget that you'll need to add a new user to be able to connect (see the "Adding a user in the database" section).