You are on page 1of 21

iApps Template Authoring

Tutorial 1
iApp(ed to get tired of these joke)s
or
Creating Your First iApps Template

Part 0: What is This?


This tutorial aims to get you started on creating and modifying iApps templates. Primarily the latter. It’s
not intended to make you an iApps expert but rather get you to the point where you understand the
framework well enough to modify the F5 suppliied iApps Templates or a template you download from
Devcentral.

Tutorial 1 - Primarily covers the presentation portion of developing an iApps Template but aims to get
you to the point where you can author a working iApps template and perhaps understand the built in
templates a bit better.

Tutorial 2 – Will go into producing an implementation section that actually does something.

Part 1: Overview of iApps

Stolen directly from the developers guide:

iApps is the BIG-IP system framework for deploying services-based, template-driven configurations on
BIG-IP systems running TMOS 11.0.0 and later. iApps allows creation of application-centric configuration
interfaces on BIG-IP, reducing configuration time and increasing accuracy of complex traffic
management configurations.

What’s that mean in English? Let’s break it down.

“iApps is the BIG-IP system framework”: iApps is a framework. That means it’s a collection of
components designed to make it easier for you to develop something bigger and better.
“services-based, template-driven configurations”: How do we think of the products we deploy? Do we
think primarily about the servers they run on (pool members) or the IPs and ports our clients access
them through (Listener addresses) or the individual quirks of the protocols they run on (Profiles?) Or do
we think of them holistically as “application A” which encompases all of the above, as a service we are
delivering to our clients whomever they are? For me it’s the latter. The iApps framework allows you to
create and manage (this bit is important more on it later) applications or services rather than pools,
monitors, virtual servers, etc using templates.

“iApps allow creation of application-centric configuration interfaces”: Same

“reducing configuration time”: How many of you have deployed an Application Service via an iApps
template and seen it create 20 or 30 objects.

“and increasing accuracy”: Humans are dumb aren’t we? How many have been thrilled when the above
created things you may have forgotten to create like an http to https redirect? Any time a human being
has to do the same thing twice we introduce the possibility of error. If it can be automated reliability
increases greatly.

Not stolen from the developers guide.

The iApps framework consists primarily of two main components. They are:
Templates – Templates define the wizard that the user interacts with, the commands that create a
number of TMOS objects based on the users input and documentation.
Fig 1.1 The wizard produced by an iApps Template

Application Service – The Application is essentially the glue. It links all the iRules, Virtual Servers, Pools,
Nodes and other objects together as a single manageable unit.
Fig 1.2 a sample Application Service deployed.

By default the Application is intended to be managed through the application rather than by managing
each object separately this can be overridden by disabling “Strict Updates” however this is dis-
recommended.

Templates consist primarily of three components. These are not the three components you probably
have learned of in the past. First They contain some basic constraints, settings for minimum and/or
maximum TMOS version, a description and a list of required modules. Secondly they contain a definition
section which is where the meat of the template lies. Below is the default template which is what you
would see if you executed the tmsh command create /sys application template thisTemplate
create template thisTemplate {
actions replace-all-with {
definition {
html-help {
<!-- insert html help text -->
}
implementation {
# insert tmsh script
}
presentation {
# insert apl script
}
}
}
description none
requires-bigip-version-max none
requires-bigip-version-min none
requires-modules none
}
Fig 1.3 The default template definition

Lastly most iApps Templates contain this line


tmsh::include "f5.app_utils"

Which includes the built in iApps library. All built in F5 templates rely on this library. It provides a
number of very useful functions for managing BIG-IP objects. These tutorials will show you how to
create an iApps Template without using the library in order to give you an overview of how the
procedures within it function as well as the syntax. The intent is to help you understand f5.app_utils
enough to use it in your own templates.

The definition section is where the meat of the template lives and the power of iApps becomes really
evident. It contains three sections; help, Implementation and Presentation.

Presentation defines the wizard that you run through. It provides the text displayed and all the fields
and menus which collect data from the user. The data collected from the user is assigned to variables
which are available to the implementation script when it is executed.

Implementation does the actual work. It is a TMSH script which provides for the creation and
modification of objects such as Virtual Servers, Profiles and others.

Help provides the user with documentation on the features the template provides and what is expected
from the end user.

Part 2: Authoring an iApps Template


Follow along step by step to create HelloiApps and learn about this powerful and flexible but often
ignored tool.
Part 2.1: Presentation
We will begin by defining the presentation section which provides the user interface. iApps can be
created from within tmsh or from within your favorite text editor however for simplicities sake this
tutorial will be done through the management GUI.

The presentation is defined using APL, Application Presentation Language. The documentation for APL
can be found on DevCentral here: https://devcentral.f5.com/wiki/iApp.APL.ashx

1. Navigate to iApp > Templates and click create or click the plus in the flyout

