Skip to content

Commit

Permalink
feat: dodoo-run session storage
Browse files Browse the repository at this point in the history
  • Loading branch information
David Arnold committed Dec 19, 2019
1 parent d7eb61e commit fb7a47f
Show file tree
Hide file tree
Showing 32 changed files with 276 additions and 599 deletions.
2 changes: 1 addition & 1 deletion .isort.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ force_grid_wrap=0
combine_as_imports=True
use_parentheses=True
line_length=88
known_third_party = click,click_pathlib,click_plugins,colorlog,dodoo_backup,dodoo_copy,dodoo_init,dodoo_run,dodoo_shell,mashumaro,pkg_resources,psycopg2,pygit2,pytest,pytest_postgresql,starlette,starlette_prometheus,strawberry,uvicorn
known_third_party = click,click_pathlib,click_plugins,colorlog,dodoo_backup,dodoo_copy,dodoo_init,dodoo_run,dodoo_shell,mashumaro,pkg_resources,psycopg2,pygit2,pytest,pytest_postgresql,secure_cookie,starlette,starlette_prometheus,strawberry,uvicorn
4 changes: 4 additions & 0 deletions dodoo-backup/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ def environ(tmp_path_factory) -> None:
admin_passwd = secrets / "admin"
admin_passwd.write_text("admin-pwd")
admin_passwd.chmod(0o500)
session_encryption_key = secrets / "sessionencryptionkey"
session_encryption_key.write_text("secret-key")
session_encryption_key.chmod(0o500)
smtpuser = secrets / "smtpuser"
smtpuser.write_text("smtp-user")
smtpuser.chmod(0o500)
smtppwd = secrets / "smtppwd"
smtppwd.write_text("smtp-pwd")
smtppwd.chmod(0o500)
os.environ.update(ODOOADMINPASSWORD_FILE=str(admin_passwd))
os.environ.update(SESSION_ENCRYPTION_KEY_FILE=str(session_encryption_key))
os.environ.update(SMTPUSER_FILE=str(smtpuser))
os.environ.update(SMTPPASSWORD_FILE=str(smtppwd))
secrets.chmod(0o500)
Expand Down
4 changes: 4 additions & 0 deletions dodoo-copy/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ def environ(tmp_path_factory) -> None:
admin_passwd = secrets / "admin"
admin_passwd.write_text("admin-pwd")
admin_passwd.chmod(0o500)
session_encryption_key = secrets / "sessionencryptionkey"
session_encryption_key.write_text("secret-key")
session_encryption_key.chmod(0o500)
smtpuser = secrets / "smtpuser"
smtpuser.write_text("smtp-user")
smtpuser.chmod(0o500)
smtppwd = secrets / "smtppwd"
smtppwd.write_text("smtp-pwd")
smtppwd.chmod(0o500)
os.environ.update(ODOOADMINPASSWORD_FILE=str(admin_passwd))
os.environ.update(SESSION_ENCRYPTION_KEY_FILE=str(session_encryption_key))
os.environ.update(SMTPUSER_FILE=str(smtpuser))
os.environ.update(SMTPPASSWORD_FILE=str(smtppwd))
secrets.chmod(0o500)
Expand Down
4 changes: 4 additions & 0 deletions dodoo-init/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ def environ(tmp_path_factory) -> None:
admin_passwd = secrets / "admin"
admin_passwd.write_text("admin-pwd")
admin_passwd.chmod(0o500)
session_encryption_key = secrets / "sessionencryptionkey"
session_encryption_key.write_text("secret-key")
session_encryption_key.chmod(0o500)
smtpuser = secrets / "smtpuser"
smtpuser.write_text("smtp-user")
smtpuser.chmod(0o500)
smtppwd = secrets / "smtppwd"
smtppwd.write_text("smtp-pwd")
smtppwd.chmod(0o500)
os.environ.update(ODOOADMINPASSWORD_FILE=str(admin_passwd))
os.environ.update(SESSION_ENCRYPTION_KEY_FILE=str(session_encryption_key))
os.environ.update(SMTPUSER_FILE=str(smtpuser))
os.environ.update(SMTPPASSWORD_FILE=str(smtppwd))
secrets.chmod(0o500)
Expand Down
25 changes: 25 additions & 0 deletions dodoo-profile/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# `dodoo profile` Component

## Abstract

`dodoo profile` subcommand ist a shim for py-spy **sampling** profiler that can
be run with negilgible overhead penalty on production processes, without anxiety.

## Spec

see manpage


