Here are the various functions you might use in your templates.
For each function, documentation specifies mandatory arguments at the beginning while optional ones are
annoted with []
.
Most of them support the optional dc attribute to use data from another datacenter. If the dc
attribute is not specified, the function will output data from the current datacenter.
To ease template development, consul-templaterb
supports HOT reload of templates, thus it is possible to
develop the templates interactively. While developing, it is possible to use the switch --hot-reload=keep
,
thus the application will display a warning if the template is invalid and won't stop
(--hot-reload=die
is the default, thus if the hot-reloaded template has issue, the application will die).
Have a look to samples/ directory to start writing your own templates.
All objects returned by those functions described below all share the same structure:
.result
: handle the result.endpoint
: get technical information about how data was retrieved and statistics.
All endpoints implement technical interface that allow to get information about what is going on in your Consul Cluster.
On each object, you can access the .endpoint
object that includes several informations about the endpoint being queried:
myresult.endpoint.x_consul_index
return the current index on blocking querymyresult.endpoint.stats
a object with interresting fields:bytes_per_sec
,bytes_per_sec_human
,successes
,errors
,body_bytes
,last_modified
. All stats details are available in the file lib/consul/async/stats.rb.
Using those statistics might be useful to trigger alerts very easily when something is going on. Have a look to samples/metrics.erb that exposes most of those metrics to Prometheus.
Most objects returned by all those functions are contained within a .result
object. However, in order
to avoid having to write .result in all templates, some shortcuts have been added: []
allow to either access values for map-based data or arrays.
Also available for all results:
- .all?
- .any?
- .assoc
- .chunk
- .chunk_while
- .class
- .clear
- .collect
- .collect_concat
- .compact
- .count
- .cycle
- .detect
- .dig
- .display
- .drop
- .drop_while
- .dup
- .each
- .each_cons
- .each_entry
- .each_slice
- .each_with_index
- .each_with_object
- .empty?
- .entries
- .enum_for
- .eql?
- .equal?
- .extend
- .fetch
- .find
- .find_all
- .find_index
- .first
- .flat_map
- .flatten
- .grep
- .grep_v
- .group_by
- .hash
- .include?
- .index
- .inject
- .inspect
- .is_a?
- .itself
- .keep_if
- .kind_of?
- .lazy
- .length
- .map
- .max
- .max_by
- .member?
- .min
- .min_by
- .minmax
- .minmax_by
- .nil?
- .none?
- .object_id
- .one?
- .partition
- .pp
- .rassoc
- .reduce
- .reject
- .replace
- .reverse_each
- .select
- .shift
- .size
- .slice
- .slice_after
- .slice_before
- .slice_when
- .sort
- .sort_by
- .sum
- .take
- .take_while
- .tap
- .to_a
- .to_enum
- .to_h
- .to_s
- .uniq
- .values_at
- .yield_self
- .zip
- .append
- .at
- .bsearch
- .bsearch_index
- .combination
- .concat
- .each_index
- .fill
- .insert
- .join
- .last
- .pack
- .permutation
- .pop
- .prepend
- .product
- .push
- .repeated_combination
- .repeated_permutation
- .reverse
- .rindex
- .rotate
- .sample
- .shuffle
- .to_ary
- .transpose
- .unshift
- .compare_by_identity
- .compare_by_identity?
- .each_key
- .each_pair
- .each_value
- .fetch_values
- .has_key?
- .has_value?
- .invert
- .key
- .key?
- .keys
- .merge
- .rehash
- .store
- .to_hash
- .to_proc
- .transform_keys
- .transform_values
- .update
- .value?
- .values
The coordinate object allow to interact with the coordinates of DCs and nodes as explained in Network Coordinates.
List the Wan Coordinates from local DC to other DCs. If dc is set, it will perform the same operation but from another DC.
Read all LAN nodes coordinates. If If dc is set, it will perform the same operation but for another DC.
Computes the rtt between 2 nodes returned by coordinate.nodes
or coordinate.datacenters
. A re-implementation of Golang sample code
Working with Coordinates.
Get the list of datacenters as string array.
Examples
<% datacenters.each do |dc| %>
* <%= dc %> with <%= services(dc:dc).keys.count %> services, <%= nodes(dc:dc).count %> nodes
<% end %>
Full example: samples/consul_template.txt.erb
List the services matching the optional tag filter, if tag is not specified, will match all the services. Note that this endpoint performs client side tag filtering for services to ease templates development since this feature is not available on Consul's endpoint.
Examples
<% services.each do |service_name, tags|
%> * <%= service_name %> [ <%= tags %> ]
<% end %>
Full example: samples/consul_template.txt.erb
<%
datacenters.each do |dc| %>
* Datacenter <%= dc %>
<%
services(dc:dc, tag:'http').each do |service_name, tags|
%>
- service <%= service_name %> <%= tags.sort %><%
end
end
%>
List the instances of a service having the given optional tag. If no tag is specified, will return all instances of service. By default, it will return all the services that are passing or not. An optional argument passing might be used to retrieve only passing instances.
This function returns a Hash of object ['Node']['Meta']
(will return empty hash if very old version of Consul not
supporting it)
This object also contains a Helper to get easily the correct Address by using service_address
which returns
the optional ['Service']['Address']
if found or ['Node']['Address']
otherwise.
This helper function will return a Hash or ['Service']['Meta']
and will return empty hash if not supported
by old versions of Consul (< 1.1.0)
This function will return a string of ['Service']['Meta']
if key is found in service meta, or
['Node']['Meta']
or nil if key does not exists in both Service.Meta and Node.Meta.
Computing the status of an instance is non-trivial as it requires to parses all statuses of all checks and take
the worse of all thoses Status object. The .status
attribute can be used as an alternative as it precomputes
this state in the same way consul does, it will then return the worse of all the statuses of all checks.
Returned value will be one of passing
|warning
|critical
.
.weights
give the ability to deal with new Weights
feature added in Consul 1.2.3.
It returns a Hash with {"Passing": weight_when_service_is_passing, "Warning": weight_when_value_is_warning}
to allow having weighted load balancing when statuses in Consul do change. It also deals nicely with versions
of Consul not yet supporting Weights.
.current_weight
computes automagically weight given the current status of service. It works the same way as
the DNS implementation of Consul.
Examples
<% services.each do |service_name, tags|
if tags.include? 'http'
%> ++ Service <%= service_name %>
<% service(service_name, tag:'http').sort {|a,b| a['Node']['Node'] <=> b['Node']['Node'] }.each do |snode|
%> * <%= service_name %> -> <%=
snode['Node']['Node'] %>:<%= snode['Service']['Port'] %> <%=
snode['Service']['Tags'] %> status: <%= snode.status %> Current Weight: <%= snode.current_weight %> Checks: <%
snode['Checks'].each do |c| %> <%= c['Status']
%><% end if snode['Checks'] %>
<% end
end
end %>
Full example: samples/consul_template.txt.erb
List all the nodes of selected datacenter. No filtering is applied.
Examples
<% nodes.sort {|a,b| a['Node'] <=> b['Node'] }.each do |snode|
%> * <%= snode['Address'].ljust(16) %> <%= snode['Node'] %>
<% end %>
Full example: samples/consul_template.txt.erb
List all the services of a given Node using its name or its ID. If DC is specified, will lookup for given node in another datacenter.
Find all the checks of a given node name.
Find all the checks of a given service.
Read keys from KV Store. It can be used for both listing the keys and getting the values. See the file in samples keys.html.erb for a working example.
Variants:
- no additional parameter: will only retrieve the key you asked for
keys: true
: will retrieve the hierarchy of keys, but without the values, useful if values might be large, in order to perform simple listingsrecurse: true
: will retrieve all hierarchy of keys with their values
Please have a look at samples/sample_keys.html.erb for examples on how using it.
Since KV has several modes, it depends whether you asked for one or several keys.
Thus, we recommend using a helper to get the value (while you might use it directly).
In order to ease the use, 3 helpers are available and all have a optional argument path
. When path is specified
and the call is retrieving several keys, it allows to select a specific one.The available helpers are the following:
get_value( [path] )
: Get a raw valueget_value_decoded( [path] )
: Get the value decoded from Base64get_value_json( [path], [catch_errors: true] )
: when your payload is JSON, decode Base64 first and then decode the JSON. If catch_errors is set to true, if will not throw an error during rendering of template and return nil. Otherwise an Error will be thrown and have to be catch if you are unsure if the value is valid JSONget_value_yaml( [path], [catch_errors: true] )
: same as above, but for yml
The easiest, use the helpers to retrieve the values in the following formats:
-
kv('/my/path/to/value').get_value
: get the raw value of a single key in KV -
kv('/my/path/to/value').get_decoded
: get the decoded value of a single key in KV -
kv('/my/path/to/value').get_value_json
: get the base64 decoded value and try decoding it as JSON -
kv('/my/path/to/value').get_value_yaml
: get the base64 decoded value and try decoding it as YAML
If you want to iterate amongst all values, you might to it that way:
<%
kv('/my/multiple/values', recurse: true).each do |tuple|
key = tuple['Key']
value_decoded = Base64.decode64(tuple['Value'])
%>
<div>Decoded value: <%= value_decoded %>
<div>JSON value: <%= JSON.parse( value_decoded ) %>
<%
end
%>
When using kv('/my/multiple/values', recurse: true)
, only a single call is performed, thus,
it is far more efficient to retrive multiple values from the KV under the same root. Thus,
in order to display several discreet values, it is possible to do the following:
result = kv('/my/multiple/values', recurse: true)
value1 : <%= result.get_decoded('/my/multiple/values/value1') %>
value42 : <%= result.get_decoded('/my/multiple/values/value42') %>
value123 : <%= result.get_decoded('/my/multiple/values/value123') %>
Since kv('/my/multiple/values', recurse: true)
will retrieve all values at once, it might be more
efficient in some cases than retrieving all values one by one.
Get the Serf information from Consul Agent point of view.
This is a list of Serf information containing serf information. This information is not consistent and should be used with care, most of the time, you should prefer nodes()
.
If you are using consul-templaterb
with a Consul server directly, you might use wan:true
to have the list of all
consul servers connected thru WAN (aka all consul servers from all datacenters).
The returned value is an array containing the following objects containing the following attributes (accessed as Hash elements):
- "Name": Name of node
- "Addr": IP Address of node as seen in serf
- "Port": Serf port
- "Tags": Hash of properties, including version, dc, VSN info...
- "Status": Serf code from 0 to 5 giving Health information
Another property is available as status()
, that translates the Hash property "Status" into something human redable ('none', 'alive', 'leaving', 'left', 'failed').
See samples/members.json.erb for example of usage.
Get the metrics of Consul Agent. Since this endpoint does not support blocking queries, data will be refreshed every few seconds, but will not use blocking queries mechanism.
Get the configuration of Consul Agent. Since this endpoint does not support blocking queries, data will be refreshed every few seconds, but will not use blocking queries mechanism.
This allow to include a template file into another one. Beware, it does not check for infinite recursion! The template can be either a static file either another template. The file has to be a valid template, but can also be raw text (if it is a valid template) and is resolved with a relative path regarding the file including it.
Example:
<%= render_file('common/header.html.erb', title: 'My Title') %>
Will render header.html.erb with parameter title = 'My Title'. title
can then be accessed within
the template using param('title', 'My default Value')
in the header.html.erb
file.
Similar to render_file but from a string. Allows to render a template from a string. Useful if you have your templates in KV for instance.
Example:
Given the value in Consul's KV my/template/to_render
: from KV: <%= 5 * 2 %>
<%= render_from_string(kv('my/template/to_render').get_value_decoded) %>
Would render the value: from KV: 10
.
That's very usefull if you want to centralize your templates and being able to change the value with a simple PUT call in the KV.
Can be used within a template to access a parameter. Parameters can be specified with render_file
directive. Optional value default_value
allow to get a value if parameter has not been set.
It allows to create re-usable sub-templates that might be used in several places with several types of parameters. Thus, templates can be called like kind of functions and generate output based on the parameters provided.
Example:
render_file('show_service.html.erb', {service_name: 'service1', title: 'My Nice Service'})
[...]
render_file('show_service.html.erb', {service_name: 'service2', title: 'My Nicer Service'})
Note that you can also add parameters into a top level service using the command line:
consul-templaterb --template "source.html.erb:dest.html:reload_command:params.yaml"
[...]
See samples/consul-ui/consul-services-ui.html.erb for example of usage.
It requires that a Vault token is given either in parameter or in environment variable The policies should be properly set.
List the secrets in vault under a given prefix.
Examples
<% ['users','groups'].each do |entity_type|
%><%= entity_type.capitalize %>: <%
secrets("auth/ldap/#{entity_type}/").each do |entity|
%> * <%=entity%>
<% end %>
<% end %>
Full example: samples/vault-ldap.txt.erb
It requires that a Vault token is given either in parameter or in environment variable The policies should be properly set.
Either read or write on a path in vault.
Having a non-nil data Hash will change the behavior from read to update and apply the given data.
Notice: For the moment the versionned KV abstration is not handled, if you want to access versioned KV, you have to hit the logical paths directly.
Examples
secret('auth/ldap/config')['data']
Full example: samples/vault-ldap.txt.erb
secret('secret/foo', [force_ttl: intInSecond])
Fetch json data from any url. This allows to create templates with consul/vault data mixed in with data coming from other services/api.
Polling interval can be controlled with refresh_delay_secs
option.
Request method (GET
, POST
, ...) can be controlled with request_method
option.
remote_resource.as_json('http://my-api.dev/fridge/list.json', [])
Example with post (json_body will be applied to_json
automatically):
remote_resource.as_json('http://my-api.dev/fridge', [], request_method: :post, json_body: {brand: 'any'})
Basic authentication can be done passing headers
option.
remote_resource.as_json('http://my-api.dev/fridge/list.json', [], headers: { Authorization: [user, password]})
Full example: samples/list_ruby_versions_from_rubygems.txt.erb
It returns information about current template being rendered. The information returned has the following structure:
destination
: absolute path where the file is gonna be writtensource
: the template absolute path file, most of the time, if will be equal tosource_root
, except when the current template is included in another template usingrender_file()
source_root
: the root template absolute file.was_rendered_once
true if whole template structure has been rendered at least once, false if current template data is still incomplete.
Examples
I am the file <%= File.basename(template_info['source']) %><%
if template_info['source'] != template_info['source_root']
%> included from template <%= File.basename(template_info['source_root']) %><%
end
%> rendered as <%= File.basename(template_info['destination']) %>
The command consul-template template_info.erb
would render:
I am the file template_info.erb rendered as template_info`
If creating a file called include.erb with contents: <%= render_file('template_info.erb') %>
,
the command consul-templaterb --template include.erb:destination_file.txt
would render:
I am the file template_info.erb included from template include.erb rendered as destination_file.txt`
It returns list of templates evaluated by this instance of consul-templaterb.
Information returned is an array of elements where elements are [template_name, template_destination, args]
.