Coordinating build and deployment
Overview
The previous two documents described how to develop interfaces to build and deployment infrastructure (SimpleAntBuilder and SimpleTomcatService, respectively). This document describes how to use base framework types to coordinate those interfaces in order to create an end-to-end build and deployment process.
There are several goals for a unified build and deployment process:
- Shorten the release cycle
- Extend the concept of continuous integration
- Apply reusable consistent process across environments
This document assumes you have familiarized yourself with basic concepts and have setup ProjectBuilder finished the interfacing a build and also managing deployment.
Introducing Updaters and Sites
Before jumping in and setting up the objects to run the end to end build and deployment process, let's first get to know the two relevant framework base types, Updater and Site.
An Updater is responsible for coordinating the build process and the deployment process. It does this by mediating two framework objects, Builders and Sites. Builders are responsible for interfacing with the underlying build tools. Sites are objects that represent a set of related Service objects which also provide central point of control to coordinate deployment across a set of Services.
The figure below describes how the coordinated process is based on collaborating framework objects. The process begins with the Updater dispatching the Build command to the Builder, which in turn executes that workflow, checking code out of the source code repository building and putting packages into the release repository. Once the build phase completes, the Updater dispatches the Update command to the Site object, which in turn, relays the Update command to its Service objects. The Service objects execute their Update command sequence, processing and installing the packages produced by the Builder.

The Updater plays one more role during the process. The Updater automates package dependency reconfiguration. It does this by modifying Service to Package dependencies in such a way that the Services will drop their current set of dependencies and then switch dependencies to use a new set of packages produced by the Builders.
The whole process described is executed via the BuildAndUpdate workflow command in the Updater.

The base types are composed in a hierarchy described in the following composition diagram:

Defining simple's Updaters and Sites
With a basic exposure to the types involved in the build and deployment process, we are ready to actually define a set of objects that will allow us to coordinate the SimpleAntBuilder and SimpleTomcatService objects defined in the last two documents.
For our simple example, we will use the Updater and Site types and do not need to create subtypes. The generic functionality of these two types are sufficient for our needs.
File listing: simpleUpdater.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE project PUBLIC "-//ControlTier Software Inc.//DTD Project Document 1.0//EN"
"project.dtd">
<project>
<deployment
name="simple" type="Site"
description="The simple site"
>
<!--
**
** Dependencies
**
-->
<resources replace="false">
<resource type="SimpleTomcatService" name="simple"/>
</resources>
<!--
**
** References where this site is hosted:
** (replace localhost with the name of your node)
-->
<referrers replace="false">
<resource type="Node" name="localhost"/>
</referrers>
</deployment>
<deployment
name="simple" type="Updater"
description="Coordinates the build and update of simple"
>
<!--
**
** Dependencies
**
-->
<resources replace="false">
<resource type="Site" name="simple"/>
<resource type="SimpleAntBuilder" name="tutorial"/>
</resources>
<!--
**
** References where this tomcat is hosted:
** (replace localhost with the name of your node)
-->
<referrers replace="false">
<resource type="Node" name="localhost"/>
</referrers>
</deployment>
</project>
Load the data
ctl -p default -m ProjectBuilder -c load-objects -- \ -filename simpleUpdater.xml
The diagram below describes the resulting shape of the dependency model.

From Workbench, you will see the Updater object in the following screenshot:

