Skip to content

Commit

Permalink
New structured completed. Next step is to merge overriding/configure …
Browse files Browse the repository at this point in the history
…templates
  • Loading branch information
muuki88 committed Dec 20, 2014
1 parent 6994400 commit fe0617d
Show file tree
Hide file tree
Showing 20 changed files with 1,733 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/sphinx/archetypes/akka_app/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Akka Microkernel
################
246 changes: 246 additions & 0 deletions src/sphinx/archetypes/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
.. _Archetypes:


.. toctree::
:maxdepth: 2

java_app/index.rst
java_server/index.rst
akka_app/index.rst

Project Archetypes
==================

Project archetypes are default deployment scripts that try to "do the right thing" for a given type of project.
Because not all projects are created equal, there is no one single archetype for all native packages, but a set
of them for usage.

The architecture of the plugin is set up so that you can customize your packages at any level of complexity.
For example, if you'd like to write Windows Installer XML by hand and manually map files, you should be able to do this while
still leveraging the default configuration for other platforms.


Curently, in the nativepackager these archetypes are available:

* Java Command Line Application
* Java Server Application (Experimental - Debian Only)


Java Command Line Application
-----------------------------

A Java Command Line application is a Java application that consists of a set of JARs and a main method. There is no
custom start scripts, or services. It is just a bash/bat script that starts up a Java project. To use
this archetype in your build, do the following in your ``build.sbt``:

.. code-block:: scala
packageArchetype.java_application
name := "A-package-friendly-name"
packageSummary in Linux := "The name you want displayed in package summaries"
packageSummary in Windows := "The name you want displayed in Add/Remove Programs"
packageDescription := " A description of your project"
maintainer in Windows := "Company"
maintainer in Debian := "Your Name <[email protected]>"
wixProductId := "ce07be71-510d-414a-92d4-dff47631848a"
wixProductUpgradeId := "4552fb0e-e257-4dbd-9ecb-dba9dbacf424"
This archetype will use the ``mainClass`` setting of sbt (automatically discovers your main class) to generate ``bat`` and ``bin`` scripts for your project. It
produces a universal layout that looks like the following:

.. code-block:: none
bin/
<app_name> <- BASH script
<app_name>.bat <- cmd.exe script
lib/
<Your project and dependent jar files here.>
You can add additional files to the project by placing things in ``src/windows``, ``src/universal`` or ``src/linux`` as needed.

The scripts under ``bin`` will execute the ``main`` method of a class found in your application. But you can specific a custom main class method with the ``-main`` flag.

The default bash script also supports having a configuration file. This config file can be used to specify default arguments to the BASH script.
To define a config location for your bash script, you can manually override the template defines:

.. code-block:: scala
bashScriptConfigLocation := "$app_home/conf/my.conf"
This string can include any variable defines in the BASH script. In this case, ``app_home`` refers to the install location of the script.

Java Server
-----------

This archetype is designed for Java applications that are intended to run as
servers or services. This archetype includes wiring an application to start
immediately upon startup. To activate this archetype replace ``packageArchetype.java_application`` with

.. code-block:: scala
packageArchetype.java_server
Currently supported operating systems:

* Ubuntu 12.04 LTS - Upstart
* Ubuntu 12.04 LTS - init.d


The Java Server archetype has a similar installation layout as the java
application archetype. The primary differneces are:

* Linux

* ``/var/log/<pkg>`` is symlinked from ``<install>/logs``

* Creates a start script in ``/etc/init.d`` or ``/etc/init/``

* Creates a startup config file in ``/etc/default/<pkg>``


For Debian servers, you can select to either use SystemV or Upstart for your servers. By default, Upstart (the current Ubuntu LTS default), is used. To switch to SystemV, add the following:

.. code-block:: scala
import NativePackagerKeys._
import com.typesafe.sbt.packager.archetypes.ServerLoader
serverLoading in Debian := ServerLoader.SystemV
By default, the native packager will install and run services using a user and group based on your package name. You can change the installation and usage user via the ``appUser`` and ``appGroup`` key:

.. code-block:: scala
appUser in Linux := "my_app_user"
appGroup in Linux := "my_app_group"
The archetype will automatically append/prepend the creation/deletion of the user
to your packaging for Debian. *Note:* All specified users are **deleted** on an ``apt-get purge <dpkg>``.

*Note:* It is not a good idea to use **root** as the ``appUser`` for services as it represents a security risk.

Akka Microkernel Application
----------------------------

An Akka microkernel application is simlar to a Java Command Line application. Instead of running the classic ``mainClass``,
an Akka microkernel application instantiates and runs a subclass of
`Bootable <https://github.com/akka/akka/blob/master/akka-kernel/src/main/scala/akka/kernel/Main.scala>`_ . A minimal example
could look like this

