Glassfish remote redeploy with maven and the mojo exec plugin

So a few days ago I run into a bug that took me almost a whole day to sort out..

I usually use cargo when I want to deploy an app to a running container but today I've spent several hours trying to make my app redeploy on a remote glassfish web profile server while working within my development/integration environment.

Just to give you some context in this environment I needed to continually deploy the same application on the same server but with different versions.

The first time I deployed the application everything will work as expected but subsequent deployments will throw an error telling me that an application already exists for that context root (see message below) :

 Caused by: org.codehaus.cargo.util.CargoException: Deployment has failed: Action failed Deploying application to target server failed; Error occurred during deployment: Application with name myapp-1.4.8 is already registered. Either specify that redeployment must be forced, or redeploy the application. Or if this is a new deployment, pick a different name. Please see server.log for more details.

Now the asadmin utility tool allows forcing a redeployment by using the --force=true option on the command line but it doesn't work if the WAR file name has changed as glassfish supports only one app per context root unless you use it in conjunction with Glassfish application versioning system but more on that later (see here)

I would argue that the "--force" param should deploy the WAR for a given context and overwrite the existing app regardless if you are using the versioning system or not but that's only my point of view

Side note : While doing some research on my problem I stumbled upon a forum post stating that when using the cargo:redeploy goal the --force=true parameter is used, at the moment I cannot find that blog post so I'm sorry..

So now let's get down to business, in this tutorial I will be showing how to use the codehaus maven exec plugin

Below are the steps that you should follow :

0.- Prerequisites

a. Glassfish versionning system naming conventions

Before beginning with this tutorial you must know that in order for it to work you need to use glassfish's versionning system with your applications otherwise it will always fail when trying to deploy an app for a given context but with a different war name (e.g. myapp-1.0.war -> myapp-1.1.war)

You can find more info on the versionning system here and here but basically glassfish will handle multiple versions of your application for a given context but allowing only 1 version of the application to be active at a given moment

For the versioning system to work you need to define a version for your WAR either in the glassfish-web.xml file or with the -name argument

In this tutorial we will be using the latest (the --name) argument

Please note that you need to respect a WAR file naming convention when versioning your applications (the value for the --name parameter), that convention is :

  {applicationName}:{applicationVersion}.war --> myapp:1.0.war
b. Access rights to Glassfish install path

You will also need to install(unzip) a glassfish instance in a place accessible to the the machine that will be executing the maven goal

c. Enabling asadmin secure admin feature

Lastly Glassfish's secure admin feature needs to be enabled in order to be allowed to do remote deploys; otherwise you will get an error message

[exec] HTTP connection failed with code 403, message

You can enable the secure admin feature by running the following command on your prompt (glassfish instance must be running)

  asadmin --host [host] --port [port] enable-secure-admin

Please note that you have to restart the glassfish instance in order for this functionality to be enabled.

1.- Installing a local glassfish instance

Go to the glassfish download website and download and unzip the appropriate glassfish version (ideally the same that the one of the remote server where you are trying to deploy your app) in a directory of your choice : e.g. /var/glassfish

2.- Defining the password file

You will then need to provide the asadmin tool with a password file since it's no longer supported as a command line argument

So go ahead and create a password file (let's name it glassfish.password) in the folder of your chice (e.g. /var/glassfish/). The file should be a properties files containing the following keys with the passwords values corresponding to your environment:

AS_ADMIN_MASTERPASSWORD=myPassword
AS_ADMIN_PASSWORD=myPassword
AS_ADMIN_USERPASSWORD=myPassword

Note: For this example the password will not be encrypted (you should encrypt it in your production environment). You can find more info on securing your master password in the glassfish documentation here here

3.- Configuring the exec plugin

Head up to your pom.xml file fire up your favorite editor and edit the POM file so it looks something like :





...

 /var/glassfish/bin/asadmin
  admin
  /var/glassfish/glassfish.password
  arte-epg-apipreprod.sdv.fr



....


   myapp
   
      
         org.codehaus.mojo
         exec-maven-plugin
         1.2.1
         
            ${glassfish.asadmin.executable}
            
               --user
               ${glassfish.user}
               --passwordfile
               ${glassfish.password.file}
               --host
               ${glassfish.remote.host}
               deploy
               --force=true
               --name=${project.build.finalName}:${project.version}
               --enabled=true
               ${project.build.directory}/${project.build.finalName}.war
            
         
         
            
               
                  exec
               
               verify
            
         
      
...
   


Please ensure that the value of the --name argument respects glassfish's application versioning naming conventions {appName}:{appVersion}.war

 mvn clean verify
Note: Here we are binding the execution of the goal to the verify phase but you can freely change that or use instead one of the plugin's goals directly from the command line.

4.- Sum-up and final thoughts

Firstly let me tell you that this method is probably not the cleanest way to get things done but for the time being, it will suffice... (at least to me :p)

Secondly, this is not a silver bullet, as sometimes I did encounter problems for example : if the database was not up and the application was marked as not enabled in the glassfish server, or the first time that I switched from deploying without glassfish versioning system to using glassfish's versioning system

Finally, I really don't like the fact that I need a local glassfish instance to deploy on a remote server, and I wonder if it's possible to achieve something similar using the glassfish deployment-client as a maven dependency and invoking the java classes inside the dependency or somehow extend the plugin to take into account force redeploys. So if I have some free time in the near future I will explore the possibility of accomplishing the same thing without needing a glassfish installed locally

4 comments:

  1. Can you expand on what you mean by "you need to respect a WAR file naming convention when versioning your applications"

    ReplyDelete
  2. Hi,
    Yes I'm referring to the value of the '--name' parameter.
    If you take a look at the documentation over at Oracle(see the bottom of my response) It is stated that when you want to exploit the versioning feature you will need to provide with a version identifier suffix that will append to your application name separated by a colon (:).
    So when deploying an application to a glassfish server using the versioning feature you will need to provide the mandatory '--name' parameter with a value that respects that naming convention (i.e. appName:version).
    Here is an exemple on how a asadmin command would look like with the different params

    asadmin deploy --host localhost --user=admin --passwordfile=mypasswordFile.txt deploy --name=myApp:1.0 --force=true --enabled=true myapp.war

    Hope that helps

    oracle docs : http://docs.oracle.com/cd/E18930_01/html/821-2417/gihzx.html#gkhhv

    ReplyDelete
  3. Hi Ulises.

    This is a great tutorial! I would like to suggest a few things though.

    When I first tried this out, I was not able to run it successfully. I was having the following errors:
    [exec] HTTP connection failed with code 403, message: Forbidden
    [exec] Command deploy failed.

    After google-ing things up, I found out that the domain where I am trying to deploy on my remote glassfish instance should have been "enable-secure-admin".

    Maybe you could add such information on your blog so newbies like me would know the prerequisites on deploying applications to remote glassfish instances?

    This could, maybe, be just one of the set-ups needed and some other more are there which we do not know of.

    This was a great tutorial!

    Cheers!

    ~Michael

    ReplyDelete
    Replies
    1. Hi Michael,
      Thanks for the comment, you are right I should have pointed out that you need to have the "secure admin" feature enabled in order to be able to deploy remotely on a glassfish instance.
      I will edit the tutorial and add this for future reference, thanks for pointing it out.

      Cheers

      Ulises

      Delete

OSX show used ports or listening applications with their PID

On OSX you can display applications listening on a given port using the lsof the commands described below will show listening application...