-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge HAN-54: Creacion dummy handoff gateway #1
- Loading branch information
Showing
12 changed files
with
378 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
LOGGING_LEVEL= | ||
USERS_HOST= | ||
MEASUREMENTS_HOST= | ||
PLANTS_HOST= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
name: Flake8 and Black | ||
|
||
on: [push] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up Python ${{ matrix.python-version }} | ||
uses: actions/setup-python@v3 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install flake8 black | ||
- name: Checking code style with Flake8 | ||
run: | | ||
flake8 . | ||
- name: Formatting code with Black | ||
run: | | ||
black . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
FROM python:3.11-slim-buster | ||
WORKDIR /src | ||
|
||
COPY . /src | ||
|
||
RUN pip install -r requirements.txt | ||
|
||
EXPOSE 5000 | ||
|
||
CMD ["gunicorn", "wsgi:app", "-b", "0.0.0.0:5000"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
default: docker-compose-up | ||
|
||
all: | ||
|
||
create-network: | ||
@if ! docker network inspect common_network >/dev/null 2>&1; then \ | ||
docker network create common_network; \ | ||
fi | ||
.PHONY: create-network | ||
|
||
docker-image: create-network | ||
docker build -f ./Dockerfile -t "gateway:latest" . | ||
.PHONY: docker-image | ||
|
||
docker-compose-up: docker-image | ||
docker-compose -f docker-compose.yaml up -d --build | ||
.PHONY: docker-compose-up | ||
|
||
docker-compose-down: | ||
docker-compose -f docker-compose.yaml stop -t 20 | ||
docker-compose -f docker-compose.yaml down --remove-orphans | ||
.PHONY: docker-compose-down | ||
|
||
docker-compose-logs: | ||
docker-compose -f docker-compose.yaml logs -f | ||
.PHONY: docker-compose-logs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import os | ||
import logging | ||
from flask import Flask | ||
from flask_restful import Api | ||
from werkzeug.routing import BaseConverter | ||
from src.resource import Gateway | ||
|
||
|
||
def initialize_log(logging_level): | ||
""" | ||
Python custom logging initialization | ||
Current timestamp is added to be able to identify in docker | ||
compose logs the date when the log has arrived | ||
""" | ||
logging.basicConfig( | ||
format='%(asctime)s %(levelname)-8s %(message)s', | ||
level=logging_level, | ||
datefmt='%Y-%m-%d %H:%M:%S', | ||
) | ||
|
||
|
||
logging_level = os.getenv("LOGGING_LEVEL", "INFO") | ||
initialize_log(logging_level) | ||
app = Flask(__name__) | ||
|
||
|
||
class RegexConverter(BaseConverter): | ||
def __init__(self, url_map, *items): | ||
super(RegexConverter, self).__init__(url_map) | ||
self.regex = items[0] | ||
|
||
|
||
@app.after_request | ||
def _build_cors_post_response(response): | ||
response.headers.add("Access-Control-Allow-Origin", "*") | ||
response.headers.add("Access-Control-Allow-Headers", "*") | ||
response.headers.add("Access-Control-Allow-Methods", "*") | ||
return response | ||
|
||
|
||
app.url_map.converters['regex'] = RegexConverter | ||
api = Api(app) | ||
api.add_resource(Gateway, '/<path:url>') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
version: '3.9' | ||
|
||
services: | ||
|
||
gateway: | ||
build: | ||
context: ./ | ||
container_name: gateway | ||
env_file: | ||
- .env | ||
ports: | ||
- "5000:5000" | ||
networks: | ||
- common_network | ||
|
||
networks: | ||
common_network: | ||
external: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
requests | ||
Werkzeug | ||
Flask | ||
flask_restful | ||
gunicorn | ||
PyJWT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import os | ||
import logging | ||
|
||
import requests | ||
from flask import make_response | ||
|
||
|
||
def get_query_params(queryParam) -> str: | ||
if not queryParam: | ||
return "" | ||
return f"?{str(queryParam, 'utf-8')}" | ||
|
||
|
||
class Measurements: | ||
def __init__(self): | ||
self.host = os.getenv("MEASUREMENTS_HOST") | ||
|
||
def getResponseJson(self, response): | ||
if response.status_code == 503 or not response.text: | ||
return {"message": "measurements service is currently unavailable," | ||
" please try again later", "status": 503} | ||
return response.json() | ||
|
||
def get(self, url, body, headers, query_params): | ||
url = f"{self.host}{url}{get_query_params(query_params)}" | ||
logging.info(f"MEASUREMENTS | GET | {url}") | ||
response = requests.get(url, json=body, headers=headers) | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) | ||
|
||
def post(self, url, body, headers, query_params): | ||
response = requests.post(f"{self.host}{url}" | ||
f"{get_query_params(query_params)}", | ||
json=body, | ||
headers=headers) | ||
logging.info(f"MEASUREMENTS | POST | {url}") | ||
logging.debug(f"BODY: {body}") | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) | ||
|
||
def patch(self, url, body, headers, query_params): | ||
response = requests.patch(f"{self.host}{url}" | ||
f"{get_query_params(query_params)}", | ||
json=body, | ||
headers=headers) | ||
logging.info(f"MEASUREMENTS | PATCH | {url}") | ||
logging.debug(f"BODY: {body}") | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) | ||
|
||
def delete(self, url, body, headers, query_params): | ||
response = requests.delete(f"{self.host}{url}" | ||
f"{get_query_params(query_params)}", | ||
headers=headers) | ||
logging.info(f"MEASUREMENTS | DELETE | {url}") | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import os | ||
import logging | ||
|
||
import requests | ||
from flask import make_response | ||
|
||
|
||
def get_query_params(queryParam) -> str: | ||
if not queryParam: | ||
return "" | ||
return f"?{str(queryParam, 'utf-8')}" | ||
|
||
|
||
class Plants: | ||
def __init__(self): | ||
self.host = os.getenv("PLANTS_HOST") | ||
|
||
def getResponseJson(self, response): | ||
if response.status_code == 503 or not response.text: | ||
return {"message": "plants service is currently unavailable," | ||
"please try again later", "status": 503} | ||
return response.json() | ||
|
||
def get(self, url, body, headers, query_params): | ||
url = f"{self.host}{url}{get_query_params(query_params)}" | ||
response = requests.get(url, json=body, headers=headers) | ||
logging.info(f"PLANTS | GET | {url}") | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) | ||
|
||
def post(self, url, body, headers, query_params): | ||
response = requests.post(f"{self.host}{url}" | ||
f"{get_query_params(query_params)}", | ||
json=body, | ||
headers=headers) | ||
logging.info(f"PLANTS | POST | {url}") | ||
logging.debug(f"BODY: {body}") | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) | ||
|
||
def patch(self, url, body, headers, query_params): | ||
response = requests.patch(f"{self.host}{url}" | ||
f"{get_query_params(query_params)}", | ||
json=body, | ||
headers=headers) | ||
logging.info(f"PLANTS | PATCH | {url}") | ||
logging.debug(f"BODY: {body}") | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) | ||
|
||
def delete(self, url, body, headers, query_params): | ||
response = requests.delete(f"{self.host}{url}" | ||
f"{get_query_params(query_params)}", | ||
headers=headers) | ||
logging.info(f"PLANTS | DELETE | {url}") | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import os | ||
import logging | ||
|
||
import requests | ||
from flask import make_response | ||
|
||
|
||
def get_query_params(queryParam) -> str: | ||
if not queryParam: | ||
return "" | ||
return f"?{str(queryParam, 'utf-8')}" | ||
|
||
|
||
class Users: | ||
def __init__(self): | ||
self.host = os.getenv("USERS_HOST") | ||
|
||
def getResponseJson(self, response): | ||
if response.status_code == 503 or not response.text: | ||
return {"message": "users service is currently unavailable, please" | ||
"try again later", "status": 503} | ||
return response.json() | ||
|
||
def get(self, url, body, headers, query_params): | ||
url = f"{self.host}{url}{get_query_params(query_params)}" | ||
response = requests.get(url, json=body, headers=headers) | ||
logging.info(f"USERS | GET | {url}") | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) | ||
|
||
def post(self, url, body, headers, query_params): | ||
response = requests.post(f"{self.host}{url}" | ||
f"{get_query_params(query_params)}", | ||
json=body, | ||
headers=headers) | ||
logging.info(f"USERS | POST | {url}") | ||
logging.debug(f"BODY: {body}") | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) | ||
|
||
def patch(self, url, body, headers, query_params): | ||
response = requests.patch(f"{self.host}{url}" | ||
f"{get_query_params(query_params)}", | ||
json=body, | ||
headers=headers) | ||
logging.info(f"USERS | PATCH | {url}") | ||
logging.debug(f"BODY: {body}") | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) | ||
|
||
def delete(self, url, body, headers, query_params): | ||
response = requests.delete(f"{self.host}{url}" | ||
f"{get_query_params(query_params)}", | ||
headers=headers) | ||
logging.info(f"USERS | DELETE | {url}") | ||
return make_response(self.getResponseJson(response), | ||
response.status_code) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import logging | ||
from flask import request, make_response # type: ignore | ||
from flask_restful import Resource | ||
|
||
from src.apps.users import Users | ||
from src.apps.measurements import Measurements | ||
from src.apps.plants import Plants | ||
|
||
|
||
def getExtraData(): | ||
if request.is_json: | ||
body = request.json | ||
else: | ||
body = {} | ||
headers = dict(request.headers) | ||
if 'Host' in headers: | ||
headers.pop('Host') # Invalid header | ||
query_params = request.query_string | ||
return body, headers, query_params | ||
|
||
|
||
SERVICE_MAP = { | ||
"users": Users(), | ||
"measurements": Measurements(), | ||
"device-plant": Measurements(), | ||
"plants": Plants(), | ||
"plant-type": Plants(), | ||
"logs": Plants(), | ||
"login": Users() | ||
} | ||
|
||
|
||
def getCorrectEndpoint(url: str): | ||
values = url.split("/") | ||
return SERVICE_MAP.get(values[0]) if len(values) else None | ||
|
||
|
||
class Gateway(Resource): | ||
def get(self, url): | ||
resource = getCorrectEndpoint(url) | ||
if not resource: | ||
logging.error(f"Resource not found for url {url}") | ||
return make_response({"message": "not found"}, 404) | ||
return resource.get(url, *getExtraData()) | ||
|
||
def post(self, url): | ||
resource = getCorrectEndpoint(url) | ||
if not resource: | ||
logging.error(f"Resource not found for url {url}") | ||
return make_response({"message": "not found"}, 404) | ||
return resource.post(url, *getExtraData()) | ||
|
||
def patch(self, url): | ||
resource = getCorrectEndpoint(url) | ||
if not resource: | ||
logging.error(f"Resource not found for url {url}") | ||
return make_response({"message": "not found"}, 404) | ||
return resource.patch(url, *getExtraData()) | ||
|
||
def delete(self, url): | ||
resource = getCorrectEndpoint(url) | ||
if not resource: | ||
logging.error(f"Resource not found for url {url}") | ||
return make_response({"message": "not found"}, 404) | ||
return resource.delete(url, *getExtraData()) | ||
|
||
def put(self, url): | ||
resource = getCorrectEndpoint(url) | ||
if not resource: | ||
logging.error(f"Resource not found for url {url}") | ||
return make_response({"message": "not found"}, 404) | ||
return resource.put(url, *getExtraData()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from app import app | ||
|
||
if __name__ == "__main__": | ||
app.run() |