Start jenkins-slave using systemd on modern systems
diff --git a/jenkins/files/slave/default b/jenkins/files/slave/default
new file mode 100644
index 0000000..e5ab906
--- /dev/null
+++ b/jenkins/files/slave/default
@@ -0,0 +1,56 @@
+{%- from "jenkins/map.jinja" import slave with context %}
+# defaults for jenkins-slave component of the jenkins continuous integration 
+# system
+
+# pulled in from the init script; makes things easier.
+NAME=jenkins-slave
+
+# location of java
+JAVA=/usr/bin/java
+
+# arguments to pass to java - optional
+#JAVA_ARGS="-Xmx256m"
+
+# for daemon to use
+PIDFILE=/var/run/$NAME.pid
+
+# user id to be invoked as (otherwise will run as root; not wise!)
+JENKINS_USER=jenkins
+
+# location of jenkins arch indep files
+JENKINS_ROOT=/usr/share/jenkins
+
+# jenkins home location
+JENKINS_HOME=/var/lib/jenkins
+
+# jenkins /run location
+JENKINS_RUN=/var/run/jenkins
+
+{%- if slave.user is defined %}
+# Authentication to jenkins master
+JENKINS_LOGIN="{{ slave.user.name }}"
+JENKINS_PASSWORD="{{ slave.user.password }}"
+{%- endif %}
+
+# URL of jenkins server to connect to
+JENKINS_URL="{{ slave.master.protocol }}://{{ slave.master.host }}:{{ slave.master.port }}"
+
+# Name of slave configuration to use at JENKINS_URL
+# Override if it need to be something other than the
+# hostname of the server the slave is running on.
+JENKINS_HOSTNAME="{{ slave.hostname }}"
+
+# Log file location for use in Debian init script
+JENKINS_SLAVE_LOG=/var/log/jenkins/$NAME.log
+
+# OS LIMITS SETUP
+#   comment this out to observe /etc/security/limits.conf
+#   this is on by default because http://github.com/feniix/hudson/commit/d13c08ea8f5a3fa730ba174305e6429b74853927
+#   reported that Ubuntu's PAM configuration doesn't include pam_limits.so, and as a result the # of file
+#   descriptors are forced to 1024 regardless of /etc/security/limits.confa
+# NOTE - Ubuntu Users - this is not used by the upstart configuration - please use an upstart overrides file
+# to change the OS limits setup.
+MAXOPENFILES=8192
+
+# Arguments to pass to jenkins slave on startup
+JENKINS_ARGS="-jnlpUrl ${JENKINS_URL}/computer/$JENKINS_HOSTNAME/slave-agent.jnlp -jnlpCredentials ${JENKINS_LOGIN}:${JENKINS_PASSWORD}"
diff --git a/jenkins/files/slave/init.d/jenkins-slave b/jenkins/files/slave/init.d/jenkins-slave
new file mode 100644
index 0000000..688ec2c
--- /dev/null
+++ b/jenkins/files/slave/init.d/jenkins-slave
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+### BEGIN INIT INFO
+# Provides:		jenkins-slave
+# Required-Start:	$remote_fs $syslog
+# Required-Stop:	$remote_fs $syslog
+# Default-Start:	2 3 4 5
+# Default-Stop:
+# Short-Description:	Jenkins slave
+### END INIT INFO
+
+set -e
+
+# /etc/init.d/jenkins-slave: start and stop Jenkins slave
+
+if test -f /etc/default/jenkins-slave; then
+	. /etc/default/jenkins-slave
+else
+	echo "Configuration for jenkins-slave does not exist" 1>&2
+	exit 1
+fi
+
+. /lib/lsb/init-functions
+
+COMMAND="/usr/bin/java"
+COMMAND_ARGS="-jar slave.jar ${JENKINS_ARGS}"
+
+function check_running() {
+	start-stop-daemon -T --pidfile ${PIDFILE}
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		log_end_msg 1 || true
+		exit $ret
+	fi
+}
+
+function start() {
+	# Get slave.jar from master
+	[ -n "${JENKINS_LOGIN}" ] && WGET_ARGS="--user=$JENKINS_LOGIN --password=$JENKINS_PASSWORD"
+	[ -f ${JENKINS_HOME}/slave.jar ] || wget $WGET_ARGS -O ${JENKINS_HOME}/slave.jar -q ${JENKINS_URL}/jnlpJars/slave.jar
+
+	if start-stop-daemon -c ${JENKINS_USER} -d ${JENKINS_HOME} --background --start --quiet --oknodo -m --pidfile ${PIDFILE} --exec ${COMMAND} -- ${COMMAND_ARGS}; then
+		log_end_msg 0 || true
+	else
+		log_end_msg 1 || true
+	fi
+}
+
+function stop() {
+	if start-stop-daemon --stop --quiet --oknodo --pidfile ${PIDFILE}; then
+		log_end_msg 0 || true
+	else
+		log_end_msg 1 || true
+	fi
+}
+
+case "$1" in
+	start)
+		log_daemon_msg "Starting Jenkins slave" "jenkins-slave" || true
+		start
+		;;
+	stop)
+		log_daemon_msg "Stopping Jenkins slave" "jenkins-slave" || true
+		stop
+		;;
+	status)
+		status_of_proc -p ${PIDFILE} ${COMMAND} jenkins-slave && exit 0 || exit $?
+		;;
+	restart)
+		log_daemon_msg "Restarting Jenkins slave" "jenkins-slave" || true
+		stop
+		start
+		;;
+
+	*)
+		log_action_msg "Usage: /etc/init.d/jenkins-slave {start|stop|restart}" || true
+		exit 1
+		;;
+esac
+
+exit 0
diff --git a/jenkins/files/slave/jenkins-slave b/jenkins/files/slave/jenkins-slave
new file mode 100644
index 0000000..b6b7c9d
--- /dev/null
+++ b/jenkins/files/slave/jenkins-slave
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+if test -f /etc/default/jenkins-slave; then
+	. /etc/default/jenkins-slave
+else
+	echo "Configuration for jenkins-slave does not exist" 1>&2
+	exit 1
+fi
+
+# Get slave.jar from master
+[ -n "${JENKINS_LOGIN}" ] && WGET_ARGS="--user=$JENKINS_LOGIN --password=$JENKINS_PASSWORD"
+[ -f ${JENKINS_HOME}/slave.jar ] || wget $WGET_ARGS -O ${JENKINS_HOME}/slave.jar -q ${JENKINS_URL}/jnlpJars/slave.jar
+
+java -jar ${JENKINS_HOME}/slave.jar ${JENKINS_ARGS}
diff --git a/jenkins/files/slave/jenkins-slave.service b/jenkins/files/slave/jenkins-slave.service
new file mode 100644
index 0000000..74f7fc2
--- /dev/null
+++ b/jenkins/files/slave/jenkins-slave.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Jenkins Slave
+After=network.target
+
+[Service]
+User=jenkins
+ExecStart=/usr/local/bin/jenkins-slave
+Restart=always
+RestartSec=5
+
+[Install]
+WantedBy=multi-user.target
diff --git a/jenkins/files/slave/keystonerc b/jenkins/files/slave/keystonerc
new file mode 100644
index 0000000..d9d2e38
--- /dev/null
+++ b/jenkins/files/slave/keystonerc
@@ -0,0 +1,5 @@
+{%- set server = pillar.jenkins.slave.keystone %}
+export OS_USERNAME="{{ server.user }}"
+export OS_PASSWORD="{{ server.password }}"
+export OS_TENANT_NAME="{{ server.tenant }}"
+export OS_AUTH_URL="{{ server.url }}"
diff --git a/jenkins/files/slave/pbuilderrc b/jenkins/files/slave/pbuilderrc
new file mode 100644
index 0000000..4312a75
--- /dev/null
+++ b/jenkins/files/slave/pbuilderrc
@@ -0,0 +1,120 @@
+{%- from "jenkins/map.jinja" import slave with context %}
+{%- if slave.pbuilder is defined %}
+
+{%- if slave.pbuilder.mirrorsite is defined %}
+MIRRORSITE="{{ slave.pbuilder.mirrorsite }}"
+{%- endif %}
+
+{%- if slave.pbuilder.othermirror is defined %}
+OTHERMIRROR="deb{% if slave.pbuilder.othermirror.get('trusted', True) %} [trusted=yes]{% endif %} {{ slave.pbuilder.othermirrror.url }} {{ slave.pbuilder.othermirror.dist }} {{ slave.pbuilder.othermirror.components|join(' ') }}"
+{%- endif %}
+
+{%- if slave.pbuilder.components is defined %}
+COMPONENTS="{{ slave.pbuilder.components|join(' ') }}"
+{%- endif %}
+
+{%- set keyring = slave.pbuilder.get('keyring', '/etc/apt/trusted.gpg') %}
+DEBOOTSTRAPOPTS=(${DEBOOTSTRAPOPTS[@]} "--keyring={{ keyring }}")
+APTKEYRINGS=(${APTKEYRINGS[@]} "{{ keyring }}")
+
+{%- if slave.pbuilder.aptcache is defined %}
+APTCACHE="{{ slave.pbuilder.aptcache }}"
+{%- endif %}
+
+{%- if slave.pbuilder.aptcachehardlink is defined %}
+APTCACHEHARDLINK="{{ 'yes' if slave.pbuilder.aptcachehardlink else 'no' }}"
+{%- endif %}
+
+{%- if slave.pbuilder.buildplace is defined %}
+BUILDPLACE="{{ slave.pbuilder.buildplace }}"
+{%- endif %}
+
+{%- if slave.pbuilder.buildresult is defined %}
+BUILDRESULT="{{ slave.pbuilder.buildresult }}"
+{%- endif %}
+
+{%- if slave.pbuilder.ccachedir is defined %}
+CCACHEDIR="{{ slave.pbuilder.ccachedir }}"
+{%- endif %}
+
+{%- if slave.pbuilder.usenetwork is defined %}
+USENETWORK="{{ 'yes' if slave.pbuilder.usenetwork else 'no' }}"
+{%- endif %}
+
+BINDMOUNTS="/var/cache/pbuilder/build"
+
+{%- if slave.pbuilder.parallel is defined %}
+{%- if slave.pbuilder.parallel %}
+{# Automatically set jobs to no. of cpus #}
+JOBS=$(grep -c processor /proc/cpuinfo)
+{%- else %}
+JOBS={{ slave.pbuilder.parallel }}
+{%- endif %}
+
+DEB_BUILD_OPTIONS="parallel=${JOBS} $DEB_BUILD_OPTIONS"
+{%- endif %}
+
+{%- if slave.pbuilder.get('eatmydata', False) %}
+EXTRAPACKAGES="$EXTRAPACKAGES eatmydata"
+export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+"$LD_LIBRARY_PATH:"}/usr/lib/libeatmydata
+export LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}libeatmydata.so"
+{%- endif %}
+
+{%- for os, distribution in slave.pbuilder.get('os', {}).iteritems() %}
+if [ "$OS" == "{{ os }}" ]; then
+    {%- for dist_name, dist in distribution.iteritems() %}
+    if [ "$DIST" == "{{ dist_name }}" ]; then
+        DISTRIBUTION="$DIST"
+        MIRRORSITE="{{ dist.mirrorsite }}"
+
+        {%- if dist.othermirror is defined %}
+        OTHERMIRROR="deb{% if dist.othermirror.get('trusted', True) %} [trusted=yes]{% endif %} {{ dist.othermirror.url }} {{ dist.othermirror.get('dist', dist_name) }} {{ dist.othermirror.components|join(' ') }}"
+        {%- endif %}
+
+        COMPONENTS="{{ dist.components|join(' ') }}"
+
+        {%- if dist.keyring is defined %}
+        DEBOOTSTRAPOPTS=(${DEBOOTSTRAPOPTS[@]} "--keyring={{ dist.keyring }}")
+        APTKEYRINGS=(${APTKEYRINGS[@]} "{{ dist.keyring }}")
+        {%- endif %}
+        ARCH="${ARCH:-{{ dist.get('arch', '$(dpkg --print-architecture)') }}}"
+
+        {%- if dist.extrapackages is defined %}
+        EXTRAPACKAGES="$EXTRAPACKAGES {{ dist.extrapackages|join(' ') }}"
+        {%- endif %}
+
+        {%- if dist.get('eatmydata', False) %}
+        EXTRAPACKAGES="$EXTRAPACKAGES eatmydata"
+        export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+"$LD_LIBRARY_PATH:"}/usr/lib/libeatmydata
+        export LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}libeatmydata.so"
+        {%- endif %}
+
+        NAME="${OS}-${DIST}-${ARCH}"
+        BASETGZ="/var/cache/pbuilder/${NAME}-base.tgz"
+        BUILDRESULT="/var/cache/pbuilder/${NAME}/result/"
+        APTCACHE="/var/cache/pbuilder/${NAME}/aptcache/"
+        BASEPATH="/var/cache/pbuilder/${NAME}-base.cow"
+    fi
+    {%- endfor %}
+fi
+{%- endfor %}
+
+ARCH="${ARCH:-{{ slave.pbuilder.get('arch', '$(dpkg --print-architecture)') }}}"
+
+if [ "$ARCH" == "armel" ] && [ "$(dpkg --print-architecture)" != "armel" ]; then
+    DEBOOTSTRAP="qemu-debootstrap"
+fi
+if [ "$ARCH" == "armhf" ] && [ "$(dpkg --print-architecture)" != "armhf" ]; then
+    DEBOOTSTRAP="qemu-debootstrap"
+fi
+if [ "$ARCH" == "arm64" ] && [ "$(dpkg --print-architecture)" != "arm64" ]; then
+    DEBOOTSTRAP="qemu-debootstrap"
+fi
+
+DEBOOTSTRAPOPTS=("${DEBOOTSTRAPOPTS[@]}" "--arch=$ARCH")
+
+{%- endif %}
+
+{#-
+vim: syntax=jinja
+-#}
diff --git a/jenkins/files/slave/sudoer b/jenkins/files/slave/sudoer
new file mode 100644
index 0000000..a06260b
--- /dev/null
+++ b/jenkins/files/slave/sudoer
@@ -0,0 +1,5 @@
+# jenkins user with passwordless sudo functionality.
+
+jenkins ALL=(ALL) NOPASSWD:ALL
+
+Defaults:jenkins !requiretty
diff --git a/jenkins/files/slave/sudoer_debian_glue b/jenkins/files/slave/sudoer_debian_glue
new file mode 100644
index 0000000..988682d
--- /dev/null
+++ b/jenkins/files/slave/sudoer_debian_glue
@@ -0,0 +1,4 @@
+# allow jenkins to use cowbuilder, preserve important environment variables
+
+jenkins ALL=NOPASSWD: /usr/sbin/cowbuilder, /usr/sbin/chroot
+Defaults env_keep+="DEB_* DIST ARCH ADT"
diff --git a/jenkins/slave/init.sls b/jenkins/slave/init.sls
index e34d0ec..6e285cd 100644
--- a/jenkins/slave/init.sls
+++ b/jenkins/slave/init.sls
@@ -25,19 +25,34 @@
 {% else %}
 
 # No jenkins-slave package, use magic init script instead
-{{ slave.init_script }}:
+{%- if grains.init == 'systemd' %}
+jenkins_slave_init_script:
   file.managed:
-    - source: salt://jenkins/files/init.d/jenkins-slave
+    - name: /etc/systemd/system/jenkins-slave.service
+    - source: salt://jenkins/files/slave/jenkins-slave.service
+    - user: root
+    - group: root
+    - mode: 644
+    - require:
+      - file: jenkins_slave_start_script
+{%- else %}
+jenkins_slave_init_script:
+  file.managed:
+    - name: {{ slave.init_script }}
+    - source: salt://jenkins/files/slave/init.d/jenkins-slave
     - user: root
     - group: root
     - mode: 755
     - template: jinja
+    - require:
+      - file: jenkins_slave_start_script
+{%- endif %}
 
 {% endif %}
 
 {{ slave.config }}:
   file.managed:
-  - source: salt://jenkins/files/jenkins-slave
+  - source: salt://jenkins/files/slave/default
   - user: root
   - group: root
   - template: jinja
@@ -45,19 +60,29 @@
     {% if slave.pkgs %}
     - pkg: jenkins_slave_package
     {% else %}
-    - file: {{ slave.init_script }}
+    - file: jenkins_slave_init_script
     {% endif %}
 
+jenkins_slave_start_script:
+  file.managed:
+  - name: /usr/local/bin/jenkins-slave
+  - source: salt://jenkins/files/slave/jenkins-slave
+  - user: root
+  - group: root
+  - mode: 755
+  - template: jinja
+
 jenkins_slave_service:
   service.running:
   - name: {{ slave.service }}
   - watch:
     - file: {{ slave.config }}
+  - enable: true
   - require:
     {% if slave.pkgs %}
     - pkg: jenkins_slave_package
     {% else %}
-    - file: {{ slave.init_script }}
+    - file: jenkins_slave_init_script
     {% endif %}
 
 {%- if pillar.linux.system.user.jenkins is not defined %}
@@ -81,7 +106,7 @@
 
 /etc/sudoers.d/99-jenkins-user:
   file.managed:
-  - source: salt://jenkins/files/sudoer
+  - source: salt://jenkins/files/slave/sudoer
   - template: jinja
   - user: root
   - group: root
diff --git a/jenkins/slave/keystone.sls b/jenkins/slave/keystone.sls
index d308f76..26e51e3 100644
--- a/jenkins/slave/keystone.sls
+++ b/jenkins/slave/keystone.sls
@@ -2,7 +2,7 @@
 
 /var/lib/jenkins/keystonerc:
   file.managed:
-  - source: salt://jenkins/files/keystonerc
+  - source: salt://jenkins/files/slave/keystonerc
   - user: jenkins
   - group: jenkins
   - mode: 0400
diff --git a/jenkins/slave/pbuilder.sls b/jenkins/slave/pbuilder.sls
index 851d1f7..7ffedb2 100644
--- a/jenkins/slave/pbuilder.sls
+++ b/jenkins/slave/pbuilder.sls
@@ -23,7 +23,7 @@
 
 /etc/sudoers.d/98-jenkins-debian-glue:
   file.managed:
-  - source: salt://jenkins/files/sudoer_debian_glue
+  - source: salt://jenkins/files/slave/sudoer_debian_glue
   - template: jinja
   - user: root
   - group: root
@@ -33,7 +33,7 @@
 
 /etc/pbuilderrc:
   file.managed:
-    - source: salt://jenkins/files/pbuilderrc
+    - source: salt://jenkins/files/slave/pbuilderrc
     - template: jinja
     - user: root
     - group: root