Last Updated Jan 04, 2015 — DevOps Expert
XL Deploy Variables Demystified : Part 1
DevOps
A lot of new people starting on XL Deploy always get these questions in mind,
"How do it get to know what variables i could use in my script ?" "What variable are exposed by Freemarker ?" "Maybe ${deployed.id} might work to give me the right value?" Finally to answer all those questions, here's a freemarker snippet which exposes all the variables ( I mean, not all.. that will be too much ) that can be used in the script to derive values from types, deployeds, containers and what not. At the end of the day, its all java objects embedded in freemarker context so there's much more information like the methods exposed in there apart from just the properties. So without wasting any further time, here the code..<#-- This function recursively digs the values of variables exposed for use in script --> <#function dig obj level depth captureMethod> <#assign result =[] > <#assign result = result + ["Complex Object: " + obj] > <#assign prefix=".vars.${obj}" > <#if prefix?eval??> <#if prefix?eval?is_hash_ex > <#list prefix?eval?keys as key> <#assign basevar="${obj}.${key}" > <#attempt> <#assign valuevar="${basevar}"?eval > <#if valuevar?is_method > <#if captureMethod > <#assign result = result + [r"METHOD: ${" + basevar + r"(...)}"] > </#if> <#else> <#if valuevar?is_string || valuevar?is_boolean || valuevar?is_number> <#assign result = result + [r"PROPERTY: ${" + basevar + r"} || VALUE: " + valuevar?string] > </#if> <#if valuevar?is_enumerable> <#assign result = result + [r"PROPERTY: ${" + basevar + r"} || TYPE : LIST "] > </#if> <#if valuevar?is_hash_ex > <#if level < depth > <#assign result = result + dig(basevar,level + 1,depth, captureMethod) > </#if> </#if> </#if> <#recover> <#assign result = result + [r"PROPERTY: ${" + basevar + r"} || VALUE: (UNDEFINED/UNRESOLVED) "]> </#attempt> </#list> <#else> <#assign result = result + [" Cannot be parsed as {" + obj + "} is not a hash or simple property"] > </#if> </#if> <#return result> </#function> <#-- Macro initiates variable digging and then prints them --> <#macro variableList depth captureMethod> <#assign result=[]> <#list .data_model?keys as keyouter> <#assign result = result + dig(keyouter, 0, depth, captureMethod)> </#list> VARIABLE LISTING TILL DEPTH: ${depth} ===================================== <#list result as item> ${item} </#list> </#macro> <#-- Specify the depth till which to explore --> <@variableList depth=0 captureMethod=false/>This code snippet can be copied into a script that is used with XLD artifacts as a createScript. It can be used with generic plugin and with XL-rules and any other plugins that have execution scripts specified such that they show up under plan analyzer and can be opened by double clicking eyeball icon. This script would expose all the variables and the properties with them. It works recursively so you can specify the what level of depth you want to go to. eg. base depth is 0. so setting depth=1, will show properties like deployed.container.os. It prints the value of literal properties, also lists the methods available with objects is captureMethod=true. For generic plugin, with captureMethod=false, output shows up like this.
VARIABLE LISTING TILL DEPTH: 0 ===================================== Complex Object: deployed PROPERTY: ${deployed.createScript} || VALUE: script/osscript.sh.ftl PROPERTY: ${deployed.remoteWorkingDirectoryPath} || VALUE: (UNDEFINED/UNRESOLVED) PROPERTY: ${deployed.inspectScript} || VALUE: (UNDEFINED/UNRESOLVED) PROPERTY: ${deployed.planOperation} || VALUE: CREATE PROPERTY: ${deployed.modifyScript} || VALUE: (UNDEFINED/UNRESOLVED) PROPERTY: ${deployed.noopOrder} || VALUE: 50 PROPERTY: ${deployed.modifyOrder} || VALUE: 50 PROPERTY: ${deployed.noopScript} || VALUE: (UNDEFINED/UNRESOLVED) PROPERTY: ${deployed.$ciAttributes} || VALUE: com.xebialabs.XL Deploy.plugin.api.udm.CiAttributes@42472788 PROPERTY: ${deployed.noopVerb} || VALUE: Modify PROPERTY: ${deployed.destroyVerb} || VALUE: Destroy PROPERTY: ${deployed.retainRemoteWorkingDirectory} || VALUE: false PROPERTY: ${deployed.destroyScript} || VALUE: (UNDEFINED/UNRESOLVED) PROPERTY: ${deployed.createVerb} || VALUE: Create PROPERTY: ${deployed.type} || VALUE: test.scripttype1 PROPERTY: ${deployed.restartRequired} || VALUE: false PROPERTY: ${deployed.class} || VALUE: class com.xebialabs.XL Deploy.plugin.generic.deployed.ExecutedScript PROPERTY: ${deployed.createOrder} || VALUE: 50 PROPERTY: ${deployed.modifyVerb} || VALUE: Modify PROPERTY: ${deployed.id} || VALUE: Infrastructure/local/newtype PROPERTY: ${deployed.name} || VALUE: newtype PROPERTY: ${deployed.destroyOrder} || VALUE: 40 PROPERTY: ${deployed.$token} || VALUE: (UNDEFINED/UNRESOLVED) PROPERTY: ${deployed.restartRequiredForNoop} || VALUE: false Complex Object: step PROPERTY: ${step.uploadedArtifactPath} || VALUE: (UNDEFINED/UNRESOLVED) PROPERTY: ${step.hostFileSeparator} || VALUE: / PROPERTY: ${step.localConnection} || VALUE: local: PROPERTY: ${step.retainRemoteWorkingDirOnCompletion} || VALUE: false PROPERTY: ${step.hostLineSeparator} || VALUE: PROPERTY: ${step.scriptTemplatePath} || VALUE: script/osscript.sh.ftl PROPERTY: ${step.class} || VALUE: class com.xebialabs.XL Deploy.plugin.generic.step.ScriptExecutionStep PROPERTY: ${step.preview} || VALUE: com.xebialabs.XL Deploy.plugin.api.flow.Preview@552fae2e PROPERTY: ${step.remoteWorkingDirPath} || VALUE: (UNDEFINED/UNRESOLVED) PROPERTY: ${step.remoteConnection} || VALUE: local: PROPERTY: ${step.scriptPath} || VALUE: script/osscript.sh.ftl PROPERTY: ${step.artifact} || VALUE: (UNDEFINED/UNRESOLVED) PROPERTY: ${step.remoteWorkingDirectory} || VALUE: local:/var/folders/mf/wyk69xfn6_nfg04s6vt4gjrw0000gn/T/ot-20150101T191228243/generic_plugin.tmp Complex Object: statics Cannot be parsed as {statics} is not a hash or simple propertyFor XL-Rules, with captureMethod=true, output shows like this.
VARIABLE LISTING TILL DEPTH: 0 ===================================== Complex Object: deployed METHOD: ${deployed.putSyntheticProperty(...)} METHOD: ${deployed.hasSyntheticProperty(...)} METHOD: ${deployed.get$ciAttributes(...)} METHOD: ${deployed.getSyntheticProperties(...)} METHOD: ${deployed.hashCode(...)} PROPERTY: ${deployed.type} || VALUE: test.scripttype METHOD: ${deployed.putSyntheticProperties(...)} METHOD: ${deployed.setDeployable(...)} PROPERTY: ${deployed.id} || VALUE: Infrastructure/local/osscript METHOD: ${deployed.getType(...)} METHOD: ${deployed.setContainer(...)} METHOD: ${deployed.getSyntheticProperty(...)} PROPERTY: ${deployed.name} || VALUE: osscript METHOD: ${deployed.setId(...)} METHOD: ${deployed.get$token(...)} METHOD: ${deployed.getId(...)} METHOD: ${deployed.getClass(...)} METHOD: ${deployed.getContainer(...)} METHOD: ${deployed.hasProperty(...)} METHOD: ${deployed.equals(...)} METHOD: ${deployed.setType(...)} PROPERTY: ${deployed.class} || VALUE: class com.xebialabs.XL Deploy.plugin.api.udm.base.BaseDeployed METHOD: ${deployed.compareTo(...)} PROPERTY: ${deployed.$token} || VALUE: (UNDEFINED/UNRESOLVED) METHOD: ${deployed.setProperty(...)} METHOD: ${deployed.set$token(...)} PROPERTY: ${deployed.$ciAttributes} || VALUE: com.xebialabs.XL Deploy.plugin.api.udm.CiAttributes@54707e93 METHOD: ${deployed.setSyntheticProperties(...)} METHOD: ${deployed.getName(...)} METHOD: ${deployed.getProperty(...)} METHOD: ${deployed.set$ciAttributes(...)} METHOD: ${deployed.getDeployable(...)} METHOD: ${deployed.toString(...)}Now this Freemarker snippet can be used wherever a free marker context is available. It gives you convenient output if you include it in a script that shows up in plan analyzer while planning for deployment. NOTE: This won't work for jython step in XL-rules since that doesn't exposes the freemarker contextIMPORTANT : If you use this with generic or another plugin except XL-rules, it will mostly include 3 top level variables that will be explored further. deployed, step and statics.statics : is not explored since its not of type hash or a simple typestep : when this is being explored, you'll see a lot of exceptions being generated in the log and it takes a lot of time but it would still show up in a while. Exception are generated while trying to find out values of certain properties who are unresolved at that point and throws exceptions. TIP: Prefer keeping depth=0 or depth=1 if you prefer to use it with plugins other than XL-rules. Or if you're just more interested in getting details of deployed, you can do this
- Comment out this block in the snippet
<#-- <#list .data_model?keys as keyouter> <#assign result = result + dig(keyouter, 0, depth, captureMethod)> </#list> -->
- Replace the block with just this line.
<#assign result = result + dig("deployed", 0, depth, captureMethod)>
- Then you can specify a higher depth.
- Create a new type in synthetic.xml
<!-- example with xl-rules --> <type type="test.scripttype" deployable-type="test.scriptdeployable" extends="udm.BaseDeployed" container-type="overthere.LocalHost"> <generate-deployable type="test.scriptdeployable" extends="udm.BaseDeployable" /> </type> <!-- example with generic plugin --> <type type="test.scripttype1" deployable-type="test.scriptdeployable1" extends="generic.ExecutedScript" > <generate-deployable type="test.scriptdeployable1" extends="generic.Resource" /> <property name="createScript" default="script/osscript.sh.ftl" /> </type>
- Create a new rule in xl-rules.xml
<rule name="scriptrule" scope="deployed"> <conditions> <type>test.scripttype</type> <operation>CREATE</operation> <operation>MODIFY</operation> <operation>DESTROY</operation> </conditions> <steps> <os-script> <script>script/osscript.sh.ftl</script> <freemarker-context> <delta expression="true">delta</delta> </freemarker-context> </os-script> </steps> </rule>
- Create a folder script under XLDEPLOY_HOME/ext folder and create a new file called osscript.sh.ftl under that folder
- Copy the above free marker snippet into that file
- Restart server
- Create new Application or include "test.scriptdeployable" type under existing package. This type will deploy on overthere.LocalHost by default. You may change the type to deploy on any container type.
- Now start a new deployment and open the Plan Analyzer after mapping the type to container.
- You should be able to see the output of variable list on double clicking the script.