web: docker packaging, env-based config

This commit is contained in:
informatic 2024-07-04 19:43:02 +02:00
parent 363ab2b3f6
commit 60021fb738
No known key found for this signature in database
7 changed files with 95 additions and 51 deletions

1
.gitignore vendored
View file

@ -1,6 +1,5 @@
olddata
webapp/data.db
config.py
*pyc
*sublime*
kasownik.ini

13
docker-compose.yml Normal file
View file

@ -0,0 +1,13 @@
version: "3.8"
services:
kasownik-web:
build: web
ports:
- 5000:5000
volumes:
- ./web:/usr/src
environment:
- SPACEAUTH_CONSUMER_KEY
- SPACEAUTH_CONSUMER_SECRET
- DISABLE_LDAP=true

14
web/Dockerfile Normal file
View file

@ -0,0 +1,14 @@
FROM python:3.9-slim
RUN apt-get update && apt-get install --no-install-recommends -y build-essential libsasl2-dev libldap2-dev
ADD requirements.txt .
# Downgrade setuptools to fix anyjson dependency
RUN pip install setuptools~=57.5.0 && \
pip install -r requirements.txt
WORKDIR /usr/src
ADD . .
STOPSIGNAL SIGINT
CMD ["uwsgi", "--http-socket", "0.0.0.0:5000", "--plugins", "python3", "--wsgi", "webapp.wsgi:app", "--threads", "10", "--master"]

34
web/config.py Normal file
View file

@ -0,0 +1,34 @@
import environs
env = environs.Env()
env.read_env()
DEBUG = env.bool("DEBUG", False)
SQLALCHEMY_DATABASE_URI = env.str("SQLALCHEMY_DATABASE_URI", "sqlite:///data.db")
DUMMY_TRANSFER_UID = "NOTAMEMBER"
SPACEAUTH_CONSUMER_KEY = env.str("SPACEAUTH_CONSUMER_KEY", "kasownik")
SPACEAUTH_CONSUMER_SECRET = env.str("SPACEAUTH_CONSUMER_SECRET", "changeme")
SECRET_KEY = env.str("SECRET_KEY", "changeme")
DISABLE_LDAP = env.bool("DISABLE_LDAP", False)
LDAP_URI = env.str("LDAP_URI", "ldaps://ldap.hackerspace.pl")
LDAP_BIND_DN = env.str("LDAP_BIND_DN", "cn=kasownik,ou=Services,dc=hackerspace,dc=pl")
LDAP_BIND_PASSWORD = env.str("LDAP_BIND_PASSWORD", "changeme")
LDAP_USER_FILTER = env.str("LDAP_USER_FILTER", "(objectClass=hsMember)")
LDAP_USER_BASE = env.str("LDAP_USER_BASE", "ou=People,dc=hackerspace,dc=pl")
LDAP_CA_PATH = env.str("LDAP_CA_PATH", "/etc/ssl/certs/ca-certificates.crt")
CACHE_TYPE = env.str("CACHE_TYPE", "null")
CACHE_NO_NULL_WARNING = True
MEMBERSHIP_FEES = env.json(
"MEMBERSHIP_FEES",
{
"starving": 75,
"fatty": 150,
},
)

View file

@ -1,33 +0,0 @@
class Config(object):
DEBUG = False
TESTING = False
SQLALCHEMY_DATABASE_URI = "sqlite:///data.db"
DUMMY_TRANSFER_UID = 'NOTAMEMBER'
SPACEAUTH_CONSUMER_KEY = 'kasownik'
SPACEAUTH_CONSUMER_SECRET = 'changeme'
SECRET_KEY = 'changeme'
LDAP_URI = 'ldap://ldap.hackerspace.pl'
LDAP_BIND_DN = 'cn=fascist,ou=Services,dc=hackerspace,dc=pl'
LDAP_BIND_PASSWORD = 'changeme'
LDAP_USER_FILTER = '(objectClass=hsMember)'
LDAP_USER_BASE = 'ou=People,dc=hackerspace,dc=pl'
LDAP_CA_PATH = '/etc/ssl/certs/ca-certificates.crt'
CACHE_TYPE = 'null'
CACHE_NO_NULL_WARNING = True
MEMBERSHIP_FEES = {
'starving': 75,
'fatty': 150,
}
class DevelopmentConfig(Config):
DEBUG = True
DISABLE_LDAP = True
class CurrentConfig(DevelopmentConfig):
pass

View file

