Skip to content

Commit

Permalink
Merge pull request #149 from atlanticwave-sdx/86.wsgi
Browse files Browse the repository at this point in the history
Make SDX Local Controller a WSGI app
  • Loading branch information
sajith authored Jun 19, 2024
2 parents 7d6e15b + d8a5169 commit a8d56e9
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 37 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ test-db

# Ignore copies of env
env.*
.env
.env*

# Ignore files written by code coverage tools
.coverage
Expand Down
7 changes: 7 additions & 0 deletions .hadolint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ignored:
# DL3013 recommends that Python dependencies be pinned, but we
# probably do not want to do that right now. Unpinned dependencies
# has been working okay for us so far, and pinning (using pip-tools
# would be ideal) should be done separately after a discussion,
# because that would change the workflow a bit.
- DL3013
11 changes: 7 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ WORKDIR /usr/src/app

COPY . /usr/src/app

RUN pip3 install --no-cache-dir .
# create a venv.
RUN python3 -m venv /opt/venv --upgrade-deps

EXPOSE 8080
# Make sure we use the venv.
ENV PATH="/opt/venv/bin:$PATH"
ENV VIRTUAL_ENV="/opt/venv"

ENTRYPOINT ["python3"]
RUN pip3 install --no-cache-dir .[wsgi]

CMD ["-m", "sdx_lc"]
CMD ["./entrypoint.sh"]
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ example -- see above), and then run the server:

```console
$ source .env
$ python3 -m sdx_lc
$ flask --app sdx_lc.app:app run --debug
```


Expand Down Expand Up @@ -123,7 +123,6 @@ $ source ./venv/bin/activate
$ pip3 install --editable .[test]
$ pytest
```
`

## Communication between SDX Controller and Local Controller

Expand Down
10 changes: 10 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#! /bin/sh

# A helper script that can be executed off docker, just so that
# uvicorn will print the right port number. Docker will not do
# environment variable substitution in CMD lines, so this script
# became necessary.

set -eu

python3 -m uvicorn sdx_lc.app:asgi_app --host 0.0.0.0 --port "$SDXLC_PORT"
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies = [
"setuptools >= 21.0.0",
"pika >= 1.2.0",
"connexion[swagger-ui] == 2.14.2",
"asgiref >= 3.7.2",
"pymongo > 3.0",
]

Expand All @@ -43,6 +44,9 @@ format = [
"black == 24.*",
"isort == 5.*",
]
wsgi = [
"uvicorn"
]

[options.packages.find]
where = "sdx_lc"
Expand Down
82 changes: 52 additions & 30 deletions sdx_lc/__main__.py → sdx_lc/app.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,18 @@
#!/usr/bin/env python3

import argparse
import json
import logging
import os
import threading
import time
from optparse import OptionParser
from queue import Queue
from subprocess import call

import connexion
from asgiref.wsgi import WsgiToAsgi
from flask import redirect

from sdx_lc import encoder
from sdx_lc.messaging.topic_queue_consumer import *
from sdx_lc.utils.db_utils import *

logger = logging.getLogger(__name__)
logging.getLogger("pika").setLevel(logging.WARNING)
LOG_FILE = os.environ.get("LOG_FILE")


def is_json(myjson):
try:
json.loads(myjson)
except ValueError as e:
return False
return True
from sdx_lc.messaging.topic_queue_consumer import TopicQueueConsumer
from sdx_lc.utils.db_utils import DbUtils


def start_consumer(thread_queue, db_instance):
Expand All @@ -37,9 +24,6 @@ def start_consumer(thread_queue, db_instance):
function.
"""

MESSAGE_ID = 0
HEARTBEAT_ID = 0

rpc = TopicQueueConsumer(thread_queue=thread_queue, exchange_name="connection")
t1 = threading.Thread(target=rpc.start_consumer, args=())
t1.start()
Expand All @@ -51,22 +35,32 @@ def start_pull_topology_change():
call(["python", "sdx_lc/jobs/pull_topo_changes.py"])


def main():
if LOG_FILE:
logging.basicConfig(filename=LOG_FILE, level=logging.INFO)
def create_app():
"""
Create a Flas/Connexion App.
"""

logger = logging.getLogger(__name__)
logging.getLogger("pika").setLevel(logging.WARNING)

log_file = os.getenv("LOG_FILE")

if log_file:
logging.basicConfig(filename=log_file, level=logging.INFO)
else:
logging.basicConfig(level=logging.INFO)

logger.info(
f"SDX Local Controller starting up ("
f"name: {os.getenv('SDXLC_NAME')}, "
f"domain: {os.getenv('SDXLC_DOMAIN')})"
)

# Run swagger service
app = connexion.App(__name__, specification_dir="./swagger/")
app.app.json_encoder = encoder.JSONEncoder
app.add_api("swagger.yaml", arguments={"title": "SDX LC"}, pythonic_params=True)

# Run swagger in a thread
threading.Thread(
target=lambda: app.run(port=os.getenv("SDXLC_PORT") or 8080)
).start()

# Start pulling topology changes from domain controller in a
# separate subprocess
processThread = threading.Thread(target=start_pull_topology_change)
Expand All @@ -75,9 +69,37 @@ def main():
# Get DB connection and tables set up.
db_instance = DbUtils()
db_instance.initialize_db()

# Consume connection/link messages
thread_queue = Queue()
start_consumer(thread_queue, db_instance)

return app.app


# We can run the app using flask, like so:
#
# $ flask --app sdx_lc.app:app run --debug
#
# Or with an WSGI server such as gunicorn:
#
# $ gunicorn --bind localhost:$SDXLC_PORT sdx_lc.app:app
#
app = create_app()

# We use WsgiToAsgi adapter so that we can use an ASGI server (such as
# uvicorn or hypercorn), like so:
#
# $ uvicorn sdx_lc.app:asgi_app --host 0.0.0.0 --port $SDXLC_PORT
#
asgi_app = WsgiToAsgi(app)


# Set up a redirect for convenience.
@app.route("/", methods=["GET"])
def index():
return redirect("/SDX-LC/2.0.0/ui/")


if __name__ == "__main__":
main()
app.run(port=os.getenv("SDXLC_PORT") or 8080)

0 comments on commit a8d56e9

Please sign in to comment.