Rework logging and execution

It is now possible to run adlermanager with:
python -m adlermanager

While there we improve logging.
This commit is contained in:
Evilham 2023-12-11 18:39:23 +01:00
parent 1a44337ded
commit 45ed9bbed7
Signed by: evilham
GPG key ID: AE3EE30D970886BF
6 changed files with 64 additions and 33 deletions

View file

@ -70,10 +70,14 @@ And give yourself access to the given site, by adding your username to its
### Running
To run the server for development you can use the following command:
To run the server for development you can one of the following commands:
```sh
# Using twistd
# https://docs.twisted.org/en/stable/core/howto/basics.html#twistd
pipenv run twistd -ny app.py
# Running as a module
python -m adlermanager
```
And for deployment, you can use [`twistd`][twistd] itself to run the process

View file

@ -1,9 +1,9 @@
import functools
import json
from typing import TYPE_CHECKING, Any, Dict, Optional, Union
import attr
import yaml
from twisted.logger import Logger
from twisted.python.filepath import FilePath
from .conch_helpers import SSHSimpleAvatar, SSHSimpleProtocol
@ -12,6 +12,8 @@ from .model import SiteConfig
if TYPE_CHECKING:
from adlermanager.SitesManager import SiteManager, SitesManager
log = Logger()
class AdlerManagerSSHProtocol(SSHSimpleProtocol):
sites_manager: "SitesManager"
@ -21,8 +23,7 @@ class AdlerManagerSSHProtocol(SSHSimpleProtocol):
Create an instance of AdlerManagerSSHProtocol.
"""
SSHSimpleProtocol.__init__(self, user)
# TODO: Do stuff like getting user sites, showing alert warnings, etc.
log.info("SSH login for {user}", user=user.username)
def do_list_sites(self) -> None:
"""
@ -95,22 +96,13 @@ class AdlerManagerSSHProtocol(SSHSimpleProtocol):
sm.site_config = sc
sm.config_file.setContent(sc.to_YAML().encode("utf-8"))
sm.config_file.chmod(0o640)
log.info(
"User {user} changed {site} config", user=self.user.username, site=site
)
if self.interactive:
self.terminal_write("Persisted SiteConfiguration")
self.terminal.nextLine()
def do_tmp_dump_state(self) -> None:
"""
This command is temporary and just dumps all known state.
"""
for k, sm in self.sites_manager.get_user_sites(self.user.username).items():
self.terminal_write(f"\n#\n# {k}\n#\n")
for _, srv in sm.service_managers.items():
self.terminal_write(f"## {srv.label}\n")
self.terminal_write(json.dumps(srv.components))
self.terminal.nextLine()
self.terminal.nextLine()
@functools.lru_cache() # we don't need to re-read every time
def motd(self) -> Union[str, bytes]:
custom_motd = FilePath(self.sites_manager.global_config.data_dir).child(

View file

@ -17,10 +17,20 @@ class SitesManager(object):
global_config: ConfigClass = attr.ib()
site_managers: Dict[str, "SiteManager"] = attr.ib(factory=dict)
tokens: Dict[str, "SiteManager"] = attr.ib(factory=dict)
log = Logger()
log: Logger = attr.ib(factory=Logger)
def __attrs_post_init__(self) -> None:
def startup_message() -> None:
self.log.info(
f"Starting server with this configuration:\n{self.global_config}",
system=SitesManager.__name__,
)
# Inform people of current configuration when reactor starts
_ = task.deferLater(reactor, 0, startup_message).addErrback( # type: ignore
default_errback
)
# Load data
self.reload()
def reload(self) -> "SitesManager":
@ -79,7 +89,6 @@ class SiteManager(object):
path: FilePath = attr.ib()
tokens: List[str] = attr.ib(factory=list)
ssh_users: List[str] = attr.ib(factory=list)
log = Logger()
monitoring_is_down: bool = attr.ib(default=False)
definition: Dict[str, Any] = attr.ib(factory=dict)
title: str = attr.ib(default="")
@ -92,10 +101,12 @@ class SiteManager(object):
# Default to 2 mins
_timeout_seconds = 2 * 60
def __attrs_post_init__(self) -> None:
self.reload(first_run=True)
log: Logger = attr.ib(factory=Logger)
def reload(self, first_run: bool = False) -> "SiteManager":
def __attrs_post_init__(self) -> None:
self.reload()
def reload(self) -> "SiteManager":
self.load_definition()
self.title = self.definition["title"]
self.load_tokens()

View file

@ -1,10 +1,13 @@
from typing import Any, Dict, Generator, Union, cast
from twisted.internet import defer
from twisted.logger import Logger
from twisted.web import resource, server
from twisted.web._responses import INTERNAL_SERVER_ERROR, OK, UNAUTHORIZED
from twisted.web.server import Request
log = Logger()
class TokenResource(resource.Resource):
"""
@ -78,9 +81,8 @@ class TokenResource(resource.Resource):
res = yield defer.maybeDeferred(self.processToken, token_data, request)
code: int = cast(int, res)
except Exception:
import traceback
log.failure("Unknown error")
traceback.print_stack()
code = INTERNAL_SERVER_ERROR
request.setResponseCode(code) # type: ignore
defer.returnValue(code)

View file

@ -15,6 +15,8 @@ from .AdlerManagerTokenResource import AdlerManagerTokenResource
from .Config import Config
from .SitesManager import SiteManager, SitesManager
log = Logger()
def get_jinja_env(supportDir: str) -> jinja2.Environment:
"""
@ -52,7 +54,6 @@ def get_jinja_env(supportDir: str) -> jinja2.Environment:
def web_root(sites_manager: "SitesManager") -> KleinResource:
app = Klein()
log = Logger()
@app.route("/") # type: ignore
def index(request: Request):
@ -70,9 +71,6 @@ def web_root(sites_manager: "SitesManager") -> KleinResource:
try:
site = sites_manager.site_managers[host]
except Exception:
import traceback
traceback.print_stack()
log.failure("sad cat")
return resource.ErrorPage(
500, "Sad cat", '<a href="http://http.cat/500">http://http.cat/500</a>'

View file

@ -1,9 +1,13 @@
#!/usr/bin/env python3
"""
Run in foreground using:
- a generic service manager: python -m adlermanager
- twistd: twistd -ny src/adlermanager/__main__.py
"""
# Run with twistd -ny app.py
from typing import Iterable, cast
from twisted.application import service, strports
from twisted.logger import Logger
from twisted.python.filepath import FilePath
from twisted.web import server
@ -38,6 +42,26 @@ if Config.ssh_enabled:
)
i.setServiceParent(serv_collection) # type: ignore
# Inform people of current configuration
log = Logger()
log.info(f"Starting server with this configuration:\n{Config}")
if __name__ == "__main__":
import sys
from twisted import logger
# Setup global logging to stdout
logger.globalLogPublisher.addObserver(
cast(logger.ILogObserver, logger.textFileLogObserver(sys.stdout))
)
# Run without twistd as documented upstream:
# https://docs.twisted.org/en/stable/core/howto/basics.html#twistd
from twisted.internet import reactor as _reactor # type: ignore
from twisted.internet.base import ReactorBase
reactor = cast(ReactorBase, _reactor)
for srv in cast(Iterable[service.IService], serv_collection):
srv.startService()
reactor.addSystemEventTrigger("before", "shutdown", srv.stopService)
# Finally, start the reactor
reactor.run()