diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..d9f8ccd --- /dev/null +++ b/.drone.yml @@ -0,0 +1,33 @@ +kind: pipeline +type: docker +name: default + +steps: + - name: code-analysis + image: aosapps/drone-sonar-plugin + settings: + sonar_host: + from_secret: SONAR_HOST + sonar_token: + from_secret: SONAR_CODE + + - name: kaniko + image: banzaicloud/drone-kaniko + settings: + registry: registry.kmlabz.com + repo: videon/${DRONE_REPO_NAME} + username: + from_secret: DOCKER_USERNAME + password: + from_secret: DOCKER_PASSWORD + tags: + - latest + - ${DRONE_BUILD_NUMBER} + + - name: ms-teams + image: kuperiu/drone-teams + settings: + webhook: + from_secret: TEAMS_WEBHOOK + when: + status: [ failure ] \ No newline at end of file diff --git a/.gitignore b/.gitignore index 13d1490..e532603 100644 --- a/.gitignore +++ b/.gitignore @@ -129,3 +129,4 @@ dmypy.json # Pyre type checker .pyre/ +.idea/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..717487a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +FROM python:3.9-slim + +ENV TZ Europe/Budapest +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +WORKDIR /app + +ARG RELEASE_ID +ENV RELEASE_ID ${RELEASE_ID:-""} + +COPY requirements.txt ./ + +RUN pip install --no-cache-dir -r requirements.txt && rm -rf requirements.txt + +COPY ./src . + +EXPOSE 8080 + +ENTRYPOINT ["gunicorn", "-b", "0.0.0.0:8080", "--workers", "1", "--threads", "1", "app:app"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9a8cd8a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +version: '3' + +networks: + postgres: + external: false + +services: + db: + image: postgres:13 + restart: always + ports: + - "127.0.0.1:5432:5432" + environment: + - POSTGRES_USER=videon + - POSTGRES_PASSWORD=videon + - POSTGRES_DB=videon + networks: + - postgres + volumes: + - postres-volume:/var/lib/postgresql/data + +volumes: + postres-volume: \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..98c8ffb --- /dev/null +++ b/requirements.txt @@ -0,0 +1,13 @@ +flask +sentry-sdk[flask] +flask-restful +flask-security +kubernetes +gunicorn +psycopg2-binary +sqlalchemy +flask_sqlalchemy +marshmallow +marshmallow-sqlalchemy +flask-marshmallow +py-healthcheck \ No newline at end of file diff --git a/src/app.py b/src/app.py new file mode 100644 index 0000000..1dd35c0 --- /dev/null +++ b/src/app.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +import logging +from flask import Flask +from flask_restful import Api +import sentry_sdk +from sentry_sdk.integrations.flask import FlaskIntegration +from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration +from healthcheck import HealthCheck + +from config import * +from db import db +from marshm import ma +from healthchecks import health_database_status + +""" +Main Flask RESTful API +""" + +__author__ = "@tormakris" +__copyright__ = "Copyright 2020, videON Team" +__module_name__ = "app" +__version__text__ = "1" + +if SENTRY_DSN: + sentry_sdk.init( + dsn=SENTRY_DSN, + integrations=[FlaskIntegration(), SqlalchemyIntegration()], + traces_sample_rate=1.0, + send_default_pii=True, + release=RELEASE_ID, + environment=RELEASEMODE, + _experiments={"auto_enabling_integrations": True} + ) + +app = Flask(__name__) +app.config['SQLALCHEMY_DATABASE_URI'] =\ + f"postgresql://{POSTGRES_USERNAME}:{POSTGRES_PASSWORD}@{POSTGRES_HOSTNAME}:5432/{POSTGRES_DB}" + +api = Api(app) +health = HealthCheck(app, "/healthz") +db.init_app(app) +ma.init_app(app) + +with app.app_context(): + db.create_all() + +formatter = logging.Formatter( + fmt="%(asctime)s - %(levelname)s - %(module)s - %(message)s" +) + +handler = logging.StreamHandler() +handler.setFormatter(formatter) + +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) +logger.addHandler(handler) + +# api.add_resource(SampleResource, "/sample") + +health.add_check(health_database_status) + +if __name__ == "__main__": + app.run( + debug=bool(DEBUG), + host="0.0.0.0", + port=int(PORT), + ) diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..90d931c --- /dev/null +++ b/src/config.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +import os + + +""" +Configuration +""" + + +__author__ = "@tormakris" +__copyright__ = "Copyright 2020, Birbnetes Team" +__module_name__ = "config" +__version__text__ = "1" + + +PORT = os.environ.get("VIDEON_PORT", 8080) +DEBUG = os.environ.get("VIDEON_DEBUG", True) + + +SENTRY_DSN = os.environ.get("SENTRY_DSN") +RELEASE_ID = os.environ.get("RELEASE_ID", "test") +RELEASEMODE = os.environ.get("VIDEON_RELEASEMODE", "dev") + +POSTGRES_HOSTNAME = os.getenv("VIDEON_POSTGRES_HOSTNAME", "localhost") +POSTGRES_USERNAME = os.getenv("VIDEON_POSTGRES_USERNAME", "videon") +POSTGRES_PASSWORD = os.getenv("VIDEON_POSTGRES_PASSWORD", "videon") +POSTGRES_DB = os.getenv("VIDEON_POSTGRES_DB", "videon") diff --git a/src/db.py b/src/db.py new file mode 100644 index 0000000..fad3ce1 --- /dev/null +++ b/src/db.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +from flask_sqlalchemy import SQLAlchemy + +""" +Databse object +""" + +__author__ = '@tormakris' +__copyright__ = "Copyright 2020, videON Team" +__module_name__ = "db" +__version__text__ = "1" + +db = SQLAlchemy() diff --git a/src/healthchecks.py b/src/healthchecks.py new file mode 100644 index 0000000..debe72d --- /dev/null +++ b/src/healthchecks.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +from db import db + +""" +Healthchek functions +""" + +__author__ = "@tormakris" +__copyright__ = "Copyright 2020, videON Team" +__module_name__ = "healthchecks" +__version__text__ = "1" + + +def health_database_status(): + is_database_working = True + output = 'database is ok' + try: + db.session.execute('SELECT 1') + except Exception as e: + output = str(e) + is_database_working = False + return is_database_working, output diff --git a/src/marshm.py b/src/marshm.py new file mode 100644 index 0000000..4fbcb2b --- /dev/null +++ b/src/marshm.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +from flask_marshmallow import Marshmallow + +""" +Marshmallow +""" + +__author__ = '@tormakris' +__copyright__ = "Copyright 2020, videON Team" +__module_name__ = "marshm" +__version__text__ = "1" + +ma = Marshmallow()