Before you can run any commands, ensure the objects are installed in CTL:
ctl-depot -p default -a install defaulting to project: default "Install" command running for object: (SimpleTomcatService) simple "Install" command running for object: (SimpleAntBuilder) tutorial "Install" command running for object: (Site) simple "Install" command running for object: (Updater) simple
From CTL, one can view the data about the Updater object using the Properties command:
ctl -p default -t Updater -o simple -c Properties -- -nochildinfo [MULTI_LINE] # simple [Updater] # Coordinates the build and update of simple ## Attributes ## * basedir: "/Users/alexh/simple/src" * defaultAllowMultiplePackageMatches: "false" * defaultDeploymentType: "Deployment" * defaultFailIfPackageNotReplaced: "true" * defaultPackageName: "^$" * defaultPackageType: "Package" * dispatchBaseType: "(?:service|deployment|mediator)" * dispatchChangeDependencies: "false" * dispatchExecutionStrategy: "nodedispatch" * dispatchOptions: "" * dispatchResourceName: ".*" * dispatchResourceType: "[^\.]*Site" * dispatchSortOrder: "ascending" * targetdir: "/Users/alexh/simple/target" * threadCount: "1" * updaterNotificationList: "" ## Dependencies ## ### Parent Dependencies ### 1. strongbad [Node] ### Child Dependencies ### 1. tutorial [SimpleAntBuilder] 2. simple [Site] - - - [/MULTI_LINE] ...
Test the commands
With the objects created and bound together via dependencies, we can begin running the Updater commands. We'll run through them in the order that they would run via BuildAndUpdate. It is also important to point out that these commands come in handy whenever it is desirable to run just part of the end-to-end process.
Run Build
The Build command iterates over all Builder object dependencies and for each one, dispatches to it, the Build command. This command also takes advantage of the CTL "nodedispatch" execution strategy which will execute the command locally or remotely depending on where the Builder object resides.
ctl -p default -t Updater -o simple -c Build -- -buildstamp 123
Run Change-Dependencies
You may have noticed we did not create a Service-to-Package dependency to support the deployment process in the define object dependencies section. While we could have used Register-Dependency to bind (SimpleTomcatService) tutorial -> (war) simple-123.war we will leave that to the Updater Change-Dependencies command.
Change-Dependencies works by searching for all Services that are part of the Sites managed by the Updater and then searches for objects of Package types allowed by the model, filtering those by buildstamp and then swaps the dependencies. If an equal set of packages are found, the command will complete on its own. If there are any ambiguities, Change-Dependencies will prompt you. There is also a command line flag to provide a standard answer to avoid prompting.
ctl -p default -t Updater -o simple -c Change-Dependencies -- -buildstamp 123
Again, the Get-Properties command is useful to confirm the results. Query the affected service object and check for a package child dependency. It should show simple-123.war:
ctl -p default -t SimpleTomcatService -o simple -c Get-Properties -- -print
[MULTI_LINE]
# simple [SimpleTomcatService] #
A simple Service to interface with Tomcat
## Attributes ##
* basedir: "/Users/ctier/simple/tomcat"
* catalinaHttpPort: "8081"
* install-root: "/Users/ctier/simple/tomcat"
## Dependencies ##
### Parent Dependencies ###
1. strongbad [Node]
2. simple [Site]
### Child Dependencies ###
1. simple-123.war [war]
* doc: ""
* package-arch: "noarch"
* package-base: "simple"
* package-buildtime: "20082522022537"
* package-filename: "simple.war"
* package-filetype: "war"
* package-install-rank: "0"
* package-install-root: "/Users/ctier/simple/tomcat/webapps"
* package-release: "0"
* package-release-tag: ""
* package-repo-url: "http://strongbad:8080/jackrabbit/repository/workbench/pkgs/default/war/wars/simple-123.war"
* package-restart: "false"
* package-vendor: ""
* package-version: "123"
- - -
[/MULTI_LINE]
Run Update
The Update command iterates over all Site object dependencies and for each one, dispatches to it, the Update command. This command also takes advantage of the CTL "nodedispatch" execution strategy which will execute the command locally or remotely depending on where the Site object resides.
ctl -p default -t Updater -o simple -c Update -- -buildstamp 123 Start: "Changes package dependencies and runs the coordinated deployment cycle across the configured Sites." commands: Change-Dependencies,Deploy begin workflow command (1/2) -> "Change-Dependencies -buildstamp 123 -resourcename .* -resourcetype [^\.]*" ... ... begin workflow command (2/2) -> "Deploy -buildstamp 123 -resourcename .* -resourcetype [^\.]*" ... ... dispatching to object: simple [Site] -> "Deploy " ... dispatching to object: simple [SimpleTomcatService] -> "Deploy " ... begin workflow command (1/4) -> "Stop " ... ... begin workflow command (2/4) -> "Packages-Install " ... Start: "Install the configured package dependencies for the deployment." Beginning installation for packages: (war) simple-123.war ... ... Now running package-install for this package ... running war command: prepare running war command: get Getting: http://strongbad:8080/jackrabbit/repository/workbench/pkgs/default/war/wars/simple-123.war ... Expanding: /Users/ctier/simple/tomcat/webapps/simple.war into /Users/ctier/simple/tomcat/webapps/simple running war command: finish ... begin workflow command (3/4) -> "Configure " ... ... begin workflow command (4/4) -> "Start " ... ... end Update workflow command (2/2) -> "Deploy -buildstamp 123 -resourcename .* -resourcetype [^\.]*"
The Site object also uses the "nodedispatch" execution strategy when dispatching the Update command to its Service object dependencies.
Run BuildAndUpdate
Now that each of the three Updater commands have been individually tested, we can be confident the end-to-end process should work without a hitch.
ctl -p default -t Updater -o simple -c BuildAndUpdate -- -buildstamp 123
Assuming you are running Tomcat on port 8081, you should be able to access the simple webapp via the URL http://localhost:8081/simple.
The BuildAndUpdate workflow command sequenced through: Build, Change-Dependencies and Update. Those commands in turn delegated actions to workflows executed by SimpleAntBuilder and SimpleTomcatService objects. The end-to-end process exhibited by BuildAndUpdate really exemplifies the parts of the framework working together.
The command implementations defined along the way were each very simple and organized into their own modules. Because the ControlTier server maintains a live integrated view of the dependency model no commands needed to be hardcoded with deployment-to-machine information, this same workflow could be used to build and deploy to different environments. The framework is also very flexible in that we can easily add new Builders and Services as the application evolves.
Next steps
This guide provided an introduction to developing a ControlTier project using ProjectBuilder. It presented a general overview of the basic framework types and how you interface your tools by defining new types. These examples should give you a sense of the typical type development cycle: edit type.xml and command implementations, run build-type, register objects and then test commands.
From this point you might aquaint yourself with other commands available in ProjectBuilder by reviewing the ProjectBuilder reference. You might want to understand the command dispatching environment provided by CTL by reading CTL concepts.
The motivation behind ProjectBuilder is to make the developer's life easier so feel free to send feedback to the mailing list if you have ideas to improve it.


