Commit d6b2e404 authored by James Kirk's avatar James Kirk
Browse files

feat: dockerised the app

feat: added docker-compose setup, inc run-compose and .env to handle vars for locally running
refactor: changed rmq to fail when it can't connect, allowing stuff to wait until the MQ is available
refactor: moved from assuming pipenv to just pip
refactor: mounted volumes, so changed interactions with clients.json to match
parent 298299d5
MQ_HOST=rmq
# DATA_DIR=
# SOAR_TOKEN_LIFETIME=
# SOAR_TOKEN_SECRET=
\ No newline at end of file
clients.json clients.json
examples/ examples/
rmq.log rmq.log
Pipfile
Pipfile.lock
\ No newline at end of file
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
pubsubpy = "*"
pika = "*"
pyrabbit = "*"
flask = "*"
flask-restful = "*"
marshmallow = "*"
bson = "*"
flask-cors = "*"
cryptography = "*"
[dev-packages]
[requires]
python_version = "3.8"
This diff is collapsed.
from flask import Flask from flask import Flask
from flask_cors import CORS
from flask_restful import Api from flask_restful import Api
from endpoints.clients import Client, ClientList from endpoints.clients import Client, ClientList
from endpoints.notify import Notify
from endpoints.receive import Receive from endpoints.receive import Receive
from endpoints.send import Send from endpoints.send import Send
from endpoints.notify import Notify
from endpoints.token import Token from endpoints.token import Token
from flask_cors import CORS
from models.token import TokenModel from models.token import TokenModel
token = TokenModel() token = TokenModel()
...@@ -23,4 +24,4 @@ api.add_resource(Notify, "/notify") ...@@ -23,4 +24,4 @@ api.add_resource(Notify, "/notify")
api.add_resource(Token, "/token") api.add_resource(Token, "/token")
if __name__ == "__main__": if __name__ == "__main__":
app.run(debug=True, port=8087) app.run(debug=False, port=8087, host="0.0.0.0")
FROM python:alpine3.17
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
ENTRYPOINT [ "python" ]
\ No newline at end of file
version: '3.8'
services:
rabbitmq__local:
image: rabbitmq:management
ports:
- "5672:5672"
# - "15672:15672" # Admin web console
expose:
- "5672"
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
interval: 5s
timeout: 20s
retries: 3
container_name: rmq
soar_bus:
build:
context: ..
dockerfile: docker/Dockerfile
restart: on-failure
depends_on:
- rabbitmq__local
environment:
- MQ_HOST=${MQ_HOST}
command: "soar_bus.py"
soar_api:
build:
context: ..
dockerfile: docker/Dockerfile
ports:
- "8087:8087"
expose:
- "8087"
command: "api.py"
environment:
- MQ_HOST=${MQ_HOST}
volumes:
- ${DATA_DIR}/data:/data
\ No newline at end of file
import json import json
import os
from flask_restful import Resource, abort from flask_restful import Resource, abort
from models.token import TokenModel from models.token import TokenModel
class AuthResource(Resource): class AuthResource(Resource):
def __init__(self): def __init__(self):
self.token = TokenModel() self.token = TokenModel()
with open("clients.json", "r") as clients_file: data_dir = os.getenv("DATA_DIR")
with open("/data/clients.json", "r") as clients_file:
self.clients = json.load(clients_file) self.clients = json.load(clients_file)
def auth(self, request): def auth(self, request):
......
...@@ -13,7 +13,7 @@ class ClientSchema(Schema): ...@@ -13,7 +13,7 @@ class ClientSchema(Schema):
class ClientsFile: class ClientsFile:
file = "clients.json" file = "/data/clients.json"
mtime = 0 mtime = 0
clients = {} clients = {}
parser = None parser = None
......
...@@ -18,7 +18,7 @@ class Token(Resource): ...@@ -18,7 +18,7 @@ class Token(Resource):
def __init__(self): def __init__(self):
self.schema = TokenQuerySchema() self.schema = TokenQuerySchema()
self.model = TokenModel() self.model = TokenModel()
with open("clients.json", "r") as clients_file: with open("/data/clients.json", "r") as clients_file:
self.clients = json.load(clients_file) self.clients = json.load(clients_file)
def get(self): def get(self):
......
-i https://pypi.org/simple
amqp==5.1.1 ; python_version >= '3.6'
aniso8601==9.0.1
bson==0.5.10
cffi==1.15.1
click==8.1.3 ; python_version >= '3.7'
cryptography==38.0.3
flask==2.2.2
flask-cors==3.0.10
flask-restful==0.3.9
future==0.18.2 ; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'
httplib2==0.21.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
importlib-metadata==5.1.0 ; python_version < '3.10'
itsdangerous==2.1.2 ; python_version >= '3.7'
jinja2==3.1.2 ; python_version >= '3.7'
kombu==5.2.4 ; python_version >= '3.7'
markupsafe==2.1.1 ; python_version >= '3.7'
marshmallow==3.19.0
packaging==21.3 ; python_version >= '3.6'
pika==1.3.1
pubsubpy==2.3.0
pycparser==2.21
pyparsing==3.0.9 ; python_full_version >= '3.6.8'
pyrabbit==1.1.0
python-dateutil==2.8.2 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
pytz==2022.6
six==1.16.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
vine==5.0.0 ; python_version >= '3.6'
werkzeug==2.2.2 ; python_version >= '3.7'
zipp==3.10.0 ; python_version >= '3.7'
import json import json
import os
import pika import pika
host='localhost' # TODO Handle host being passed in (https://git.noc.ac.uk/communications-backbone-system/communications-backbone/-/issues/17) host = os.getenv("MQ_HOST", "localhost") # Sets to whatever MQ_HOST is, or defaults to localhost
# ------------------------------------------------------------------------------------------------------------------------------------------------------------- # -------------------------------------------------------------------------------------------------------------------------------------------------------------
def pika_connect(host): def pika_connect(host):
try:
connection = pika.BlockingConnection(pika.ConnectionParameters(host)) connection = pika.BlockingConnection(pika.ConnectionParameters(host))
except Exception:
connection = None
if connection is not None:
channel = connection.channel() channel = connection.channel()
else:
print("ERROR: Pika has been unable to connect to host '%s'. Is RabbitMQ running?" % host)
raise Exception("ERROR: Pika has been unable to connect to host '%s'. Is RabbitMQ running?" % host)
return connection, channel return connection, channel
...@@ -154,7 +164,6 @@ def subscribe(queue_name, exchange_name, topic=None): ...@@ -154,7 +164,6 @@ def subscribe(queue_name, exchange_name, topic=None):
# setup bindings between queue and exchange, # setup bindings between queue and exchange,
# exchange_type is either 'fanout' or 'topic' based on if the topic arg is passed # exchange_type is either 'fanout' or 'topic' based on if the topic arg is passed
connection, channel = pika_connect(host=host) connection, channel = pika_connect(host=host)
setup_queue(channel=channel, queue_name=queue_name) setup_queue(channel=channel, queue_name=queue_name)
if topic is None: if topic is None:
......
set -a
source .env
if [[ -z "${DATA_DIR}" ]]; then
DATA_DIR=$(pwd)
fi
docker-compose -f docker/docker-compose.yaml up --build
\ No newline at end of file
...@@ -10,8 +10,9 @@ ...@@ -10,8 +10,9 @@
# soar-broadcast - admin messages forwarded to all client-inboxes regardless of subscriptions # soar-broadcast - admin messages forwarded to all client-inboxes regardless of subscriptions
import concurrent.futures import concurrent.futures
from endpoints.clients import ClientsFile from endpoints.clients import ClientsFile
from rmq import publish, subscribe, broadcast, forward from rmq import broadcast, forward, publish, subscribe
THREADS = [] THREADS = []
EXCHANGES = { EXCHANGES = {
...@@ -21,6 +22,7 @@ EXCHANGES = { ...@@ -21,6 +22,7 @@ EXCHANGES = {
def main(): def main():
print("Starting SOAR bus...")
clients_file = ClientsFile() clients_file = ClientsFile()
clients = clients_file.get() clients = clients_file.get()
...@@ -45,6 +47,7 @@ def main(): ...@@ -45,6 +47,7 @@ def main():
EXCHANGES.get("publish"), EXCHANGES.get("publish"),
client["subscription"] # topic client["subscription"] # topic
) )
THREADS.append(thread)
thread = executor.submit( thread = executor.submit(
subscribe, subscribe,
f"{id}-inbox", f"{id}-inbox",
...@@ -55,6 +58,14 @@ def main(): ...@@ -55,6 +58,14 @@ def main():
# TODO - add optional webhook target to client and post to webhook target # TODO - add optional webhook target to client and post to webhook target
# if present # if present
# Make sure the threads are actually running, error if not,
# this allows the SOAR Bus to actually wait for RMQ to start running
for thread in THREADS:
thread.result()
try:
print(thread.result())
except Exception as e:
print(e)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment