mirror of
https://github.com/chatmail/relay.git
synced 2026-05-11 08:24:37 +00:00
Compare commits
9 Commits
link2xt/av
...
ssh-host-6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1493acb87b | ||
|
|
3ce350de9e | ||
|
|
1e05974970 | ||
|
|
577c04d537 | ||
|
|
d880937d44 | ||
|
|
46d2334e9c | ||
|
|
0ba94dc613 | ||
|
|
d379feea4f | ||
|
|
e82abee1b9 |
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
## untagged
|
## untagged
|
||||||
|
|
||||||
|
- Check whether GCC is installed in initenv.sh
|
||||||
|
([#608](https://github.com/chatmail/relay/pull/608))
|
||||||
|
|
||||||
- Expire push notification tokens after 90 days
|
- Expire push notification tokens after 90 days
|
||||||
([#583](https://github.com/chatmail/relay/pull/583))
|
([#583](https://github.com/chatmail/relay/pull/583))
|
||||||
|
|
||||||
@@ -14,6 +17,9 @@
|
|||||||
- Reconfigure Dovecot imap-login service to high-performance mode
|
- Reconfigure Dovecot imap-login service to high-performance mode
|
||||||
([#578](https://github.com/chatmail/relay/pull/578))
|
([#578](https://github.com/chatmail/relay/pull/578))
|
||||||
|
|
||||||
|
- Set timezone to improve dovecot performance
|
||||||
|
([#584](https://github.com/chatmail/relay/pull/584))
|
||||||
|
|
||||||
- Increase nginx connection limits
|
- Increase nginx connection limits
|
||||||
([#576](https://github.com/chatmail/relay/pull/576))
|
([#576](https://github.com/chatmail/relay/pull/576))
|
||||||
|
|
||||||
|
|||||||
@@ -541,3 +541,6 @@ Here are some related projects that you may be interested in:
|
|||||||
progress](https://github.com/mjl-/mox/issues/251) to modify it to support all
|
progress](https://github.com/mjl-/mox/issues/251) to modify it to support all
|
||||||
of the features and configuration settings required to operate as a chatmail
|
of the features and configuration settings required to operate as a chatmail
|
||||||
relay.
|
relay.
|
||||||
|
- [Maddy-Chatmail](https://github.com/sadraiiali/maddy_chatmail): a plugin for the
|
||||||
|
[Maddy email server](https://maddy.email/) which aims to implement the
|
||||||
|
chatmail relay features and configuration options.
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ def _install_dovecot_package(package: str, arch: str):
|
|||||||
src=url,
|
src=url,
|
||||||
dest=deb_filename,
|
dest=deb_filename,
|
||||||
sha256sum=sha256,
|
sha256sum=sha256,
|
||||||
cache_time=9999999999999, # never redownload the package
|
cache_time=60 * 60 * 24 * 365 * 10, # never redownload the package
|
||||||
)
|
)
|
||||||
|
|
||||||
apt.deb(name=f"Install dovecot-{package}", src=deb_filename)
|
apt.deb(name=f"Install dovecot-{package}", src=deb_filename)
|
||||||
@@ -410,6 +410,13 @@ def _configure_dovecot(config: Config, debug: bool = False) -> bool:
|
|||||||
persist=True,
|
persist=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
timezone_env = files.line(
|
||||||
|
name="Set TZ environment variable",
|
||||||
|
path="/etc/environment",
|
||||||
|
line="TZ=:/etc/localtime",
|
||||||
|
)
|
||||||
|
need_restart |= timezone_env.changed
|
||||||
|
|
||||||
return need_restart
|
return need_restart
|
||||||
|
|
||||||
|
|
||||||
@@ -709,9 +716,10 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
|
|||||||
packages="postfix",
|
packages="postfix",
|
||||||
)
|
)
|
||||||
|
|
||||||
_install_dovecot_package("core", host.get_fact(facts.server.Arch))
|
if not "dovecot.service" in host.get_fact(SystemdEnabled):
|
||||||
_install_dovecot_package("imapd", host.get_fact(facts.server.Arch))
|
_install_dovecot_package("core", host.get_fact(facts.server.Arch))
|
||||||
_install_dovecot_package("lmtpd", host.get_fact(facts.server.Arch))
|
_install_dovecot_package("imapd", host.get_fact(facts.server.Arch))
|
||||||
|
_install_dovecot_package("lmtpd", host.get_fact(facts.server.Arch))
|
||||||
|
|
||||||
apt.packages(
|
apt.packages(
|
||||||
name="Install nginx",
|
name="Install nginx",
|
||||||
@@ -808,8 +816,14 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
|
|||||||
name="Ensure cron is installed",
|
name="Ensure cron is installed",
|
||||||
packages=["cron"],
|
packages=["cron"],
|
||||||
)
|
)
|
||||||
git_hash = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode()
|
try:
|
||||||
git_diff = subprocess.check_output(["git", "diff"]).decode()
|
git_hash = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode()
|
||||||
|
except Exception:
|
||||||
|
git_hash = "unknown\n"
|
||||||
|
try:
|
||||||
|
git_diff = subprocess.check_output(["git", "diff"]).decode()
|
||||||
|
except Exception:
|
||||||
|
git_diff = ""
|
||||||
files.put(
|
files.put(
|
||||||
name="Upload chatmail relay git commiit hash",
|
name="Upload chatmail relay git commiit hash",
|
||||||
src=StringIO(git_hash + git_diff),
|
src=StringIO(git_hash + git_diff),
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from packaging import version
|
|||||||
from termcolor import colored
|
from termcolor import colored
|
||||||
|
|
||||||
from . import dns, remote
|
from . import dns, remote
|
||||||
from .sshexec import SSHExec
|
from .sshexec import SSHExec, Local
|
||||||
|
|
||||||
#
|
#
|
||||||
# cmdeploy sub commands and options
|
# cmdeploy sub commands and options
|
||||||
@@ -62,13 +62,18 @@ def run_cmd_options(parser):
|
|||||||
"--ssh-host",
|
"--ssh-host",
|
||||||
dest="ssh_host",
|
dest="ssh_host",
|
||||||
help="specify an SSH host to deploy to; uses mail_domain from chatmail.ini by default",
|
help="specify an SSH host to deploy to; uses mail_domain from chatmail.ini by default",
|
||||||
|
default=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def run_cmd(args, out):
|
def run_cmd(args, out):
|
||||||
"""Deploy chatmail services on the remote server."""
|
"""Deploy chatmail services on the remote server."""
|
||||||
|
|
||||||
sshexec = args.get_sshexec()
|
ssh_host = args.ssh_host if args.ssh_host else args.config.mail_domain
|
||||||
|
if ssh_host == "localhost":
|
||||||
|
sshexec = Local(ssh_host)
|
||||||
|
else:
|
||||||
|
sshexec = args.get_sshexec(ssh_host)
|
||||||
require_iroh = args.config.enable_iroh_relay
|
require_iroh = args.config.enable_iroh_relay
|
||||||
remote_data = dns.get_initial_remote_data(sshexec, args.config.mail_domain)
|
remote_data = dns.get_initial_remote_data(sshexec, args.config.mail_domain)
|
||||||
if not dns.check_initial_remote_data(remote_data, print=out.red):
|
if not dns.check_initial_remote_data(remote_data, print=out.red):
|
||||||
@@ -80,7 +85,7 @@ def run_cmd(args, out):
|
|||||||
env["CHATMAIL_REQUIRE_IROH"] = "True" if require_iroh else ""
|
env["CHATMAIL_REQUIRE_IROH"] = "True" if require_iroh else ""
|
||||||
deploy_path = importlib.resources.files(__package__).joinpath("deploy.py").resolve()
|
deploy_path = importlib.resources.files(__package__).joinpath("deploy.py").resolve()
|
||||||
pyinf = "pyinfra --dry" if args.dry_run else "pyinfra"
|
pyinf = "pyinfra --dry" if args.dry_run else "pyinfra"
|
||||||
ssh_host = args.config.mail_domain if not args.ssh_host else args.ssh_host
|
ssh_host = "@local" if ssh_host == "localhost" else f"--ssh-host {ssh_host}"
|
||||||
cmd = f"{pyinf} --ssh-user root {ssh_host} {deploy_path} -y"
|
cmd = f"{pyinf} --ssh-user root {ssh_host} {deploy_path} -y"
|
||||||
if version.parse(pyinfra.__version__) < version.parse("3"):
|
if version.parse(pyinfra.__version__) < version.parse("3"):
|
||||||
out.red("Please re-run scripts/initenv.sh to update pyinfra to version 3.")
|
out.red("Please re-run scripts/initenv.sh to update pyinfra to version 3.")
|
||||||
@@ -330,9 +335,9 @@ def main(args=None):
|
|||||||
if not hasattr(args, "func"):
|
if not hasattr(args, "func"):
|
||||||
return parser.parse_args(["-h"])
|
return parser.parse_args(["-h"])
|
||||||
|
|
||||||
def get_sshexec():
|
def get_sshexec(host):
|
||||||
print(f"[ssh] login to {args.config.mail_domain}")
|
print(f"[ssh] login to {host}")
|
||||||
return SSHExec(args.config.mail_domain, verbose=args.verbose)
|
return SSHExec(host, verbose=args.verbose)
|
||||||
|
|
||||||
args.get_sshexec = get_sshexec
|
args.get_sshexec = get_sshexec
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
|
|
||||||
@@ -44,30 +45,16 @@ def print_stderr(item="", end="\n"):
|
|||||||
print(item, file=sys.stderr, end=end)
|
print(item, file=sys.stderr, end=end)
|
||||||
|
|
||||||
|
|
||||||
class SSHExec:
|
class Exec:
|
||||||
RemoteError = execnet.RemoteError
|
|
||||||
FuncError = FuncError
|
FuncError = FuncError
|
||||||
|
|
||||||
def __init__(self, host, verbose=False, python="python3", timeout=60):
|
def __init__(self, host, verbose, timeout):
|
||||||
self.gateway = execnet.makegateway(f"ssh=root@{host}//python={python}")
|
self.host = host
|
||||||
self._remote_cmdloop_channel = bootstrap_remote(self.gateway, remote)
|
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
|
|
||||||
def __call__(self, call, kwargs=None, log_callback=None):
|
def __call__(self, call, kwargs=None, log_callback=None):
|
||||||
if kwargs is None:
|
return subprocess.check_output(call)
|
||||||
kwargs = {}
|
|
||||||
assert call.__module__.startswith("cmdeploy.remote")
|
|
||||||
modname = call.__module__.replace("cmdeploy.", "")
|
|
||||||
self._remote_cmdloop_channel.send((modname, call.__name__, kwargs))
|
|
||||||
while 1:
|
|
||||||
code, data = self._remote_cmdloop_channel.receive(timeout=self.timeout)
|
|
||||||
if log_callback is not None and code == "log":
|
|
||||||
log_callback(data)
|
|
||||||
elif code == "finish":
|
|
||||||
return data
|
|
||||||
elif code == "error":
|
|
||||||
raise self.FuncError(data)
|
|
||||||
|
|
||||||
def logged(self, call, kwargs):
|
def logged(self, call, kwargs):
|
||||||
def log_progress(data):
|
def log_progress(data):
|
||||||
@@ -85,3 +72,33 @@ class SSHExec:
|
|||||||
res = self(call, kwargs, log_callback=log_progress)
|
res = self(call, kwargs, log_callback=log_progress)
|
||||||
print_stderr()
|
print_stderr()
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
class Local(Exec):
|
||||||
|
|
||||||
|
def __init__(self, host, verbose=False, timeout=60):
|
||||||
|
super().__init__(host, verbose, timeout)
|
||||||
|
|
||||||
|
|
||||||
|
class SSHExec(Exec):
|
||||||
|
RemoteError = execnet.RemoteError
|
||||||
|
|
||||||
|
def __init__(self, host, verbose=False, timeout=60):
|
||||||
|
super().__init__(host, verbose, timeout)
|
||||||
|
self.gateway = execnet.makegateway(f"ssh=root@{host}//python=python3")
|
||||||
|
self._remote_cmdloop_channel = bootstrap_remote(self.gateway, remote)
|
||||||
|
|
||||||
|
def __call__(self, call, kwargs=None, log_callback=None):
|
||||||
|
if kwargs is None:
|
||||||
|
kwargs = {}
|
||||||
|
assert call.__module__.startswith("cmdeploy.remote")
|
||||||
|
modname = call.__module__.replace("cmdeploy.", "")
|
||||||
|
self._remote_cmdloop_channel.send((modname, call.__name__, kwargs))
|
||||||
|
while 1:
|
||||||
|
code, data = self._remote_cmdloop_channel.receive(timeout=self.timeout)
|
||||||
|
if log_callback is not None and code == "log":
|
||||||
|
log_callback(data)
|
||||||
|
elif code == "finish":
|
||||||
|
return data
|
||||||
|
elif code == "error":
|
||||||
|
raise self.FuncError(data)
|
||||||
|
|||||||
@@ -65,6 +65,14 @@ class TestSSHExecutor:
|
|||||||
assert (now - since_date).total_seconds() < 60 * 60 * 51
|
assert (now - since_date).total_seconds() < 60 * 60 * 51
|
||||||
|
|
||||||
|
|
||||||
|
def test_timezone_env(remote):
|
||||||
|
for line in remote.iter_output("env"):
|
||||||
|
print(line)
|
||||||
|
if line == "tz=:/etc/localtime":
|
||||||
|
return True
|
||||||
|
pytest.fail("TZ is not set")
|
||||||
|
|
||||||
|
|
||||||
def test_remote(remote, imap_or_smtp):
|
def test_remote(remote, imap_or_smtp):
|
||||||
lineproducer = remote.iter_output(imap_or_smtp.logcmd)
|
lineproducer = remote.iter_output(imap_or_smtp.logcmd)
|
||||||
imap_or_smtp.connect()
|
imap_or_smtp.connect()
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ if command -v lsb_release 2>&1 >/dev/null; then
|
|||||||
echo "You need to install python3-dev for installing the other dependencies."
|
echo "You need to install python3-dev for installing the other dependencies."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
if ! gcc --version 2>&1 >/dev/null
|
||||||
|
then
|
||||||
|
echo "You need to install gcc for building Python dependencies."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user