diff --git a/core/server.py b/core/server.py index 407d0ba..6c1ffc7 100644 --- a/core/server.py +++ b/core/server.py @@ -1,9 +1,11 @@ #!/usr/bin/env python3 import asyncio import logging +import os +from abc import ABCMeta import uvicorn -from aiosmtpd.controller import Controller, UnixSocketController +from aiosmtpd.controller import Controller, UnixSocketController, BaseController, UnixSocketMixin from aiosmtpd.lmtp import LMTP @@ -47,17 +49,39 @@ class LTMPController(Controller): return LMTP(self.handler) -class UnixSocketLMTPController(UnixSocketController): +class BaseAsyncController(BaseController, metaclass=ABCMeta): + def __init__( + self, + handler, + loop, + **SMTP_parameters, + ): + super().__init__( + handler, + loop, + **SMTP_parameters, + ) + + def serve(self): + return self._create_server() + + +class UnixSocketLMTPController(UnixSocketMixin, BaseAsyncController): def factory(self): return LMTP(self.handler) + def _trigger_server(self): # pragma: no-unixsock + # Prevent confusion on which _trigger_server() to invoke. + # Or so LGTM.com claimed + UnixSocketMixin._trigger_server(self) + class UvicornServer(uvicorn.Server): def install_signal_handlers(self): pass -async def web(): +async def web(loop): log_config = uvicorn.config.LOGGING_CONFIG log_config["handlers"]["default"] = {"class": "logging.FileHandler", "filename": "web.log", "formatter": "default"} log_config["handlers"]["access"] = {"class": "logging.FileHandler", "filename": "web-access.log", @@ -67,8 +91,10 @@ async def web(): await server.serve() -async def tcp(): - log = logging.getLogger('test') +async def tcp(loop): + log = logging.getLogger('test.log') + log.addHandler(logging.FileHandler('test.log')) + log.setLevel(logging.DEBUG) log.info("Starting TCP server") server = await asyncio.start_unix_server(handle_echo, path='test.sock') @@ -80,11 +106,20 @@ async def tcp(): log.info("TCP done") -async def lmtp(): - log = logging.getLogger('lmtp') +async def lmtp(loop): + log = logging.getLogger('mail.log') + log.addHandler(logging.FileHandler('mail.log')) + log.setLevel(logging.DEBUG) log.info("Starting LMTP server") - cont = UnixSocketLMTPController(ExampleHandler(), unix_socket='lmtp.sock') - cont.start() + server = await UnixSocketLMTPController(ExampleHandler(), unix_socket='lmtp.sock', loop=loop).serve() + + addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets) + log.info(f'Serving on {addrs}') + + os.chmod('lmtp.sock', 0o775) + + async with server: + await server.serve_forever() log.info("LMTP done") @@ -104,18 +139,18 @@ def main(): import sdnotify import signal import setproctitle + import os setproctitle.setproctitle("c3lf-sys3") - logging.basicConfig(filename='server.log', level=logging.DEBUG, encoding='utf-8') - logging.basicConfig(filename='test.log', level=logging.DEBUG, encoding='utf-8') - logging.basicConfig(filename='lmtp.log', level=logging.DEBUG, encoding='utf-8') - log = logging.getLogger() + log = logging.getLogger('server.log') + log.addHandler(logging.FileHandler('server.log')) + log.setLevel(logging.DEBUG) log.info("Starting server") loop = asyncio.get_event_loop() loop.add_signal_handler(signal.SIGTERM, lambda: asyncio.create_task(shutdown(signal.SIGTERM, loop))) loop.add_signal_handler(signal.SIGINT, lambda: asyncio.create_task(shutdown(signal.SIGINT, loop))) - loop.create_task(web()) - loop.create_task(tcp()) - loop.create_task(lmtp()) + loop.create_task(web(loop)) + loop.create_task(tcp(loop)) + loop.create_task(lmtp(loop)) n = sdnotify.SystemdNotifier() n.notify("READY=1") log.info("Server ready") @@ -123,8 +158,13 @@ def main(): loop.run_forever() finally: loop.close() + os.remove("lmtp.sock") + os.remove("test.sock") + os.remove("web.sock") logging.info("Server stopped") + logging.shutdown() + if __name__ == '__main__': main() diff --git a/deploy/ansible/inventory.yml.sample b/deploy/ansible/inventory.yml.sample index 87891c7..6ba14ac 100644 --- a/deploy/ansible/inventory.yml.sample +++ b/deploy/ansible/inventory.yml.sample @@ -8,6 +8,7 @@ c3lf-nodes: git_branch: master git_repo: db_password: + mail_domain: main_email: legacy_api_user: legacy_api_password: \ No newline at end of file diff --git a/deploy/ansible/playbooks/deploy-c3lf-sys3.yml b/deploy/ansible/playbooks/deploy-c3lf-sys3.yml index 8c0646a..6748f4c 100644 --- a/deploy/ansible/playbooks/deploy-c3lf-sys3.yml +++ b/deploy/ansible/playbooks/deploy-c3lf-sys3.yml @@ -274,4 +274,11 @@ service: name: c3lf-sys3 state: started - enabled: yes \ No newline at end of file + enabled: yes + + - name: configure postfix + template: + src: templates/postfix.cf.j2 + dest: /etc/postfix/main.cf + notify: + - restart postfix \ No newline at end of file diff --git a/deploy/ansible/playbooks/templates/postfix.cf.j2 b/deploy/ansible/playbooks/templates/postfix.cf.j2 new file mode 100644 index 0000000..74f05d8 --- /dev/null +++ b/deploy/ansible/playbooks/templates/postfix.cf.j2 @@ -0,0 +1,50 @@ +# See /usr/share/postfix/main.cf.dist for a commented, more complete version + + +# Debian specific: Specifying a file name will cause the first +# line of that file to be used as the name. The Debian default +# is /etc/mailname. +#myorigin = /etc/mailname + +smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU) +biff = no + +# appending .domain is the MUA's job. +append_dot_mydomain = no + +readme_directory = no + +# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 3.6 on +# fresh installs. +compatibility_level = 3.6 + +# TLS parameters +smtp_use_tls = yes +smtp_force_tls = yes +smtpd_use_tls = yes +smtpd_tls_cert_file=/etc/letsencrypt/live/{{ web_domain }}/fullchain.pem; +smtpd_tls_key_file=/etc/letsencrypt/live/{{ web_domain }}/privkey.pem; +smtpd_tls_security_level=may + +smtp_tls_CApath=/etc/ssl/certs +smtp_tls_security_level=may +smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache + + +smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination +myhostname = polaris.c3lf.de +alias_maps = hash:/etc/aliases +alias_database = hash:/etc/aliases +myorigin = /etc/mailname +mydestination = $myhostname, polaris.c3lf.de, localhost.c3lf.de, , localhost, {{ mail_domain }} +#relayhost = firefly.lab.or.it +mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 +mailbox_size_limit = 0 +recipient_delimiter = + +inet_interfaces = all +inet_protocols = all + +maillog_file = /var/log/mail.log + + +virtual_transport=lmtp:unix:/var/www/c3lf-sys3/lmtp.sock