.. code-block:: scala
class HelloKernel extends Bootable {
val system = ActorSystem("hellokernel")
def startup = {
// HelloActor and Start case object must of course be defined
system.actorOf(Props[HelloActor]) ! Start
}
def shutdown = {
system.terminate()
}
}
The *bash/bat* script that starts up the Akka application is copied from the Akka distribution.

To use this archetype in your build, add the following to your ``build.sbt``:

.. code-block:: scala
packageArchetype.akka_application
name := "A-package-friendly-name"
mainClass in Compile := Some("HelloKernel")
For more information take a look at the akka docs

* `Akka microkernel <http://doc.akka.io/docs/akka/snapshot/scala/microkernel.html>`_
* `akka.kernel.Main source <https://github.com/akka/akka/blob/master/akka-kernel/src/main/scala/akka/kernel/Main.scala>`_
* `akka.kernel.Bootable docs <http://doc.akka.io/api/akka/snapshot/index.html#akka.kernel.Bootable>`_


Overriding Templates
--------------------

You can override the default template used to generate any of the scripts in
any archetype. Listed below are the overridable files and variables that
you can use when generating scripts.

``src/templates/bat-template``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Creating a file here will override the default template used to
generate the ``.bat`` script for windows distributions.

**Syntax**

``@@APP_ENV_NAME@@`` - will be replaced with the script friendly name of your package.

``@@APP_NAME@@`` - will be replaced with user friendly name of your package.

``@APP_DEFINES@@`` - will be replaced with a set of variable definitions, like
``APP_MAIN_CLASS``, ``APP_MAIN_CLASS``.

You can define addiitonal variable definitions using ``batScriptExtraDefines``.

``src/templates/bash-template``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Creating a file here will override the default template used to
generate the BASH start script found in ``bin/<application>`` in the
universal distribution

**Syntax**

``${{template_declares}}`` - Will be replaced with a series of ``declare <var>``
lines based on the ``bashScriptDefines`` key. You can add more defines to
the ``bashScriptExtraDefines`` that will be used in addition to the default set:

* ``app_mainclass`` - The main class entry point for the application.
* ``app_classpath`` - The complete classpath for the application (in order).



``src/templates/start``
~~~~~~~~~~~~~~~~~~~~~~~

Creating a file here will override either the init.d startup script or
the upstart start script. It will either be located at
``/etc/init/<application>`` or ``/etc/init.d/<application>`` depending on which
serverLoader is being used.

**Syntax**

You can use ``${{variable_name}}`` to reference variables when writing your scirpt. The default set of variables is:

* ``descr`` - The description of the server.
* ``author`` - The configured author name.
* ``exec`` - The script/binary to execute when starting the server
* ``chdir`` - The working directory for the server.
* ``retries`` - The number of times to retry starting the server.
* ``retryTimeout`` - The amount of time to wait before trying to run the server.
* ``app_name`` - The name of the application (linux friendly)
* ``app_main_class`` - The main class / entry point of the application.
* ``app_classpath`` - The (ordered) classpath of the application.
* ``daemon_user`` - The user that the server should run as.

``src/templates/etc-default``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Creating a file here will override the ``/etc/default/<application>`` template
used when SystemV is the server loader.

147 changes: 147 additions & 0 deletions src/sphinx/archetypes/java_app/AddingConfiguration.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
Adding configuration
####################

After :doc:`creating a package <MyFirstProject>`, the very next thing needed, usually, is the ability for users/ops to customize the application once it's deployed. Let's add some configuration to the newly deployed application.

There are generally two types of configurations:

* Configuring the JVM and the process
* Configuring the Application itself.

The native packager provides a direct hook into the generated scripts for JVM configuration. Let's make use of this. First, add the following to the ``src/universal/conf/jvmopts`` file in the project ::

-DsomeProperty=true

Now, if we run the ``stage`` task, we'll see this file show up in the distribution ::

$ sbt stage
$ ls target/universal/stage
bin/
conf/
lib/
$ ls target/universal/stage/conf
jvmopts

By default, any file in the ``src/universal`` directory is packaged. This is a convenient way to include things like licenses, and readmes.

Now, we need to modify the script templates to load this configuration. To do so, add the following
to ``build.sbt`` ::

bashScriptConfigLocation := Some("${app_home}/../conf/jvmopts")

Here, we define the configuration location for the BASH script too look for the ``conf/jvmopts`` file. Now, let's run ``sbt stage`` and then execute the script in debug mode to see what command line it executes ::

./target/universal/stage/bin/example-cli -d
# Executing command line:
java
-Xms1024m
-Xmx1024m
-XX:MaxPermSize=256m
-XX:ReservedCodeCacheSize=128m
-DsomeProperty=true
-cp
/home/jsuereth/projects/sbt/sbt-native-packager/tutorial-example/target/universal/stage/lib/example-cli.example-cli-1.0.jar:/home/jsuereth/projects/sbt/sbt-native-packager/tutorial-example/target/universal/stage/lib/org.scala-lang.scala-library-2.10.3.jar:/home/jsuereth/projects/sbt/sbt-native-packager/tutorial-example/target/universal/stage/lib/com.typesafe.config-1.2.0.jar
TestApp


