diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/postinst-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/postinst-template new file mode 100644 index 000000000..2413721ec --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/postinst-template @@ -0,0 +1,10 @@ +${{header}} +${{loader-functions}} +${{control-functions}} + +addGroup ${{daemon_group}} +addUser ${{daemon_user}} ${{daemon_group}} "${{app_name}} user-daemon" "${{daemon_shell}}" + +${{chown-paths}} + +startService ${{app_name}} || echo "${{app_name}} could not be registered or started" diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/postrm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/postrm-template new file mode 100644 index 000000000..3b6ecf338 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/postrm-template @@ -0,0 +1,17 @@ +${{header}} +${{control-functions}} + +# Deleting user: ${{daemon_user}} and group: ${{daemon_group}} +case "$1" in + remove|failed-upgrade|abort-upgrade|abort-install|disappear) + ;; + purge) + deleteUser ${{daemon_user}} + deleteGroup ${{daemon_group}} + ;; + upgrade) + ;; + *) + echo "postinst called with unknown argument \`\$1'" >&2 + ;; +esac diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/preinst-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/preinst-template new file mode 100644 index 000000000..aa20152c1 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/preinst-template @@ -0,0 +1,2 @@ +${{header}} +${{control-functions}} diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/prerm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/prerm-template new file mode 100644 index 000000000..cceb045f6 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/debian/prerm-template @@ -0,0 +1,4 @@ +${{header}} +${{loader-functions}} + +stopService ${{app_name}} || echo "${{app_name}} wasn't even running!" \ No newline at end of file diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/postinst-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/postinst-template new file mode 100644 index 000000000..2cb93e25a --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/postinst-template @@ -0,0 +1,7 @@ +${{loader-functions}} +${{control-functions}} + +addGroup ${{daemon_group}} +addUser ${{daemon_user}} ${{daemon_group}} "${{app_name}} user-daemon" "${{daemon_shell}}" + +startService ${{app_name}} || echo "${{app_name}} could not be registered or started" diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postun-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/postun-template similarity index 71% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postun-rpm-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/postun-template index bea84ae8c..df7626144 100644 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postun-rpm-template +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/postun-template @@ -7,12 +7,12 @@ then echo "Try deleting system user and group [${{daemon_user}}:${{daemon_group}}]" if getent passwd | grep -q "^${{daemon_user}}:"; then - echo "Deleting system user: ${{daemon_user}}" - userdel ${{daemon_user}} + echo "Deleting system user: ${{daemon_user}}" + deleteUser ${{daemon_user}} fi if getent group | grep -q "^${{daemon_group}}:" ; then - echo "Deleting system group: ${{daemon_group}}" - groupdel ${{daemon_group}} + echo "Deleting system group: ${{daemon_group}}" + deleteGroup ${{daemon_group}} fi fi diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/pre-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/preinst-template similarity index 77% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/pre-rpm-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/preinst-template index 12ae3e449..411de8fbe 100644 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/pre-rpm-template +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/preinst-template @@ -4,8 +4,8 @@ then echo "Creating system group: ${{daemon_group}}" groupadd --system ${{daemon_group}} fi -if ! getent passwd | grep -q "^${{daemon_user}}:"; +if ! getent passwd | grep -q "^${{daemon_user}}:"; then echo "Creating system user: ${{daemon_user}}" - useradd --gid ${{daemon_group}} --no-create-home --system -c '${{descr}}' ${{daemon_user}} + useradd --gid ${{daemon_group}} --no-create-home --system -c '${{app_name}} daemon-user' ${{daemon_user}} fi diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/preun-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/preun-template new file mode 100644 index 000000000..ef97b2642 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/preun-template @@ -0,0 +1,3 @@ +# Halting ${{app_name}} +echo "Shutdown ${{app_name}}" +service ${{app_name}} stop || echo "Could not stop ${{app_name}}" diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemd/loader-functions b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemd/loader-functions new file mode 100644 index 000000000..cea366d27 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemd/loader-functions @@ -0,0 +1,18 @@ +# +# Adding service to autostart +# $1 = service name +# +startService() { + app_name=$1 + systemctl enable "$app_name.service" + systemctl start "$app_name.service" +} + +# +# Removing service from autostart +# $1 = service name +# +stopService() { + app_name=$1 + systemctl disable "$app_name.service" +} diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/start-debian-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemd/start-template similarity index 88% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/start-debian-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemd/start-template index 291c5618c..0fc73f9e6 100644 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/start-debian-template +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemd/start-template @@ -10,4 +10,4 @@ Restart=always RestartSec=${{retryTimeout}} [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemv/loader-functions b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemv/loader-functions new file mode 100644 index 000000000..ec948adc5 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemv/loader-functions @@ -0,0 +1,41 @@ +# +# Adding service to autostart +# $1 = service name +# +startService() { + app_name=$1 + if hash update-rc.d 2>/dev/null; then + echo "Adding $app_name to autostart using update-rc.d" + update-rc.d $app_name defaults + service $app_name start + elif hash chkconfig 2>/dev/null; then + echo "Adding $app_name to autostart using chkconfig" + chkconfig --add ${{app_name}} + chkconfig $app_name on + service $app_name start + else + echo "WARNING: Could not put $app_name in autostart: update-rc and chkconfig or found!" + fi +} + +# +# Removing service from autostart +# $1 = service name +# +stopService() { + app_name=$1 + service $app_name stop + if hash update-rc.d 2>/dev/null; then + echo "Removing $app_name from autostart using update-rc.d" + update-rc.d -f $app_name remove + service $app_name stop + elif chkconfig 2>/dev/null; then + echo "Removing $app_name from autostart using chkconfig" + chkconfig $app_name off + chkconfig --del $app_name + service $app_name stop + else + echo "WARNING: Could not put $app_name in autostart: update-rc or chkconfig not found!" + fi + +} diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/start-debian-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemv/start-debian-template similarity index 100% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/start-debian-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemv/start-debian-template diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/start-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemv/start-rpm-template similarity index 85% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/start-rpm-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemv/start-rpm-template index 3082f8b54..6950b75aa 100644 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/start-rpm-template +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/systemv/start-rpm-template @@ -20,7 +20,7 @@ ### ----------------- # This script was created using following sources -# +# # http://stackoverflow.com/questions/8124345/call-to-daemon-in-a-etc-init-d-script-is-blocking-not-running-in-background # https://fedoraproject.org/wiki/Packaging:SysVInitScript#Initscript_template ### ----------------- @@ -50,19 +50,19 @@ start() { [ -x $RUN_CMD ] || exit 5 echo -n $"Starting $prog: " cd ${{chdir}} - + # FIXME figure out how to use daemon correctly nohup runuser $DAEMON_USER ${RUN_CMD} >> /var/log/${{app_name}}/daemon.log 2>&1 & # The way to go, but doesn't work properly # If the app creates the pid file this gets messy # daemon --user $DAEMON_USER --pidfile $PIDFILE $RUN_CMD & - - + + retval=$? # last error code PID=$! # pid of last backgrounded process [ $retval -eq 0 ] && touch ${lockfile} && success || failure - + # Insert pid into pid file for CentOS killproc function [ -d "/var/run/${{app_name}}" ] || install -d -o "$DAEMON_USER" -m750 "/var/run/${{app_name}}" echo @@ -103,32 +103,32 @@ rh_status_q() { case "$1" in start) - rh_status_q && exit 0 - $1 - ;; + rh_status_q && exit 0 + $1 + ;; stop) - rh_status_q || exit 0 - $1 - ;; + rh_status_q || exit 0 + $1 + ;; restart) - $1 - ;; + $1 + ;; reload) - rh_status || exit 7 - $1 - ;; + rh_status || exit 7 + $1 + ;; force-reload) - force_reload - ;; + force_reload + ;; status) - rh_status - ;; + rh_status + ;; condrestart|try-restart) - rh_status || exit 0 - restart - ;; + rh_status || exit 0 + restart + ;; *) - echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" - exit 2 + echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" + exit 2 esac exit $? diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/upstart/loader-functions b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/upstart/loader-functions new file mode 100644 index 000000000..2f00b0aba --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/upstart/loader-functions @@ -0,0 +1,18 @@ +# +# Adding service to autostart +# $1 = service name +# +startService() { + app_name=$1 + initctl reload-configuration + service $app_name start +} + +# +# Removing service from autostart +# $1 = service name +# +stopService() { + app_name=$1 + service $app_name stop +} diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/start-debian-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/upstart/start-template similarity index 81% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/start-debian-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/upstart/start-template index 97a95824f..73d18ba49 100644 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/start-debian-template +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/systemloader/upstart/start-template @@ -10,16 +10,18 @@ author "${{author}}" # When to start the service start on runlevel ${{start_runlevels}} +${{start_facilities}} # When to stop the service stop on runlevel ${{stop_runlevels}} +${{stop_facilities}} # Automatically restart process if crashed. Tries ${{retries}} times every ${{retryTimeout}} seconds respawn respawn limit ${{retries}} ${{retryTimeout}} pre-start script - [ -d /var/run/${{app_name}} ] || install -m 755 -o ${{daemon_user}} -g ${{daemon_user}} -d /var/run/${{app_name}} + [ -d /var/run/${{app_name}} ] || install -m 755 -o ${{daemon_user}} -g ${{daemon_user}} -d /var/run/${{app_name}} end script # set the working directory of the job processes diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/post-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/post-rpm-template deleted file mode 100644 index 42a641f25..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/post-rpm-template +++ /dev/null @@ -1,2 +0,0 @@ -systemctl enable ${{app_name}}.service -systemctl start ${{app_name}}.service || echo "${{app_name}} could not be started. Try manually with service ${{app_name}} start" diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/postinst-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/postinst-template deleted file mode 100644 index 42a641f25..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/postinst-template +++ /dev/null @@ -1,2 +0,0 @@ -systemctl enable ${{app_name}}.service -systemctl start ${{app_name}}.service || echo "${{app_name}} could not be started. Try manually with service ${{app_name}} start" diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/postrm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/postrm-template deleted file mode 100644 index 9b3fd2ee0..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/postrm-template +++ /dev/null @@ -1 +0,0 @@ -systemctl disable ${{app_name}}.service diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/postun-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/postun-rpm-template deleted file mode 100644 index bea84ae8c..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/postun-rpm-template +++ /dev/null @@ -1,18 +0,0 @@ -# Removing system user/group : ${{daemon_user}} and ${{daemon_group}} - -# Scriptlet syntax: http://fedoraproject.org/wiki/Packaging:ScriptletSnippets#Syntax -# $1 == 1 is upgrade and $1 == 0 is uninstall -if [[ $1 == 0 ]] -then - echo "Try deleting system user and group [${{daemon_user}}:${{daemon_group}}]" - if getent passwd | grep -q "^${{daemon_user}}:"; - then - echo "Deleting system user: ${{daemon_user}}" - userdel ${{daemon_user}} - fi - if getent group | grep -q "^${{daemon_group}}:" ; - then - echo "Deleting system group: ${{daemon_group}}" - groupdel ${{daemon_group}} - fi -fi diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/prerm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/prerm-template deleted file mode 100644 index 80f80fa08..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/prerm-template +++ /dev/null @@ -1 +0,0 @@ -systemctl ${{app_name}} stop || echo "${{app_name}} wasn't even running!" \ No newline at end of file diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/preun-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/preun-rpm-template deleted file mode 100644 index 628b4af7f..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/preun-rpm-template +++ /dev/null @@ -1,3 +0,0 @@ -# Halting ${{app_name}} -echo "Shutdown ${{app_name}}" -systemctl stop ${{app_name}} diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/start-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/start-rpm-template deleted file mode 100644 index 291c5618c..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemd/start-rpm-template +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=${{descr}} -Requires=${{start_facilities}} - -[Service] -Type=simple -WorkingDirectory=${{chdir}} -ExecStart=${{chdir}}/bin/${{exec}} -Restart=always -RestartSec=${{retryTimeout}} - -[Install] -WantedBy=multi-user.target \ No newline at end of file diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/post-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/post-rpm-template deleted file mode 100644 index 58c5bce9b..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/post-rpm-template +++ /dev/null @@ -1,18 +0,0 @@ -# -# Adding ${{app_name}} to autostart -# -addservice() { - if hash update-rc.d 2>/dev/null; then - echo "Adding ${{app_name}} to autostart using update-rc.d" - update-rc.d ${{app_name}} defaults - elif chkconfig 2>/dev/null; then - echo "Adding ${{app_name}} to autostart using chkconfig" - chkconfig --add ${{app_name}} - chkconfig ${{app_name}} on - else - echo "WARNING: Could not put ${{app_name}} in autostart" - fi -} - -addservice -service ${{app_name}} start diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postinst-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postinst-template deleted file mode 100644 index fd4da4702..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postinst-template +++ /dev/null @@ -1,2 +0,0 @@ -update-rc.d ${{app_name}} defaults -service ${{app_name}} start || echo "${{app_name}} could not be started. Try manually with service ${{app_name}} start" diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postrm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postrm-template deleted file mode 100644 index 87316bd0d..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postrm-template +++ /dev/null @@ -1 +0,0 @@ -update-rc.d -f ${{app_name}} remove diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/pre-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/pre-rpm-template deleted file mode 100644 index 12ae3e449..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/pre-rpm-template +++ /dev/null @@ -1,11 +0,0 @@ -# Adding system user/group : ${{daemon_user}} and ${{daemon_group}} -if ! getent group | grep -q "^${{daemon_group}}:" ; -then - echo "Creating system group: ${{daemon_group}}" - groupadd --system ${{daemon_group}} -fi -if ! getent passwd | grep -q "^${{daemon_user}}:"; -then - echo "Creating system user: ${{daemon_user}}" - useradd --gid ${{daemon_group}} --no-create-home --system -c '${{descr}}' ${{daemon_user}} -fi diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/prerm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/prerm-template deleted file mode 100644 index 52a993a8e..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/prerm-template +++ /dev/null @@ -1 +0,0 @@ -service ${{app_name}} stop || echo "${{app_name}} wasn't even running!" \ No newline at end of file diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/preun-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/preun-rpm-template deleted file mode 100644 index 503e49060..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/preun-rpm-template +++ /dev/null @@ -1,3 +0,0 @@ -# Halting ${{app_name}} -echo "Shutdown ${{app_name}}" -service ${{app_name}} stop diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/postinst-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/postinst-template deleted file mode 100644 index f242bb5fa..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/postinst-template +++ /dev/null @@ -1,2 +0,0 @@ -initctl reload-configuration -service ${{app_name}} start || echo "${{app_name}} could not be started. Try manually with service ${{app_name}} start" \ No newline at end of file diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/prerm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/prerm-template deleted file mode 100644 index 52a993a8e..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/prerm-template +++ /dev/null @@ -1 +0,0 @@ -service ${{app_name}} stop || echo "${{app_name}} wasn't even running!" \ No newline at end of file diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/start-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/start-rpm-template deleted file mode 100644 index 04bb0c594..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/start-rpm-template +++ /dev/null @@ -1,32 +0,0 @@ -# generated upstart config - -description "${{descr}}" -author "${{author}}" - -# Stanzas -# -# Stanzas control when and how a process is started and stopped -# See a list of stanzas here: http://upstart.ubuntu.com/wiki/Stanzas#respawn - -# When to start the service -start on runlevel ${{start_runlevels}} -start on started ${{start_facilities}} - -# When to stop the service -stop on runlevel ${{stop_runlevels}} -stop on stopping ${{stop_facilities}} - -# Automatically restart process if crashed. Tries ${{retries}} times every ${{retryTimeout}} seconds -respawn -respawn limit ${{retries}} ${{retryTimeout}} - -# set the working directory of the job processes -chdir ${{chdir}} - -# changes to the user and group before running the job's process -setuid ${{daemon_user}} - -# Start the process -script - exec ./bin/${{exec}} -end script diff --git a/src/main/resources/com/typesafe/sbt/packager/debian/header b/src/main/resources/com/typesafe/sbt/packager/debian/header deleted file mode 100644 index 1a2485251..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/debian/header +++ /dev/null @@ -1 +0,0 @@ -#!/bin/sh diff --git a/src/main/resources/com/typesafe/sbt/packager/debian/postinst-chown b/src/main/resources/com/typesafe/sbt/packager/debian/postinst-chown deleted file mode 100644 index 8076ed5e8..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/debian/postinst-chown +++ /dev/null @@ -1 +0,0 @@ -chown ${{user}}:${{group}} ${{path}} diff --git a/src/main/resources/com/typesafe/sbt/packager/debian/postinst-groupadd b/src/main/resources/com/typesafe/sbt/packager/debian/postinst-groupadd deleted file mode 100644 index 20f624a69..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/debian/postinst-groupadd +++ /dev/null @@ -1,6 +0,0 @@ -# Adding ${{group}} as system group -if ! getent group ${{group}} > /dev/null 2>&1 -then - echo "Creating system group: ${{group}}" - addgroup --system ${{group}} -fi diff --git a/src/main/resources/com/typesafe/sbt/packager/debian/postinst-template b/src/main/resources/com/typesafe/sbt/packager/debian/postinst-template new file mode 100644 index 000000000..f5ed87cc5 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/debian/postinst-template @@ -0,0 +1,7 @@ +${{header}} +${{control-functions}} + +addGroup ${{daemon_group}} +addUser ${{daemon_user}} ${{daemon_group}} "${{app_name}} daemon-user" ${{daemon_shell}} + +${{chown-paths}} diff --git a/src/main/resources/com/typesafe/sbt/packager/debian/postinst-useradd b/src/main/resources/com/typesafe/sbt/packager/debian/postinst-useradd deleted file mode 100644 index 20a39efb3..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/debian/postinst-useradd +++ /dev/null @@ -1,5 +0,0 @@ -# Adding ${{user}} -if ! id -u ${{user}} > /dev/null 2>&1; then - echo "Creating user ${{user}} in group ${{group}}" - useradd --system --no-create-home --gid ${{group}} --shell ${{shell}} ${{user}} -fi diff --git a/src/main/resources/com/typesafe/sbt/packager/debian/postrm-purge b/src/main/resources/com/typesafe/sbt/packager/debian/postrm-template similarity index 65% rename from src/main/resources/com/typesafe/sbt/packager/debian/postrm-purge rename to src/main/resources/com/typesafe/sbt/packager/debian/postrm-template index adc349efe..60f47d662 100644 --- a/src/main/resources/com/typesafe/sbt/packager/debian/postrm-purge +++ b/src/main/resources/com/typesafe/sbt/packager/debian/postrm-template @@ -1,10 +1,13 @@ +${{header}} +${{control-functions}} + # Deleting user: ${{user}} and group: ${{group}} case "$1" in remove|failed-upgrade|abort-upgrade|abort-install|disappear) ;; purge) - deluser --quiet --system ${{user}} > /dev/null || true - delgroup --quiet --system ${{group}} > /dev/null || true + deleteUser ${{daemon_user}} + deleteGroup ${{daemon_group}} ;; upgrade) ;; diff --git a/src/main/resources/com/typesafe/sbt/packager/debian/preinst-template b/src/main/resources/com/typesafe/sbt/packager/debian/preinst-template new file mode 100644 index 000000000..8c58988f0 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/debian/preinst-template @@ -0,0 +1 @@ +${{header}} diff --git a/src/main/resources/com/typesafe/sbt/packager/debian/prerm-template b/src/main/resources/com/typesafe/sbt/packager/debian/prerm-template new file mode 100644 index 000000000..8c58988f0 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/debian/prerm-template @@ -0,0 +1 @@ +${{header}} diff --git a/src/main/resources/com/typesafe/sbt/packager/linux/control-functions b/src/main/resources/com/typesafe/sbt/packager/linux/control-functions new file mode 100644 index 000000000..58a1a9a30 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/linux/control-functions @@ -0,0 +1,61 @@ +# ####################################### +# ## SBT Native Packager Bash Library ## +# ####################################### + +# Adding system user +# $1 = user +# $2 = group +# $3 = description +# $4 = shell (defaults to /bin/false) +addUser() { + user="$1" + if [ -z "$user" ]; then + echo "usage: addUser user [group] [description] [shell]" + exit 1 + fi + group=${2:-$user} + descr=${3:-No description} + shell=${4:-/bin/false} + if ! getent passwd | grep -q "^$user:"; + then + echo "Creating system user: $user in $group with $descr and shell $shell" + useradd --gid $group --no-create-home --system --shell $shell -c "$descr" $user + fi +} + +# Adding system group +# $1 = group +addGroup() { + group="$1" + if ! getent group | grep -q "^$group:" ; + then + echo "Creating system group: $group" + groupadd --system $group + fi +} + +# Will return true even if deletion fails +# $1 = user +deleteUser() { + if hash deluser 2>/dev/null; then + deluser --quiet --system $1 > /dev/null || true + elif hash userdel 2>/dev/null; then + userdel $1 + else + echo "WARNING: Could not delete user $1 . No suitable program (deluser, userdel) found" + fi +} + +# Will return true even if deletion fails +# $1 = group +deleteGroup() { + if hash delgroup 2>/dev/null; then + delgroup --quiet --system $1 > /dev/null || true + elif hash groupdel 2>/dev/null; then + groupdel $1 + else + echo "WARNING: Could not delete user $1 . No suitable program (delgroup, groupdel) found" + fi +} + +# ####################################### diff --git a/src/main/resources/com/typesafe/sbt/packager/rpm/postinstall b/src/main/resources/com/typesafe/sbt/packager/rpm/postinstall deleted file mode 100644 index fb5c13fbd..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/rpm/postinstall +++ /dev/null @@ -1 +0,0 @@ -service ${{app_name}} start diff --git a/src/main/resources/com/typesafe/sbt/packager/rpm/postuninstall b/src/main/resources/com/typesafe/sbt/packager/rpm/postuninstall deleted file mode 100644 index 0d3d61f14..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/rpm/postuninstall +++ /dev/null @@ -1,19 +0,0 @@ -# Removing system user/group : ${{daemon_user}} and ${{daemon_group}} - -# Scriptlet syntax: http://fedoraproject.org/wiki/Packaging:ScriptletSnippets#Syntax -# $1 == 1 is upgrade and $1 == 0 is uninstall -if [[ $1 == 0 ]] -then - echo "Try deleting system user and group [${{daemon_user}}:${{daemon_group}}]" - if getent passwd | grep -q "^${{daemon_user}}:"; - then - echo "Deleting system user: ${{daemon_user}}" - userdel ${{daemon_user}} - fi - if getent group | grep -q "^${{daemon_group}}:" ; - then - echo "Deleting system group: ${{daemon_group}}" - groupdel ${{daemon_group}} - fi -fi - diff --git a/src/main/resources/com/typesafe/sbt/packager/rpm/preinstall b/src/main/resources/com/typesafe/sbt/packager/rpm/preinstall deleted file mode 100644 index 12ae3e449..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/rpm/preinstall +++ /dev/null @@ -1,11 +0,0 @@ -# Adding system user/group : ${{daemon_user}} and ${{daemon_group}} -if ! getent group | grep -q "^${{daemon_group}}:" ; -then - echo "Creating system group: ${{daemon_group}}" - groupadd --system ${{daemon_group}} -fi -if ! getent passwd | grep -q "^${{daemon_user}}:"; -then - echo "Creating system user: ${{daemon_user}}" - useradd --gid ${{daemon_group}} --no-create-home --system -c '${{descr}}' ${{daemon_user}} -fi diff --git a/src/main/resources/com/typesafe/sbt/packager/rpm/preuninstall b/src/main/resources/com/typesafe/sbt/packager/rpm/preuninstall deleted file mode 100644 index 503e49060..000000000 --- a/src/main/resources/com/typesafe/sbt/packager/rpm/preuninstall +++ /dev/null @@ -1,3 +0,0 @@ -# Halting ${{app_name}} -echo "Shutdown ${{app_name}}" -service ${{app_name}} stop diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppStartScript.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppStartScript.scala deleted file mode 100644 index 98b0936e3..000000000 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppStartScript.scala +++ /dev/null @@ -1,143 +0,0 @@ -package com.typesafe.sbt.packager.archetypes - -import java.io.File -import java.net.URL - -/** - * Trait for building start scripts. - */ -trait JavaAppStartScriptBuilder { - - import ServerLoader._ - - /** Used for prefix files generated with this builder */ - val name: String - - /** Name of the start script template without '-template' suffix */ - val startScript: String - - /** Scripts to include for upstart. By default only startScript */ - val upstartScripts: Seq[String] - - /** Scripts to include for systemV. By default only startScript */ - val systemvScripts: Seq[String] - - /** Scripts to include for systemd. By default only startScript */ - val systemdScripts: Seq[String] - - /** - * Generating the URL to the startScript template. - * 1. Looking in defaultLocation - * 2. Using default fallback - * - * @param loader - used, when no file in the defaultLocation - * @param defaultLocation - use if exists - */ - def defaultStartScriptTemplate(loader: ServerLoader, defaultLocation: File): URL = - if (defaultLocation.exists) defaultLocation.toURI.toURL - else templateUrl(startScript, loader) getOrElse sys.error("Default startscript not available for loader: " + loader) - - /** - * - * @param templateName - DebianPlugin.Names for maintainer scripts and "start" - * @param loader - which startup system - * @param replacements - default replacements - * @param template - if specified, it will override the default one - */ - def generateTemplate( - templateName: String, - loader: ServerLoader, - replacements: Seq[(String, String)], - template: Option[URL] = None): Option[String] = { - - // use template orElse search for a default - val url = templateUrl(templateName, loader, template) - - // if an url was found, create the script - url map { template => - TemplateWriter generateScript (template, replacements) - } - } - - /** - * @return url to the template if it's defined for the server loader - */ - def templateUrl(templateName: String, loader: ServerLoader, template: Option[URL] = None): Option[URL] = template orElse { - Option(loader match { - case Upstart if upstartScripts contains templateName => - getClass getResource ("upstart/" + templateName + "-template") - case SystemV if systemvScripts contains templateName => - getClass getResource ("systemv/" + templateName + "-template") - case Systemd if systemdScripts contains templateName => - getClass getResource ("systemd/" + templateName + "-template") - case _ => null - }) - } - - /** - * TODO move this to TemplateWriter or case class - * - * @param author - - * @param description - short description - * @param execScript - name of the script in /usr/bin - * @param chdir - execution path of the script - * @param retries - on fail, how often should a restart be tried - * @param retryTimeout - pause between retries - * @return Seq of key,replacement pairs - */ - def makeReplacements( - author: String, - description: String, - execScript: String, - chdir: String, - appName: String, - daemonUser: String, - daemonGroup: String, - daemonShell: String, - retries: Int = 0, - retryTimeout: Int = 60): Seq[(String, String)] = - Seq( - "author" -> author, - "descr" -> description, - "exec" -> execScript, - "chdir" -> chdir, - "retries" -> retries.toString, - "retryTimeout" -> retryTimeout.toString, - "app_name" -> appName, - "daemon_user" -> daemonUser, - "daemon_group" -> daemonGroup, - "daemon_shell" -> daemonShell) -} - -/** - * Constructs an start script for running a java application. - * Can build the neccessary maintainer scripts, too. - */ -object JavaAppStartScript { - - object Rpm extends JavaAppStartScriptBuilder { - import com.typesafe.sbt.packager.rpm.RpmPlugin.Names._ - - val name = "rpm" - val startScript = "start-rpm" - val upstartScripts = Seq(startScript) - val systemvScripts = Seq(startScript, Pre, Post, Preun, Postun) - val systemdScripts = Seq(startScript, Pre, Post, Preun, Postun) - } - - object Debian extends JavaAppStartScriptBuilder { - import com.typesafe.sbt.packager.debian.DebianPlugin.Names._ - - val name = "debian" - val startScript = "start-debian" - val upstartScripts = Seq(startScript, Postinst, Prerm) - val systemvScripts = Seq(startScript, Postinst, Prerm, Postrm) - val systemdScripts = Seq(startScript, Postinst, Prerm, Postrm) - } - -} - -object ServerLoader extends Enumeration { - type ServerLoader = Value - val Upstart, SystemV, Systemd = Value -} diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala index 506d3814a..0642406b6 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala @@ -23,62 +23,12 @@ object JavaServerAppPackaging { import ServerLoader._ import LinuxPlugin.Users - def settings: Seq[Setting[_]] = JavaAppPackaging.settings ++ linuxSettings ++ debianSettings ++ rpmSettings - protected def etcDefaultTemplateSource: java.net.URL = getClass.getResource("etc-default-template") + val ARCHETYPE = "java_server" - private[this] def makeStartScriptReplacements( - requiredStartFacilities: String, - requiredStopFacilities: String, - startRunlevels: String, - stopRunlevels: String, - loader: ServerLoader): Seq[(String, String)] = { - loader match { - case SystemV => - Seq("start_runlevels" -> startRunlevels, - "stop_runlevels" -> stopRunlevels, - "start_facilities" -> requiredStartFacilities, - "stop_facilities" -> requiredStopFacilities) - case Upstart => - Seq("start_runlevels" -> startRunlevels, - "stop_runlevels" -> stopRunlevels, - "start_facilities" -> requiredStartFacilities, - "stop_facilities" -> requiredStopFacilities) - case Systemd => - Seq("start_facilities" -> requiredStartFacilities) - } - } - - private[this] def defaultFacilities(loader: ServerLoader): String = { - loader match { - case SystemV => "$remote_fs $syslog" - case Upstart => "" - case Systemd => "network.target" - } - } - - private[this] def defaultStartRunlevels(loader: ServerLoader): String = { - loader match { - case SystemV => "2 3 4 5" - case Upstart => "[2345]" - case Systemd => "" - } - } - - private[this] def defaultStopRunlevels(loader: ServerLoader): String = { - loader match { - case SystemV => "0 1 6" - case Upstart => "[016]" - case Systemd => "" - } - } + /** These settings will be provided by this archetype*/ + def settings: Seq[Setting[_]] = JavaAppPackaging.settings ++ linuxSettings ++ debianSettings ++ rpmSettings - private[this] def getStartScriptLocation(loader: ServerLoader): String = { - loader match { - case Upstart => "/etc/init/" - case SystemV => "/etc/init.d/" - case Systemd => "/usr/lib/systemd/system/" - } - } + protected def etcDefaultTemplateSource: java.net.URL = getClass.getResource("etc-default-template") /** * general settings which apply to all linux server archetypes @@ -106,13 +56,15 @@ object JavaServerAppPackaging { map makeEtcDefaultScript, linuxPackageMappings <++= (makeEtcDefault, packageName in Linux) map { (conf, name) => conf.map(c => LinuxPackageMapping(Seq(c -> ("/etc/default/" + name)), - LinuxFileMetaData(Users.Root, Users.Root, "644")).withConfig()).toSeq + LinuxFileMetaData(Users.Root, Users.Root, "644")).withConfig()).toSeq }, // === /var/run/app pid folder === linuxPackageMappings <+= (packageName in Linux, daemonUser in Linux, daemonGroup in Linux) map { (name, user, group) => packageTemplateMapping("/var/run/" + name)() withUser user withGroup group withPerms "755" - }) + } + + ) def debianSettings: Seq[Setting[_]] = { import DebianPlugin.Names.{ Preinst, Postinst, Prerm, Postrm } @@ -122,25 +74,29 @@ object JavaServerAppPackaging { stopRunlevels <<= (serverLoading) apply defaultStopRunlevels, requiredStartFacilities <<= (serverLoading) apply defaultFacilities, requiredStopFacilities <<= (serverLoading) apply defaultFacilities, - linuxJavaAppStartScriptBuilder := JavaAppStartScript.Debian, // === Startscript creation === linuxScriptReplacements <++= (requiredStartFacilities, requiredStopFacilities, startRunlevels, stopRunlevels, serverLoading) apply - makeStartScriptReplacements, - linuxStartScriptTemplate <<= (serverLoading, sourceDirectory, linuxJavaAppStartScriptBuilder) map { - (loader, dir, builder) => builder.defaultStartScriptTemplate(loader, dir / "templates" / "start") - }, - defaultLinuxStartScriptLocation <<= (serverLoading) apply getStartScriptLocation, - linuxMakeStartScript <<= (target in Universal, serverLoading, linuxScriptReplacements, linuxStartScriptTemplate, linuxJavaAppStartScriptBuilder) - map { (tmpDir, loader, replacements, template, builder) => - makeMaintainerScript(builder.startScript, Some(template))(tmpDir, loader, replacements, builder) - }, + makeStartScriptReplacements, + linuxScriptReplacements += JavaServerLoaderScript.loaderFunctionsReplacement(serverLoading.value, ARCHETYPE), + + linuxStartScriptTemplate := JavaServerLoaderScript( + script = startScriptName(serverLoading.value, Debian), + loader = serverLoading.value, + archetype = ARCHETYPE, + template = Option(sourceDirectory.value / "templates" / "start") + ), + defaultLinuxStartScriptLocation <<= serverLoading apply getStartScriptLocation, + linuxMakeStartScript in Debian <<= (linuxStartScriptTemplate in Debian, + linuxScriptReplacements in Debian, + target in Universal, + serverLoading in Debian) map makeStartScript, linuxPackageMappings <++= (packageName, linuxMakeStartScript, serverLoading, defaultLinuxStartScriptLocation) map startScriptMapping )) ++ Seq( - // === Maintainer scripts === - debianMakePreinstScript <<= (target in Universal, serverLoading in Debian, linuxScriptReplacements, linuxJavaAppStartScriptBuilder in Debian) map makeMaintainerScript(Preinst), - debianMakePostinstScript <<= (target in Universal, serverLoading in Debian, linuxScriptReplacements, linuxJavaAppStartScriptBuilder in Debian) map makeMaintainerScript(Postinst), - debianMakePrermScript <<= (target in Universal, serverLoading in Debian, linuxScriptReplacements, linuxJavaAppStartScriptBuilder in Debian) map makeMaintainerScript(Prerm), - debianMakePostrmScript <<= (target in Universal, serverLoading in Debian, linuxScriptReplacements, linuxJavaAppStartScriptBuilder in Debian) map makeMaintainerScript(Postrm)) + // === Maintainer scripts === + debianMakePreinstScript <<= (target in Universal, serverLoading in Debian, linuxScriptReplacements) map makeMaintainerScript(Preinst), + debianMakePostinstScript <<= (target in Universal, serverLoading in Debian, linuxScriptReplacements) map makeMaintainerScript(Postinst), + debianMakePrermScript <<= (target in Universal, serverLoading in Debian, linuxScriptReplacements) map makeMaintainerScript(Prerm), + debianMakePostrmScript <<= (target in Universal, serverLoading in Debian, linuxScriptReplacements) map makeMaintainerScript(Postrm)) } def rpmSettings: Seq[Setting[_]] = { @@ -151,39 +107,38 @@ object JavaServerAppPackaging { stopRunlevels in Rpm <<= (serverLoading) apply defaultStopRunlevels, requiredStartFacilities in Rpm <<= (serverLoading) apply defaultFacilities, requiredStopFacilities in Rpm <<= (serverLoading) apply defaultFacilities, - linuxJavaAppStartScriptBuilder := JavaAppStartScript.Rpm, linuxScriptReplacements <++= (requiredStartFacilities, requiredStopFacilities, startRunlevels, stopRunlevels, serverLoading) apply - makeStartScriptReplacements + makeStartScriptReplacements, + linuxScriptReplacements += JavaServerLoaderScript.loaderFunctionsReplacement(serverLoading.value, ARCHETYPE) )) ++ Seq( // === Startscript creation === - linuxStartScriptTemplate in Rpm <<= (serverLoading in Rpm, sourceDirectory, linuxJavaAppStartScriptBuilder in Rpm) map { - (loader, dir, builder) => - builder.defaultStartScriptTemplate(loader, dir / "templates" / "start") - }, - linuxMakeStartScript in Rpm <<= (target in Universal, serverLoading in Rpm, linuxScriptReplacements in Rpm, linuxStartScriptTemplate in Rpm, linuxJavaAppStartScriptBuilder in Rpm) - map { (tmpDir, loader, replacements, template, builder) => - makeMaintainerScript(builder.startScript, Some(template))(tmpDir, loader, replacements, builder) - }, + linuxStartScriptTemplate := JavaServerLoaderScript( + script = startScriptName((serverLoading in Rpm).value, Rpm), + loader = (serverLoading in Rpm).value, + archetype = ARCHETYPE, + template = Option(sourceDirectory.value / "templates" / "start") + ), + linuxMakeStartScript in Rpm <<= (linuxStartScriptTemplate in Rpm, + linuxScriptReplacements in Rpm, + target in Universal, + serverLoading in Rpm) map makeStartScript, + defaultLinuxStartScriptLocation in Rpm <<= (serverLoading in Rpm) apply getStartScriptLocation, linuxPackageMappings in Rpm <++= (packageName in Rpm, linuxMakeStartScript in Rpm, serverLoading in Rpm, defaultLinuxStartScriptLocation in Rpm) map startScriptMapping, // == Maintainer scripts === // TODO this is very basic - align debian and rpm plugin - rpmPre <<= (rpmScriptsDirectory, rpmPre, linuxScriptReplacements, serverLoading in Rpm, linuxJavaAppStartScriptBuilder in Rpm) apply { - (dir, pre, replacements, loader, builder) => - Some(pre.map(_ + "\n").getOrElse("") + rpmScriptletContent(dir, Pre, loader, replacements, builder)) + rpmPre <<= (rpmScriptsDirectory, rpmPre, linuxScriptReplacements in Rpm, serverLoading in Rpm) apply { + (dir, pre, replacements, loader) => rpmScriptletContent(dir, Pre, replacements, pre) }, - rpmPost <<= (rpmScriptsDirectory, rpmPost, linuxScriptReplacements, serverLoading in Rpm, linuxJavaAppStartScriptBuilder in Rpm) apply { - (dir, post, replacements, loader, builder) => - Some(post.map(_ + "\n").getOrElse("") + rpmScriptletContent(dir, Post, loader, replacements, builder)) + rpmPost <<= (rpmScriptsDirectory, rpmPost, linuxScriptReplacements in Rpm, serverLoading in Rpm) apply { + (dir, post, replacements, loader) => rpmScriptletContent(dir, Post, replacements, post) }, - rpmPostun <<= (rpmScriptsDirectory, rpmPostun, linuxScriptReplacements, serverLoading in Rpm, linuxJavaAppStartScriptBuilder in Rpm) apply { - (dir, postun, replacements, loader, builder) => - Some(postun.map(_ + "\n").getOrElse("") + rpmScriptletContent(dir, Postun, loader, replacements, builder)) + rpmPostun <<= (rpmScriptsDirectory, rpmPostun, linuxScriptReplacements in Rpm, serverLoading in Rpm) apply { + (dir, postun, replacements, loader) => rpmScriptletContent(dir, Postun, replacements, postun) }, - rpmPreun <<= (rpmScriptsDirectory, rpmPreun, linuxScriptReplacements, serverLoading in Rpm, linuxJavaAppStartScriptBuilder in Rpm) apply { - (dir, preun, replacements, loader, builder) => - Some(preun.map(_ + "\n").getOrElse("") + rpmScriptletContent(dir, Preun, loader, replacements, builder)) + rpmPreun <<= (rpmScriptsDirectory, rpmPreun, linuxScriptReplacements in Rpm, serverLoading in Rpm) apply { + (dir, preun, replacements, loader) => rpmScriptletContent(dir, Preun, replacements, preun) } ) } @@ -192,6 +147,64 @@ object JavaServerAppPackaging { /* ============ Helper Methods ============== */ /* ========================================== */ + private[this] def startScriptName(loader: ServerLoader, config: Configuration): String = (loader, config.name) match { + // SystemV has two different start scripts + case (SystemV, name) => s"start-$name-template" + case _ => "start-template" + } + + private[this] def makeStartScriptReplacements( + requiredStartFacilities: Option[String], + requiredStopFacilities: Option[String], + startRunlevels: Option[String], + stopRunlevels: Option[String], + loader: ServerLoader): Seq[(String, String)] = { + + // Upstart cannot handle empty values + val (startOn, stopOn) = loader match { + case Upstart => (requiredStartFacilities.map("start on started " + _), requiredStopFacilities.map("stop on stopping " + _)) + case _ => (requiredStartFacilities, requiredStopFacilities) + } + Seq( + "start_runlevels" -> startRunlevels.getOrElse(""), + "stop_runlevels" -> stopRunlevels.getOrElse(""), + "start_facilities" -> startOn.getOrElse(""), + "stop_facilities" -> stopOn.getOrElse("") + ) + } + + private[this] def defaultFacilities(loader: ServerLoader): Option[String] = { + Option(loader match { + case SystemV => "$remote_fs $syslog" + case Upstart => null + case Systemd => "network.target" + }) + } + + private[this] def defaultStartRunlevels(loader: ServerLoader): Option[String] = { + Option(loader match { + case SystemV => "2 3 4 5" + case Upstart => "[2345]" + case Systemd => null + }) + } + + private[this] def defaultStopRunlevels(loader: ServerLoader): Option[String] = { + Option(loader match { + case SystemV => "0 1 6" + case Upstart => "[016]" + case Systemd => null + }) + } + + private[this] def getStartScriptLocation(loader: ServerLoader): String = { + loader match { + case Upstart => "/etc/init/" + case SystemV => "/etc/init.d/" + case Systemd => "/usr/lib/systemd/system/" + } + } + protected def startScriptMapping(name: String, script: Option[File], loader: ServerLoader, scriptDir: String): Seq[LinuxPackageMapping] = { val (path, permissions) = loader match { case Upstart => ("/etc/init/" + name + ".conf", "0644") @@ -203,13 +216,22 @@ object JavaServerAppPackaging { } yield LinuxPackageMapping(Seq(s -> path), LinuxFileMetaData(Users.Root, Users.Root, permissions, "true")) } - protected def makeMaintainerScript(scriptName: String, template: Option[URL] = None)( - tmpDir: File, loader: ServerLoader, replacements: Seq[(String, String)], builder: JavaAppStartScriptBuilder): Option[File] = { - builder.generateTemplate(scriptName, loader, replacements, template) map { scriptBits => - val script = tmpDir / "tmp" / "bin" / (builder.name + scriptName) - IO.write(script, scriptBits) - script + protected def makeStartScript(template: URL, replacements: Seq[(String, String)], tmpDir: File, loader: ServerLoader): Option[File] = { + val scriptBits = TemplateWriter generateScript (template, replacements) + val script = tmpDir / "tmp" / "bin" / s"$loader-init" + IO.write(script, scriptBits) + Some(script) + } + + protected def makeMaintainerScript(scriptName: String, + template: Option[URL] = None, archetype: String = ARCHETYPE, config: Configuration = Debian)( + tmpDir: File, loader: ServerLoader, replacements: Seq[(String, String)]): Option[File] = { + val scriptBits = JavaServerBashScript(scriptName, archetype, config, replacements, template) getOrElse { + sys.error(s"Couldn't load [$scriptName] for config [${config.name}] in archetype [$archetype]") } + val script = tmpDir / "tmp" / "bin" / (config.name + scriptName) + IO.write(script, scriptBits) + Some(script) } protected def makeEtcDefaultScript(name: String, tmpDir: File, source: java.net.URL, replacements: Seq[(String, String)]): Option[File] = { @@ -220,9 +242,15 @@ object JavaServerAppPackaging { } protected def rpmScriptletContent(dir: File, script: String, - loader: ServerLoader, replacements: Seq[(String, String)], builder: JavaAppStartScriptBuilder): String = { + replacements: Seq[(String, String)], definedScript: Option[String], archetype: String = ARCHETYPE, config: Configuration = Rpm): Option[String] = { val file = (dir / script) val template = if (file exists) Some(file.toURI.toURL) else None - builder.generateTemplate(script, loader, replacements, template).getOrElse(sys.error("Could generate content for script: " + script)) + + val content = definedScript.map(_ + "\n").getOrElse("") + + JavaServerBashScript(script, archetype, config, replacements, template) map { + case script => TemplateWriter generateScriptFromString (content + script, replacements) + } } + } diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerBashScript.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerBashScript.scala new file mode 100644 index 000000000..1301c0570 --- /dev/null +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerBashScript.scala @@ -0,0 +1,63 @@ +package com.typesafe.sbt.packager.archetypes + +import sbt._ +import com.typesafe.sbt.packager.archetypes.ServerLoader._ + +object JavaServerBashScript { + + /** + * + * @param templateName - DebianPlugin.Names for maintainer scripts and "start" + * @param loader - which startup system + * @param replacements - default replacements + * @param template - if specified, it will override the default one + */ + def apply( + script: String, + archetype: String, + config: Configuration, + replacements: Seq[(String, String)], + template: Option[URL] = None): Option[String] = { + // use template or else search for a default + val url = template orElse { + Option(getClass getResource s"$archetype/${config.name}/$script-template") + } + // if an url was found, create the script + url map { + TemplateWriter generateScript (_, replacements) + } + } + +} + +object JavaServerLoaderScript { + + val LOADER_FUNCTIONS = "loader-functions" + + def apply(script: String, archetype: String, loader: ServerLoader, template: Option[File]): URL = { + template flatMap { + case file if file.exists => Some(file.toURI.toURL) + case _ => Option(getClass getResource templatePath(script, loader, archetype)) + } getOrElse (sys.error(s"Could not find init [$script] for system [$loader] in archetype [$archetype]")) + } + + /** + * Loads the [[ServerLoader]] specific "functions" resource, + * replaces all placeholders and returns the resolved string. + * + * The functions script resides in "[archetype]/[loader]/functions" + * + * @param loader - Upstart, SystemV, SystemD + * @param replacements - tuple of name->replacement + * @param script - default is "functions" + * @return functions - addService/stopService with resolved variables + */ + def loaderFunctionsReplacement(loader: ServerLoader, archetype: String, + script: String = LOADER_FUNCTIONS): (String, String) = { + val source = getClass.getResource(templatePath(script, loader, archetype)) + LOADER_FUNCTIONS -> TemplateWriter.generateScript(source, Nil) + } + + def templatePath(script: String, loader: ServerLoader, archetype: String): String = + archetype + "/systemloader/" + loader.toString + "/" + script +} diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/ServerLoader.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/ServerLoader.scala new file mode 100644 index 000000000..89158fc2e --- /dev/null +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/ServerLoader.scala @@ -0,0 +1,11 @@ +package com.typesafe.sbt.packager.archetypes + +import java.io.File +import java.net.URL + +object ServerLoader extends Enumeration { + type ServerLoader = Value + val Upstart = Value("upstart") + val SystemV = Value("systemv") + val Systemd = Value("systemd") +} diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/TemplateWriter.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/TemplateWriter.scala index 5c35212e2..76aeeb7eb 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/TemplateWriter.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/TemplateWriter.scala @@ -39,4 +39,13 @@ object TemplateWriter { val lines = sbt.IO.readLinesURL(source, charset) replaceValues(lines, replacements, eol, keySurround) } + + def generateScriptFromString( + source: String, + replacements: Seq[(String, String)], + eol: String = "\n", + keySurround: String => String = bashFriendlyKeySurround, + charset: java.nio.charset.Charset = defaultCharset): String = { + replaceValues(source split eol, replacements, eol, keySurround) + } } \ No newline at end of file diff --git a/src/main/scala/com/typesafe/sbt/packager/debian/metadata.scala b/src/main/scala/com/typesafe/sbt/packager/debian/DebianMetadata.scala similarity index 100% rename from src/main/scala/com/typesafe/sbt/packager/debian/metadata.scala rename to src/main/scala/com/typesafe/sbt/packager/debian/DebianMetadata.scala diff --git a/src/main/scala/com/typesafe/sbt/packager/debian/DebianPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/debian/DebianPlugin.scala index c35998533..3bcbd6b48 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/DebianPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/DebianPlugin.scala @@ -9,6 +9,7 @@ import linux.{ LinuxFileMetaData, LinuxPackageMapping, LinuxSymlink } import linux.Keys.{ linuxScriptReplacements, daemonShell } import com.typesafe.sbt.packager.Hashing import com.typesafe.sbt.packager.archetypes.TemplateWriter +import com.typesafe.sbt.packager.linux.LinuxPackageMapping trait DebianPlugin extends Plugin with linux.LinuxPlugin with NativePackaging with JDebPackaging { val Debian = config("debian") extend Linux @@ -16,7 +17,9 @@ trait DebianPlugin extends Plugin with linux.LinuxPlugin with NativePackaging wi import com.typesafe.sbt.packager.universal.Archives import DebianPlugin.Names + import DebianPlugin.defaultMaintainerScript import linux.LinuxPlugin.Users + import SbtNativePackager.Universal def debianSettings: Seq[Setting[_]] = Seq( /* ==== Debian default settings ==== */ @@ -38,10 +41,10 @@ trait DebianPlugin extends Plugin with linux.LinuxPlugin with NativePackaging wi /* ==== Debian configuration settings ==== */ debianControlScriptsDirectory <<= (sourceDirectory) apply (_ / "debian" / Names.Debian), debianMaintainerScripts := Seq.empty, - debianMakePreinstScript := None, - debianMakePrermScript := None, - debianMakePostinstScript := None, - debianMakePostrmScript := None, + debianMakePreinstScript := defaultMaintainerScript(Names.Preinst, linuxScriptReplacements.value, (target in Universal).value), + debianMakePrermScript := defaultMaintainerScript(Names.Prerm, linuxScriptReplacements.value, (target in Universal).value), + debianMakePostinstScript := defaultMaintainerScript(Names.Postinst, linuxScriptReplacements.value, (target in Universal).value), + debianMakePostrmScript := defaultMaintainerScript(Names.Postrm, linuxScriptReplacements.value, (target in Universal).value), debianChangelog := None, /* ==== Debian maintainer scripts ==== */ @@ -95,7 +98,7 @@ trait DebianPlugin extends Plugin with linux.LinuxPlugin with NativePackaging wi (mappings, dir) => val md5file = dir / Names.Debian / "md5sums" val md5sums = for { - (file, name) <- (dir.*** --- dir x relativeTo(dir)) + (file, name) <- (dir.*** --- dir pair relativeTo(dir)) if file.isFile if !(name startsWith Names.Debian) if !(name contains "debian-binary") @@ -107,8 +110,10 @@ trait DebianPlugin extends Plugin with linux.LinuxPlugin with NativePackaging wi chmod(md5file, "0644") md5file }, - debianExplodedPackage <<= (linuxPackageMappings, debianControlFile, debianMaintainerScripts, debianConffilesFile, debianChangelog, daemonShell in Linux, linuxScriptReplacements, linuxPackageSymlinks, target, streams) - map { (mappings, _, maintScripts, _, changelog, shell, replacements, symlinks, t, streams) => + debianMakeChownReplacements <<= (linuxPackageMappings, streams) map makeChownReplacements, + debianExplodedPackage <<= (linuxPackageMappings, debianControlFile, debianMaintainerScripts, debianConffilesFile, debianChangelog, daemonShell in Linux, + linuxScriptReplacements, debianMakeChownReplacements, linuxPackageSymlinks, target, streams) + map { (mappings, _, maintScripts, _, changelog, shell, replacements, chown, symlinks, t, streams) => // Create files and directories mappings foreach { @@ -135,54 +140,14 @@ trait DebianPlugin extends Plugin with linux.LinuxPlugin with NativePackaging wi for ((file, name) <- maintScripts) { val targetFile = t / Names.Debian / name copyAndFixPerms(file, targetFile, LinuxFileMetaData()) - filterAndFixPerms(targetFile, replacements, LinuxFileMetaData()) - } - - // Check for non root user/group and append to postinst / postrm - // filter all root mappings, map to (user,group) key, group by, append everything - mappings filter { - case LinuxPackageMapping(_, LinuxFileMetaData(Users.Root, Users.Root, _, _, _), _) => false - case _ => true - } map { - case LinuxPackageMapping(paths, LinuxFileMetaData(user, group, _, _, _), _) => (user, group) -> paths - } groupBy (_._1) foreach { - case ((user, group), pathList) => - streams.log info ("Altering postrm/postinst files to add user " + user + " and group " + group) - val postinst = createFileIfRequired(t / Names.Debian / Names.Postinst, LinuxFileMetaData()) - val postrm = createFileIfRequired(t / Names.Debian / Names.Postrm, LinuxFileMetaData()) - val prerm = createFileIfRequired(t / Names.Debian / Names.Prerm, LinuxFileMetaData()) - val headerScript = IO.readLinesURL(Native.headerSource) - - val replacements = Seq("group" -> group, "user" -> user, "shell" -> shell) - - prependAndFixPerms(prerm, headerScript, LinuxFileMetaData()) - - // remove key, flatten it and then go through each file - pathList.map(_._2).flatten foreach { - case (_, target) => - val pathReplacements = replacements :+ ("path" -> target.toString) - val chownAdd = Seq(TemplateWriter.generateScript(Native.postinstChownTemplateSource, pathReplacements)) - prependAndFixPerms(postinst, chownAdd, LinuxFileMetaData()) - } - - validateUserGroupNames(user, streams) - validateUserGroupNames(group, streams) - - val userGroupAdd = Seq( - TemplateWriter.generateScript(Native.postinstGroupaddTemplateSource, replacements), - TemplateWriter.generateScript(Native.postinstUseraddTemplateSource, replacements)) - - prependAndFixPerms(postinst, userGroupAdd, LinuxFileMetaData()) - prependAndFixPerms(postinst, headerScript, LinuxFileMetaData()) - - val purgeAdd = Seq(TemplateWriter.generateScript(Native.postrmPurgeTemplateSource, replacements)) - appendAndFixPerms(postrm, purgeAdd, LinuxFileMetaData()) - prependAndFixPerms(postrm, headerScript, LinuxFileMetaData()) + filterAndFixPerms(targetFile, chown +: replacements, LinuxFileMetaData()) } t }, // Setting the packaging strategy - packageBin <<= debianNativePackaging + packageBin <<= debianNativePackaging, + // Replacement for ${{header}} as debian control scripts are bash scripts + linuxScriptReplacements += ("header" -> "#!/bin/sh\n") // Adding package specific implementation settings ) ++ debianNativeSettings ++ debianJDebSettings) @@ -261,6 +226,42 @@ trait DebianPlugin extends Plugin with linux.LinuxPlugin with NativePackaging wi appName + "_" + version + "_" + arch + ".changes" } + /** + * Debian assumes the application chowns the necessary files and directories in the + * control scripts (Pre/Postinst). + * + * This method generates a replacement which can be inserted in bash script to chown + * all files which are not root. While adding the chown commands it checks if the users + * and groups have valid names. + * + * @param mappings - all mapped files + * @param streams - logging + * @return (CHOWN_REPLACEMENT -> ".. list of chown commands") + */ + private[debian] def makeChownReplacements(mappings: Seq[LinuxPackageMapping], streams: TaskStreams): (String, String) = { + // how to create the chownCmd. TODO maybe configurable? + def chownCmd(user: String, group: String)(path: String): String = s"chown $user:$group $path" + + val header = "# Chown definitions created by SBT Native Packager\n" + // Check for non root user/group and create chown commands + // filter all root mappings, map to (user,group) key, group by, append everything + val chowns = mappings filter { + case LinuxPackageMapping(_, LinuxFileMetaData(Users.Root, Users.Root, _, _, _), _) => false + case _ => true + } map { + case LinuxPackageMapping(paths, meta, _) => (meta.user, meta.group) -> paths + } groupBy (_._1) map { + case ((user, group), pathList) => + validateUserGroupNames(user, streams) + validateUserGroupNames(group, streams) + val chown = chownCmd(user, group) _ + // remove key, flatten it and then use mapping path (_.2) to create chown command + pathList.map(_._2).flatten map (m => chown(m._2)) + } + val replacement = header :: chowns.flatten.toList mkString "\n" + DebianPlugin.CHOWN_REPLACEMENT -> replacement + } + } /** @@ -283,4 +284,16 @@ object DebianPlugin { val Changelog = "changelog" val Files = "files" } + + val CHOWN_REPLACEMENT = "chown-paths" + + def defaultMaintainerScript(name: String, replacements: Seq[(String, String)], tmpDir: File): Option[File] = { + val url = Option(getClass getResource s"$name-template") + url map { source => + val scriptBits = TemplateWriter.generateScript(source, replacements) + val script = tmpDir / "tmp" / "etc" / "default" / name + IO.write(script, scriptBits) + script + } + } } diff --git a/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala b/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala index 8a761d520..2475f1527 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala @@ -40,6 +40,7 @@ trait DebianKeys { val debianMakePrermScript = TaskKey[Option[File]]("makePrermScript", "Creates or discovers the prerm script used by this project") val debianMakePostinstScript = TaskKey[Option[File]]("makePostInstScript", "Creates or discovers the postinst script used by this project") val debianMakePostrmScript = TaskKey[Option[File]]("makePostrmScript", "Creates or discovers the postrm script used by this project") + val debianMakeChownReplacements = TaskKey[(String, String)]("debianMakeChownReplacements", "Creates the chown commands for correct own files and directories") } diff --git a/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala b/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala index cf1ede477..a1023608a 100644 --- a/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala @@ -4,7 +4,6 @@ package linux import sbt._ import com.typesafe.sbt.packager.archetypes.ServerLoader.ServerLoader -import com.typesafe.sbt.packager.archetypes.JavaAppStartScriptBuilder /** Linux packaging generic build targets. */ trait Keys { @@ -16,10 +15,10 @@ trait Keys { val daemonGroup = SettingKey[String]("daemon-group", "Group to start application daemon") val daemonShell = SettingKey[String]("daemon-shell", "Shell provided for the daemon user") val serverLoading = SettingKey[ServerLoader]("server-loader", "Loading system to be used for application start script") - val startRunlevels = SettingKey[String]("start-runlevels", "Sequence of runlevels on which application will start up") - val stopRunlevels = SettingKey[String]("stop-runlevels", "Sequence of runlevels on which application will stop") - val requiredStartFacilities = SettingKey[String]("required-start-facilities", "Names of system services that should be provided at application start") - val requiredStopFacilities = SettingKey[String]("required-stop-facilities", "Names of system services that should be provided at application stop") + val startRunlevels = SettingKey[Option[String]]("start-runlevels", "Sequence of runlevels on which application will start up") + val stopRunlevels = SettingKey[Option[String]]("stop-runlevels", "Sequence of runlevels on which application will stop") + val requiredStartFacilities = SettingKey[Option[String]]("required-start-facilities", "Names of system services that should be provided at application start") + val requiredStopFacilities = SettingKey[Option[String]]("required-stop-facilities", "Names of system services that should be provided at application stop") val linuxPackageMappings = TaskKey[Seq[LinuxPackageMapping]]("linux-package-mappings", "File to install location mappings including owner and privileges.") val linuxPackageSymlinks = TaskKey[Seq[LinuxSymlink]]("linux-package-symlinks", "Symlinks we should produce in the underlying package.") val generateManPages = TaskKey[Unit]("generate-man-pages", "Shows all the man files in the current project") @@ -27,7 +26,6 @@ trait Keys { val linuxMakeStartScript = TaskKey[Option[File]]("makeStartScript", "Creates or discovers the start script used by this project") val linuxStartScriptTemplate = TaskKey[URL]("linuxStartScriptTemplate", "The location of the template start script file we use for debian (upstart or init.d") val linuxEtcDefaultTemplate = TaskKey[URL]("linuxEtcDefaultTemplate", "The location of the /etc/default/ template script.") - val linuxJavaAppStartScriptBuilder = SettingKey[JavaAppStartScriptBuilder]("linuxJavaAppStartScriptBuilder", "Responsible for loading the start scripts. Only used with archetype.java_server") val linuxScriptReplacements = SettingKey[Seq[(String, String)]]("linuxScriptReplacements", """|Replacements of template parameters used in linux scripts. | Default supported templates: diff --git a/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPlugin.scala index bb68f1f69..c741e245a 100644 --- a/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPlugin.scala @@ -11,7 +11,7 @@ import packager.Keys.{ defaultLinuxLogsLocation } import com.typesafe.sbt.packager.linux.LinuxPlugin.Users -import com.typesafe.sbt.packager.archetypes.{ ServerLoader, JavaAppStartScript } +import com.typesafe.sbt.packager.archetypes.{ ServerLoader, TemplateWriter } /** * Plugin trait containing all the generic values used for @@ -44,26 +44,25 @@ trait LinuxPlugin extends Plugin { defaultLinuxLogsLocation := "/var/log", defaultLinuxConfigLocation := "/etc", - linuxJavaAppStartScriptBuilder := JavaAppStartScript.Debian, - // This one is begging for sbt 0.13 syntax... - linuxScriptReplacements <<= ( - maintainer in Linux, packageSummary in Linux, daemonUser in Linux, daemonGroup in Linux, daemonShell in Linux, - packageName in Linux, executableScriptName in Linux, - sbt.Keys.version, defaultLinuxInstallLocation, linuxJavaAppStartScriptBuilder) - apply { (author, descr, daemonUser, daemonGroup, daemonShell, name, execScript, version, installLocation, builder) => - val appDir = installLocation + "/" + name - - // TODO Making replacements should be done somewhere else. Maybe TemplateWriter - builder.makeReplacements( - author = author, - description = descr, - execScript = execScript, - chdir = appDir, - appName = name, - daemonUser = daemonUser, - daemonGroup = daemonGroup, - daemonShell = daemonShell) - } + // Default settings for service configurations + startRunlevels := None, + stopRunlevels := None, + requiredStartFacilities := None, + requiredStopFacilities := None, + + // Default linux bashscript replacements + linuxScriptReplacements := makeReplacements( + author = (maintainer in Linux).value, + description = (packageSummary in Linux).value, + execScript = (executableScriptName in Linux).value, + chdir = s"${defaultLinuxInstallLocation.value}/${(packageName in Linux).value}", + appName = (packageName in Linux).value, + version = sbt.Keys.version.value, + daemonUser = (daemonUser in Linux).value, + daemonGroup = (daemonGroup in Linux).value, + daemonShell = (daemonShell in Linux).value + ), + linuxScriptReplacements += controlScriptFunctionsReplacement( /* Add key for control-functions */ ) ) @@ -93,6 +92,52 @@ trait LinuxPlugin extends Plugin { path <- (src ***).get } yield path -> path.toString.replaceFirst(src.toString, dest) + /** + * + * @param author - + * @param description - short description + * @param execScript - name of the script in /usr/bin + * @param chdir - execution path of the script + * @param retries - on fail, how often should a restart be tried + * @param retryTimeout - pause between retries + * @return Seq of placeholder>replacement pairs + */ + def makeReplacements( + author: String, + description: String, + execScript: String, + chdir: String, + appName: String, + version: String, + daemonUser: String, + daemonGroup: String, + daemonShell: String, + retries: Int = 0, + retryTimeout: Int = 60): Seq[(String, String)] = + Seq( + "author" -> author, + "descr" -> description, + "exec" -> execScript, + "chdir" -> chdir, + "retries" -> retries.toString, + "retryTimeout" -> retryTimeout.toString, + "app_name" -> appName, + "version" -> version, + "daemon_user" -> daemonUser, + "daemon_group" -> daemonGroup, + "daemon_shell" -> daemonShell) + + /** + * Load the default controlscript functions which contain + * addUser/removeUser/addGroup/removeGroup + * + * @return placeholder->content + */ + def controlScriptFunctionsReplacement(template: Option[URL] = None): (String, String) = { + val url = template getOrElse LinuxPlugin.controlFunctions + LinuxPlugin.CONTROL_FUNCTIONS -> TemplateWriter.generateScript(source = url, replacements = Nil) + } + // TODO - we'd like a set of conventions to take universal mappings and create linux package mappings. /** Create a ascii friendly string for a man page. */ @@ -104,4 +149,7 @@ object LinuxPlugin { object Users { val Root = "root" } + val CONTROL_FUNCTIONS = "control-functions" + + def controlFunctions(): URL = getClass getResource CONTROL_FUNCTIONS } \ No newline at end of file diff --git a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmHelper.scala b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmHelper.scala index 11cecba5d..afbaeed48 100644 --- a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmHelper.scala +++ b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmHelper.scala @@ -85,7 +85,7 @@ object RpmHelper { ) ++ Seq(spec.meta.name + ".spec") log.debug("Executing rpmbuild with: " + args.mkString(" ")) (Process(args, Some(specsDir)) ! log) match { - case 0 => () + case 0 => () case code => sys.error("Unable to run rpmbuild, check output for details. Errorcode " + code) } } diff --git a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala index 79736a2cf..38ef8a6cb 100644 --- a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala @@ -88,9 +88,9 @@ object RpmPlugin { val Scriptlets = "scriptlets" //maintainer script names - val Post = "post-rpm" - val Pre = "pre-rpm" - val Postun = "postun-rpm" - val Preun = "preun-rpm" + val Post = "postinst" + val Pre = "preinst" + val Postun = "postun" + val Preun = "preun" } } diff --git a/src/sbt-test/debian/daemon-user-deb/build.sbt b/src/sbt-test/debian/daemon-user-deb/build.sbt index 5d87f6663..9a33baac5 100644 --- a/src/sbt-test/debian/daemon-user-deb/build.sbt +++ b/src/sbt-test/debian/daemon-user-deb/build.sbt @@ -26,14 +26,14 @@ TaskKey[Unit]("check-control-files") <<= (target, streams) map { (target, out) = val debian = target / "debian-test-0.1.0" / "DEBIAN" val postinst = IO.read(debian / "postinst") val postrm = IO.read(debian / "postrm") - assert(postinst contains "addgroup --system daemongroup", "postinst misses addgroup for daemongroup: " + postinst) - assert(postinst contains "useradd --system --no-create-home --gid daemongroup --shell /bin/false daemonuser", "postinst misses useradd for daemonuser: " + postinst) + assert(postinst contains "addGroup daemongroup", "postinst misses addgroup for daemongroup: " + postinst) + assert(postinst contains """addUser daemonuser daemongroup "debian-test user-daemon" "/bin/false"""", "postinst misses useradd for daemonuser: " + postinst) assert(postinst contains "chown daemonuser:daemongroup /var/log/debian-test", "postinst misses chown daemonuser /var/log/debian-test: " + postinst) assert(postinst contains "chown daemonuser:daemongroup /var/run/debian-test", "postinst misses chown daemonuser /var/run/debian-test: " + postinst) assert(!(postinst contains "addgroup --system daemonuser"), "postinst has addgroup for daemonuser: " + postinst) assert(!(postinst contains "useradd --system --no-create-home --gid daemonuser --shell /bin/false daemonuser"), "postinst has useradd for daemongroup: " + postinst) - assert(postrm contains "deluser --quiet --system daemonuser > /dev/null || true", "postrm misses purging daemonuser user: " + postrm) - assert(postrm contains "delgroup --quiet --system daemongroup > /dev/null || true", "postrm misses purging daemongroup group: " + postrm) + assert(postrm contains "deleteUser daemonuser", "postrm misses purging daemonuser user: " + postrm) + assert(postrm contains "deleteGroup daemongroup", "postrm misses purging daemongroup group: " + postrm) assert(!(postinst contains "chown debian-test:daemongroup"), "postinst contains wrong user: \n" + postinst) assert(!(postinst contains "chown daemonuser:debian-test"), "postinst contains wrong group: \n" + postinst) assert(!(postinst contains "chown debian-test:debian-test"), "postinst contains wrong user and group: \n" + postinst) diff --git a/src/sbt-test/debian/daemon-user-shell-deb/build.sbt b/src/sbt-test/debian/daemon-user-shell-deb/build.sbt index a4b8024cc..90afa2886 100644 --- a/src/sbt-test/debian/daemon-user-shell-deb/build.sbt +++ b/src/sbt-test/debian/daemon-user-shell-deb/build.sbt @@ -28,7 +28,7 @@ TaskKey[Unit]("check-control-files") <<= (target, streams) map { (target, out) = val debian = target / "debian-test-0.1.0" / "DEBIAN" val postinst = IO.read(debian / "postinst") val postrm = IO.read(debian / "postrm") - assert(postinst contains "useradd --system --no-create-home --gid daemongroup --shell /bin/bash daemonuser", "postinst misses useradd for daemonuser: " + postinst) + assert(postinst contains """addUser daemonuser daemongroup "debian-test user-daemon" "/bin/bash"""", "postinst misses useradd for daemonuser: " + postinst) () } diff --git a/src/sbt-test/debian/systemd-deb/build.sbt b/src/sbt-test/debian/systemd-deb/build.sbt index ccb5ee21a..16ce883b8 100644 --- a/src/sbt-test/debian/systemd-deb/build.sbt +++ b/src/sbt-test/debian/systemd-deb/build.sbt @@ -16,7 +16,7 @@ packageSummary := "Test debian package" packageDescription := """A fun package description of our software, with multiple lines.""" -requiredStartFacilities in Debian := "network.target" +requiredStartFacilities in Debian := Some("network.target") TaskKey[Unit]("check-startup-script") <<= (target, streams) map { (target, out) => val script = IO.read(target / "debian-test-0.1.0" / "usr" / "lib" / "systemd" / "system" / "debian-test.service") diff --git a/src/sbt-test/debian/sysvinit-deb/build.sbt b/src/sbt-test/debian/sysvinit-deb/build.sbt index 869ad6a29..09f83fa64 100644 --- a/src/sbt-test/debian/sysvinit-deb/build.sbt +++ b/src/sbt-test/debian/sysvinit-deb/build.sbt @@ -20,9 +20,9 @@ packageSummary := "Test debian package" packageDescription := """A fun package description of our software, with multiple lines.""" -requiredStartFacilities := "$test-service" +requiredStartFacilities := Some("$test-service") -requiredStartFacilities in Debian := "$test-deb-service" +requiredStartFacilities in Debian := Some("$test-deb-service") TaskKey[Unit]("check-control-files") <<= (target, streams) map { (target, out) => val header = "#!/bin/sh" diff --git a/src/sbt-test/debian/upstart-deb-facilities/build.sbt b/src/sbt-test/debian/upstart-deb-facilities/build.sbt new file mode 100644 index 000000000..246baf489 --- /dev/null +++ b/src/sbt-test/debian/upstart-deb-facilities/build.sbt @@ -0,0 +1,37 @@ +import NativePackagerKeys._ +import com.typesafe.sbt.packager.archetypes.ServerLoader + +packageArchetype.java_server + +serverLoading in Debian := ServerLoader.Upstart + +daemonUser in Debian := "root" + +mainClass in Compile := Some("empty") + +name := "debian-test" + +name in Debian := "debian-test" + +version := "0.1.0" + +maintainer := "Josh Suereth " + +packageSummary := "Test debian package" + +requiredStartFacilities in Debian := Some("[networking]") + +requiredStopFacilities in Debian := Some("[networking]") + +packageDescription := """A fun package description of our software, + with multiple lines.""" + +TaskKey[Unit]("check-startup-script") <<= (target, streams) map { (target, out) => + val script = IO.read(target / "debian-test-0.1.0" / "etc" / "init" / "debian-test.conf") + assert(script.contains("start on runlevel [2345]"), "script doesn't contain start on runlevel header\n" + script) + assert(script.contains("stop on runlevel [016]"), "script doesn't contain stop on runlevel header\n" + script) + assert(script.contains("start on started [networking]"), "script contains start on started header\n" + script) + assert(script.contains("stop on stopping [networking]"), "script contains stop on stopping header\n" + script) + out.log.success("Successfully tested systemV start up script") + () +} \ No newline at end of file diff --git a/src/sbt-test/debian/upstart-deb-facilities/project/plugins.sbt b/src/sbt-test/debian/upstart-deb-facilities/project/plugins.sbt new file mode 100644 index 000000000..b53de154c --- /dev/null +++ b/src/sbt-test/debian/upstart-deb-facilities/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % sys.props("project.version")) diff --git a/src/sbt-test/debian/upstart-deb-facilities/test b/src/sbt-test/debian/upstart-deb-facilities/test new file mode 100644 index 000000000..5eb51cfae --- /dev/null +++ b/src/sbt-test/debian/upstart-deb-facilities/test @@ -0,0 +1,6 @@ +# Run the debian packaging. +> debian:package-bin +$ exists target/debian-test_0.1.0_all.deb +$ exists target/debian-test-0.1.0/etc/init/debian-test.conf + +> check-startup-script diff --git a/src/sbt-test/debian/upstart-deb/build.sbt b/src/sbt-test/debian/upstart-deb/build.sbt index 70dbbaa38..e2b6fe53c 100644 --- a/src/sbt-test/debian/upstart-deb/build.sbt +++ b/src/sbt-test/debian/upstart-deb/build.sbt @@ -27,8 +27,8 @@ TaskKey[Unit]("check-control-files") <<= (target, streams) map { (target, out) = val postinst = IO.read(debian / "postinst") val prerm = IO.read(debian / "prerm") assert(postinst contains "initctl reload-configuration", "postinst misses initctl: " + postinst) - assert(postinst contains """service debian-test start || echo "debian-test could not be started. Try manually with service debian-test start"""", "postinst misses service start: " + postinst) - assert(prerm contains """service debian-test stop || echo "debian-test wasn't even running!"""", "prerm misses stop: " + prerm) + assert(postinst contains """startService debian-test""", "postinst misses service start: " + postinst) + assert(prerm contains """stopService debian-test""", "prerm misses stop: " + prerm) out.log.success("Successfully tested upstart control files") () } @@ -48,6 +48,7 @@ TaskKey[Unit]("check-startup-script") <<= (target, streams) map { (target, out) val script = IO.read(target / "debian-test-0.1.0" / "etc" / "init" / "debian-test.conf") assert(script.contains("start on runlevel [2345]"), "script doesn't contain start on runlevel header\n" + script) assert(script.contains("stop on runlevel [016]"), "script doesn't contain stop on runlevel header\n" + script) - out.log.success("Successfully tested systemV start up script") + assert(!script.contains("start on started"), "script contains start on started header\n" + script) + assert(!script.contains("stop on stopping"), "script contains stop on stopping header\n" + script) () } diff --git a/src/sbt-test/rpm/scriptlets-override-rpm/build.sbt b/src/sbt-test/rpm/scriptlets-override-rpm/build.sbt index ebcab63e8..e7e4231d3 100644 --- a/src/sbt-test/rpm/scriptlets-override-rpm/build.sbt +++ b/src/sbt-test/rpm/scriptlets-override-rpm/build.sbt @@ -1,5 +1,6 @@ import NativePackagerKeys._ +// only works with java_server archetype packageArchetype.java_server name := "rpm-test" diff --git a/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/post-rpm b/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/postinst similarity index 100% rename from src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/post-rpm rename to src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/postinst diff --git a/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/postun-rpm b/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/postun similarity index 100% rename from src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/postun-rpm rename to src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/postun diff --git a/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/pre-rpm b/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/preinst similarity index 100% rename from src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/pre-rpm rename to src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/preinst diff --git a/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/preun-rpm b/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/preun similarity index 100% rename from src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/preun-rpm rename to src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/preun diff --git a/src/sbt-test/rpm/systemd-rpm/build.sbt b/src/sbt-test/rpm/systemd-rpm/build.sbt index 761d70692..e0e7d9b19 100644 --- a/src/sbt-test/rpm/systemd-rpm/build.sbt +++ b/src/sbt-test/rpm/systemd-rpm/build.sbt @@ -24,7 +24,7 @@ rpmUrl := Some("http://github.com/sbt/sbt-native-packager") rpmLicense := Some("BSD") -requiredStartFacilities in Rpm := "serviceA.service" +requiredStartFacilities in Rpm := Some("serviceA.service") TaskKey[Unit]("unzip") <<= (packageBin in Rpm, streams) map { (rpmFile, streams) => val rpmPath = Seq(rpmFile.getAbsolutePath) diff --git a/src/sbt-test/rpm/sysvinit-rpm/build.sbt b/src/sbt-test/rpm/sysvinit-rpm/build.sbt index ceae488ca..f9e3909a2 100644 --- a/src/sbt-test/rpm/sysvinit-rpm/build.sbt +++ b/src/sbt-test/rpm/sysvinit-rpm/build.sbt @@ -26,19 +26,19 @@ TaskKey[Unit]("unzipAndCheck") <<= (packageBin in Rpm, streams) map { (rpmFile, val rpmPath = Seq(rpmFile.getAbsolutePath) Process("rpm2cpio" , rpmPath) #| Process("cpio -i --make-directories") ! streams.log val scriptlets = Process("rpm -qp --scripts " + rpmFile.getAbsolutePath) !! streams.log - assert(scriptlets contains "groupadd --system rpm-test", "groupadd not present in \n" + scriptlets) - assert(scriptlets contains "useradd --gid rpm-test --no-create-home --system -c 'Test rpm package' rpm-test", "Incorrect useradd command in \n" + scriptlets) - assert(scriptlets contains "groupdel rpm-test", "groupdel not present in \n" + scriptlets) - assert(scriptlets contains "userdel rpm-test", "userdel rpm not present in \n" + scriptlets) + assert(scriptlets contains "addGroup rpm-test", "addGroup not present in \n" + scriptlets) + assert(scriptlets contains "addUser rpm-test", "Incorrect useradd command in \n" + scriptlets) + assert(scriptlets contains "deleteGroup rpm-test", "deleteGroup not present in \n" + scriptlets) + assert(scriptlets contains "deleteUser rpm-test", "deleteUser rpm not present in \n" + scriptlets) // TODO check symlinks () } TaskKey[Unit]("check-spec-file") <<= (target, streams) map { (target, out) => val spec = IO.read(target / "rpm" / "SPECS" / "rpm-test.spec") - assert(spec contains "groupadd --system rpm-test", "groupadd not present in \n" + spec) - assert(spec contains "useradd --gid rpm-test --no-create-home --system -c 'Test rpm package' rpm-test", "Incorrect useradd command in \n" + spec) - assert(spec contains "groupdel rpm-test", "groupdel not present in \n" + spec) - assert(spec contains "userdel rpm-test", "userdel rpm not present in \n" + spec) + assert(spec contains "addGroup rpm-test", "addGroup not present in \n" + spec) + assert(spec contains "addUser rpm-test", "Incorrect useradd command in \n" + spec) + assert(spec contains "deleteGroup rpm-test", "deleteGroup not present in \n" + spec) + assert(spec contains "deleteUser rpm-test", "deleteUser rpm not present in \n" + spec) () } diff --git a/src/sbt-test/rpm/test-executableScriptName/build.sbt b/src/sbt-test/rpm/test-executableScriptName/build.sbt index 47c06b788..8acf73577 100644 --- a/src/sbt-test/rpm/test-executableScriptName/build.sbt +++ b/src/sbt-test/rpm/test-executableScriptName/build.sbt @@ -25,7 +25,6 @@ rpmLicense := Some("BSD") TaskKey[Unit]("check-spec-file") <<= (target, streams) map { (target, out) => val spec = IO.read(target / "rpm" / "SPECS" / "rpm-test.spec") - out.log.success(spec) assert(spec contains "%attr(0644,root,root) /usr/share/rpm-test/lib/rpm-test.rpm-test-0.1.0.jar", "Wrong installation path\n" + spec) assert(spec contains "%config %attr(0755,root,root) /etc/init.d/rpm-test", "Wrong /etc/init.d/\n" + spec) assert(spec contains "%config %attr(644,root,root) /etc/default/rpm-test", "Wrong etc default file\n" + spec) diff --git a/test-project/src/templates/etc-default b/test-project/src/templates/etc-default new file mode 100644 index 000000000..b3eabc9f8 --- /dev/null +++ b/test-project/src/templates/etc-default @@ -0,0 +1,2 @@ +-Dpidfile.path=/var/run/${{app_name}}/play.pid +-mem 128