liab-deployments/liab_deployments/deploy/copyparty.py

155 lines
3.6 KiB
Python

#
# Deploy copyparty (https://github.com/9001/copyparty) fileserver
#
# An example inventory may look like this:
#
# group = [
# (
# 'edu.datalad.org',
# {
# 'copyparty': {
# 'sites': [
# {
# 'serve_address': 'copyparty.example.org',
# 'container_tag': 'docker.io/copyparty/ac:latest',
# 'user': ('copyparty', '5000'),
# 'host_port': 30500,
# 'config_file_asset': 'assets/copyparty-example-config.conf',
# },
# ...
#
from pyinfra.api import deploy
from pyinfra import (
host,
)
from pyinfra.operations import (
files,
server,
)
from liab_deployments.operations import (
caddy,
user,
user_systemd,
)
container_unit_tmpl = """\
[Container]
Image={container_tag}
ContainerName=copyparty
PublishPort={host_port}:3923
Volume={user_home}/config:/cfg:z
Volume={user_home}/data:/data:z
# Give the container time to stop in case the thumbnailer is still running.
# It is allowed to continue finishing up for 10s after the shutdown signal, give it a 5s buffer
StopTimeout=15
# hide it from logs with "/._" so it matches the default --lf-url filter
HealthCmd="wget --spider -q 127.0.0.1:3923/?reset=/._"
HealthInterval=1m
HealthTimeout=2s
HealthRetries=5
HealthStartPeriod=15s
[Unit]
After=default.target
[Install]
# Start by default on boot
WantedBy=default.target
[Service]
# Give the container time to start in case it needs to pull the image
TimeoutStartSec=600
"""
caddyfile_block_tmpl = """\
{serve_address} {{
reverse_proxy localhost:{host_port}
}}
"""
@deploy("Deploy copyparty")
def deploy_sites():
if not hasattr(host.data, 'copyparty'):
return
for spec in host.data.copyparty.get('sites', []):
_deploy_site(
spec['serve_address'],
spec['container_tag'],
spec['config_file_asset'],
spec['user'],
spec['host_port'],
name=spec.get('name', 'copyparty'),
caddyfile_block_tmpl=spec.get(
'caddyfile_block_tmpl', caddyfile_block_tmpl
),
)
def _deploy_site(
serve_address,
container_tag,
config_file_asset,
user_spec: tuple[str, int],
host_port,
*,
name,
caddyfile_block_tmpl,
):
user_name, uid = user_spec
user_home = f'/home/{user_name}'
user.systemd_service(
user_name,
uid,
user_home,
)
for i in ['config', 'data']:
files.directory(
path=f'{user_home}/{i}',
present=True,
_sudo_user=user_name,
)
user_systemd.container_unit(
user_name,
user_home,
name,
container_unit_tmpl.format(
user_home=user_home,
container_tag=container_tag,
host_port=host_port,
),
)
files.put(
name='Copyparty config',
src=config_file_asset,
dest=f'{user_home}/config/copyparty.conf',
_sudo_user=user_name,
)
user_systemd.run_service(
user_name,
uid,
'copyparty',
# container unit cannot be enabled, but auto-start
# is handled via "install" in the unit spec
enabled=False,
)
server.wait(
name=f"Wait for copyparty {serve_address!r} to start",
port=host_port,
)
caddy.caddyfile_block(
marker=f'COPYPARTY {serve_address}',
content=caddyfile_block_tmpl.format(
serve_address=serve_address,
host_port=host_port,
),
)