Using XL Deploy Rules to Inject Custom Deployment Actions
I had marked today on my calendar as a day of preparation for the POCs I have coming up this month, it's a day I always enjoy as it gives me a chance to get into our technology and have some fun building things. Before I get into my main topic I do want to highlight that the majority of customers deployment requirements are meet by our solution out of the box, but there is usually a couple of key points for the prospect where we have a gap to close. This is where having some great and easy to use extensibility options comes into it's own. XL Deploy has a number of points where we can modify it's behavior, but all of these fit together, so for example interrogating a Environment object looks the same using our CLI, our REST API or our internal Jython API, so learn once and use many!So, to come back to my main topic, for a particular POC I need to add a deployment step to take any dictionaries used for the deployment and commit them to Subversion at the end of the deployment. To do this I have decided to use the Rules mechanism which was made available in XL Deploy 4.5. In particular I created a post-plan rule, which will fire at the end of a deployment. There are 2 main parts to this rule, the first is definition in xl-rules.xml (which is in the ext directory of a XL Deploy installation). The XML I added is:
<rule name="CommitDictionaryToSVN" scope="post-plan"> <steps> <jython> <order>60</order> <description>Commit dictionary to SVN</description> <script-path>dictCommit/retrieveAndCommitDictionary.py</script-path> <jython-context> <dicts expression="true">context.deployedApplication.environment.dictionaries</dicts> </jython-context> </jython> </steps> </rule>There are a couple of key items worth calling out in the above. First is the contents of the "script-path" tag, this points to the Jython script which this rule will invoke internally to the XL Deploy server. More information on this is in the Jython step reference. The second is the "jython-context" tag. The tag in here creates a "dicts" variable which I can use in the script below, and the value of that is from the Jython expression "context.deployedApplication.environment.dictionaries", which is the dictionaries in my deployment environment. So the XML above will add a step to my deployment plan at the end to run the script "dictCommit/retrieveAndCommitDictionary.py". This script is below:
import commands for dict in dicts: fileName = dict.name.rpartition('/') fileName = fileName + '.txt' file = open('/tmp/xld_temp/' + fileName, 'w') for entry in dict.entries: file.write(entry + '=' + dict.entries[entry] + '\n') file.close()This script is actually partial, it doesn't do the SVN commit. Right now it will look over the dictionaries, which we can get to through the "dicts" variable, and write each one out to a file ('/tmp/xld_temp/$DICTIONARY_NAME.txt') with lines in the form:
KEY=VALUEI have already imported the commands Jython module and I'll use this once onsite to run the commit command, I expect to add a line at the end similar to the following:
commands.getoutput('svn commit -m "Dictionary from deployment"')Of course, I could calculate the message text, maybe add in application and environment name. To do this I would just need to add these variables to the "jython-context" in the XML portion and use them in the script. The Rules manual describes what is averrable for you to use. Finally, what does this look like in XL Deploy, here is an example deployment with the new rule in the "Finalize deployment" section, ready to run. It's pretty quick to get a rule implemented and easy to modify the behavior of your deployments. It's important to note that here we are not specifying out a workflow or describing the specific steps to deploy an application. We are changing how XL Deploy builds it's deployment plans in a way we can track, for example in source control. This means that we can retain the automatically generated plans which will take account of application or environment changes without our intervention while still adding anything specific a scenario calls for.