Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make DESDEO2 runnable on Rahti #137

Merged
merged 24 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions .s2i/bin/assemble
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#!/bin/bash

function is_django_installed() {
python -c "import django" &>/dev/null
}

function should_collectstatic() {
is_django_installed && [[ -z "$DISABLE_COLLECTSTATIC" ]]
}

function virtualenv_bin() {
# New versions of Python (>3.6) should use venv module
# from stdlib instead of virtualenv package
python3.12 -m venv $1
}

# Install pipenv or micropipenv to the separate virtualenv to isolate it
# from system Python packages and packages in the main
# virtualenv. Executable is simlinked into ~/.local/bin
# to be accessible. This approach is inspired by pipsi
# (pip script installer).
function install_tool() {
echo "---> Installing $1 packaging tool ..."
VENV_DIR=$HOME/.local/venvs/$1
virtualenv_bin "$VENV_DIR"
# First, try to install the tool without --isolated which means that if you
# have your own PyPI mirror, it will take it from there. If this try fails, try it
# again with --isolated which ignores external pip settings (env vars, config file)
# and installs the tool from PyPI (needs internet connetion).
# $1$2 combines package name with [extras] or version specifier if is defined as $2```
if ! $VENV_DIR/bin/pip install -U $1$2; then
echo "WARNING: Installation of $1 failed, trying again from official PyPI with pip --isolated install"
$VENV_DIR/bin/pip install --isolated -U $1$2 # Combines package name with [extras] or version specifier if is defined as $2```
fi
mkdir -p $HOME/.local/bin
ln -s $VENV_DIR/bin/$1 $HOME/.local/bin/$1
}

set -e

# First of all, check that we don't have disallowed combination of ENVs
if [[ ! -z "$ENABLE_PIPENV" && ! -z "$ENABLE_MICROPIPENV" ]]; then
echo "ERROR: Pipenv and micropipenv cannot be enabled at the same time!"
# podman/buildah does not relay this exit code but it will be fixed hopefuly
# https://github.com/containers/buildah/issues/2305
exit 3
fi

