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 new file mode 100644 index 000000000..fb5c13fbd --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/post-rpm-template @@ -0,0 +1 @@ +service ${{app_name}} start diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postun-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postun-rpm-template new file mode 100644 index 000000000..13c6a24ee --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postun-rpm-template @@ -0,0 +1,12 @@ +# Removing system user/group : ${{daemon_user}} and ${{daemon_group}} +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 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 new file mode 100644 index 000000000..12ae3e449 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/pre-rpm-template @@ -0,0 +1,11 @@ +# 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/preun-rpm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/preun-rpm-template new file mode 100644 index 000000000..503e49060 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/preun-rpm-template @@ -0,0 +1,3 @@ +# Halting ${{app_name}} +echo "Shutdown ${{app_name}}" +service ${{app_name}} stop diff --git a/src/main/resources/com/typesafe/sbt/packager/rpm/preuninstall b/src/main/resources/com/typesafe/sbt/packager/rpm/preuninstall index 2ffa1da1a..503e49060 100644 --- a/src/main/resources/com/typesafe/sbt/packager/rpm/preuninstall +++ b/src/main/resources/com/typesafe/sbt/packager/rpm/preuninstall @@ -1,3 +1,3 @@ # Halting ${{app_name}} echo "Shutdown ${{app_name}}" -service ${{app_name}} stop \ No newline at end of file +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 index 796b25536..587650901 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppStartScript.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppStartScript.scala @@ -109,10 +109,12 @@ trait JavaAppStartScriptBuilder { 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) + val systemvScripts = Seq(startScript, Pre, Post, Preun, Postun) } object Debian extends JavaAppStartScriptBuilder { 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 09aeb4a10..1ffb8aee1 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala @@ -22,7 +22,6 @@ import com.typesafe.sbt.packager.rpm.RpmPlugin object JavaServerAppPackaging { import ServerLoader._ import LinuxPlugin.Users - import DebianPlugin.Names.{ Preinst, Postinst, Prerm, Postrm } def settings: Seq[Setting[_]] = JavaAppPackaging.settings ++ linuxSettings ++ debianSettings ++ rpmSettings protected def etcDefaultTemplateSource: java.net.URL = getClass.getResource("etc-default-template") @@ -61,7 +60,8 @@ object JavaServerAppPackaging { packageTemplateMapping("/var/run/" + name)() withUser user withGroup group withPerms "755" }) - def debianSettings: Seq[Setting[_]] = + def debianSettings: Seq[Setting[_]] = { + import DebianPlugin.Names.{ Preinst, Postinst, Prerm, Postrm } Seq( linuxJavaAppStartScriptBuilder in Debian := JavaAppStartScript.Debian, serverLoading := Upstart, @@ -82,41 +82,45 @@ object JavaServerAppPackaging { 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)) + } - def rpmSettings: Seq[Setting[_]] = Seq( - linuxJavaAppStartScriptBuilder in Rpm := JavaAppStartScript.Rpm, - serverLoading in Rpm := SystemV, + def rpmSettings: Seq[Setting[_]] = { + import RpmPlugin.Names.{ Pre, Post, Preun, Postun } + Seq( + linuxJavaAppStartScriptBuilder in Rpm := JavaAppStartScript.Rpm, + serverLoading in Rpm := SystemV, - // === 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, linuxStartScriptTemplate in Rpm, linuxJavaAppStartScriptBuilder in Rpm) - map { (tmpDir, loader, replacements, template, builder) => - makeMaintainerScript(builder.startScript, Some(template))(tmpDir, loader, replacements, builder) + // === Startscript creation === + linuxStartScriptTemplate in Rpm <<= (serverLoading in Rpm, sourceDirectory, linuxJavaAppStartScriptBuilder in Rpm) map { + (loader, dir, builder) => + builder.defaultStartScriptTemplate(loader, dir / "templates" / "start") }, - linuxPackageMappings in Rpm <++= (normalizedName, linuxMakeStartScript in Rpm, serverLoading in Rpm) map startScriptMapping, + linuxMakeStartScript in Rpm <<= (target in Universal, serverLoading in Rpm, linuxScriptReplacements, linuxStartScriptTemplate in Rpm, linuxJavaAppStartScriptBuilder in Rpm) + map { (tmpDir, loader, replacements, template, builder) => + makeMaintainerScript(builder.startScript, Some(template))(tmpDir, loader, replacements, builder) + }, + linuxPackageMappings in Rpm <++= (normalizedName, linuxMakeStartScript in Rpm, serverLoading in Rpm) map startScriptMapping, - // == Maintainer scripts === - // TODO this is very basic - align debian and rpm plugin - rpmPre <<= (rpmPre, linuxScriptReplacements) apply { (pre, replacements) => - val scriptBits = TemplateWriter.generateScript(RpmPlugin.preinstTemplateSource, replacements) - Some(pre.map(_ + "\n").getOrElse("") + scriptBits) - }, - rpmPost <<= (rpmPost, linuxScriptReplacements) apply { (pre, replacements) => - val scriptBits = TemplateWriter.generateScript(RpmPlugin.postinstTemplateSource, replacements) - Some(pre.map(_ + "\n").getOrElse("") + scriptBits) - }, - rpmPostun <<= (rpmPostun, linuxScriptReplacements) apply { (post, replacements) => - val scriptBits = TemplateWriter.generateScript(RpmPlugin.postuninstallTemplateSource, replacements) - Some(post.map(_ + "\n").getOrElse("") + scriptBits) - }, - rpmPreun <<= (rpmPostun, linuxScriptReplacements) apply { (post, replacements) => - val scriptBits = TemplateWriter.generateScript(RpmPlugin.preuninstallTemplateSource, replacements) - Some(post.map(_ + "\n").getOrElse("") + scriptBits) - } - ) + // == 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)) + }, + 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)) + }, + 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)) + }, + rpmPreun <<= (rpmScriptsDirectory, rpmPostun, linuxScriptReplacements, serverLoading in Rpm, linuxJavaAppStartScriptBuilder in Rpm) apply { + (dir, preun, replacements, loader, builder) => + Some(preun.map(_ + "\n").getOrElse("") + rpmScriptletContent(dir, Preun, loader, replacements, builder)) + } + ) + } /* ========================================== */ /* ============ Helper Methods ============== */ @@ -147,4 +151,11 @@ object JavaServerAppPackaging { IO.write(script, scriptBits) Some(script) } + + protected def rpmScriptletContent(dir: File, script: String, + loader: ServerLoader, replacements: Seq[(String, String)], builder: JavaAppStartScriptBuilder): 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)) + } } diff --git a/src/main/scala/com/typesafe/sbt/packager/rpm/Keys.scala b/src/main/scala/com/typesafe/sbt/packager/rpm/Keys.scala index b32675c43..288ef9591 100644 --- a/src/main/scala/com/typesafe/sbt/packager/rpm/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/rpm/Keys.scala @@ -38,6 +38,8 @@ trait RpmKeys { // SCRIPTS val rpmScripts = SettingKey[RpmScripts]("rpm-scripts", "Configuration of pre- and post-integration scripts.") + val rpmScriptsDirectory = SettingKey[File]("debian-control-scripts-directory", + "Directory where all debian control scripts reside. Default is 'src/rpm/scriptlets'") val rpmPretrans = SettingKey[Option[String]]("rpm-pretrans", "%pretrans scriptlet") val rpmPre = SettingKey[Option[String]]("rpm-pre", "%pre scriptlet") 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 001c971dd..8e6edf5c0 100644 --- a/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/packager/rpm/RpmPlugin.scala @@ -5,12 +5,15 @@ package rpm import Keys._ import linux._ import sbt._ +import sbt.Keys.sourceDirectory import java.nio.charset.Charset /** Plugin trait containing all generic values used for packaging linux software. */ trait RpmPlugin extends Plugin with LinuxPlugin { val Rpm = config("rpm") extend Linux + import RpmPlugin.Names + def rpmSettings: Seq[Setting[_]] = Seq( rpmOs := "Linux", // TODO - default to something else? rpmRelease := "0", @@ -36,6 +39,7 @@ trait RpmPlugin extends Plugin with LinuxPlugin { rpmPreun := None, rpmPostun := None, rpmBrpJavaRepackJars := false, + rpmScriptsDirectory <<= sourceDirectory apply (_ / "rpm" / Names.Scriptlets), packageSummary in Rpm <<= packageSummary in Linux, packageDescription in Rpm <<= packageDescription in Linux, target in Rpm <<= target(_ / "rpm") @@ -72,9 +76,15 @@ trait RpmPlugin extends Plugin with LinuxPlugin { object RpmPlugin { - def preinstTemplateSource: java.net.URL = getClass getResource "preinstall" - def postinstTemplateSource: java.net.URL = getClass getResource "postinstall" - def preuninstallTemplateSource: java.net.URL = getClass getResource "preuninstall" - def postuninstallTemplateSource: java.net.URL = getClass getResource "postuninstall" def osPostInstallMacro: java.net.URL = getClass getResource "brpJavaRepackJar" + + object Names { + val Scriptlets = "scriptlets" + + //maintainer script names + val Post = "post-rpm" + val Pre = "pre-rpm" + val Postun = "postun-rpm" + val Preun = "preun-rpm" + } } diff --git a/src/sbt-test/rpm/scriptlets-override-rpm/build.sbt b/src/sbt-test/rpm/scriptlets-override-rpm/build.sbt new file mode 100644 index 000000000..428f16f07 --- /dev/null +++ b/src/sbt-test/rpm/scriptlets-override-rpm/build.sbt @@ -0,0 +1,35 @@ +import NativePackagerKeys._ + +packageArchetype.java_server + +name := "rpm-test" + +version := "0.1.0" + +maintainer := "Josh Suereth " + +packageSummary := "Test rpm package" + +packageDescription := "Description" + +rpmRelease := "1" + +rpmVendor := "typesafe" + +rpmUrl := Some("http://github.com/sbt/sbt-native-packager") + +rpmLicense := Some("BSD") + +mainClass in (Compile, run) := Some("com.example.MainApp") + +TaskKey[Unit]("unzipAndCheck") <<= (packageBin in Rpm, streams) map { (rpmFile, streams) => + 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 "echo postinst", "'echo 'postinst' not present in \n" + scriptlets) + assert(scriptlets contains "echo preinst", "'echo 'preinst' not present in \n" + scriptlets) + assert(scriptlets contains "echo postun", "'echo 'postun' not present in \n" + scriptlets) + assert(scriptlets contains "echo preun", "'echo 'preun' not present in \n" + scriptlets) + () +} + diff --git a/src/sbt-test/rpm/scriptlets-override-rpm/project/plugins.sbt b/src/sbt-test/rpm/scriptlets-override-rpm/project/plugins.sbt new file mode 100644 index 000000000..b53de154c --- /dev/null +++ b/src/sbt-test/rpm/scriptlets-override-rpm/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % sys.props("project.version")) diff --git a/src/sbt-test/rpm/scriptlets-override-rpm/src/main/scala/com/example/MainApp.scala b/src/sbt-test/rpm/scriptlets-override-rpm/src/main/scala/com/example/MainApp.scala new file mode 100644 index 000000000..faa497b3e --- /dev/null +++ b/src/sbt-test/rpm/scriptlets-override-rpm/src/main/scala/com/example/MainApp.scala @@ -0,0 +1,3 @@ +object MainApp extends App { + println("Hello World") +} 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/post-rpm new file mode 100644 index 000000000..7e497850e --- /dev/null +++ b/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/post-rpm @@ -0,0 +1 @@ +echo postinst \ No newline at end of file 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-rpm new file mode 100644 index 000000000..d3d4f26c6 --- /dev/null +++ b/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/postun-rpm @@ -0,0 +1 @@ +echo postun \ No newline at end of file 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/pre-rpm new file mode 100644 index 000000000..0f1840241 --- /dev/null +++ b/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/pre-rpm @@ -0,0 +1 @@ +echo preinst \ No newline at end of file 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-rpm new file mode 100644 index 000000000..f03b46d52 --- /dev/null +++ b/src/sbt-test/rpm/scriptlets-override-rpm/src/rpm/scriptlets/preun-rpm @@ -0,0 +1 @@ +echo preun \ No newline at end of file diff --git a/src/sbt-test/rpm/scriptlets-override-rpm/test b/src/sbt-test/rpm/scriptlets-override-rpm/test new file mode 100644 index 000000000..6acdc7dd0 --- /dev/null +++ b/src/sbt-test/rpm/scriptlets-override-rpm/test @@ -0,0 +1,20 @@ +# Run the debian packaging. +> rpm:package-bin +$ exists target/rpm/RPMS/noarch/rpm-test-0.1.0-1.noarch.rpm + +# Check rpm contents +> unzipAndCheck +$ exists etc/default/rpm-test +$ exists etc/init.d/rpm-test + +$ exists usr/share/rpm-test + +$ exists usr/share/rpm-test/bin +$ exists usr/share/rpm-test/bin/rpm-test + +$ exists usr/share/rpm-test/lib + +$ exists var/log/rpm-test +$ exists var/run/rpm-test + +# TODO symlinks aren't checked diff --git a/src/sphinx/GettingStartedServers/OverrdingTemplates.rst b/src/sphinx/GettingStartedServers/OverrdingTemplates.rst index 8f9683cc0..71d1d6622 100644 --- a/src/sphinx/GettingStartedServers/OverrdingTemplates.rst +++ b/src/sphinx/GettingStartedServers/OverrdingTemplates.rst @@ -1,5 +1,123 @@ Overriding templates #################### -This works the same way as for the standard application type. Read more on :doc:`../GettingStartedApplications/OverridingTemplates` +Some scripts are covered in the standard application type. Read more on :doc:`../GettingStartedApplications/OverridingTemplates`. +For the ``java_server`` package lifecycle scripts are customized to provide the following additional features +* Chowning directories and files correctly +* Create/Delete users and groups according to your mapping +* Register application at your init system + +For this purpose *sbt-native-packager* ships with some predefined templates. These can be +override with different techniques, depending on the packaging system. + +RPM Scriptlets +============== + +RPM puts all scripts into one file. To override or append settings to your +scriptlets use these settings: + + ``rpmPre`` + %pre scriptlet + + ``rpmPost`` + %post scriptlet + + ``rpmPosttrans`` + %posttrans scriptlet + + ``rpmPreun`` + "%preun scriptlet" + + ``rpmPostun`` + %postun scriptlet + + ``rpmVerifyscript`` + %verifyscript scriptlet + +If you want to have your files separated from the build definition use the +default location for rpm scriptlets. To override default templates in a RPM +build put the new scriptlets in the ``rpmScriptsDirectory`` (by default ``src/rpm/scriptlets``). + + ``rpmScriptsDirectory`` + By default to ``src/rpm/scriptlets``. Place your templates here. + +Available templates are + + ``post-rpm`` + ``pre-rpm`` + ``postun-rpm`` + ``preun-rpm`` + +Override Postinst scriplet +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default the ``post-rpm`` template only starts the service, but doesn't register it. + +.. code-block :: bash + + service ${{app_name}} start + +For **CentOS** we can do + +.. code-block :: bash + + chkconfig ${{app_name}} defaults + service ${{app_name}} start || echo "${{app_name}} could not be started. Try manually with service ${{app_name}} start" + +For **RHEL** + +.. code-block :: bash + + update-rc.d ${{app_name}} defaults + service ${{app_name}} start || echo "${{app_name}} could not be started. Try manually with service ${{app_name}} start" + + + +Debian Control Scripts +====================== + +To override default templates in a Debian build put the new control files in the +``debianControlScriptsDirectory`` (by default ``src/debian/DEBIAN``). + + ``debianControlScriptsDirectory`` + By default to ``src/debian/DEBIAN``. Place your templates here. + + ``debianMakePreinstScript`` + creates or discovers the preinst script used by this project. + + ``debianMakePrermScript`` + creates or discovers the prerm script used by this project. + + ``debianMakePostinstScript`` + creates or discovers the postinst script used by this project. + + ``debianMakePostrmScript`` + creates or discovers the postrm script used by this project. + + +Available templates are + + ``postinst`` + ``preinst`` + ``postun`` + ``preun`` + + +Linux Replacements +================== + + This is a list of values you can access in your templates + + .. code-block :: bash + + ${{author}} + ${{descr}} + ${{exec}} + ${{chdir}} + ${{retries}} + ${{retryTimeout}} + ${{app_name}} + ${{daemon_user}} + ${{daemon_group}} + \ No newline at end of file