<div align="center">
<div>
<a href="https://xoe.solutions">
<img width="100" src="https://erp.xoe.solutions/logo.png" alt="XOE Corp. SAS">
</a>
</div>
<p>
<sub>Currently, folks <a href="https://github.com/xoe-labs/">@xoe-labs</a> try to keep up with their task to maintain this.</sub>
</p>
<p>
<sub>If you're the kind of person, willing to sponsor open source projects, consider sending some spare XLM banana to <code>blaggacao*keybase.io</code></sub>
</p>
</div>
12 changes: 7 additions & 5 deletions dodoo-run/dodoo_run/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import enum
import dodoo

from pathlib import Path

from dodoo import RUN_MODE

_log = logging.getLogger(__name__)
Expand All @@ -28,7 +30,7 @@ def _is_dev():
return dodoo.framework().dodoo_run_mode == RUN_MODE.Develop


def http(host, port):
def http(host: str, port: int) -> None:
from .server import server
from .server.http import app as _app

Expand All @@ -37,7 +39,7 @@ def http(host, port):
server(app, host, port, prod=not is_dev)


def bus(host, port):
def bus(host: str, port: int) -> None:
from .server import server
from .server.bus import app as _app

Expand All @@ -46,7 +48,7 @@ def bus(host, port):
server(app, host, port, prod=not is_dev)


def graphql(host, port, schema):
def graphql(schema: Path, host: str, port: int) -> None:
from .server import server
from .server.graphql import app as _app

Expand All @@ -55,13 +57,13 @@ def graphql(host, port, schema):
server(app, host, port, prod=not is_dev)


def cron():
def cron() -> None:
from .workers import cron as _cron

_cron()


def queue():
def queue() -> None:
from .workers import queue as _queue

_queue()
8 changes: 7 additions & 1 deletion dodoo-run/dodoo_run/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@


import click
import click_pathlib

