mirror of
https://github.com/chatmail/relay.git
synced 2026-05-10 16:04:37 +00:00
Compare commits
2 Commits
ssh-host-6
...
staging-ci
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
614b955351 | ||
|
|
7b1ffc1410 |
@@ -5,6 +5,9 @@
|
||||
- Check whether GCC is installed in initenv.sh
|
||||
([#608](https://github.com/chatmail/relay/pull/608))
|
||||
|
||||
- Automate file ownership setting from host migration process
|
||||
([#609](https://github.com/chatmail/relay/pull/609))
|
||||
|
||||
- Expire push notification tokens after 90 days
|
||||
([#583](https://github.com/chatmail/relay/pull/583))
|
||||
|
||||
|
||||
@@ -395,15 +395,6 @@ in this case, just run `ssh-keygen -R "mail.example.org"` as recommended.
|
||||
Postfix and Dovecot are disabled for now; we will enable them later.
|
||||
We first need to make the new site fully operational.
|
||||
|
||||
3. On the new site, run the following to ensure the ownership is correct in case UIDs/GIDs changed:
|
||||
|
||||
```
|
||||
chown root: -R /var/lib/acme
|
||||
chown opendkim: -R /etc/dkimkeys
|
||||
chown vmail: -R /home/vmail/mail
|
||||
chown echobot: -R /run/echobot
|
||||
```
|
||||
|
||||
4. Now, update DNS entries.
|
||||
|
||||
If other MTAs try to deliver messages to your chatmail domain they may fail intermittently,
|
||||
|
||||
@@ -748,6 +748,20 @@ def deploy_chatmail(config_path: Path, disable_mail: bool) -> None:
|
||||
_remove_rspamd()
|
||||
opendkim_need_restart = _configure_opendkim(mail_domain, "opendkim")
|
||||
|
||||
#
|
||||
# If this system is pre-populated with data from a previous instance,
|
||||
# we might need to adjust ownership of files.
|
||||
#
|
||||
stateful_paths = {
|
||||
"/etc/dkimkeys": "opendkim",
|
||||
"/home/vmail/mail": "vmail",
|
||||
"/run/echobot": "echobot",
|
||||
"/var/lib/acme": "root",
|
||||
}
|
||||
for stateful_path, path_owner in stateful_paths.items():
|
||||
files.directory(stateful_path) # In case it doesn't exist yet.
|
||||
server.shell("chown {}: -R {}".format(path_owner, stateful_path))
|
||||
|
||||
systemd.service(
|
||||
name="Start and enable OpenDKIM",
|
||||
service="opendkim.service",
|
||||
|
||||
@@ -19,7 +19,7 @@ from packaging import version
|
||||
from termcolor import colored
|
||||
|
||||
from . import dns, remote
|
||||
from .sshexec import SSHExec, Local
|
||||
from .sshexec import SSHExec
|
||||
|
||||
#
|
||||
# cmdeploy sub commands and options
|
||||
@@ -62,18 +62,13 @@ def run_cmd_options(parser):
|
||||
"--ssh-host",
|
||||
dest="ssh_host",
|
||||
help="specify an SSH host to deploy to; uses mail_domain from chatmail.ini by default",
|
||||
default=None,
|
||||
)
|
||||
|
||||
|
||||
def run_cmd(args, out):
|
||||
"""Deploy chatmail services on the remote server."""
|
||||
|
||||
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)
|
||||
sshexec = args.get_sshexec()
|
||||
require_iroh = args.config.enable_iroh_relay
|
||||
remote_data = dns.get_initial_remote_data(sshexec, args.config.mail_domain)
|
||||
if not dns.check_initial_remote_data(remote_data, print=out.red):
|
||||
@@ -85,7 +80,7 @@ def run_cmd(args, out):
|
||||
env["CHATMAIL_REQUIRE_IROH"] = "True" if require_iroh else ""
|
||||
deploy_path = importlib.resources.files(__package__).joinpath("deploy.py").resolve()
|
||||
pyinf = "pyinfra --dry" if args.dry_run else "pyinfra"
|
||||
ssh_host = "@local" if ssh_host == "localhost" else f"--ssh-host {ssh_host}"
|
||||
ssh_host = args.config.mail_domain if not args.ssh_host else args.ssh_host
|
||||
cmd = f"{pyinf} --ssh-user root {ssh_host} {deploy_path} -y"
|
||||
if version.parse(pyinfra.__version__) < version.parse("3"):
|
||||
out.red("Please re-run scripts/initenv.sh to update pyinfra to version 3.")
|
||||
@@ -335,9 +330,9 @@ def main(args=None):
|
||||
if not hasattr(args, "func"):
|
||||
return parser.parse_args(["-h"])
|
||||
|
||||
def get_sshexec(host):
|
||||
print(f"[ssh] login to {host}")
|
||||
return SSHExec(host, verbose=args.verbose)
|
||||
def get_sshexec():
|
||||
print(f"[ssh] login to {args.config.mail_domain}")
|
||||
return SSHExec(args.config.mail_domain, verbose=args.verbose)
|
||||
|
||||
args.get_sshexec = get_sshexec
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import inspect
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from queue import Queue
|
||||
|
||||
@@ -45,16 +44,30 @@ def print_stderr(item="", end="\n"):
|
||||
print(item, file=sys.stderr, end=end)
|
||||
|
||||
|
||||
class Exec:
|
||||
class SSHExec:
|
||||
RemoteError = execnet.RemoteError
|
||||
FuncError = FuncError
|
||||
|
||||
def __init__(self, host, verbose, timeout):
|
||||
self.host = host
|
||||
def __init__(self, host, verbose=False, python="python3", timeout=60):
|
||||
self.gateway = execnet.makegateway(f"ssh=root@{host}//python={python}")
|
||||
self._remote_cmdloop_channel = bootstrap_remote(self.gateway, remote)
|
||||
self.timeout = timeout
|
||||
self.verbose = verbose
|
||||
|
||||
def __call__(self, call, kwargs=None, log_callback=None):
|
||||
return subprocess.check_output(call)
|
||||
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)
|
||||
|
||||
def logged(self, call, kwargs):
|
||||
def log_progress(data):
|
||||
@@ -72,33 +85,3 @@ class Exec:
|
||||
res = self(call, kwargs, log_callback=log_progress)
|
||||
print_stderr()
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user