- Try hard to make all files work on all platforms you support.
- Maintaining separate scripts, config, service files, etc for each platform quickly becomes difficult
- Put as much conditional logic in the pre/post install scripts as possible instead of trying to build it into the nfpm.yaml
- if you need to know the packaging system I have found it useful to add a
/etc/path-to-cfg/package.env
that contains_INSTALLED_FROM=apk|deb|rpm
which can be sourced into the pre/post install/remove scripts - if/when you need to ask questions during the installation process, create an
install.sh
||setup.sh
script that asks those questions and stores the answers as env vars in/etc/path-to-cfg/package.env
for use by the pre/post install/remove scripts- If you only need to support deb packages you can use the debconf template/config feature, but since rpm does not support this I would try to unify the way you ask questions.
#!/bin/sh
# Step 1, decide if we should use systemd or init/upstart
use_systemctl="True"
systemd_version=0
if ! command -V systemctl >/dev/null 2>&1; then
use_systemctl="False"
else
systemd_version=$(systemctl --version | head -1 | sed 's/systemd //g')
fi
cleanup() {
# This is where you remove files that were not needed on this platform / system
if [ "${use_systemctl}" = "False" ]; then
rm -f /path/to/<SERVICE NAME>.service
else
rm -f /etc/chkconfig/<SERVICE NAME>
rm -f /etc/init.d/<SERVICE NAME>
fi
}
cleanInstall() {
printf "\033[32m Post Install of an clean install\033[0m\n"
# Step 3 (clean install), enable the service in the proper way for this platform
if [ "${use_systemctl}" = "False" ]; then
if command -V chkconfig >/dev/null 2>&1; then
chkconfig --add <SERVICE NAME>
fi
service <SERVICE NAME> restart ||:
else
# rhel/centos7 cannot use ExecStartPre=+ to specify the pre start should be run as root
# even if you want your service to run as non root.
if [ "${systemd_version}" -lt 231 ]; then
printf "\033[31m systemd version %s is less then 231, fixing the service file \033[0m\n" "${systemd_version}"
sed -i "s/=+/=/g" /path/to/<SERVICE NAME>.service
fi
printf "\033[32m Reload the service unit from disk\033[0m\n"
systemctl daemon-reload ||:
printf "\033[32m Unmask the service\033[0m\n"
systemctl unmask <SERVICE NAME> ||:
printf "\033[32m Set the preset flag for the service unit\033[0m\n"
systemctl preset <SERVICE NAME> ||:
printf "\033[32m Set the enabled flag for the service unit\033[0m\n"
systemctl enable <SERVICE NAME> ||:
systemctl restart <SERVICE NAME> ||:
fi
}
upgrade() {
printf "\033[32m Post Install of an upgrade\033[0m\n"
# Step 3(upgrade), do what you need
...
}
# Step 2, check if this is a clean install or an upgrade
action="$1"
if [ "$1" = "configure" ] && [ -z "$2" ]; then
# Alpine linux does not pass args, and deb passes $1=configure
action="install"
elif [ "$1" = "configure" ] && [ -n "$2" ]; then
# deb passes $1=configure $2=<current version>
action="upgrade"
fi
case "$action" in
"1" | "install")
cleanInstall
;;
"2" | "upgrade")
printf "\033[32m Post Install of an upgrade\033[0m\n"
upgrade
;;
*)
# $1 == version being installed
printf "\033[32m Alpine\033[0m"
cleanInstall
;;
esac
# Step 4, clean up unused files, yes you get a warning when you remove the package, but that is ok.
cleanup
#!/bin/sh
remove() {
printf "\033[32m Post Remove of a normal remove\033[0m\n"
echo "Remove" > /tmp/postremove-proof
}
purge() {
printf "\033[32m Post Remove purge, deb only\033[0m\n"
echo "Purge" > /tmp/postremove-proof
}
upgrade() {
printf "\033[32m Post Remove of an upgrade\033[0m\n"
echo "Upgrade" > /tmp/postremove-proof
}
echo "$@"
action="$1"
case "$action" in
"0" | "remove")
remove
;;
"1" | "upgrade")
upgrade
;;
"purge")
purge
;;
*)
printf "\033[32m Alpine\033[0m"
remove
;;
esac
- On upgrade, the scripts are being executed in the following order:
pretrans
of new package (only applies to RPM)preinstall
of new packagepostinstall
of new packagepreremove
of old packagepostremove
of old packageposttrans
of new package (only applies to RPM)
- try to just say no to supporting this, but if you must make sure you have a single script that works on all platforms you need to support.
- as the
post-install
script above does.
- as the
- The docs you find for systemd are generally for the latest and greatest version, and it can be hard to find docs for older versions.
- In the above
post-install
script you see I am doing a systemd version check to correct theExecStartPre=+...
andExecStop=+...
lines
- In the above
- You should always use Table 2. Automatic directory creation and environment variables
- With the note that only
RuntimeDirectory
is used in systemd < 231
- With the note that only
/bin/bash -c "$(which ...) ...
is a great way to make your single service file work on all platforms since rhel and debian based systems have standard executables in differing locations and complain aboutexecutable path is not absolute
- eg
/bin/bash -c '$(which mkdir) -p /var/log/your-service'
- eg
Its recommended to run lintian against your deb packages to see if there are any problems.
You can also add a lintian-overrides
file:
contents:
- src: .lintian-overrides
dst: ./usr/share/lintian/overrides/nfpm
packager: deb
file_info:
mode: 0644
You can read more in lintian's documentation.