8. Example: Deploying Applications Through Bundles (General)

Bundles are a very clean and easy way to deploy full applications, configuration files, or other content to resources. Whether a given resource type supports bundles is defined in its plug-in descriptor. By default, platform resources and JBoss AS 4, 5, and 6 resources all support bundles.
Bundles are convenient from an administrative perspective because all of the content is maintained in a single place that is resource-agnostic. The main bundle entry or bundle definition contains a set of versions of the actual bundle files and a set of destinations for where that content can be deployed. A destination is a combination of a compatible group, resource type, and directory path. When a version is actually deployed to a destination, it is saved as a specific deployment for that destination.
The bundles system maintains multiple versions of a given package and can deploy any of those versions to any destination. This is a great workflow for application lifecycles, since a stable version can be deployed to production servers while a development version can be deployed to test machines. Having each deployment represented as a different child of the destination makes it easy to revert changes; you can move from the live version to a previous version and know exactly what that previous deployment looked like.

8.1. Setting up Bundle Versions and Destinations

There are two parts to the bundle definition: the bundle version and the destination. Both of these parts are set up independently, and then saved into the final definition.
The bundles.js script in the cliRoot/rhq-remoting-cli-3.1.2.GA/samples directory defines a set of custom functions that quickly create a bundle version and definition.
Using the bundles.js script also requires the util.js script. This is easiest to do when running the CLI interactively, because all of the scripts can be loaded using the exec command.
[root@server bin]# ./rhq-cli.sh -u rhqadmin -p rhqadmin
rhqadmin@localhost:7080$ exec -f cliRoot/rhq-remoting-cli-3.1.2.GA/samples/util.js
rhqadmin@localhost:7080$ exec -f cliRoot/rhq-remoting-cli-3.1.2.GA/samples/bundles.js
To create the destination, give the absolute path on the local system to the bundle archive to upload.
rhqadmin@localhost:7080$ var path = '/export/files/myApp.zip'
rhqadmin@localhost:7080$ createBundleVersion(path)
The createBundleVersion function in the bundles.js file uploads the files as a byte array.
function createBundleVersion(pathToBundleZipFile) {
        var bytes = getFileBytes(pathToBundleZipFile)
        return BundleManager.createBundleVersionViaByteArray(bytes)
}
The second part of the bundle definition is creating at least one destination where the bundle version could be deployed. Creating a destination requires two things to exist already:
  • A bundle version (which was just created with createBundleVersion)
  • A compatible group
A destination is a combination of a compatible group and the directory to deploy to. Each resource type defines its own available base directory, then a subdirectory beneath that root can be specified as the deployment directory.
The other configuration properties are details for the entry, such as the destination name and description.
rhqadmin@localhost:7080$ var destinationName = 'New Destination'
rhqadmin@localhost:7080$ var description = 'My new example destination'
rhqadmin@localhost:7080$ var bundleName = 'myApp'
rhqadmin@localhost:7080$ var groupName = 'Linux Group'
rhqadmin@localhost:7080$ var baseDirName = '/'
rhqadmin@localhost:7080$ var deployDir = 'var/www/html/'
rhqadmin@localhost:7080$ createBundleDestination(destinationName, description, bundleName, groupName, baseDirName, deployDir)
The createBundleDestination function runs the searches for the group and the bundle based on the specified names, which makes it possible to set up the destination without having to run additional searches.
function createBundleDestination(destinationName, description, bundleName, groupName, baseDirName, deployDir) {
        var groupCrit = new ResourceGroupCriteria;
        groupCrit.addFilterName(groupName);
        var groups = ResourceGroupManager.findResourceGroupsByCriteria(groupCrit);

... 8< ...

        var group = groups.get(0);

        var bundleCrit = new BundleCriteria;
        bundleCrit.addFilterName(bundleName);
        var bundles = BundleManager.findBundlesByCriteria(bundleCrit);

... 8< ...
}

8.2. Deploying Bundles

Deploying a bundle sends a bundle version to a specific destination. The bundles.js file has a function, deployBundle, which makes this pretty easy, but you need to obtain some information first.
First, load the required scripts.
[root@server bin]# ./rhq-cli.sh -u rhqadmin -p rhqadmin
rhqadmin@localhost:7080$ exec -f cliRoot/rhq-remoting-cli-3.1.2.GA/samples/util.js
rhqadmin@localhost:7080$ exec -f cliRoot/rhq-remoting-cli-3.1.2.GA/samples/bundles.js
Get the ID for the destination. This searches for the destination by name.
rhqadmin@localhost:7080$ var destinationName = "New Destination"
rhqadmin@localhost:7080$ var destcrit = new BundleDestinationCriteria()
rhqadmin@localhost:7080$ destcrit.addFilterName(destinationName)

var dest = BundleManager.findBundleDestinationsByCriteria(destcrit)
Then, get the ID number for the bundle version to deploy. Any version can be deployed, not just the most recent. This little script prints all of the versions for the bundle, with their ID numbers.
rhqadmin@localhost:7080$ var crit = new BundleVersionCriteria()

