How To
Summary
This tutorial will outline how to replace Flask with Gunicorn as an alternative HTTP server. The app will be a simple hello world app.
Steps
Prerequisites
- QRadar App SDK v2
- Python 3
- pip
Create the App
Create a new folder for your app:
mkdir GunicornApp && cd GunicornApp
Use the QRadar App SDK to initialise the app code:
qapp create
Add the Gunicorn pip Dependency
Make a new folder for storing the Gunicorn pip dependencies that will be installed called container/pip
.
mkdir container/pip
Download the Gunicorn pip and any of its dependencies using pip download
:
pip download \
--only-binary=:all: \
--platform linux_x86_64 \
--dest container/pip \
gunicorn
This should download the Gunicorn pip and any of its dependencies into the container/pip
folder.
Add the Supervisord configuration
Create a new folder to hold our supervisord configuration files called container/conf/supervisord.d
:
mkdir -p container/conf/supervisord.d
This container/conf/supervisord.d
folder holds Supervisord configuration and all configuration in this folder is copied into /etc/supervisord.d
on startup.
Create your app's Gunicorn configuration file container/conf/supervisord.d/gunicorn.conf
:
[program:gunicorn]
directory=/opt/app-root
command=/usr/local/bin/gunicorn -b 0.0.0.0:5000 --timeout 120 --access-logfile - --workers=4 --preload "app:create_app()"
autostart=true
autorestart=unexpected
stdout_logfile=/opt/app-root/store/log/gunicorn.log
stderr_logfile=/opt/app-root/store/log/gunicorn.log
This configuration file defines how Supervisord should run Gunicorn as part of this app, with log files defined, automatic restarts and the command to start Gunicorn (with all of its command line parameters) stated.
Write the Manifest
Open the manifest.json
file to edit some values to make it more relevant to the app, making it look like this:
{
"name": "Gunicorn App",
"description": "Custom supervisord configuration which starts gunicorn as a replacement for flask and exposes port 5000 as the webserver port",
"version": "1.0.0",
"image": "qradar-app-base:2.0.0",
"load_flask": "false",
"areas": [
{
"id": "GunicornSupervisordTab",
"text": "Gunicorn supervisord",
"description": "Dummy tab that displays text from the flask app",
"url": "index",
"required_capabilities": []
}
],
"services": [
{
"name": "gunicorn",
"port": 5000,
"version": "1.0"
}
],
"uuid": "<your unique app UUID>"
}
This manifest defines a lot, first the Flask webserver is overridden and QRadar is informed it should not be loaded with:
"load_flask": "false",
The manifest then defines an 'area' in the QRadar UI to display the app, called GunicornSupervisordTab
that is populated by calling the /index
endpoint:
"areas": [
{
"id": "GunicornSupervisordTab",
"text": "Gunicorn supervisord",
"description": "Dummy tab that displays text from the flask app",
"url": "index",
"required_capabilities": []
}
],
Finally the manifest describes and defines a named service which will run the Supervisord program we have configured above called gunicorn
alongside the port it should serve on, exposing the path /index
:
"services": [
{
"name": "gunicorn",
"port": 5000,
"version": "1.0"
}
],
Since this named service is running on port 5000 the area does not need to include a reference to the named service that it is querying - it can be accessed directly. This is only the case if the named service is running on port 5000.
Run the App/Package the App
The app can then be run locally from the project root with:
qapp run
Or packaged and deployed from the project root with:
qapp package -p <app zip name>
qapp deploy -p <app zip name> -q <qradar console> -u <qradar user>
Document Location
Worldwide
Was this topic helpful?
Document Information
Modified date:
30 March 2021
UID
ibm16437467