Templating with F5 BIG-IP FAST¶
This chapter is dedicated to explaining the relationship of schema vs templates. BIG-IP FAST makes use of Mustache, JSON schema and JSONPath, therefore BIG-IP FAST may be familiar if you already understand any of these syntaxes. BIG-IP FAST combines these technologies to provide a complete templating solution. At the foundation, BIG-IP FAST uses a templating specification called mustache to convert parameters into a fully rendered API body. Parameter types can be specified in JSON schema, and are used to validate template inputs when the template is rendered. BIG-IP FAST will auto generate a schema for each template based off the template and json-schema provided. Schema is generated from template text, combined with definitions, and used to validate template parameters.
Mustache¶
Mustache is not the templating engine. Mustache is a specification for a templating language, and it specifies how the template file must look. You write templates adhering to the Mustache specification, and it works by expanding tags in a template using values provided in a hash or object. The template is then rendered to create an output.
Tags¶
Tags are easily identifiable by the double mustache of opening and closing curley braces {{ }}
.
The most basic type of tag is a variable. When Mustache process the template it passes an object or hash containing the variable name and associated values.
A {{tenant}}
tag in a template renders the value of the tenant key.
Sections¶
Using the person section example from above, 2 types of lists can be created: Empty List or Non-Empty List.
False Values or Empty Lists
If the person key exists, and has a value of false, or an empty list, the text between the pound and slash will not be displayed.
In the following example, person has a parameter: false
, therefore RED will not be displayed, resulting in the Rendered Output: BLUE
.
{{#person}}
"RED"],
{{/person}
{{^person}}
"BLUE",
{{/person}}
Parameters:
person: false
Output:
BLUE
Non-Empty Lists
When the value is a non-empty list, the text in the block will be displayed once for each item in the list. The context of the block will be set to the current item for each iteration. In this way we can loop over collections.
Template:
{{#repo}}
<b>{{name}}</b>
{{/repo}}
"repo": [
{ "name": "resque" },
{ "name": "hub" },
{ "name": "rip" }
]
}
Outputs:
<b>resque</b>
<b>hub</b>
<b>rip</b>
See also
Mustache Manual for more information on Sections.
Partials¶
Along with sections, Mustache utilizes partials. Mustache partials can be thought of as a way to insert template snippets. The syntax for including a partial uses curley braces and an angle bracket {{> }}.
For BIG-IP FAST, a partial definition must contain template text, i.e., define a template property
definitions:
partialDef:
template: |
{{#useVar}}
{{var}}
{{/useVar}}
useVar:
type: boolean
template: |
{{> partialDef}}
{{> partialDef}}
Parameters:
{
"useVar": true,
"var": "sample"
}
Outputs:
sample
sample
See also
Mustache Manual for more information on Partials.
Overlaid Definitions¶
The way BIG-IP FAST generates parameter definitions can be surprising at times if that parameter shows up multiple times in the template text.
When generating parameter definitions, BIG-IP FAST looks at the following locations in the following order, with later definitions overriding/modifying previous ones:
Embedded mustache tags in any merged templates. For example:
{{var:f5:port}}
The definitions properties of any merged templates. Templates are merged by name using
$ref
inside a oneOf, anyOf, or allOf clause.Embedded mustache tags in the primary template.
The definitions property in the primary template.
The parameters property in any merged templates.
The parameters property in the primary template.
Notes
If a duplicate Mustache tag exists in the template, then the last encountered tag is used for the definition. The order that Mustache tags are parsed in should not be assumed.
Properties within the definition (e.g., title, description, type, format, default, etc.) are merged together as they are found with newer data taking precedence over old data on key conflicts.
Values from the parameters property of YAML templates will be used in place of the default from the parameter definition but will not actually update the definition itself.
JSON Schema Basic Types¶
Definitions¶
To establish a difference between the main schema and the auxiliary definitions, we adopt the convention that every JSON Schema document consists of two parts; a JSON Schema, and a set of definitions.
For example, if we want a definition for virtuals, it may look like this:
definitions:
virtuals:
type: array
items: {
type: string,
format: ipv4
}
See also
JSON Editor: $ref and definitions for additional code examples.
In JSON, each element in an array may be of a different type. Elements of the array may be ordered or unordered based on the API being templated. This section covers typical JSON schema definitions for common patterns.
For example, virtuals is defined with a type: array having items defined with type: string and format: ipv4 (more on formats later).
definitions:
virtuals:
type: array
items:
type: string
format: ipv4
Ranges: Combining minimum and maximum keywords for ranges or exclusiveMinimum and exclusiveMaximum for expressing exclusive ranges. The example below defines the range of port numbers as type: integer.
type: integer
minimum: 0
maximum: 65535
Another example is combining minimum and exclusiveMaximum. When using a minimum range of 0, then 0 is valid. With an exclusiveMaximum of 65535, 65534 is valid while 65535 is not.
type: number
minimum: 0
exclusiveMaximum: 65535
String: The string type is used for strings of text and may contain Unicode characters. The length of a string may be constrained using minLength and maxLength which cannot be a negative number.
type: string
minLength: 2
maxLength: 5
Along with the string type, JSON has some built in formats, using the format keyword. This allows for basic validation and can be used for certain strings such as IPv4 and IPv6 addressing.
String zeroTo255 = "([01]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])"
See also
JSON schema Built-in Formats and Regular Expressions for more information.
{ type: boolean }
matches two values; true or false and must be used in all lower case characters.Combining Schema¶
It is less restrictive than allOf as more than one of the same type may be specified.
{
"anyOf": [
{ "type": "string" },
{ "type": "number" }
]
}
It will also fail on 15 as it is a multipleOf both 5 and 3 not oneOf.
{
"oneOf": [
{ "type": "number", "multipleOf": 5 },
{ "type": "number", "multipleOf": 3 }
]
}
{
"allOf": [
{ "type": "string" },
{ "maxLength": 5 }
]
}
Note
When using allOf, be cautious of specifying multiple types such as { type: string }
and { type: number }
as a type cannot be a string and a number at the same time.
When authoring templates using yaml, allOf takes on a special meaning by referencing another template in the set, known as Template Merging.
allOf will merge the schema of the merge template with external template(s) just as JSON schema will when generating schema for the merged templates
When a merge template is rendered, the JSON output of the templates will be merged together
Merge can be used to add additional configuration to a template
parameters:
...
definitions:
...
template: |
...
allOf:
- $ref: "tcp.yaml#"
See also
For detailed information, additional code examples and references, visit Understanding JSON Schema