Pandora's Box for Liferay: CRaSH Portlet

After building a hook that wraps the FakeSMTP application and a portlet that gives you file management capabilities in Liferay we now get to part 3 of the series: the CRaSH portlet. I must admit: I did actually build this portlet first, but during its development needed something to show/inspect emails and to upload, download and edit files and ended building the other apps too. It seems I have a bit of a problem staying on target and get easily distracted by something new and shiny.
 
But in the end I managed to get all 3 portlets finished and now it is finally time to write a blog post about the most important and powerful one: t he CRaSH portlet (the way it is written is intentional, you'll see why a bit further down).
 
The idea occurred to me when I came by this blog post, https://www.exoplatform.com/company/en/resource-viewer/Getting-Started-Guide/introduction-to-crash-the-cache-visualization-use-case, where CRaSH was used for cache visualization on the eXo platform. As I was having a problem with a customer's Liferay environment where I needed to view cache hits/misses, but didn't have any access to the server except for Administrator access to the Control Panel, I wondered if I maybe could wrap CRaSH as a portlet and retrieve my cache information that way?
 

What is CRaSH?

CRaSH, http://www.crashub.org, is a project by Julien Viet, that basically provides a shell environment for the Java platform. When embedded it allows you to connect to a running JVM via SSH, Telnet or a web interface (which is what we'll be using) and run commands. It already comes with a bunch of commands on board and you can easily add your custom commands,  written in Groovy or Java to better integrate with the application you're embedding CRaSH in.  You can add your custom commands directly to the portlet's WAR file, in WEB-INF/crash/commands, or you can use LFM to add them on the fly. The portlet will create a directory named crash in your Liferay root and will continuously try to load new scripts or reload existing ones from this location.
 
Now you might say: that seems pretty similar to the script portlet that is already available in Liferay or even the Script Helper portlet that can be found in the Liferay Marketplace? Well there are couple of things that IMHO set CRaSH apart from the already available options:
  • Unlike scripts, CRaSH commands can take parameters
  • Commands can be chained/piped like in a shell
  • It has man like functionality that describes the available commands
  • It has tab completion for the commands, their parameters and even parameter values like file paths (and you can write your own completions)
  • Other shell-like functionality like a history, clear screen, ...
  • The result of a command can be updated on an interval like for example 'ps'
Out of the box you already have access to a bunch of commands (which it will list when you type 'help') like: dashboard,  egrep, env, filter, jdbc, jmx, jndi, jvm, mail, ... . Below you can see the output of the dashboard command that shows a continuously updated view of thread info, your environment properties and your JVM memory usage:
 
 

Integrating CRaSH

For its web integration CRaSH uses websockets and this is where I a hit a little snag: the version of Tomcat in my Liferay bundle, 7.0.42, doesn't have official websocket support. It does however have an unofficial, pre-standard, websocket implementation that we can use. With some small adjustments to the existing web integration code and by using the Liferay PortalDelegateServlet it wasn't too difficult to get CRaSH to work in a portlet. The visual part, the terminal view, is handled by a very interesting JS library: http://terminal.jcubic.pl. This library is able to give you a complete terminal view in a browser, complete with things like tab completion, history, shortcuts, etc... and the websocket integration we did is used to communicate between the browser and the CRaSH backend.
 
To further integrate CRaSH with Liferay I also made alternate versions of the OOTB  jdbc and mail commands. They're called db and email and are basically copies of the original commands, but are changed to directly use the the Liferay database and email system/configuration by using the InfrastructureUtil class. 
 
You can also SSH into the CRaSH portlet, on port 9999, and the authentication has been integrated with the Liferay authentication. Any user that has the Administrator role should be able to connect using his screenname and password, e.g.:  ssh test@127.0.0.1 -p 9999
 

Working with the portlet

While the OOTB commands are already very useful, and could give me my cache information via de jmx command, I also made some additional ones to do some more interesting stuff and serve as examples of how to create your own:
  • company: shows a list of all the companies present in your Liferay installation
  • cluster: displays information about all cluster nodes
  • cache: a different non-JMX way to show EHCache cache names and their hits/misses (some fancy classloader magic was needed to make this work)
  • tasks: shows a list of running tasks
  • user: can show the list of all users and can also be used create a user
  • file: can read/write CSV and JSON files
By combining the OOTB commands, the custom commands and the LFM portlet you can start to do some really interesting things, e.g.: 
  • Create a CSV file containing user information via the LFM portlet
  • Chain the file command with the user command to read this CSV and  actually create the users in Liferay (you can see the 'Your new account' emails in FakeSMTP)
  • Retrieve all users, including your new one by executing: user all | file write -f JSON --fields MIXIN ../../crash/users.json
  • Download this JSON file via the LFM portlet and use it as the input from another program/process/...

 

Being able to do these kinds of things from within Liferay or via SSH made me feel a little like this:

 

Creating your own commands

As the system is very extensible I urge you to clone the project from GitHub, build the CRaSH portlet, deploy it and start experimenting! A simple example of a command to start with could be the echo command:
  • Open the LFM portlet and navigate to the crash directory
  • Create a new file named echo.groovy
  • Edit it and add the following content
import org.crsh.cli.Command
import org.crsh.cli.Usage

class echo {
   @Usage("echo text")
   @Command
   Object main(
         @Usage("the text to echo")
         @Argument String text) {
      if (text == null)
         text = "";
      return text;
   }
}
  • Save it and open the CRaSH portlet
  • Type help and you should see your new command appear in the list of commands
  • Type echo "Hello World" to output that text to the terminal

Starting from this base and the code you can find on GitHub should open a whole world of new possibilities within Liferay!

Blogs
[...] In the beginning of the year I had some fun creating the CRaSH portlet. Once it is deployed, it allows a portal administrator to work with the portal/JVM in a very flexible way using a command line... [...] Read More