@ -11,13 +11,14 @@ chardet==3.0.4
click==6.7
configparser==3.5.0
enum34==1.1.6
environs==11.0.0
Flask==0.12.2
Flask-Caching==1.3.3
Flask-Gravatar==0.4.2
Flask-Login==0.4.1
Flask-OAuthlib==0.9.4
Flask-Prometheus==0.0.1
Flask-SpaceAuth @ git+https://code.hackerspace.pl/informatic/flask-spaceauth@0f997ab8fa307f7eabacf27e5f19fc1c715a69f3
Flask-SpaceAuth @ https://code.hackerspace.pl/informatic/flask-spaceauth/archive/v0.2.0.tar.gz
Flask-SQLAlchemy==2.1
Flask-WTF==0.10.3
idna==2.10
@ -27,14 +28,17 @@ Jinja2==2.11.3
lazy-object-proxy==1.3.1
Mako==1.0.0
MarkupSafe==1.1.0
marshmallow==3.21.3
mccabe==0.6.1
oauthlib==2.0.7
packaging==24.1
prometheus-client==0.1.1
prometheus-flask-exporter==0.8.0
psycopg2==2.9.4
psycopg2-binary==2.9.4
pyasn1==0.4.8
pyasn1-modules==0.2.8
pylint==1.8.2
python-dotenv==1.0.1
python-ldap==3.3.1
python-memcached==1.59
pytz==2014.10
@ -46,6 +50,7 @@ SQLAlchemy==1.3.24
sqlparse==0.4.1
sqltap==0.3.5
urllib3==1.25.10
uWSGI==2.0.26
Werkzeug==0.16.1
wrapt==1.10.11
WTForms==2.0.1

View file

@ -25,7 +25,6 @@
import os
from functools import wraps
import memcache
import requests
import sqltap.wsgi
import click
@ -40,13 +39,19 @@ from flask_gravatar import Gravatar
from spaceauth import SpaceAuth
app = Flask(__name__)
app.config.from_object("config.CurrentConfig")
app.config.from_object("config")
auth = SpaceAuth()
db = SQLAlchemy()
cache = Cache()
gravatar = Gravatar(size=256, rating='g', default='retro',
force_default=False, use_ssl=True, base_url=None)
gravatar = Gravatar(
size=256,
rating="g",
default="retro",
force_default=False,
use_ssl=True,
base_url=None,
)
# TODO unsubscribe me from life
cache_enabled = False
@ -57,16 +62,20 @@ import webapp.models # noqa
from webapp.authutils import AnonymousUser, User
auth.anonymous_user = AnonymousUser
@auth.user_loader
def load_user(username, profile=None):
return User(username)
def admin_required(func):
@wraps(func)
def wrapper(*args, **kwargs):
if not current_user.is_admin:
return auth.unauthorized()
return func(*args, **kwargs)
return wrapper
@ -77,10 +86,10 @@ class DecimalEncoder(json.JSONEncoder):
# but that would mean a yield on the line with super(...),
# which wouldn't work (see my comment below), so...
return str(o)
#return (str(o) for o in [o])
# return (str(o) for o in [o])
elif isinstance(o, datetime.datetime):
return str(o)
#return (str(o) for o in [o])
# return (str(o) for o in [o])
return super(DecimalEncoder, self).default(o)
@ -95,40 +104,43 @@ def create_app():
app.wsgi_app = sqltap.wsgi.SQLTapMiddleware(app.wsgi_app)
# Setup prometheus metrics
if app.config.get('PROMETHEUS_DIR'):
if app.config.get("PROMETHEUS_DIR"):
# This needs to be set before importing prometheus_client
os.environ['prometheus_multiproc_dir'] = app.config['PROMETHEUS_DIR']
os.environ["prometheus_multiproc_dir"] = app.config["PROMETHEUS_DIR"]
# FIXME: we could expose this somehow
from prometheus_flask_exporter.multiprocess import UWsgiPrometheusMetrics
metrics = UWsgiPrometheusMetrics(group_by='url_rule')
metrics = UWsgiPrometheusMetrics(group_by="url_rule")
metrics.init_app(app)
#metrics.register_endpoint('/varz', app)
# metrics.register_endpoint('/varz', app)
# Register blueprints
import webapp.views
import webapp.admin
import webapp.api
app.register_blueprint(webapp.admin.bp)
app.register_blueprint(webapp.api.bp)
# Custom filters
@app.template_filter('inflect')
@app.template_filter("inflect")
def inflect(v, one, two, five):
num = abs(v)
if num == 0:
return '%d %s' % (v, five)
return "%d %s" % (v, five)
elif num == 1:
return '%d %s' % (v, one)
return "%d %s" % (v, one)
elif num <= 4:
return '%d %s' % (v, two)
return "%d %s" % (v, two)
return '%d %s' % (v, five)
return "%d %s" % (v, five)
# Custom CLI commands
import webapp.commands
app.cli.commands.update(webapp.commands.group.commands)
app.json_encoder = DecimalEncoder