rhqadmin@localhost:7080$ crit.addFilterBundleName(name)

rhqadmin@localhost:7080$ var vers = BundleManager.findBundleVersionsByCriteria(crit)

rhqadmin@localhost:7080$ if( vers != null ) { \
rhqadmin@localhost:7080$   if( vers.size() > 1 ) { \
rhqadmin@localhost:7080$      for( i =0; i < vers.size(); ++i) { \
rhqadmin@localhost:7080$           ver = vers.get(i); \
rhqadmin@localhost:7080$           println("Version: " + ver.version + "   " + "ID: " + ver.id) \
rhqadmin@localhost:7080$      } \
rhqadmin@localhost:7080$   } \
rhqadmin@localhost:7080$   else if( vers.size() == 1 ) { \
rhqadmin@localhost:7080$      ver = vers.get(0); \
rhqadmin@localhost:7080$      println("Version: " + ver.version + + "   " + "ID: " + ver.id) \
rhqadmin@localhost:7080$   } \
rhqadmin@localhost:7080$ }
Version: 2.0 ID: 10021
Version: 1.0 ID: 10012
With those two ID numbers, you can deploy the bundle. The first parameter is the destination ID, then the bundle version ID, then a configuration object if the bundle configuration has any tokens to realize. In this example, no properties are passed, so the value is null. Details about the configuration are in the comments in the bundles.js file and general configuration information is in Section 6.2, “Changing Simple Configuration Properties”.
rhqadmin@localhost:7080$ deployBundle(dest.get(0).id,10021,null,'my description',true)
BundleDeployment:
                     bundleVersion: BundleVersion[id=10021,name=null,version=null]
                     configuration: Configuration[id=15021]
                             ctime: 1337286719259
                       description: my description
                       destination: BundleDestination[id=10021, bundle=driftBundle, group=Linux Group - Thu May 10 15:10:28 EDT 2012, name=NewDestination]
                          duration: 0
                      errorMessage:
                                id: 10051
                              live: true
                             mtime: 1337286719259
                              name: Deployment [1] of Version [2.0] to [NewDestination]
        replacedBundleDeploymentId:
               resourceDeployments: [BundleResourceDeployment: bdd=[BundleDeployment[id=10051, name=Deployment [1] of Version [2.0] to [new-test]]], resource=[Resource[id=10001, uuid=535b3f54-0bd8-4653-bdd3-323ea69b98fd, type={Platforms}Linux, key=gs-dl585g2-01.rhts.eng.bos.redhat.com, name=server.example.com, parent=<null>, version=Linux 2.6.32-220.el6.x86_64]]]
                            status: Failure
                       subjectName: rhqadmin
		              tags:
The deployBundle function runs through a couple of steps to manage the deployment. This uses one of the functions from the util.js file to convert the deployment configuration (if any is sent) into the proper into a hash.
... 8< ...

        var deploymentConfig = deploymentConfiguration;
        if (!(deploymentConfiguration instanceof Configuration)) {
                deploymentConfig = asConfiguration(deploymentConfiguration);
	}
The next creates the deployment (through the remote API) and then schedules the deployment.
... 8< ...
        var deployment = BundleManager.createBundleDeployment(bundleVersionId, destinationId, description, deploymentConfig);

        deployment = BundleManager.scheduleBundleDeployment(deployment.id, isCleanDeployment);
... 8< ...

8.3. Reverting a Bundle

Reverting a bundle automatically moves a destination one step backward, from whatever version is currently deployed to whatever version was last deployed.
This is done only with the remote API, not using any functions from the bundles.js file.
The method to run is scheduleRevertBundleDeployment. This requires two interesting pieces of information. The first is the destination ID, which can be retrieved with a simple criteria search.
rhqadmin@localhost:7080$ var destinationName = "NewDestination"
rhqadmin@localhost:7080$ var destCrit = new BundleDestinationCriteria()
rhqadmin@localhost:7080$ destCrit.addFilterName(destinationName)

rhqadmin@localhost:7080$ var dest = BundleManager.findBundleDestinationsByCriteria(destCrit)
The next, and more interesting, piece of information is the deployment description. The description is what is passed to the revert method to help identify the deployment to revert.
rhqadmin@localhost:7080$ var depCrit = new BundleDeploymentCriteria()
rhqadmin@localhost:7080$ depCrit.addFilterDestinationName(destinationName)
rhqadmin@localhost:7080$ var deploy = BundleManager.findBundleDeploymentsByCriteria(depCrit)
rhqadmin@localhost:7080$ var dep = deploy.get(0);
rhqadmin@localhost:7080$ var description = dep.description;
The last part actually invokes the method.
rhqadmin@localhost:7080$ BundleManager.scheduleRevertBundleDeployment(dest.get(0).id, description, true)