Requirements for Building Spartan

Spartan has been built and tested on RedHat/Centos distros of 6.7 and 7.4 (and Fedora 26, 27 as well as Ubuntu 14.04.5). Spartan consist of both Java and C++11 source code. It is built via the Java build tool, Maven. A Maven plugin is used to invoke cmake, which in turn compiles and links the C++ source code using GNU g++ compiler. Here are build provisioning prerequisites:

You might choose to have the following environment variables defined in your spartan build context, setting directory paths appropriately to match your installation (it's possible to build spartan on a 512 MB VM but you may have to reduce Maven max Java heap to, say, -Xmx208m, which then leaves sufficient memory for the cmake portion of the build):

By default this plugin will locate cmake at /usr/bin/cmake. If for your distro you have to install cmake, it might wind up placed at a different path. The GitHub project page of cmake-maven-plugin has information about customizing the plugin through configuration to use cmake at a different location:

The Spartan Java API is made available per the Spartan.jar library, which will be located in the spartan installation directory. When doing a Maven build, use the install goal so that Spartan.jar will be installed in your Maven local repository, there it will be available for when building the spartan example programs.

Spartan Example Programs

There are three Spartan example programs located in the examples sub-directory:

spartan-ex: illustrates all the Spartan annotations, also shows how to do a singleton worker child process sub-command, as well as how to use Spartan.invokeCommand().

spartan-cfg-ex: illustrates how the supervisor service main thread can serialize a JCommanderobject instance to a file so that worker child process sub-commands can de‑serialize from that file in order to populate their JCommanderobject.

spartan-watchdog-ex: illustrates how to code the supervisor to be a watchdog over some worker child process that it runs continuously.

Each is built using Maven, which produces a .jar file of the program in the respective target directory. The .jar file is what should be copied to a runtime directory; the spartan-cfg-ex program also requires the file examples/spartan-cfg-ex/target/config.properties and jcommander-1.72.jar to be copied to accompany it's .jar file.

How to Deploy and Run a Spartan Example Program

We will illustrate using spartan-cfg-ex. We will place all the programs discussed under the /opt/ directory (Wikipedia Filesystem Hierarchy Standard describes this as the location for optional or add-on software packages). The first step is to install the spartan launcher program.

Tip: In practice, because Spartan is intended for running Java programs as Linux services, it is recommended to create a spartanuser and spartangroup - deploy Spartan into a folder to where spartan:spartanis set as owner/group of the folder and all its files content. Then create a user account for running the service. This user account can be be added to the spartangroup and that group given execution permission of the spartan Java launcher program. Just add service user accounts to the spartangroup as any new services are stood up. The idea is to insure each service runs in a user account by which to control permissions/access, but then share the spartan executable between them for Java program launching.

Notice that there is a symbolic link spartan-cfg-ex which links to the spartan executable. This symbolic link and the config.ini file are the spartan conventions for launching a Java program.

When the symbolic link name is invoked as the program name of the service

./spartan-cfg-ex -service

The spartan program launcher will look in the directory where the symbolic link is located to find the file config.ini, where it will obtain various runtime options, such as JVM options for invoking the supervisor process. The config.ini file needs to be setup properly:

Copy /opt/spartan/config.ini into directory /opt/spartan-cfg-ex/.

Run chown to set the owner:group of the /opt/spartan-cfg-ex/config.ini file appropriately.

Open config.ini in a text editor and edit the CommandLineArgs property.

Given above install directories and file paths, the file should end up looking like so:

The logging level setting here is for the spartan program itself and when Java code calls the Spartan.log() API; the Java program will likely use logback, log4j, etc., for application logging in which case logging verbosity will be set through some other means for the general application logging.

Spartan currently only uses JAVA_HOME environment variable to locate the Java JVM shared library, so that will need to be defined appropriately in the runtime context of invoking the service.

If a user account has been established for executing the service, then the home directory could have been set as a default on that user account. However, it is possible to have multiple instances of a service being invoked to where each instance has its own home directory. The HOME environment variable can be defined in the context of invoking a particular instance of a service, in which case that will take precedence over any home directory associated to the service's user account.

Tip: Double check that JAVA_HOME and HOME have the values that are expected within the invoked execution context of the service.

Using the symbolic link name as the name of the program that is being run as a service has the nice effect that one can use that name with the Linux ps command to view its process status:

The process pid 31595, in this case, is Spartan invoked in client mode in order to handle launching a worker child process - the command line to the sub-command cdcetlis displayed here. The actual worker child process is pid 31596, which has another instantiated Java JVM instance. The -serviceoption appearing on the JVM child process is just an artifact of the fork()call being utilized, but in actuality that child process received the command line arguments it was invoked with.

Presuming that the service is running foreground in one terminal console, then by opening another terminal, the command to see application status can be issued (notice the use of sudoto invoke the command as the same user the service is running as):

The pid 31639 is spartanas invoked in client mode (the client mode process handles the output generated by the sub-command by echoing it to stdout).

Then to terminate the service, which will cause all processes to exit, can issue the supervisorstopsub-command:

$ sudo -u my_user /opt/spartan-cfg-ex/spartan-cfg-ex stop

As mentioned previously, the kill -TERMcommand can be used to cause a worker child process to exit without effecting the supervisor process of the service — just specify the child process pid number to the killcommand as it is seen displayed in the statuslisting. Run the statuscommand again and it will be seen that the child process has gone away.

This command line will cause a singleton worker child process to be launched:

Tip: Keep in mind that if file paths are passed as arguments to a sub-command, the user that the service runs as will need to have access permission established to that file. The example programs are not taking real files as arguments - they only serve for illustrating passing various arguments to sub commands.

A Spartan singleton refers to a worker child process sub-command that is restricted to being run as a single process at any given time. The Spartan.isFirstInstance() API is used to establish a fence around the core activity of the singleton sub-command.

The normal posture is that multiple instances of a worker child process sub-command can be invoked to run concurrently. The sub-command genetlis an example of a command that can be invoked to run many times concurrently; you can try it out by using the same command line as above but change cdcetlto genetl(you will have to start another terminal to run each sub-command, or else use a utility such as GNU Screen). All of these child processes will be listed by the statuscommand — spartankeeps track of when these child processes are launched and when they terminate so the status stays updated automatically.

NOTE: Currently, the Spartan client mode does not respond to Control-C — the child process at the other end of the pipe it is reading from can instead be caused to terminate by using kill -TERMon its pid, which the client mode will sense as the pipe will indicate no more input to be read.