From df16f74b74b716a530f015732ab57dd1c912c765 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Tue, 9 Apr 2024 18:53:10 -0700 Subject: [PATCH] nextcloud: Use systemd generator for creating container service - See quadlet(5). - Using 'podman generate systemd' is deprecated. Quadlets are recommended. - When using the systemd generator, enable/disable is not possible. The container is automatically started when system is booted or systemd is reloaded after .container file changes. Signed-off-by: Sunil Mohan Adapa Reviewed-by: James Valleroy --- plinth/action_utils.py | 67 ++++++++++++++------------ plinth/modules/nextcloud/privileged.py | 27 ++++++----- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/plinth/action_utils.py b/plinth/action_utils.py index ac6e617bc..baa662dae 100644 --- a/plinth/action_utils.py +++ b/plinth/action_utils.py @@ -489,50 +489,55 @@ def is_package_manager_busy(): return False -def podman_run(network_name: str, subnet: str, bridge_ip: str, host_port: str, - container_port: str, container_ip: str, container_name: str, - image_name: str, extra_run_options: list[str] | None = None, - extra_network_options: list[str] | None = None): - """Remove, recreate and run a podman container.""" +def podman_create(network_name: str, subnet: str, bridge_ip: str, + host_port: str, container_port: str, container_ip: str, + container_name: str, image_name: str, + volumes: dict[str, str] | None = None, + env: dict[str, str] | None = None, + extra_network_options: list[str] | None = None): + """Remove and recreate a podman container.""" + service_stop(container_name) + try: - service_stop(container_name) subprocess.run(['podman', 'network', 'rm', '--force', network_name], check=False) except subprocess.CalledProcessError: pass + # Create bridge network network_create_command = [ 'podman', 'network', 'create', '--driver', 'bridge', '--subnet', subnet, '--gateway', bridge_ip, '--dns', bridge_ip, '--interface-name', network_name, network_name ] + (extra_network_options or []) - - # Create bridge network subprocess.run(network_create_command, check=True) - args = [ - 'podman', 'run', '--detach', '--network', network_name, '--ip', - container_ip, '--name', container_name, '--restart', 'unless-stopped', - '--quiet' - ] - # Only listen on localhost. This is to prevent exposing the host port to - # the internet. - args += ['--publish', f'127.0.0.1:{host_port}:{container_port}'] - # Enable automatic updates. - args += ['--label', 'io.containers.autoupdate=registry'] - # If another container with the same name already exists, replace and - # remove it. - args += ['--replace'] - args += (extra_run_options or []) + [image_name] - subprocess.run(args, check=True) + directory = pathlib.Path('/etc/containers/systemd') + directory.mkdir(parents=True, exist_ok=True) + service_file = directory / f'{container_name}.container' + volume_lines = '\n'.join([ + f'Volume={source}:{dest}' for source, dest in (volumes or {}).items() + ]) + env_lines = '\n'.join( + [f'Environment={key}={value}' for key, value in (env or {}).items()]) + contents = f'''[Container] +AutoUpdate=registry +ContainerName=%N +{env_lines} +Image={image_name} +IP={container_ip} +Network={network_name} +PublishPort=127.0.0.1:{host_port}:{container_port} +{volume_lines} - # Create service file for starting/stopping container using systemd - service_file = pathlib.Path( - '/etc/systemd/system') / f'{container_name}.service' - with service_file.open('wb') as file_handle: - subprocess.run( - ['podman', 'generate', 'systemd', '--new', container_name], - stdout=file_handle, check=True) +[Service] +Restart=always + +[Install] +WantedBy=default.target +''' + service_file.write_text(contents) + service_daemon_reload() def podman_uninstall(container_name: str, network_name: str, volume_name: str, @@ -542,6 +547,6 @@ def podman_uninstall(container_name: str, network_name: str, volume_name: str, subprocess.run(['podman', 'volume', 'rm', volume_name], check=True) subprocess.run(['podman', 'image', 'rm', image_name], check=True) service_file = pathlib.Path( - '/etc/systemd/system/') / f'{container_name}.service' + '/etc/containers/systemd/') / f'{container_name}.container' service_file.unlink(missing_ok=True) service_daemon_reload() diff --git a/plinth/modules/nextcloud/privileged.py b/plinth/modules/nextcloud/privileged.py index 2021374bc..12479b7c9 100644 --- a/plinth/modules/nextcloud/privileged.py +++ b/plinth/modules/nextcloud/privileged.py @@ -52,19 +52,20 @@ def setup(): # Setup redis for caching _redis_listen_socket() - action_utils.podman_run( - network_name=NETWORK_NAME, subnet='172.16.16.0/24', - bridge_ip=BRIDGE_IP, host_port='8181', container_port='80', - container_ip=CONTAINER_IP, container_name=CONTAINER_NAME, - image_name=IMAGE_NAME, extra_run_options=[ - '--volume=/run/mysqld/mysqld.sock:/run/mysqld/mysqld.sock', - '--volume=/run/redis/redis-server.sock:' - '/run/redis/redis-server.sock', - '--volume=/run/slapd/ldapi:/run/slapd/ldapi', - f'--volume={VOLUME_NAME}:/var/www/html', - f'--env=TRUSTED_PROXIES={BRIDGE_IP}', - '--env=OVERWRITEWEBROOT=/nextcloud' - ]) + volumes = { + '/run/mysqld/mysqld.sock': '/run/mysqld/mysqld.sock', + '/run/redis/redis-server.sock': '/run/redis/redis-server.sock', + '/run/slapd/ldapi': '/run/slapd/ldapi', + VOLUME_NAME: '/var/www/html' + } + env = {'TRUSTED_PROXIES': BRIDGE_IP, 'OVERWRITEWEBROOT': '/nextcloud'} + action_utils.podman_create(network_name=NETWORK_NAME, + subnet='172.16.16.0/24', bridge_ip=BRIDGE_IP, + host_port='8181', container_port='80', + container_ip=CONTAINER_IP, + container_name=CONTAINER_NAME, + image_name=IMAGE_NAME, volumes=volumes, env=env) + action_utils.service_start(CONTAINER_NAME) _configure_firewall(action='add', interface_name=NETWORK_NAME) # OCC isn't immediately available after the container is spun up.