-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Service Support
A third party application packaged for Synology often provide a web user interface and users expect to get simple access to it thanks to a service shortcut.
A packager may consider running such a user interface as root is a non-affordable security risk and will push effort to get it run as non-privileged user.
As maintainer facing a large upgrade, work on packages created with copy-paste pattern of many similar files are both time consumming and error prone; so generated files from generic support appear as a requirement.
Thanks to a small set of spk Makefile
variables, a package designer can
benefit from generic installer
and start-stop-status
scripts, with
possibility to adapt default behavior thanks to hooks as shell functions.
- User creation (
SERVICE_USER
) and removal to run backgroup service process - Share folder creation based on wizard variable (
SERVICE_WIZARD_SHARE
) - Group creation for managing access to share folder (
SERVICE_WIZARD_GROUP
) - Service port (
SERVICE_PORT
) configuration for firewall and DSM shortcut - Logging support in both
installer
andstart-stop-status
script - Hooks in package specific script (
SERVICE_SETUP
) - A specific
start-stop-status
script is provided for package withSTARTABLE=no
Support is enabled as far as a SERVICE_
variable is set in spk Makefile
.
Package spk/demoservice
is provided as non-arch example of how to design your
package and wizard screens.
If INSTALLER_SCRIPT
is set with a installer script, it replaces generic one.
If SSS_SCRIPT
is set with a specific start-stop script, it replaces generic one.
In any case, scripts/service-setup
is generated from package variables and
SERVICE_SETUP
, if provided.
For package that has been built without this new support, refer to migration guidelines.
An application shortcut is available when both SPK_ICON
and SERVICE_PORT
are set in Makefile.
A single URL link is built from:
DISPLAY_NAME
DESCRIPTION
SERVICE_PORT
-
SERVICE_PORT_PROTOCOL
, defaults tohttp
-
SERVICE_URL
, defaults to/
-
SERVICE_PORT_ALL_USERS
, defaults totrue
Generated ${DSM_UI_DIR}/config
and icons are included in package.tgz
. If
not set in Makefile
, DSM_UI_DIR
default value is app
.
Setting NO_SERVICE_SHORTCUT
prevents this file generation, typically when
SERVICE_PORT
is not intended to be browsed.
For information, ADMIN_PORT
, ADMIN_PROTOCOL
and ADMIN_URL
are also
available to generate administration link visible from Package Center entry.
To prevent user account name collision when migrating from previous busybox
usage, a prefix is added to package name to create service account:
-
sc-USER
for DSM 6 privilege framework -
svc-USER
for DSM 5synouser
account
For usage in scripts, variable EFF_USER
contains effective account name with
prefix.
conf/privilege
is generated with username=sc-SPK_NAME
if SERVICE_USER
variable is set, by defaults to auto
.
In rare case package requires an alternate service account name, SERVICE_USER
value other than auto
can be used.
For DSM 5 compatibility, installer
script will create a system account with
synouser
but prefixed with svc-
. Script start-stop-status
invokes su
to start SERVICE_COMMAND
as non-priviliged user.
In case script start-stop-status
has to run as root
on DSM 6, package can
provide its own conf/privilege
file as far as CONF_DIR
variable is set.
conf/resource/SPK_NAME.sc
is generated except if FWPORTS_FILE
is provide in
Makefile. By defaults, it configure SERVICE_PORT
as tcp with port forwarding
enabled.
[SPK_NAME]
title="(SERVICE_PORT_TITLE:SPK_NAME)"
desc="(DISPLAY_NAME:SPK_NAME)"
port_forward="yes"
dst.ports="SERVICE_PORT/tcp"
If that default behaviour do not suit your need (for instance to declare two
ports), provide a package specific file relative path as FWPORTS_FILE
variable. File is then copied as conf/resource/SPK_NAME.sc
and handled by
installer
script as standard one.
Both generic installer
and start-stop-status
scripts source service-setup
script which is generated aggregating following variables and SERVICE_SETUP
script if set in spk
Makefile
GROUP
and SHARE_PATH
are set from wizard variable names declared in
Makefile variables SERVICE_WIZARD_GROUP
and SERVICE_WIZARD_SHARE
# Base service USER to run background process prefixed according to DSM
USER="demoservice"
PRIV_PREFIX=sc-
SYNOUSER_PREFIX=svc-
if [ ${SYNOPKG_DSM_VERSION_MAJOR} -lt 6 ]; then EFF_USER="${SYNOUSER_PREFIX}${USER}"; else EFF_USER="${PRIV_PREFIX}${USER}"; fi
# Group name from UI if provided
if [ -n "${wizard_group}" ]; then GROUP="${wizard_group}"; fi
# Share download location from UI if provided
if [ -n "${wizard_download_dir}" ]; then SHARE_PATH="${wizard_download_dir}"; fi
# Service port
SERVICE_PORT=8888
# start-stop-status script redirect stdout/stderr to LOG_FILE
LOG_FILE="${SYNOPKG_PKGDEST}/var/${SYNOPKG_PKGNAME}.log"
# Service command has to deliver its pid into PID_FILE
PID_FILE="${SYNOPKG_PKGDEST}/var/${SYNOPKG_PKGNAME}.pid"
# Service command to execute (either with shell or as is)
SERVICE_COMMAND="${SYNOPKG_PKGDEST}/bin/demoservice.sh ${SERVICE_PORT} ${PID_FILE}"
SERVICE_SETUP
script can provide shell function invoked as hook when
installer
steps are run by DSM: service_preinst
, service_postinst
,
service_preuninst
, service_postuninst
, service_preupgrade
,
service_save
, service_restore
, service_postupgrade
.
For DSM 5 compatibility, scripts have to be designed to run with busybox
.
installer
script logs to /tmp/${SPK_NAME}_install.log
and if successfully
installed file is copied as
/var/packages/${SPK_NAME}/target/var/${SPK_NAME}_install.log
and also available at /usr/local/${SPK_NAME}/var/${SPK_NAME}_install.log
By defaults on DSM 5, only var
folder is writable by service account. If
required, add required commands in service_postinst
shell function in package
specific SERVICE_SETUP
script.
Wizard variables are stored in
/var/packages/${SPK_NAME}/etc/installer-variables
so that they can be
retreived and used in uninstall or upgrade.
start-stop-status
generic script starts SERVICE_COMMAND
as non-privileged
user, account name defaults to package name SPK_NAME
except if SERVICE_USER
is different from auto
.
Package status feedback relies on pid file
/var/packages/${SPK_NAME}/target/var/${SPK_NAME}.pid
available as PID_FILE
shell variable.
Service process is expected to fork in background and to provides PID_FILE
containing its own main process PID. Two means are available to do so:
-
if application supports such PID file generation,
service_postinst
shell function should configure service fromPID_FILE
variable -
PID_FILE
variable has to be provided as command argument inSERVICE_COMMAND
so that process writes down its own PID there, at least from shell special variable$!
Process standard output and error streams are aggregated into log file
/var/packages/${SPK_NAME}/target/var/${SPK_NAME}.log
which is readable thanks
to Package Center "View Log" package action.
Script is verbose by default. This behavior can be switched off setting
variables in SERVICE_SETUP
script:
-
SVC_NO_REDIRECT=y
prevents process streams to be collected in package log -
SVC_QUIET=y
prevents logging start/stop date and action -
SVC_KEEP_LOG=y
prevent log content to be cleared before each startup -
SERVICE_SHELL
can be used to replace default/bin/sh
on DSM 5 only
In case application binary does not support background execution, a work-around
is to execute command from service_prestart
instead of setting
SERVICE_COMMAND
. This prevents to create an additional script to do so.
SERVICE_USER = auto
SERVICE_SETUP = src/service-setup.sh
STARTABLE = yes
In src/service-setup.sh
, replace generic command execution with shell
background execution and PID_FILE
generation. LOG_FILE
can be use to
collect stderr
and stdout
. Example from demoservice
:
service_prestart ()
{
# Replace generic service startup, fork process in background
echo "Starting python -m SimpleHTTPServer ${SERVICE_PORT} at ${SYNOPKG_PKGDEST}" >> ${LOG_FILE}
COMMAND="python -m SimpleHTTPServer ${SERVICE_PORT}"
if [ $SYNOPKG_DSM_VERSION_MAJOR -lt 6 ]; then
su ${EFF_USER} -s /bin/sh -c "cd ${SYNOPKG_PKGDEST}; ${COMMAND}" >> ${LOG_FILE} 2>&1 &
else
cd ${SYNOPKG_PKGDEST};
${COMMAND} >> ${LOG_FILE} 2>&1 &
fi
echo "$!" > "${PID_FILE}"
}
In case application binary has to start as root
and forks to non-privileged
user from parameter (with setuid
syscall), it is possible to keep benefit of
SERVICE_USER
support.
CONF_DIR = src/conf
SERVICE_USER = auto
SERVICE_SETUP = src/service-setup.sh
STARTABLE = yes
Provide a specific src/conf/privilege
, using package name in sc-USER
,
defaults remain package
so that files are own by service user:
{
"defaults":{
"run-as": "package"
},
"username": "sc-USER",
"ctrl-script": [{
"action": "preinst",
"run-as": "root"
}, {
"action": "postinst",
"run-as": "root"
}, {
"action": "preuninst",
"run-as": "root"
}, {
"action": "postuninst",
"run-as": "root"
}, {
"action": "preupgrade",
"run-as": "root"
}, {
"action": "postupgrade",
"run-as": "root"
}, {
"action": "start",
"run-as": "root"
}, {
"action": "stop",
"run-as": "root"
}]
}
In SERVICE_SETUP
, execute application specific startup command:
service_prestart ()
{
COMMAND="${SYNOPKG_PKGDEST}/bin/appservice --background --user ${EFF_USER} --pidfile ${PID_FILE}"
# Run as root in both DSM 5 and 6
${COMMAND} >> ${LOG_FILE} 2>&1
}
- Home
-
Packages
- Adminer
- Aria2
- Beets
- BicBucStriim
- Borgmatic
- cloudflared
- Comskip
- Debian Chroot
- Deluge
- Duplicity
- dnscrypt-proxy
- FFmpeg
- FFsync
- Flexget
- Gstreamer
- Google Authenticator
- Home Assistant Core
- Jellyfin
- Kiwix
- [matrix] Synapse homeserver
- MinIO
- Mono
- Mosh
- Mosquitto
- Node-Exporter
- Radarr/Sonarr/Lidarr/Jackett
- SaltStack
- SickBeard Custom
- SynoCLI-Disk
- SynoCLI-Devel
- SynoCLI-File
- SynoCLI-Kernel
- SynoCLI-Misc.
- SynoCLI-Monitor
- SynoCLI-NET
- Synogear
- Concepts
- Development
- Resources