2. The iApps Template editing screen will appear

Fig 2.1 A blank iApps Template

3. In “Template Name(s)” enter “HelloiApps”

4. For “Required BIG-IP Modules” Select LTM from the available list and click << to move it to the
selected list.
5. The first component we will add is called a section. Sections divide the wizard into logical groups
like “Virtual Server configuration” “Client side configuration” or whatever makes the template
easier to understand. Sections contain almost all other presentation elements. They are
required and cannot be nested. The syntax of a section is: section <section name> <section
definition>

a. Click in the presentation box and type the following:


section intro {

a. So here intro is the <section name> and the empty curly braces “{}” are the <section
definition>

6. Inside the section element, add a message element. The syntax of a message is: message
<message name> <message text>

a. Click in the presentation box and type the following:


message hello_message “Hello iApps!”

7. Click finish

Yay you’re done, you have now authored a Template. But what does it do? Let’s find out.

1. Go to Application Services and hit new (or hit the plus)

2. Leave the name blank for now we aren’t going to finish

3. Choose HelloiApps as the template

4. Gaze upon your first wizard it should look something like this

Fig 2.2 HelloiApps first run

As you can see it doesn’t do much. But we have so far only specified the text “Hello iApps!” Where did
the rest of that text come from? More importantly how do I change it?
Most of the text in APL is defined in the text string element of the template. By default if no text string is
defined then the wizard will display the element name. This is where both intro and hello come from.

The Text component is the exception to sections containing “almost all other elements.” The text
section is typically added at the end of the presentation and strings are defined by list of dot separated
elements which reference each of the previously defined elements.

Let’s add a text section now.

1. Re-open your template by navigating to iApp > Templates and clicking on the link HelloiApps

2. Below the intro section add the text section


text {

3. Within the text section we will add an element for each of the above elements.
text {
intro “Welcome to my first iApps Template”
intro.hello_message “The Application Service wizard says”
}
Note: beware smart quotes

4. Click save to update your template

5. Navigate back to iApp > Application Services and run your wizard again by clicking create or the
plus in the flyout.

6. You should now see something more like the below

Fig 2.3 A slightly better HelloiApps run


One Interesting note is that if your element names contain underscores they will be turned into spaces as seen in our first step.
The up-shot of this is that if you name your variables like The_Application_Service_Wizard_Says. You don’t need to provide a
text element for it. In the name of code legibility I hope you don’t do this but it’s neat to know that you can.

Now let’s collect some user input. We will go ahead and add all of the user input types just to get our
feet wet and because it’s fun. Note the syntax samples given in this tutorial are simplified. Many
elements contain more options than shown such as required or validation.

1. Re-open your Template

2. Add a new section called “my_variables”

3. Add a string element named my_first_string. The syntax of the string element is: string <string
name>

4. Next add a choice element named basic_choice. The syntax of the choice element is: choice
<choice name> <list of choices>

5. Next add a multichoice element named multi_choice. The syntax of the multichoice element is:
multichoice <multichoice name> <list of choices>

6. Next add an editchoice element named edit_choice. The syntax of the editchoice element is:
editchoice <editchoice name> <list of default choices>

7. You should end up with something like the following:


section intro {
message hello_message "Hello iApps!"
}
section my_variables {
string my_first_string
choice basic_choice {
"Be",
"Not Be"
}
multichoice multi_choice {
"Option 1",
"Option 2",
"Option C",
"It's good to know your options"
}
editchoice edit_choice {
"Option A",
"Option B",
"Option 3"
}
}
text {
# Look familiar? What is the name of our first section above?
intro "Welcome to my first iApps Template"
# And what is the only element it contains?
intro.hello "The Application Service wizard says"

# So this is the section title


my_variables "Lets collect some data"
# And everything here is question like "what address should this virtual server listen on?"
my_variables.my_first_string "Enter a string value."
my_variables.basic_choice "What is the question?"
my_variables.multi_choice "Choose a few options"
my_variables.edit_choice "Choose more flexible options"
}
Fig 2.4 Moar Presentation

8. Save your template and then re-enter your wizard by creating a service

9. Experiment with the various input options


Fig 2.5 Experiment With the Inputs

Nice but it still lacks something. What about the fancy user inputs like adding multiple pool elements
and hidden options?

Value Elements are the APL elements which collect user input. Above are ALL of the Value elements. We
get fancier behavior by adding a Layout Element called “table” and a Functional Element called Optional.
Let’s see how these work. Let’s also snap up our choice box by specifying a default choice.

1. Edit your template

2. Within the my_variables section add another choice called fancy_yes_no. This time, between
the name and the options add a default like so:
choice fancy_yes_no default "Nope" {
#Without the default statement this would use "Sure" as the default
"Sure",
"Nope"
}
3. Next add an optional section which will only display if the value of fancy_yes_no is “Sure”
optional ( fancy_yes_no == "Sure" ) {
# Message does actually require a message body though it could be ""
message pool_members "IP and Port for back end pool members of your favorate virtual server."
table pool_member {
string address
string port
}
# This is a fancy choice box. We will see how it works later
choice load_balancing_method {
"Round Robin" => "round-robin",
"Least Connections" => "least-connections"
}
}
4. And finally let’s not forget to add text strings for the new options.
my_variables.fancy_yes_no "Do you want to show the hidden options?"
my_variables.pool_members "Now things are starting to get hot"
my_variables.pool_member "Member:"
# This one is a bit more complex...
my_variables.pool_member.address "Server address:"
my_variables.pool_member.port "Port"
my_variables.load_balancing_method "Which is better?"
# Notice anything missing? What about that 'optional' command? Optional tells the bigip to only display
contents if specific criteria are met. It doesn’t have a display element of it’s own which is why we needed the
pool_members message element
5. Save your template and re-enter its wizard and see what the new elements give us.

Part 2.2: Help


Why? Because otherwise you wouldn’t do it. I don’t trust you people. ^_-

I know it sounds a little arrogant but in my opinion documentation is non-optional and I know I’m not
alone. I also know however that documentation takes a back seat and then we have the following scene:

- sounds of typing. -

Bob the consultant – “There, it works. Now the help section”


- sounds of typing. -

Bob the consultant – “Wait, why isn’t the help showing up? Darn, must be something wrong
with my syntax. I’ll have to come back to it.”

We all know where this goes. To prevent it. I’m not going to teach you the implementation until after
you learn the help. Don’t worry it’s short, it’s basically text with a few HTML commands supported. It
will hurt less than the dentist I swear.

The Help section supports about two dozen HTML tags for defining your help. The tags we care the most
about right now are:
h1 – The highest level of header. Creates a bolded title with an underline
h2 – Creates a bolded title with no underline

p – Paragraph. Creates a block of text

ul – Unsorted List. Creates a list of bulleted items

li – list element. Each and every item within the ul

1. Edit your presentation section

2. Within the help section add the following:


<h1>Hello iApps!</h1>
<p>This is an iApp lab to learn how to author iApps Templates.</p>
<h1>Sections</h1>
<h2>1. Intro</h2>
<p>Just an intro with a description</p>
<h2>2. Variables (Let's collect some variables)</h2>
<p>This is where we are actually collecting variables</p>
<p><b>Enter a string value</b></p>
<p>Really, just enter a value</p>
<p><b>Choose a few options</b></p>
<ul>
<li><b>Option 1</b> - The first option.</li>
<li><b>Option 2</b> - The second option.</li>
<li><b>Option C</b> - The third option.</li>
<li><b>It's good to know your options</b> - The silliest of all the options</li>
</ul>

3. Save your template

4. Re-enter the template’s wizard and view the help tab to see how each of those items worked.
Fig 2.6 Help!

See, painless. See the Developers guide for a complete list of the HTML elements that can be used in the
help section or just use the above as a starting point. Optionally, my feelings wouldn’t be hurt if you
chose to use message elements for your documentation instead of help. This combined with the
optional element can provide nice in-line help with basic and advanced (or detailed) instructions.

Part 2.3: Implementation

We’ve written a template that can collect user data. Now let’s actually DO something with it.

1. Edit your template

2. Add the following in the implementation section


tmsh::log_dest file
tmsh::log_level err

puts "Values entered:"


puts "------------------------"
puts "My First String = |$::my_variables__my_first_string|"
puts "Basic Choice = |$::my_variables__basic_choice|"
puts "Multi Choice = |$::my_variables__multi_choice|"
puts "Edit Choice = |$::my_variables__edit_choice|"
puts "pool Members = |$::my_variables__pool_members|"
puts "Fancy Yes/No = |$::my_variables__fancy_yes_no|"
puts "LBMethod = |$::my_variables__load_balancing_method|"
puts "Another String = |$::my_variables__another_string|"

3. Save your template

User input data will be available to the tmsh portion of your Template (the implementation section) as
global variables. They will also retain their hierarchy the way that the elements do in the text section
except instead of being separated by dots here they are separated by a double underscore. IE
my_variables.my_first_string will be available as $::my_variables__my_first_string.

The pipes on either side of the variable are there for clarity in the log output and not required.

4. Now re-enter your templates wizard

5. This time name it “HelloiApps1”

6. Enter/choose something for every option

7. Click “Finished”

8. Bask in the glory of.. wait, what happened? Oh no, an error!


Let’s take a look at that implementation section again. What’s that at the end?
puts "Another String = |$::my_variables__another_string|"

There is no variable named another_string within my_variables.

1. In another browser tab edit your template and delete that line.
2. Save your template

3. Return to the browser tab where we are trying to deploy the application service and click
finished

4. This time it should complete and you should see the following:

So why did we specifically do this in another tab? This was to illustrate the disconnect between the
presentation and implementation sections. If this had been an iRule it would not have worked. Because
the iRule is loaded in memory when it is executed and making a change while it is still active in memory
would result in the active session not seeing the change. iApps differ from iRules in a number of ways.
One of them is that the tmsh script portion* of the template (the implementation section) does not exist
until the user clicks finished.

Now let’s check the logs. “puts” is the TCL command to write to stdout. iApps implementation scripts
are executed by a process called scriptd. Scriptd’s stdout writes to /shared/tmp/scriptd.out. Let’s take a
look at it now.
Values entered:
------------------------
My First String = |a string value|
Basic Choice = |Be|
Multi Choice = |{Option 2} {It's good to know your options}|
Edit Choice = |my own option|
pool Members = |{{
address 1.2.3.4
port 22
}} {{
address 5.6.7.8
port 33
}}|
Fancy Yes/No = |Sure|
LBMethod = |round-robin|

Pool members is a great illustration of why I use the pipes around my output. As we can see it’s multi
dimensional.

* Technically you can have tmsh within the presentation section of the template. This is why I call it the
tmsh script portion. Because it is executed at the end as a stand alone script.
More to come
Apendix A: The entire Template
The end result of following this tutorial should be the following template file. If you choose to import
this file to experiment with be sure there are no issues with “Smart Quotes” word wrap or other related
problems.
cli admin-partitions {
update-partition Common
}
sys application template /Common/HelloiApps {
actions {
definition {
html-help {
<h1>Hello iApps!</h1>
<p>This is an iApp lab to learn how to author iApps Templates.</p>
<h1>Sections</h1>
<h2>1. Intro</h2>
<p>Just an intro with a description</p>
<h2>2. Variables (Let's collect some variables)</h2>
<p>This is where we are actually collecting variables</p>
<p><b>Enter a string value</b></p>
<p>Really, just enter a value</p>
<p><b>Choose a few options</b></p>
<ul>
<li><b>Option 1</b> - The first option.</li>
<li><b>Option 2</b> - The second option.</li>
<li><b>Option C</b> - The third option.</li>
<li><b>It's good to know your options</b> - The silliest of all the options</li>
</ul>
}
implementation {
tmsh::log_dest file
tmsh::log_level err

puts "Values entered:"


puts "------------------------"
puts "My First String = |$::my_variables__my_first_string|"
puts "Basic Choice = |$::my_variables__basic_choice|"
puts "Multi Choice = |$::my_variables__multi_choice|"
puts "Edit Choice = |$::my_variables__edit_choice|"
puts "pool Members = |$::my_variables__pool_member|"
puts "Fancy Yes/No = |$::my_variables__fancy_yes_no|"
puts "LBMethod = |$::my_variables__load_balancing_method|"
}
presentation {
section intro {
message hello_message "Hello iApps!"
}
section my_variables {
string my_first_string
choice basic_choice {
"Be",
"Not Be"
}
multichoice multi_choice {
"Option 1",
"Option 2",
"Option C",
"It's good to know your options"
}
editchoice edit_choice {
"Option A",
"Option B",
"Option 3"
}
choice fancy_yes_no default "Nope" {
"Sure",
"Nope"
}
optional ( fancy_yes_no == "Sure" ) {
# Message does actually require a message body
message pool_members "IP and Port for back end pool members of your favorate virtual server."
table pool_member {
string address
string port
}
# This is a fancy choice box. We will see how it works later
choice load_balancing_method {
"Round Robin" => "round-robin",
"Least Connections" => "least-connections"
}
}
}
text {
# Look familiar? What is the name of our first section above?
# intro "Welcome to my first iApps Template"
# And what is the only element it contains?
# intro.hello_message "The Application Service wizard says"

# So this is the section title


my_variables "Lets collect some data"
# And everything here is question like "what address should this virtual server listen on?"
my_variables.my_first_string "Enter a string value."
my_variables.basic_choice "What is the question?"
my_variables.multi_choice "Choose a few options"
my_variables.edit_choice "Choose more flexible options"

my_variables.fancy_yes_no "Do you want to show the hidden options?"


my_variables.pool_members "Now things are starting to get hot"
my_variables.pool_member "Member:"
# This one is a bit more complex...
my_variables.pool_member.address "Server address:"
my_variables.pool_member.port "Port"
my_variables.load_balancing_method "Which is better?"
# Notice anything missing? What about that 'optional' command? Optional tells the bigip to only display
contents if specific criteria are met. It doesn’t have a display element of it’s own which is why we needed
the pool_members message element
}
}
role-acl none
run-as none
}
}
description none
requires-bigip-version-max none
requires-bigip-version-min none
requires-modules { ltm }
}

You might also like