-
Notifications
You must be signed in to change notification settings - Fork 11
Monitoring Template Language
Roboconf Specification Request: 232
Status: Archived (2015-07-31)
Editors:
- Pierre Bourret, Université Joseph Fourier
- Vincent Zurczak, Linagora
WARNING:
This specification is a DRAFT: a work in progress that is intended to be
published, which may or may not be ready for adoption. It should not
necessarily be considered factual or authoritative.
This page proposes a template notation to generate Roboconf monitoring files. This language is needed to provide the Roboconf monitoring support feature, as requested by issue 155.
While Roboconf can manage the deployment of applications on various cloud infrastructures, the physical and virtual machines that are part of the application still need to be monitored. This monitoring task is very specific to the actual infrastructure, and operators need to collect numerous data from the physical and virtual machines, components, instances and services deployed by Roboconf.
However operative maintenance is very touchy: operators use dedicated monitoring tools (e.g. Nagios, Shinken, Cacti …). They do not want to be distracted by (yet) another tool that messes up their carefully written configuration files with generated and unpredictable content. Instead of intruding the operator's universe, Roboconf must provide a simple and universal way to present relevant data to the monitoring tools. Operators are then free to extract the data they want, whenever they want.
The proposed Roboconf Monitoring Template Language must allow the extraction
of every Roboconf model data (Application
, Component
, Instance
…). Those
data may be presented to multiple monitoring tools, that accept various input
formats. Thus, the template language must provide a universal and extensible way
to format data.
Formatted data are periodically written to files by the Roboconf Deployment Manager (DM). The operators/monitoring tools are then able to read those files, and/translate then into their native input format, and to act accordingly. So output files might be written into the monitoring native syntax, but most of the time, as more tool-specific information is needed, there are written as a pivot easy-to-parse intermediate file.
![Roboconf monitoring overview][overview]**Roboconf monitoring overview**
The monitoring of Roboconf applications can be configured during its execution. It is extended, at runtime, with new monitoring templates. The Deployment Manager register those templates in the application configuration directory (where application resources are extracted and stored).
![Runtime application monitoring][appMonitoring]**Runtime application monitoring**
When an application is configured to produce monitoring files, the DM generates
and updates files in the application configuration directory. For instance an
application named MyApp
will have its generated monitoring files located in
the monitoring-generated/MyApp/
directory. If the application configuration
directory is /tmp
(the default), then the generated monitoring files of this
same application will be located in /tmp/monitoring-generated/MyApp/
.
Each template file generates one output monitoring file. The exact name of the
output file depends upon the name of the template file, which must end with
a .tpl
extension. For instance, a template file named nagios.conf.tpl
will
generate a file named nagios.conf
:
monitoring-template/
|- MyApp/
|- nagios.conf.tpl
|- config.json.tpl
|- config.properties.tpl
monitoring-generated/
|- MyApp/
|- nagios.conf
|- config.json
|- config.properties
The Roboconf Monitoring Template Language must allow to address all the possible configuration input formats of various monitoring tools. It must not be tight to a specific configuration syntax. Quite the opposite: the template language must be universal and extensible, in order to cover changes in the monitoring tools configuration syntax, or to be able to feed newcomers.
The main concept is that a template file (TPL) is written in the target syntax, and contains special instructions, recognized by the template engine. These instructions will be substituted by some Roboconf application monitoring data (e.g. IP address, hostname …).
The Roboconf Monitoring Template Language relies on two things:
- a hairy à la mode template engine, {{ mustache }}, which is used to define the layout of the generated monitoring files. In practice, an extension of {{ mustache }}, called handlebars, is used, as it provides more syntactic sugar, better expressiveness, and less tag nesting.
- a monitoring data structure that can represent all the various Roboconf
model entities (
Application
,Component
,Instance
…). Those structured data feed the template with Roboconf objects (instance name, path & status, exported configuration properties…), so they can be written down in the generated monitoring output file.
The Roboconf monitoring engine reads templates written using an extended mustache syntax. It allows to generate files in various output formats, e.g. JSON, properties…
Here is a quick example of a template that, for each root instance of the application, outputs its path, status and IP address:
{
"VMs": [
{{#instanceOf VM}}
{
"path": "{{path}},
"status": "{{status}}",
"ip": "{{exports.ip}}"
},
{{/instanceOf}}
]
}
For instance, when applied to the Roboconf "Getting Started Tutorial" application, this template could produce the following output:
{
"VMs": [
{
"path": "/Apache VM",
"status": "DEPLOYED_STARTED",
"ip": "192.168.0.12"
},
{
"path": "/Tomcat VM 1",
"status": "DEPLOYED_STARTED",
"ip": "192.168.0.29"
},
{
"path": "/Tomcat VM 2",
"status": "DEPLOYED_STARTED",
"ip": "192.168.0.30"
},
{
"path": "/MySQL VM",
"status": "DEPLOYED_STARTED",
"ip": "192.168.0.57"
},
]
}
This section does not intend to provide a complete description of the mustache template engine syntax, but rather to show how it can actually be used to generate monitoring files for Roboconf applications. The mustache manual details more precisely all the syntactic constructions you can use in your templates.
You may also have a look at the documentation of handlebars.js template language, that extends and stretches the mustache, and at its Java implementation handlebars.java, which is internally used by the Roboconf monitoring support engine.
The following section details the underlying monitoring model: which mustache tags are defined, and how you can refer to them.
The Roboconf template language must allow to access to all the entities of a
Roboconf application model. First class entities are Application
and
Instance
s.
The Roboconf application can be accessed by using the {{application}}
tag.
Inside a monitoring, this tag is always defined to the application being
monitored. Within this tag, it is possible to access several properties of the
Roboconf application:
Syntax | Description |
---|---|
Navigation: | |
{{rootComponents}} |
The names of the root components of the application. Type = list of String
|
{{rootInstances}} |
The root instances of the application. Type = list of Instance s |
Attributes: | |
{{name}} |
The name of the application. Type = String
|
{{qualifier}} |
The qualifier of the application. Type = String
|
{{description}} |
The description of the application. Type = String
|
{{dslId}} |
The DSL identifier of the application. Type = String
|
{{namespace}} |
The name space of the application. Type = String
|
Open topic: multi-application monitoring
May we provide an access to all the applications managed by the DM from one template, e.g.{{applications}}
(type: list ofApplication
s) ? With this feature we could write generic templates that enables monitoring for a family of/all applications.
When monitoring an application, instances are first class citizens. It is indeed the main source of information, and directly reflects the actual state of the living application.
Inside the {{application}}
tag, instances can be accessed via the
{{rootInstances}}
tag, which list the root instance of the application. From
a root instance, it is possible to navigate through the instance hierarchy via
the {{parent}}
and {{children}}
tags. Those tags allows to access to the
entire instance space of the application. It is sometimes more convenient to
list leaf instances, or instance of a specific component. The
instance requests section describes a syntactic sugar that
allows such a quick and useful access to instances.
Syntax | Description |
---|---|
Navigation: | |
{{parent}} |
The parent instance. Type = Instance . Empty if this instance is a root instance. |
{{children}} |
The children instances. Type = list of Instance s. Empty if this instance has no children. |
{{component}} |
The name of the actual component type of this instance. Type = String
|
Attributes: | |
{{name}} |
The name of the instance. Type = String
|
{{path}} |
The path of this instance. Type = String
|
{{status}} |
The current status of the instance. Type = String , one of {"NOT_DEPLOYED" , "DEPLOYING" , "DEPLOYED_STOPPED" , "UNRESOLVED" , "STARTING" , "DEPLOYED_STARTED" , "STOPPING" , "UNDEPLOYING" , "PROBLEM" } |
{{isStable}} |
Flag indicating if the current status of the instance is a stable one. Type = boolean
|
{{exports}} |
The exports overridden by this instance. Type = Map<String, String> The iterating section explains how to extract information from such maps. |
{{data}} |
Custom data of this instance. Type = Map<String, String> The iterating section explains how to extract information from such maps. |
Iterating over the {{rootInstances}}
of an application, and then navigating
through the instance hierarchy is quite verbose and not very natural. We would
like, as an example, to list all the instances of type VM
, or instances which
exposes the Storage
facet.
The Roboconf template language defines a special instanceOf
tag that allows to
select instances that are descendants, either directly or indirectly, of the
provided component or facet name.
Open topic: multiple inheritance contraint
May we provide a way to select instances according to multiple criteria in a single instruction, e.g.{{#instanceOf VM & Storage}}
, or{{#instanceOf Apache | Tomcat}}
?
Open topic: complex contraints
It may be necessary to allow complex constraints, based on the properties of the components/facets implemented by the instances, e.g.{{#instanceOf VM with installerName==bash}}
, or{{#instanceOf JEE with exportedVariables.jee.version>=1.4}}
. This syntax may also be useful in other situations, as the selection of the children of an instance:{{children with status==DEPLOYED_STARTED}}
.
Example:
<div id="storage">
{#instanceOf Storage}
<h3>Instance name: {{name}}</h3>
<ul>
<li>Status: {{status}}</li>
<li>Component: {{component}}</li>
</ul>
{/instanceOf}
</div>
… could generate the following monitoring file:
<div id="storage">
<h3>Instance name: MySQL VM</h3>
<ul>
<li>Status: DEPLOYED_STARTED</li>
<li>Component: MySQL</li>
</ul>
<h3>Instance name: PostgreSQL VM</h3>
<ul>
<li>Status: DEPLOYED_STOPPED</li>
<li>Component: PostgreSQL</li>
</ul>
</div>
As a side note, and as you can see right above, Roboconf monitoring templates can be used to generate human-readable documentation too, not just configuration files.
The following sections describe how the {{ mustache }} and Handlebars syntaxes can be applied to solve/ease many situations. They are not part of the specification itself, but are rather reminders of how you can use those tools.
The Handlebars template engine allows to use tags with are constructed as paths,
e.g {{exports.ip}}
, or {{application.rootInstances.Apache VM}}
. Such
constructions are very helpful when you want to access a very specific
sub-property of a Roboconf model entity.
For instance you can use such a syntax to directly access a data of the parent instance, using the following template:
{{#instanceOf Tomcat}}
"{{name}}.ip": {{parent.data.ip}},
{{/instanceOf}}
The {{ mustache }} syntax does not allow to iterate over an arbitrary map: the
keys must be known in advance. If we know the name of the exported variable,
for instance IP
or port
, that's OK… But what if we want to list all the
exported variables?
This section defines a specific notation, inspired from
Handlebars.js, which allows to iterate over such
loosely-structured maps. The special each
tag allows to make the template
iterate over all the entries of a map, specified as an argument. Inside this
tag, the {{key}}
and {{value}}
tags allows to access respectively to the
key and the value of the entry.
For instance, the following template
…
{{#each exports}}
{{key}} = {{value}}
{{/each}}
…
Depending on the targeted language, you can insert comments inside your template. For instance, for a Java properties files, you could write:
# This is a language-specific comment.
The template engine will not interpret the above line as an instruction, and will print it out verbatim. However it may be necessary to comment the template instructions themselves, without the need to include such comments in the final generated file. The {{ mustache }} engine provides a comment syntax that allows you to include such comments:
{{! This is a template comment! }}
The above line will not be printed out in the generated monitoring file.
This section recaps all the syntaxes and model properties defined above, and show the Roboconf template language in action through the study of three real-life examples.
In this example, the output monitoring file must contain the configuration of a
single root instance of an application. The application contains several root
instances, but only a specific one is needed here. This instance has its
configuration stored in specific data
entries, such as ip
, mac
…
{{! This line selects the root instance "Apache VM" of the application}}
{{application.rootInstances.Apache VM}}
"ip": {{data.ip}},
"mac": {{data.mac}}
…
{{/application}}
In this example, we will show how to the output the configuration of all the
instances of a specific component. The application defines a Tomcat
component,
which may have several instances.
"tomcats": [
{{! This line selects all the instances of type "Tomcat" inside the application}}
{{#instanceOf Tomcat}}
{{! For each instance, the content of this block is output once.}}
{
"name": {{name}}, {{! The instance name}}
"ajpPort": {{exports.ajpPort}} {{! The ajpPort exported variable}}
},
{{/instanceOf}}
]
In this more intricate example, we would like, for each instance a specific
component (here: VM
), output the configuration of all its children with a
specific facet (here: Storage
).
**Storage application layout**
"allStorages": [
{{! This line selects all the instances of type "VM" inside the application}}
{{#instanceOf VM}}
{{! For each instance, the content of this block is output once.}}
{
"vm.name": "{{name}}",
"storages": [
{{! This line selects all the instances of type "Storage", children of this instance}}
{{#instanceOf Storage}}
{{! For each storage, output its name and capacity.}}
{
"name": "{{name}}",
"capacity": "{{exports.capacity}}"
},
{{/instanceOf}}
]
},
{{/instanceOf}}
]
For an application with the layout described by the figure above, the output of this template could look like this:
"allStorages": [
{
"vm.name": "Big Storage",
"storages": [
{
"name": "Huge but slow disk",
"capacity": "500TB"
},
{
"name": "Big and fast disk",
"capacity": "5TB"
},
]
},
{
"vm.name": "Small Storage",
"storages": [
{
"name": "Big disk",
"capacity": "1TB"
},
{
"name": "Solid state",
"capacity": "200GB"
},
]
},
]
Coming soon…