The configuration file for bash scripts takes arguments for the BASH file on each line, and allows comments which start with the ``#`` character. Essentially, this provides a set of default arguments when calling the script.

Now that we have ability to configure the JVM, let's add in a more robust method of customizing the applciation. We'll be using the `Typesafe Config <https://github.com/typesafehub/config>`_ library for this purpose.

First, let's add it as a dependency in ``build.sbt`` ::

libraryDependencies += "com.typesafe" % "config" % "1.2.0"

Next, let's create the configuration file itself. Add the following to ``src/universal/conf/app.config`` ::

example {
greeting = "Hello, World!"
}

Now, we need a means of telling the typesafe config library where to find our configuration. The library supports
a JVM property "``config.file``" which it will use to look for configuration. Let's expose this file
in the startup BASH script. To do so, add the following to ``build.sbt`` ::

bashScriptExtraDefines += """addJava "-Dconfig.file=${app_home}/../conf/app.config""""

This line modifies the generated BASH script to add the JVM options the location of the application configuration on disk. Now, let's modify the application (``src/main/scala/TestApp.scala``) to read this configuration ::

import com.typesafe.config.ConfigFactory
object TestApp extends App {
val config = ConfigFactory.load()
println(config.getString("example.greeting"))
}

Now, let's try it out on the command line ::

$ sbt stage
$ ./target/universal/stage/bin/example-cli
Hello, World!


Finally, let's see what this configuration looks like in a linux distribution. Let's run the debian packaging again ::

$ sbt debian:packageBin

The resulting structure is the following ::

/usr/
share/example-cli/
conf/
app.config
jvmopts
bin/
example-cli
lib/
example-cli.example-cli-1.0.jar
org.scala-lang.scala-library-2.10.3.jar
bin/
example-cli -> ../share/example-cli/bin/example-cli
/etc/
example-cli -> /usr/share/example-cli/conf

Here, we can see that the entire ``conf`` directory for the application is exposed on ``/etc`` as is standard for other linux applications. By convention, all files in the universal ``conf`` directory are marked as configuration files when packaged, allowing users to modify them.

Configuring for Windows
~~~~~~~~~~~~~~~~~~~~~~~
While we just covered how to do configuration for linux/mac, windows offers some subtle differences.

First, while the BASH file allows you to configure where to load JVM options and default arguments, in
windows we can only configure JVM options. The path is hardcoded, as well to:

``<install directory>/@@APP_ENV_NAME@@_config.txt``

where ``@@APP_ENV_NAME@@`` is replaced with an environment friendly name for your app. In this example, that would be: ``EXAMPLE_CLI``.

We can provide a configuration for JVM options on windows by creating a ``src/universal/EXAMPLE_CLI_config.txt`` file with the following contents ::

-Xmx512M
-Xms128M

This will add each line of the file as arguments to the JVM when running your application.


Now, if we want to add the typesafe config library again, we need to write the ``config.file`` property into the JVM options again.

One means of doing this is hooking the ``batScriptExtraDefines`` key. This allows us to insert various BAT settings/commands into the script. Let's use this to hook the config file location, using the other variables in the BASH script. Modify your ``build.sbt`` as follows ::

batScriptExtraDefines += """set _JAVA_OPTS=%_JAVA_OPTS% -Dconfig.file=%EXAMPLE_CLI_HOME%\\conf\\app.config"""

Now, the windows version will also load the configuration from the ``conf/`` directory of the package.

More Complex Scripts
--------------------

As you read earlier the ``bashScriptExtraDefines`` sequence allows you to add new lines to the default bash script used to start the application.
This is useful when you need a setting which isn't mean for the command-line parameter list passed to the java process. The lines added to
``bashScriptExtraDefines`` are placed near the end of the script and have access to a number of utility bash functions (e.g. ``addJava``,
``addApp``, ``addResidual``, ``addDebugger``). You can add lines to this script as we did for the Typesage config file above. For more complex
scripts you can also inject a seperate file managed in your source tree or resource directory: ::

bashScriptExtraDefines ++= IO.readLines(baseDirectory.value / "scripts" / "extra.sh")

This will add the contents of ``/scripts/extra.sh`` in the resource directory to the bash script. Note you should always concatenate lines
to ``bashScriptExtraDefines`` as other stages in the pipeline may be include linex to the start-script.

Next, let's :doc:`add some generated files <GeneratingFiles>`.
Loading

0 comments on commit fe0617d

Please sign in to comment.