Compare commits

..

1 Commits

Author SHA1 Message Date
holger krekel
a91aa39ec1 prepare 1.1.0 tag 2024-03-28 16:40:08 +01:00
5 changed files with 66 additions and 92 deletions

View File

@@ -4,17 +4,12 @@ on:
push: push:
branches: branches:
- main - main
pull_request: - staging-ci
paths-ignore:
- 'scripts/**'
jobs: jobs:
deploy: deploy:
name: deploy on staging.testrun.org, and run tests name: deploy on staging.testrun.org, and run tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
concurrency:
group: staging-deploy
cancel-in-progress: true
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@@ -24,45 +19,44 @@ jobs:
echo "${{ secrets.STAGING_SSH_KEY }}" >> ~/.ssh/id_ed25519 echo "${{ secrets.STAGING_SSH_KEY }}" >> ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519
ssh-keyscan staging.testrun.org > ~/.ssh/known_hosts ssh-keyscan staging.testrun.org > ~/.ssh/known_hosts
rsync -avz root@staging.testrun.org:/var/lib/acme . || true # rsync -avz root@staging.testrun.org:/var/lib/acme . || true
rsync -avz root@staging.testrun.org:/etc/dkimkeys . || true # rsync -avz root@staging.testrun.org:/var/lib/rspamd/dkim . || true
- name: rebuild staging.testrun.org to have a clean VPS #- name: rebuild staging.testrun.org to have a clean VPS
run: | # run: |
curl -X POST \ # curl -X POST \
-H "Authorization: Bearer ${{ secrets.HETZNER_API_TOKEN }}" \ # -H "Authorization: Bearer ${{ secrets.HETZNER_API_TOKEN }}" \
-H "Content-Type: application/json" \ # -H "Content-Type: application/json" \
-d '{"image":"debian-12"}' \ # -d '{"image":"debian-12"}' \
"https://api.hetzner.cloud/v1/servers/${{ secrets.STAGING_SERVER_ID }}/actions/rebuild" # "https://api.hetzner.cloud/v1/servers/${{ secrets.STAGING_SERVER_ID }}/actions/rebuild"
- run: scripts/initenv.sh - run: scripts/initenv.sh
- name: append venv/bin to PATH - name: append venv/bin to PATH
run: echo venv/bin >>$GITHUB_PATH run: echo venv/bin >>$GITHUB_PATH
- name: upload TLS cert after rebuilding
run: |
echo " --- wait until staging.testrun.org VPS is rebuilt --- "
rm ~/.ssh/known_hosts
while ! ssh -o ConnectTimeout=180 -o StrictHostKeyChecking=accept-new -v root@staging.testrun.org id -u ; do sleep 1 ; done
ssh -o StrictHostKeyChecking=accept-new -v root@staging.testrun.org id -u
rsync -avz acme/ root@staging.testrun.org:/var/lib/acme || true
rsync -avz dkimkeys/ root@staging.testrun.org:/etc/dkimkeys || true
ssh -o StrictHostKeyChecking=accept-new -v root@staging.testrun.org chown root:root -R /var/lib/acme
- name: run formatting checks - name: run formatting checks
run: cmdeploy fmt -v run: cmdeploy fmt -v
- name: run deploy-chatmail offline tests - name: run deploy-chatmail offline tests
run: pytest --pyargs cmdeploy run: pytest --pyargs cmdeploy
#- name: upload TLS cert after rebuilding
# run: |
# echo " --- wait until staging.testrun.org VPS is rebuilt --- "
# rm ~/.ssh/known_hosts
# while ! ssh -o ConnectTimeout=180 -o StrictHostKeyChecking=accept-new -v root@staging.testrun.org id -u ; do sleep 1 ; done
# ssh -o StrictHostKeyChecking=accept-new -v root@staging.testrun.org id -u
# rsync -avz acme root@staging.testrun.org:/var/lib/ || true
# rsync -avz dkim root@staging.testrun.org:/var/lib/rspamd/ || true
- run: cmdeploy init staging.testrun.org - run: cmdeploy init staging.testrun.org
- run: cmdeploy run - run: cmdeploy run
- name: set DNS entries - name: set DNS entries
run: | run: |
ssh -o StrictHostKeyChecking=accept-new -v root@staging.testrun.org chown opendkim:opendkim -R /etc/dkimkeys #ssh -o StrictHostKeyChecking=accept-new -v root@staging.testrun.org chown _rspamd:_rspamd -R /var/lib/rspamd/dkim
cmdeploy dns --zonefile staging-generated.zone cmdeploy dns --zonefile staging-generated.zone
cat staging-generated.zone >> .github/workflows/staging.testrun.org-default.zone cat staging-generated.zone >> .github/workflows/staging.testrun.org-default.zone
cat .github/workflows/staging.testrun.org-default.zone cat .github/workflows/staging.testrun.org-default.zone