shopt -s dotglob
echo "---> Installing application source ..."
mv /tmp/src/* "$HOME"

# set permissions for any installed artifacts
fix-permissions /opt/app-root -P


if [[ ! -z "$UPGRADE_PIP_TO_LATEST" ]]; then
echo "---> Upgrading pip, setuptools and wheel to latest version ..."
if ! pip install -U pip setuptools wheel; then
echo "WARNING: Installation of the latest pip, setuptools and wheel failed, trying again from official PyPI with pip --isolated install"
pip install --isolated -U pip setuptools wheel
fi
fi

pip install .[standard,api,server]


if should_collectstatic; then
(
echo "---> Collecting Django static files ..."

APP_HOME=$(readlink -f "${APP_HOME:-.}")
# Change the working directory to APP_HOME
PYTHONPATH="$(pwd)${PYTHONPATH:+:$PYTHONPATH}"
cd "$APP_HOME"

# Look for 'manage.py' in the current directory
manage_file=./manage.py

if [[ ! -f "$manage_file" ]]; then
echo "WARNING: seems that you're using Django, but we could not find a 'manage.py' file."
echo "'manage.py collectstatic' ignored."
exit
fi

if ! python $manage_file collectstatic --dry-run --noinput &> /dev/null; then
echo "WARNING: could not run 'manage.py collectstatic'. To debug, run:"
echo " $ python $manage_file collectstatic --noinput"
echo "Ignore this warning if you're not serving static files with Django."
exit
fi

python $manage_file collectstatic --noinput
)
fi

# set permissions for any installed artifacts
fix-permissions /opt/app-root -P
3 changes: 3 additions & 0 deletions .s2i/environment
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
UPGRADE_PIP_TO_LATEST=1
APP_MODULE=desdeo.api.app:app
GUNICORN_CMD_ARGS=--bind=0.0.0.0:8080 --workers=2 --access-logfile=- --worker-class uvicorn.workers.UvicornWorker
3 changes: 2 additions & 1 deletion desdeo/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from fastapi.middleware.cors import CORSMiddleware

from desdeo.api.routers import NIMBUS, NAUTILUS_navigator, UserAuth, problems, test, NAUTILUS
from desdeo.api.config import WebUIConfig

app = FastAPI(
title="DESDEO (fast)API",
Expand All @@ -19,7 +20,7 @@
app.include_router(NAUTILUS_navigator.router)
app.include_router(NAUTILUS.router)

origins = ["http://localhost", "http://localhost:8080", "*"]
origins = WebUIConfig.cors_origins

app.add_middleware(
CORSMiddleware,
Expand Down
33 changes: 20 additions & 13 deletions desdeo/api/config.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
"""Configuration file."""
import os
import json

from pydantic import (
BaseModel,
StrictStr,
StrictInt,
StrictBool
)
from typing import Optional, Union
from typing import ClassVar, Optional, Union
from datetime import timedelta

class AuthConfig(BaseModel):
"""General configurations."""

# openssl rand -hex 32
authjwt_secret_key: Optional[StrictStr] = "36b96a23d24cebdeadce6d98fa53356111e6f3e85b8144d7273dcba230b9eb18"
authjwt_algorithm: Optional[StrictStr] = "HS256"
authjwt_access_token_expires: Optional[StrictInt] = 15 # in minutes
authjwt_refresh_token_expires: Optional[StrictInt] = 30 # in minutes
authjwt_secret_key: ClassVar[StrictStr] = "36b96a23d24cebdeadce6d98fa53356111e6f3e85b8144d7273dcba230b9eb18"
authjwt_algorithm: ClassVar[StrictStr] = "HS256"
authjwt_access_token_expires: ClassVar[StrictInt] = 15 # in minutes
authjwt_refresh_token_expires: ClassVar[StrictInt] = 30 # in minutes

class DBConfig(BaseModel):
"""Database configurations."""

db_host: Optional[StrictStr] = "localhost"
db_port: Optional[StrictStr] = "5432"
db_database: Optional[StrictStr] = "DESDEO3"
db_username: Optional[StrictStr] = "bhupindersaini"
db_password: Optional[StrictStr] = ""
db_pool_size: Optional[StrictInt] = 20
db_max_overflow: Optional[StrictInt] = 20
db_pool: Optional[StrictBool] = True
db_host: ClassVar[StrictStr] = os.getenv("POSTGRES_HOST") or "localhost"
db_port: ClassVar[StrictStr] = os.getenv("POSTGRES_PORT") or "5432"
db_database: ClassVar[StrictStr] = os.getenv("POSTGRES_DB") or "test"
db_username: ClassVar[StrictStr] = os.getenv("POSTGRES_USER") or "test"
db_password: ClassVar[StrictStr] = os.getenv("POSTGRES_PASSWORD") or "testpw"
db_pool_size: ClassVar[StrictInt] = int(os.getenv("POSTGRES_POOLSIZE") or 20)
db_max_overflow: ClassVar[StrictInt] = int(os.getenv("POSTGRES_OVERFLOW") or 20)
db_pool: ClassVar[StrictBool] = (os.getenv("POSTGRES_POOL") or True) in (True, 'true', '1', 't', 'y', 'yes')

class WebUIConfig(BaseModel):
"""Webui server configurations."""
# Below defaults to ["http://localhost", "http://localhost:8080"] if no env variable is set
cors_origins: ClassVar[list] = json.loads(os.getenv("CORS_ORIGINS",'["http://localhost", "http://localhost:8080"]'))
12 changes: 7 additions & 5 deletions desdeo/api/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy_utils import create_database, database_exists, drop_database

from desdeo.api.config import DBConfig

# TODO: Extract this to a config file.
DB_USER = "postgres"
DB_PASSWORD = ""
DB_HOST = "localhost"
DB_PORT = "5432"
DB_NAME = "DESDEO"
DB_USER = DBConfig.db_username
DB_PASSWORD = DBConfig.db_password
DB_HOST = DBConfig.db_host
DB_PORT = DBConfig.db_port
DB_NAME = DBConfig.db_database


SQLALCHEMY_DATABASE_URL = f"postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
Expand Down
12 changes: 6 additions & 6 deletions desdeo/api/db_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from sqlalchemy_utils import create_database, database_exists, drop_database

from desdeo.api import db_models
from desdeo.api.db import SessionLocal, engine
from desdeo.api.db import Base, SessionLocal, engine
from desdeo.api.routers.UserAuth import get_password_hash
from desdeo.api.schema import ObjectiveKind, ProblemKind, UserPrivileges, UserRole
from desdeo.problem.schema import DiscreteRepresentation, Objective, Problem, Variable
Expand All @@ -23,13 +23,13 @@
if not database_exists(engine.url):
create_database(engine.url)
else:
warnings.warn("Database already exists. Dropping and recreating it.", stacklevel=1)
drop_database(engine.url)
create_database(engine.url)
warnings.warn("Database already exists. Clearing it.", stacklevel=1)
# Drop all tables
Base.metadata.drop_all(bind=engine)
print("Database tables created.")

# Create the tables in the database.
db_models.Base.metadata.create_all(bind=engine)
Base.metadata.create_all(bind=engine)

# Create test users
db = SessionLocal()
Expand Down Expand Up @@ -61,7 +61,7 @@
kind=ProblemKind.CONTINUOUS,
obj_kind=ObjectiveKind.ANALYTICAL,
value=problem.model_dump(mode="json"),
role_permission=[],
# role_permission=[],
)

db.add(problem_in_db)
Expand Down
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pyomo = "^6.7.0"
jupyter = "^1.0.0"
jupyterlab = "^4.0.9"
# API packages
gunicorn = { version = "^23.0.0", optional = true }
fastapi = { version = "^0.106.0", optional = true }
uvicorn = { extras = ["standard"], version = "^0.25.0", optional = true }
sqlalchemy = { version = "^2.0.23", optional = true }
Expand Down Expand Up @@ -59,6 +60,7 @@ api = [
"python-jose",
"bcrypt",
] # We could make API packages optional in the future.
server = ["gunicorn"]

[tool.poetry.group.dev.dependencies]
ruff = "^0.3.0"
Expand Down