from . import (
bus as _bus,
Expand All @@ -19,6 +20,9 @@

@click.group()
def run():
# TODO: Ideas ...
# ... Patcher feature-flag to use athenapdf microservice instead of wkhtmltopdf
#
pass


Expand All @@ -37,7 +41,9 @@ def bus(*args, **kwargs):


@run.command()
@click.argument("schema", type=str)
@click.argument(
"schema", type=click_pathlib.Path(dir_okay=False, exists=True, resolve_path=True)
)
@click.argument("addr", default="0.0.0.0", type=str)
@click.argument("port", default=8075, type=int)
def graphql(*args, **kwargs):
Expand Down
36 changes: 36 additions & 0 deletions dodoo-run/dodoo_run/interfaces/odoo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# =============================================================================
# Created By : David Arnold
# Part of : xoe-labs/dodoo
# =============================================================================
"""This module implements an interface to the odoo namespace.
Hence, maintainers have a single source of truth of it's usage.
Consequent lazy loading of patchable properties ensures patchability.
For consistency, never access the odoo namespace directly."""

from importlib import import_module

from dodoo.patchers import PatchableProperty as PProp


class Session:
def __init__(self):
self._r = import_module("odoo.http")

@property
def SessionClass(self):
return self._r.OpenERPSession


class Patchable:

# #############################
# Index of patched namespaces #
# #############################
#
# odoo.http
#
# #############################

# odoo.http
session_gc = PProp("odoo.http:session_gc")
session_store = PProp("odoo.http:Root.session_store")
26 changes: 26 additions & 0 deletions dodoo-run/dodoo_run/middleware/globalscope.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# =============================================================================
# Created By : David Arnold
# Part of : xoe-labs/dodoo
# =============================================================================
"""This module implements odoo asgi middleware to provide an Odoo Environment
for http and websocket transport"""

from starlette.types import ASGIApp, Receive, Scope, Send

import contextvars

scope = contextvars.ContextVar("scope")


class GlobalScopeAccessorMiddleware:
"""
A middleware class that exports scope to arbitrarily access it.
"""

def __init__(self, app: ASGIApp) -> None:
self.app = app

async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
token = scope.set(scope)
await self.app(scope, receive, send)
scope.reset(token)
34 changes: 34 additions & 0 deletions dodoo-run/dodoo_run/patches/odoo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# =============================================================================
# Created By : David Arnold
# Part of : xoe-labs/dodoo
# =============================================================================
"""This module implements a monkey patcher scoped for use with dodoo run"""

from dodoo_run.middleware.globalscope import scope

from dodoo.interfaces import odoo
from dodoo.patchers import BasePatcher

from ..interfaces import _odoo
from ..sessions import ClientSessionStore


class OdooClientSessionStore(ClientSessionStore):
"""Modified Odoo client session store. Provides the path interface for
session.save_request_data / session.load_request_data methods of the
Odoo Session Class.
"""

def __init__(self, session_class=_odoo.Session().SessionClass, **kwargs):
super().__init__(**kwargs)
self.path = odoo.Config().session_dir()


# Inheriting order important
class SessionStoragePatcher(_odoo.Patchable, BasePatcher):
@staticmethod
def session_gc(session_store):
return

def session_store(self):
return OdooClientSessionStore(scope=scope.get())
10 changes: 6 additions & 4 deletions dodoo-run/dodoo_run/servers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@
import logging
import uvicorn

from starlette.types import ASGIApp
from .watcher import file_changed

from ._common import resolve_devcert


_log = logging.getLogger(__name__)

server = None


def server(app, host, port, is_dev=False, ssl_keyfile=None, ssl_certfile=None):
def server(app: ASGIApp, host: str, port: int, is_dev: bool = False) -> "server":
global server

kwargs = dict(host=host, port=port, log_level="error")
Expand All @@ -24,9 +28,7 @@ def server(app, host, port, is_dev=False, ssl_keyfile=None, ssl_certfile=None):

hupper.reloader.FileMonitorProxy.file_changed = file_changed
hupper.start_reloader(f"{__name__}.run", verbose=False)

if cert_path:
kwargs.update(dict(ssl_keyfile=None, ssl_certfile=None))
kwargs.update(resolve_devcert())

server = uvicorn.run(app, **kwargs)

Expand Down
41 changes: 41 additions & 0 deletions dodoo-run/dodoo_run/servers/_common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# =============================================================================
# Created By : David Arnold
# Part of : xoe-labs/dodoo
# =============================================================================
"""This module implements the common data accessors shared among servers"""

from starlette.datastructures import Secret

import dodoo

SessionDataKey = "session_data"


class SessionSecret(Secret):
"""
Resolves to a string value that should not be revealed in tracebacks etc.
You should cast the value to `str` at the point it is required.
"""

def __init__(self):
pass

def __repr__(self) -> str:
class_name = self.__class__.__name__
return f"{class_name}('**********')"

def __str__(self) -> str:
return dodoo.dodoo_config.Odoo.Sec.session_encryption_key


SessionMiddlewareArgs = dict(
sekret_key=SessionSecret(), session_cookie=SessionDataKey, https_only=True
)
GZipMiddlewareArgs = dict(minimum_size=500)


def resolve_devcert():
ssl_keyfile = dodoo.dodoo_config.Odoo.ssl_keyfile
ssl_certfile = dodoo.dodoo_config.Odoo.ssl_certfile
assert ssl_keyfile and ssl_certfile
return dict(ssl_keyfile=str(ssl_keyfile), ssl_certfile=str(ssl_certfile))
18 changes: 8 additions & 10 deletions dodoo-run/dodoo_run/servers/bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,31 @@

import logging

from dodoo_run.middleware.odoo import (
OdooBasicAuthBackendAsync,
OdooEnvironmentMiddlewareAsync,
)
from dodoo_run.middleware.globalscope import GlobalScopeAccessorMiddleware
from starlette.applications import Starlette
from starlette.authentication import requires
from starlette.middleware import Middleware
from starlette.middleware.authentication import AuthenticationMiddleware
from starlette.middleware.gzip import GZipMiddleware
from starlette.middleware.httpsredirect import HTTPSRedirectMiddleware
from starlette.middleware.sessions import SessionMiddleware
from starlette.middleware.wsgi import WSGIMiddleware
from starlette.routing import Route
from starlette.types import ASGIApp
from starlette_prometheus import PrometheusMiddleware, metrics

import dodoo.interfaces.odoo as odoo

from ._common import GZipMiddlewareArgs, SessionMiddlewareArgs

_log = logging.getLogger(__name__)


def middleware(prod):
return [
Middleware(HTTPSRedirectMiddleware),
Middleware(SessionMiddleware),
Middleware(AuthenticationMiddleware, backend=OdooBasicAuthBackendAsync()),
Middleware(OdooEnvironmentMiddlewareAsync),
Middleware(GZipMiddleware, minimum_size=500),
Middleware(SessionMiddleware, **SessionMiddlewareArgs),
Middleware(WSGIMiddleware, workers=1),
Middleware(GZipMiddleware, **GZipMiddlewareArgs),
Middleware(GlobalScopeAccessorMiddleware),
] + ([Middleware(PrometheusMiddleware)] if prod else [])


Expand Down
Loading

0 comments on commit fb7a47f

Please sign in to comment.