View File

@@ -1,14 +1,5 @@
# Changelog for chatmail deployment # Changelog for chatmail deployment
## untagged
- better preserve notification order
([#263](https://github.com/deltachat/chatmail/pull/263))
- re-enable running the CI in pull requests, but not concurrently
([#258](https://github.com/deltachat/chatmail/pull/258))
## 1.1.0 - 2024-03-28 ## 1.1.0 - 2024-03-28
### The changelog starts to record changes from March 15th, 2024 ### The changelog starts to record changes from March 15th, 2024

View File

@@ -1,8 +1,7 @@
import pwd import pwd
from pathlib import Path from pathlib import Path
from threading import Thread from threading import Thread, Event
from queue import Queue
from socketserver import ( from socketserver import (
UnixStreamServer, UnixStreamServer,
StreamRequestHandler, StreamRequestHandler,
@@ -35,7 +34,7 @@ class Notifier:
self.notification_dir = vmail_dir / "pending_notifications" self.notification_dir = vmail_dir / "pending_notifications"
if not self.notification_dir.exists(): if not self.notification_dir.exists():
self.notification_dir.mkdir() self.notification_dir.mkdir()
self.notification_queue = Queue() self.message_arrived_event = Event()
def get_metadata_dict(self, addr): def get_metadata_dict(self, addr):
return FileDict(self.vmail_dir / addr / "metadata.json") return FileDict(self.vmail_dir / addr / "metadata.json")
@@ -61,37 +60,31 @@ class Notifier:
def new_message_for_addr(self, addr): def new_message_for_addr(self, addr):
self.notification_dir.joinpath(addr).touch() self.notification_dir.joinpath(addr).touch()
self.notification_queue.put(addr) self.message_arrived_event.set()
def thread_run_loop(self): def thread_run_loop(self):
requests_session = requests.Session() requests_session = requests.Session()
# on startup deliver all persisted notifications from last process run
self.notification_queue.put(None)
while 1: while 1:
self.message_arrived_event.wait()
self.message_arrived_event.clear()
self.thread_run_one(requests_session) self.thread_run_one(requests_session)
def thread_run_one(self, requests_session): def thread_run_one(self, requests_session):
addr = self.notification_queue.get() for addr_path in self.notification_dir.iterdir():
if addr is None: addr = addr_path.name
# startup, notify any "pending" notifications from last run if "@" not in addr:
for addr_path in self.notification_dir.iterdir(): continue
if "@" in addr_path.name: for token in self.get_tokens(addr):
self.notify_tokens_for(requests_session, addr_path.name) response = requests_session.post(
else: "https://notifications.delta.chat/notify",
self.notify_tokens_for(requests_session, addr) data=token,
timeout=60,
def notify_tokens_for(self, requests_session, addr): )
for token in self.get_tokens(addr): if response.status_code == 410:
response = requests_session.post( # 410 Gone status code
"https://notifications.delta.chat/notify", # means the token is no longer valid.
data=token, self.remove_token(addr, token)
timeout=60, addr_path.unlink()
)
if response.status_code == 410:
# 410 Gone status code
# means the token is no longer valid.
self.remove_token(addr, token)
self.notification_dir.joinpath(addr).unlink(missing_ok=True)
def handle_dovecot_protocol(rfile, wfile, notifier): def handle_dovecot_protocol(rfile, wfile, notifier):

View File

@@ -84,7 +84,7 @@ def test_handle_dovecot_request_happy_path(notifier, testaddr):
assert handle_dovecot_request(f"B{tx2}\t{testaddr}", transactions, notifier) is None assert handle_dovecot_request(f"B{tx2}\t{testaddr}", transactions, notifier) is None
msg = f"S{tx2}\tpriv/guid00/messagenew" msg = f"S{tx2}\tpriv/guid00/messagenew"
assert handle_dovecot_request(msg, transactions, notifier) is None assert handle_dovecot_request(msg, transactions, notifier) is None
assert notifier.notification_queue.get() == testaddr assert notifier.message_arrived_event.is_set()
assert handle_dovecot_request(f"C{tx2}", transactions, notifier) == "O\n" assert handle_dovecot_request(f"C{tx2}", transactions, notifier) == "O\n"
assert not transactions assert not transactions
assert notifier.notification_dir.joinpath(testaddr).exists() assert notifier.notification_dir.joinpath(testaddr).exists()
@@ -159,8 +159,8 @@ def test_handle_dovecot_protocol_messagenew(notifier):
wfile = io.BytesIO() wfile = io.BytesIO()
handle_dovecot_protocol(rfile, wfile, notifier) handle_dovecot_protocol(rfile, wfile, notifier)
assert wfile.getvalue() == b"O\n" assert wfile.getvalue() == b"O\n"
addr = notifier.notification_queue.get() assert notifier.message_arrived_event.is_set()
assert notifier.notification_dir.joinpath(addr).exists() assert notifier.notification_dir.joinpath("user@example.org").exists()
def test_notifier_thread_run(notifier, testaddr): def test_notifier_thread_run(notifier, testaddr):

View File

@@ -135,6 +135,20 @@ def _configure_opendkim(domain: str, dkim_selector: str = "dkim") -> bool:
"""Configures OpenDKIM""" """Configures OpenDKIM"""
need_restart = False need_restart = False
server.group(name="Create opendkim group", group="opendkim", system=True)
server.user(
name="Create opendkim user",
user="opendkim",
groups=["opendkim"],
system=True,
)
server.user(
name="Add postfix user to opendkim group for socket access",
user="postfix",
groups=["opendkim"],
system=True,
)
main_config = files.template( main_config = files.template(
src=importlib.resources.files(__package__).joinpath("opendkim/opendkim.conf"), src=importlib.resources.files(__package__).joinpath("opendkim/opendkim.conf"),
dest="/etc/opendkim.conf", dest="/etc/opendkim.conf",
@@ -462,24 +476,9 @@ def deploy_chatmail(config_path: Path) -> None:
from .www import build_webpages from .www import build_webpages
apt.update(name="apt update", cache_time=24 * 3600)
server.group(name="Create vmail group", group="vmail", system=True) server.group(name="Create vmail group", group="vmail", system=True)
server.user(name="Create vmail user", user="vmail", group="vmail", system=True) server.user(name="Create vmail user", user="vmail", group="vmail", system=True)
server.group(name="Create opendkim group", group="opendkim", system=True)
server.user(
name="Create opendkim user",
user="opendkim",
groups=["opendkim"],
system=True,
)
server.user(
name="Add postfix user to opendkim group for socket access",
user="postfix",
groups=["opendkim"],
system=True,
)
apt.update(name="apt update", cache_time=24 * 3600)
apt.packages( apt.packages(
name="Install rsync", name="Install rsync",
packages=["rsync"], packages=["rsync"],
@@ -566,17 +565,6 @@ def deploy_chatmail(config_path: Path) -> None:
restarted=mta_sts_need_restart, restarted=mta_sts_need_restart,
) )
# Dovecot should be started before Postfix
# because it creates authentication socket
# required by Postfix.
systemd.service(
name="Start and enable Dovecot",
service="dovecot.service",
running=True,
enabled=True,
restarted=dovecot_need_restart,
)
systemd.service( systemd.service(
name="Start and enable Postfix", name="Start and enable Postfix",
service="postfix.service", service="postfix.service",
@@ -585,6 +573,14 @@ def deploy_chatmail(config_path: Path) -> None:
restarted=postfix_need_restart, restarted=postfix_need_restart,
) )
systemd.service(
name="Start and enable Dovecot",
service="dovecot.service",
running=True,
enabled=True,
restarted=dovecot_need_restart,
)
systemd.service( systemd.service(
name="Start and enable nginx", name="Start and enable nginx",
service="nginx.service", service="nginx.service",