on 23-Feb-2012 08:22
An iApp is a user-customizable framework for deploying applications. It consists of three components: Templates, Application Services, and Analytics.
In this article, I will illustrate the format of a packaged template and how you would use the modular iControl calls to support importing and exporting with that format.
Since templates consist of several pieces, the BIG-IP dev team created a packaging format for all of the data used to configure them. This is what we refer to as a .tmpl file. A .tmpl file is a text file that follows the following format (as of BIG-IP version 11.1):
sys application template <template_name> { actions { definition { html-help { # HTML Help for the template } implementation { # TMSH implementation code } presentation { # APL presentation language } role-acl <security role> run-as <user context> } } description <template description> partition <partition name> }
The first line is the term “sys application template” followed by the template name. The template section contains the following sections:
The action (or definition) contains the following configuration elements
the presentation help component of an application template is just plain HTML with a few restrictions. We’ve blocked out components such as iframes, scripts, tables, and a few other components that could cause security implications or page formatting problems when displayed within the BIG-IP GUI. The API methods to access the presentation help are the Management::ApplicationTemplate::get_action_presentation_help() and set_action_presentation_help() methods. The get method, returns the list of help sections for the specified templates, while the set method passes them in as input. Remember, as of version 11.1, “definition” is the only supported action.
String [][] Management::ApplicationTemplate::get_action_presentation_help( in String [] templates, in String [][] actions ); Management::ApplicationTemplate::set_action_presentation_help( in String [] templates, in String [][] actions, in String [][] values );
The implementation is just another text block that contains the tmsh code used when creating the application service. The two methods used to get at this are the get_action_implementation() and set_action_implementation() methods that work in a very similar fashion to the presentation help methods.
String [][] Management::ApplicationTemplate::get_action_implementation( in String [] templates, in String [][] actions ); Management::ApplicationTemplate::set_action_implementation( in String [] templates, in String [][] actions, in String [][] values );
The presentation layer is another text block that contains the APL code that describes how the user interface presentation components are displayed. The get_action_presentation() and set_action_presentation() methods are used to get and set these values.
String [][] Management::ApplicationTemplate::get_action_presentation( in String [] templates, in String [][] actions ); Management::ApplicationTemplate::set_action_presentation( in String [] templates, in String [][] actions, in String [][] values );
The one last piece that we have exposed through iControl is the description meta-data field. The get_description() and set_description() methods are used to retrieve these values.
String [] Management::ApplicationTemplate::get_description( in String [] templates ); Management::ApplicationTemplate::set_description( in String [] templates, in String [] values );
Exporting to a .tmpl file is as simple as querying the various components and packaging them up in the .tmpl file format. The first step is to create a local PowerShell object containing the relevant template configuration data. The New-Template function does just this:
function New-Template() { $t = 1 | Select Name, Description, HtmlHelp, Implementation, Presentation; $t; }
Now comes the fun of creating a .tmpl file and saving it locally. The Export-Template function takes as parameters the name of the local template file, the name of the template on the BIG-IP. The iControl methods are called to query the description, implementation, presentation, and presentation help and stored in the Template variable $t. The $s variable is used to store the string representation of the .tmpl file.
The various sections of the .tmpl are created and then the .tmpl file is saved to disk.
function Export-Template() { param( $TemplateFile = $null, $TemplateName = $null, [Boolean]$Force = $false ); $t = New-Template; $t.Name = $TemplateName; $descA = (Get-F5.iControl).ManagementApplicationTemplate.get_description( @($t.Name) ); $implAofA = (Get-F5.iControl).ManagementApplicationTemplate.get_action_implementation( @($t.Name), @( @("definition")) ); $presAofA = (Get-F5.iControl).ManagementApplicationTemplate.get_action_presentation( @($t.Name), @( @("definition")) ); $helpAofA = (Get-F5.iControl).ManagementApplicationTemplate.get_action_presentation_help( @($t.Name), @( @("definition")) ); $t.Description = $descA[0]; if ( $t.Description.Length -eq 0 ) { $t.Description = "none"; } $t.Implementation = $implAofA[0][0]; $t.Presentation = $presAofA[0][0]; $t.HtmlHelp = $helpAofA[0][0]; $s = "sys application template "; $s += Split-Path -Leaf $t.Name; $s += " {`r`n"; # Begin Action $s += " "*4; $s += "actions {`r`n"; # Begin definition $s += " "*8; $s += "definition {`r`n"; # Help $s += " "*12; $s += "html-help {`r`n"; $s += $t.HtmlHelp; if ( $t.HtmlHelp.Length -gt 0 ) { $s += "`r`n"; } $s += "}`r`n"; # Implementation $s += " "*12; $s += "implementation {`r`n"; $s += $t.Implementation; if ( $t.Implementation.Length -gt 0 ) { $s += "`r`n"; } $s += "}`r`n"; # Presentation $s += " "*12; $s += "presentation {`r`n"; $s += $t.Presentation; if ( $t.Presentation.Length -gt 0 ) { $s += "`r`n"; } $s += "}`r`n"; $s += " "*12; $s += "role-acl none`r`n"; $s += " "*12; $s += "run-as none`r`n"; # End Definition $s += " "*8; $s += "}`r`n"; # End Action $s += " "*4; $s += "}`r`n"; $s += " "*4; $s += "description $($t.Description)`r`n"; $s += " "*4; $s += "partition $( (Split-Path $t.Name).SubString(1) )`r`n"; #End template $s += "}"; if ( $null -eq $TemplateFile ) { $TemplateFile = ".\Templates\" + (Split-Path -Leaf $t.Name) + ".tmpl"; } $s | Out-File $TemplateFile; Write-Host "Template '$TemplateName' saved to file '$TemplateFile'"; }
Once you have exported a .tmpl file (whether via iControl, the BIG-IP admin GUI, or from the iApp CodeShare on DevCentral), you may want to import them back onto the device. You can do this through the GUI, but’s that no fun. I’m going to show you how to do it programmatically.
The Import-Template function takes as input a local .tmpl file along with a Force flag to indicate whether you want to overwrite the application template if it already exists.
The content is read into the $content variable and then it’s passed into the Parse-Template function described in the next section. The Management::ApplicationTemplate::create() method is used to create the new empty template. If an exception is thrown (most likely due to prior existence), then the Force flag is used to determine whether we will overwrite the existing template. If not, an error message occurs and processing halts.
If either the template is new or we are overwriting it, the iControl methods are used to set the implementation, presentation,and presentation help for the template on the BIG-IP. At this point, the template has been imported.
function Import-Template() { param( $TemplateFile = $null, [Boolean]$Force = $false ); $content = [System.IO.File]::ReadAllText((Resolve-Path $TemplateFile).Path) $t = Parse-Template -Template $content; $bContinue = $true; if ( $null -ne $t ) { Write-Host "CREATING Template: '$($t.Name)'..."; try { (Get-F5.iControl).ManagementApplicationTemplate.create( @($t.Name) ); } catch { $bContinue = $Force; if ( $bContinue ) { Write-Host "Template exists, overwriting..."; } else { Write-Host "Template exists, stopping import. Use '-Force' to overwrite."; } } if ( $bContinue ) { Write-Host "SETTING IMPLEMENTATION..."; (Get-F5.iControl).ManagementApplicationTemplate.set_action_implementation( @($t.Name), @( @("definition")), @( @($t.Implementation)) ); Write-Host "SETTING PRESENTATION..."; (Get-F5.iControl).ManagementApplicationTemplate.set_action_presentation( @($t.Name), @( @("definition")), @( @($t.Presentation)) ); Write-Host "SETTING PRESENTATION HELP..."; (Get-F5.iControl).ManagementApplicationTemplate.set_action_presentation_help( @($t.Name), @( @("definition")), @( @($t.HtmlHelp)) ); } } }
As I mentioned above, there are a few utility methods used to parse the template file. The Parse-Template method takes in the whole content of a template file and extracts the various sections into a new Template object and returns it to the caller.
function Parse-Template() { param($Template = $null); $t = $null; if ( $Template.StartsWith("sys application template") ) { $t = New-Template; $t.Name = Get-NextToken $Template "sys application template"; $definition = Extract-Section $Template "definition"; $t.HtmlHelp = Extract-Section $definition "html-help"; $t.Implementation = Extract-Section $definition "implementation"; $t.Presentation = Extract-Section $definition "presentation"; } $t; } function Extract-Section() { param($Template = $null, $Section = $null ); $Value = $null; $idxStart = $Template.IndexOf("$Section {"); $idxEnd = -1; if ( -1 -ne $idxStart ) { $idxStart += $Section.Length + 2; $p = 1; for($i = $idxStart; $i -lt $Template.Length; $i++) { switch ($Template[$i]) { "{" { $p++; } "}" { $p--; if ( $p -eq 0 ) { $idxEnd = $i; $i = $Template.Length; break; } } } } if ( -1 -ne $idxEnd ) { $Value = $Template.SubString($idxStart, $idxEnd-$idxStart).Trim(); } } $Value; }
Armed with the functions in this script, you can now interoperate with the application template formats generated by the the BIG-IP administrative GUI and the DevCentral CodeShare.
The entire source for this sample can be downloaded from the iControl CodeShare under the topic PowerShelliAppTemplateControl.