diff --git a/.dockerignore b/.dockerignore index 3a51714..9de99dd 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,7 +1,8 @@ -.github +.github/ +build-explorer/ +helm/ *.md *.env *.gcp.json *.gcp.encoded Dockerfile -kubernetes/ \ No newline at end of file diff --git a/.env b/.env deleted file mode 100644 index 9ac9d4e..0000000 --- a/.env +++ /dev/null @@ -1,3 +0,0 @@ -TESSERACT_BACKEND=clickhouse://default:4ZgFMJZNa4s9K7QoUJsUAQMztpd9Bg@34.123.11.240:9000/bls_db -TESSERACT_SCHEMA=schema -TESSERACT_DEBUG=true diff --git a/.gcloudignore b/.gcloudignore index ce8a8f6..50e1052 100644 --- a/.gcloudignore +++ b/.gcloudignore @@ -1,5 +1,7 @@ .git +.github +build-explorer dist node_modules vendor -*.jar \ No newline at end of file +*.jar diff --git a/.gitignore b/.gitignore index 4c315de..bc5ee8e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +node_modules/ + *.gcp.json *.gcp.encoded diff --git a/Dockerfile b/Dockerfile index d430ec0..c86b9fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,42 +1,35 @@ -FROM python:3.9 +FROM python:3.10 as builder -# Install api pre requirements -RUN pip install -U pip setuptools wheel +RUN pip install setuptools wheel poetry==1.8.3 -# Define api directory -ENV APP_HOME /usr/src/app -WORKDIR $APP_HOME +ENV POETRY_NO_INTERACTION=1 \ + POETRY_VIRTUALENVS_IN_PROJECT=1 \ + POETRY_VIRTUALENVS_CREATE=1 \ + POETRY_CACHE_DIR=/tmp/poetry_cache -# Allow that statements and log messages appear in the Knative logs -ENV PYTHONUNBUFFERED True +WORKDIR /app -# Transfer api requirements -COPY requirements.txt ./ +COPY pyproject.toml poetry.lock ./ +RUN touch README.md -# Install api requirements -RUN useradd -m -r tesseract &&\ - chown tesseract $APP_HOME &&\ - pip install --no-cache-dir -r requirements.txt +RUN --mount=type=cache,target=$POETRY_CACHE_DIR poetry install --without dev --no-root -# Transfer app files -COPY --chown=tesseract:tesseract . . -RUN chown -R tesseract $APP_HOME +FROM python:3.10-slim-buster as runtime -# Define api required env vars -ARG GIT_HASH -ENV GIT_HASH=${GIT_HASH:-dev} +ENV VIRTUAL_ENV=/app/.venv \ + PATH="/app/.venv/bin:$PATH" -# Change unix user to tesseract -USER tesseract +WORKDIR /app + +# create runtime user; install required dependencies +RUN useradd --system --uid 1001 tesseract &&\ + chown -R tesseract:tesseract /app -# Expose api port -ENV PORT 7777 -EXPOSE 7777 +COPY --chown=tesseract --from=builder ${VIRTUAL_ENV} ${VIRTUAL_ENV} -# Setup host and port -# Uncomment this line for a cloudrun instance -#ENV HOST 0.0.0.0 +COPY --chown=tesseract . /app + +# change user to tesseract user +USER tesseract -# Define startup commands -CMD ["app.py"] -ENTRYPOINT ["python"] \ No newline at end of file +CMD exec granian --interface asgi --host 0.0.0.0 --port 7777 --respawn-failed-workers app:layer diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..0ecd01e --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,58 @@ +import logging.config +import os + +from fastapi.responses import RedirectResponse +from logiclayer import LogicLayer +from logiclayer_complexity import EconomicComplexityModule +from tesseract_olap import OlapServer +from tesseract_olap.logiclayer import TesseractModule + +from .debug import DebugModule + + +# PARAMETERS =================================================================== + +# These parameters are required and will prevent execution if not set +olap_backend = os.environ["TESSERACT_BACKEND"] +olap_schema = os.environ["TESSERACT_SCHEMA"] + +# These parameters are optional +olap_cache = os.environ.get("TESSERACT_CACHE", ":memory:") +app_debug = os.environ.get("TESSERACT_DEBUG", None) +log_filepath = os.environ.get("TESSERACT_LOGGING_CONFIG", "logging.ini") +commit_hash = os.environ.get("GIT_HASH", "") + +app_debug = bool(app_debug) + + +# LOGGING ====================================================================== +# To learn how logging works in python +# - https://docs.python.org/3.7/howto/logging.html +# To learn about best practices and the logging.ini file +# - https://www.datadoghq.com/blog/python-logging-best-practices/ +# - https://guicommits.com/how-to-log-in-python-like-a-pro/ + +logging.config.fileConfig(log_filepath, disable_existing_loggers=False) + + +# ASGI app ===================================================================== +olap = OlapServer(backend=olap_backend, schema=olap_schema) + +mod_tsrc = TesseractModule(olap) + +mod_cmplx = EconomicComplexityModule(olap) + +mod_debug = DebugModule() + +layer = LogicLayer(debug=app_debug) + +if app_debug: + layer.add_module("/debug", mod_debug) + +layer.add_module("/tesseract", mod_tsrc) +layer.add_module("/complexity", mod_cmplx) +layer.add_static("/ui", "./explorer/", html=True) + +@layer.route("/", response_class=RedirectResponse, status_code=302) +def route_index(): + return "/ui/" diff --git a/app/debug.py b/app/debug.py new file mode 100644 index 0000000..f024e39 --- /dev/null +++ b/app/debug.py @@ -0,0 +1,22 @@ +import html +import pathlib + +import logiclayer as ll +from fastapi.responses import StreamingResponse + + +class DebugModule(ll.LogicLayerModule): + def log_generator(self): + yield "
\n{escaped}
" + yield "If you see this message, it means the root of the server is set incorrectly.
Tell the system administrator to point the root to the dist/
folder.