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 index 2413721ec..8b453525b 100644 --- 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 @@ -2,8 +2,8 @@ ${{header}} ${{loader-functions}} ${{control-functions}} -addGroup ${{daemon_group}} -addUser ${{daemon_user}} ${{daemon_group}} "${{app_name}} user-daemon" "${{daemon_shell}}" +addGroup ${{daemon_group}} "${{daemon_group_gid}}" +addUser ${{daemon_user}} "${{daemon_user_uid}}" ${{daemon_group}} "${{app_name}} user-daemon" "${{daemon_shell}}" ${{chown-paths}} diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/preinst-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/preinst-template index 87d9e99c6..868ba1127 100644 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/preinst-template +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/java_server/rpm/preinst-template @@ -2,5 +2,5 @@ ${{control-functions}} # Adding system user/group : ${{daemon_user}} and ${{daemon_group}} -addGroup ${{daemon_group}} -addUser ${{daemon_user}} ${{daemon_group}} "${{app_name}} user-daemon" "${{daemon_shell}}" \ No newline at end of file +addGroup ${{daemon_group}} "${{daemon_group_gid}}" +addUser ${{daemon_user}} "${{daemon_user_uid}}" ${{daemon_group}} "${{app_name}} user-daemon" "${{daemon_shell}}" diff --git a/src/main/resources/com/typesafe/sbt/packager/debian/postinst-template b/src/main/resources/com/typesafe/sbt/packager/debian/postinst-template index f5ed87cc5..8c291c004 100644 --- a/src/main/resources/com/typesafe/sbt/packager/debian/postinst-template +++ b/src/main/resources/com/typesafe/sbt/packager/debian/postinst-template @@ -1,7 +1,7 @@ ${{header}} ${{control-functions}} -addGroup ${{daemon_group}} -addUser ${{daemon_user}} ${{daemon_group}} "${{app_name}} daemon-user" ${{daemon_shell}} +addGroup ${{daemon_group}} "${{daemon_group_gid}}" +addUser ${{daemon_user}} "${{debian_user_uid}}" ${{daemon_group}} "${{app_name}} daemon-user" ${{daemon_shell}} ${{chown-paths}} diff --git a/src/main/resources/com/typesafe/sbt/packager/linux/control-functions b/src/main/resources/com/typesafe/sbt/packager/linux/control-functions index 58a1a9a30..9b958bd1c 100644 --- a/src/main/resources/com/typesafe/sbt/packager/linux/control-functions +++ b/src/main/resources/com/typesafe/sbt/packager/linux/control-functions @@ -4,33 +4,47 @@ # Adding system user # $1 = user -# $2 = group -# $3 = description -# $4 = shell (defaults to /bin/false) +# $2 = uid +# $3 = group +# $4 = description +# $5 = 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} + uid="$2" + if [ -z "$uid" ]; then + uid_flags="" + else + uid_flags="--uid $uid" + fi + group=${3:-$user} + descr=${4:-No description} + shell=${5:-/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 + useradd $uid_flags --gid $group --no-create-home --system --shell $shell -c "$descr" $user fi } # Adding system group # $1 = group +# $2 = gid addGroup() { group="$1" + gid="$2" + if [ -z "$gid" ]; then + gid_flags="" + else + gid_flags="--gid $gid" + fi if ! getent group | grep -q "^$group:" ; then echo "Creating system group: $group" - groupadd --system $group + groupadd $gid_flags --system $group fi } 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 cb16dfd35..bd8931e43 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala @@ -98,7 +98,9 @@ object JavaServerAppPackaging extends AutoPlugin { )) ++ Seq( // === Daemon User and Group === daemonUser in Debian <<= daemonUser in Linux, + daemonUserUid in Debian <<= daemonUserUid in Linux, daemonGroup in Debian <<= daemonGroup in Linux, + daemonGroupGid in Debian <<= daemonGroupGid in Linux, // === Maintainer scripts === debianMakePreinstScript <<= (target in Universal, serverLoading in Debian, linuxScriptReplacements) map makeMaintainerScript(Preinst), debianMakePostinstScript <<= (target in Universal, serverLoading in Debian, linuxScriptReplacements) map makeMaintainerScript(Postinst), @@ -126,7 +128,9 @@ object JavaServerAppPackaging extends AutoPlugin { )) ++ Seq( // === Daemon User and Group === daemonUser in Rpm <<= daemonUser in Linux, + daemonUserUid in Rpm <<= daemonUserUid in Linux, daemonGroup in Rpm <<= daemonGroup in Linux, + daemonGroupGid in Rpm <<= daemonGroupGid in Linux, // === Startscript creation === linuxStartScriptTemplate := JavaServerLoaderScript( script = startScriptName((serverLoading in Rpm).value, Rpm), 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 b7150c214..50db2a158 100644 --- a/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala @@ -9,7 +9,9 @@ import com.typesafe.sbt.packager.archetypes.ServerLoader.ServerLoader trait LinuxKeys { val packageArchitecture = SettingKey[String]("package-architecture", "The architecture used for this linux package.") val daemonUser = SettingKey[String]("daemon-user", "User to start application daemon") + val daemonUserUid = SettingKey[Option[String]]("daemon-user-uid", "UID of daemonUser") val daemonGroup = SettingKey[String]("daemon-group", "Group to start application daemon") + val daemonGroupGid = SettingKey[Option[String]]("daemon-group-gid", "GID of daemonGroup") 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[Option[String]]("start-runlevels", "Sequence of runlevels on which application will start up") @@ -37,6 +39,9 @@ trait LinuxKeys { | appClasspath - application classpath | appMainClass - main class to start | daemonUser - daemon user + | daemonUserUid - daemon user uid + | daemonGroup - daemon group + | daemonGroupGid - daemon group gid """.stripMargin ) 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 f2541a251..2a29b8b1e 100644 --- a/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/linux/LinuxPlugin.scala @@ -58,7 +58,9 @@ object LinuxPlugin extends AutoPlugin { packageName in Linux <<= packageName, executableScriptName in Linux <<= executableScriptName, daemonUser in Linux <<= packageName in Linux, + daemonUserUid in Linux := None, daemonGroup in Linux <<= daemonUser in Linux, + daemonGroupGid in Linux := None, daemonShell in Linux := "/bin/false", defaultLinuxInstallLocation := "/usr/share", defaultLinuxLogsLocation := "/var/log", @@ -79,7 +81,9 @@ object LinuxPlugin extends AutoPlugin { appName = (packageName in Linux).value, version = sbt.Keys.version.value, daemonUser = (daemonUser in Linux).value, + daemonUserUid = (daemonUserUid in Linux).value, daemonGroup = (daemonGroup in Linux).value, + daemonGroupGid = (daemonGroupGid in Linux).value, daemonShell = (daemonShell in Linux).value ), linuxScriptReplacements += controlScriptFunctionsReplacement( /* Add key for control-functions */ ) @@ -150,7 +154,9 @@ object LinuxPlugin extends AutoPlugin { appName: String, version: String, daemonUser: String, + daemonUserUid: Option[String], daemonGroup: String, + daemonGroupGid: Option[String], daemonShell: String, retries: Int = 0, retryTimeout: Int = 60 @@ -165,7 +171,9 @@ object LinuxPlugin extends AutoPlugin { "app_name" -> appName, "version" -> version, "daemon_user" -> daemonUser, + "daemon_user_uid" -> daemonUserUid.getOrElse(""), "daemon_group" -> daemonGroup, + "daemon_group_gid" -> daemonGroupGid.getOrElse(""), "daemon_shell" -> daemonShell ) diff --git a/src/sbt-test/debian/daemon-group-gid-deb/build.sbt b/src/sbt-test/debian/daemon-group-gid-deb/build.sbt new file mode 100644 index 000000000..77c341539 --- /dev/null +++ b/src/sbt-test/debian/daemon-group-gid-deb/build.sbt @@ -0,0 +1,44 @@ +import com.typesafe.sbt.packager.archetypes.ServerLoader + +enablePlugins(JavaServerAppPackaging) + +serverLoading in Debian := ServerLoader.Upstart + +daemonUser in Linux := "daemonuser" + +daemonGroup in Linux := "daemongroup" + +daemonGroupGid in Linux := Some("25000") + +mainClass in Compile := Some("empty") + +name := "debian-test" + +version := "0.1.0" + +maintainer := "Josh Suereth " + +packageSummary := "Test debian package" + +packageDescription := """A fun package description of our software, + with multiple lines.""" + +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 daemongroup "25000"""", "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 "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 "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) + assert(!(postinst contains "chown daemonuser:daemongroup /usr/share/debian-test"), "postinst contains chown /usr/share/app_name: \n" + postinst) + out.log.success("Successfully tested upstart control files") + () +} + diff --git a/src/sbt-test/debian/daemon-group-gid-deb/project/plugins.sbt b/src/sbt-test/debian/daemon-group-gid-deb/project/plugins.sbt new file mode 100644 index 000000000..b53de154c --- /dev/null +++ b/src/sbt-test/debian/daemon-group-gid-deb/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % sys.props("project.version")) diff --git a/src/sbt-test/debian/daemon-group-gid-deb/test b/src/sbt-test/debian/daemon-group-gid-deb/test new file mode 100644 index 000000000..967f7a260 --- /dev/null +++ b/src/sbt-test/debian/daemon-group-gid-deb/test @@ -0,0 +1,12 @@ +# Run the debian packaging. +> debian:package-bin +$ exists target/debian-test_0.1.0_all.deb + +$ exists target/debian-test-0.1.0/etc +$ exists target/debian-test-0.1.0/etc/init/debian-test.conf +# Check defaults +$ exists target/debian-test-0.1.0/DEBIAN/prerm +$ exists target/debian-test-0.1.0/DEBIAN/postinst + +# Check files for defaults +> check-control-files diff --git a/src/sbt-test/debian/daemon-user-deb/build.sbt b/src/sbt-test/debian/daemon-user-deb/build.sbt index de530724d..52c9beb21 100644 --- a/src/sbt-test/debian/daemon-user-deb/build.sbt +++ b/src/sbt-test/debian/daemon-user-deb/build.sbt @@ -25,8 +25,8 @@ 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 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 """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 "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) 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 f5157d658..bd21c1d18 100644 --- a/src/sbt-test/debian/daemon-user-shell-deb/build.sbt +++ b/src/sbt-test/debian/daemon-user-shell-deb/build.sbt @@ -27,7 +27,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 """addUser daemonuser daemongroup "debian-test user-daemon" "/bin/bash"""", "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/daemon-user-uid-deb/build.sbt b/src/sbt-test/debian/daemon-user-uid-deb/build.sbt new file mode 100644 index 000000000..5bd9a138d --- /dev/null +++ b/src/sbt-test/debian/daemon-user-uid-deb/build.sbt @@ -0,0 +1,44 @@ +import com.typesafe.sbt.packager.archetypes.ServerLoader + +enablePlugins(JavaServerAppPackaging) + +serverLoading in Debian := ServerLoader.Upstart + +daemonUser in Linux := "daemonuser" + +daemonUserUid in Linux := Some("20000") + +daemonGroup in Linux := "daemongroup" + +mainClass in Compile := Some("empty") + +name := "debian-test" + +version := "0.1.0" + +maintainer := "Josh Suereth " + +packageSummary := "Test debian package" + +packageDescription := """A fun package description of our software, + with multiple lines.""" + +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 daemongroup """"", "postinst misses addgroup for daemongroup: " + postinst) + assert(postinst contains """addUser daemonuser "20000" 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 "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 "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) + assert(!(postinst contains "chown daemonuser:daemongroup /usr/share/debian-test"), "postinst contains chown /usr/share/app_name: \n" + postinst) + out.log.success("Successfully tested upstart control files") + () +} + diff --git a/src/sbt-test/debian/daemon-user-uid-deb/project/plugins.sbt b/src/sbt-test/debian/daemon-user-uid-deb/project/plugins.sbt new file mode 100644 index 000000000..b53de154c --- /dev/null +++ b/src/sbt-test/debian/daemon-user-uid-deb/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % sys.props("project.version")) diff --git a/src/sbt-test/debian/daemon-user-uid-deb/test b/src/sbt-test/debian/daemon-user-uid-deb/test new file mode 100644 index 000000000..967f7a260 --- /dev/null +++ b/src/sbt-test/debian/daemon-user-uid-deb/test @@ -0,0 +1,12 @@ +# Run the debian packaging. +> debian:package-bin +$ exists target/debian-test_0.1.0_all.deb + +$ exists target/debian-test-0.1.0/etc +$ exists target/debian-test-0.1.0/etc/init/debian-test.conf +# Check defaults +$ exists target/debian-test-0.1.0/DEBIAN/prerm +$ exists target/debian-test-0.1.0/DEBIAN/postinst + +# Check files for defaults +> check-control-files