
The revisions let you track differences between multiple versions of a post.
Netomata Config Generator (NCG) template files (which are commonly named with the extension .ncg) are used by ncg as templates for generating config files (or subsections of those files) for various network devices and services, using the Embedded Ruby (ERB) mechanism (which is sometimes also referred to as "eRuby").
To use ERB, you embed Ruby language syntax into your text file, and mark the Ruby language segments like this:
<% ... Ruby code ... %>so that the ERB interpreter can recognize them and apply them.
The ERB interpreter as used for ncg files recognizes the following variations of these tags:
The Ruby code is executed, but nothing is output.
The Ruby code is executed, and its resulting value is output in place of the whole <%= Ruby code %> block.
The block is treated as a comment and ignored. (This can be very useful in testing, to temporarily disable a certain block of Ruby code.)
Replaced in the output with '<%' or '%>', respectively.
<%
my_hostid = 17
(0..3).each do |i|
-%>
auto eth<%= i %>
interface eth<%= i %> inet static
address 192.168.<%= i %>.<%= my_hostid %>
netmask 255.255.255.0
<% if (i == 0) then -%>
gateway 192.168.<%= i %>.1
<% end -%>
broadcast 192.168.<%= i %>.255
<%# blank line %>
<% end -%>
When this template is processed by ERB, the result is:
auto eth0
interface eth0 inet static
address 192.168.0.17
netmask 255.255.255.0
gateway 192.168.0.1
broadcast 192.168.0.255
auto eth1
interface eth1 inet static
address 192.168.1.17
netmask 255.255.255.0
broadcast 192.168.1.255
auto eth2
interface eth2 inet static
address 192.168.2.17
netmask 255.255.255.0
broadcast 192.168.2.255
auto eth3
interface eth3 inet static
address 192.168.3.17
netmask 255.255.255.0
broadcast 192.168.3.255
Data is passed to templates through Ruby instance variables; in Ruby, instance variable names begin with a single "@" symbol).
The instance variables may be of any class, but are usually of either class "Netomata::Node" or the fundamental Ruby "String" class.
Currently, templates must agree with whatever invokes them on what variables are passed, and what the class of each of those variables is. There is no automatic checking of variable presence or type. If a template requires a variable by a particular name and/or of a particular class, then the template needs to explicitly check that it has been passed what it expects, and raise an exception if it discovers a problem.
For example, here is a template to configure an interface on a Cisco router/switch. It expects that it has been passed a variable named @interface, which is a Netomata::Node and has subkeys of "name", "target", and "active" which are strings.
<%
template_arg("@interface")
template_arg_node_key("@interface", "name")
template_arg_node_key("@interface", "target")
template_arg_node_key("@interface", "active")
-%>
interface <%= @interface["name"] %>
description IPMI <%= @interface["target"] %>
switchport access vlan 48
switchport mode access
<%= apply_idiom("shutdown", @interface, {"@active" => @interface["active"]}) %>
!
In the above example, you can also see how to apply other templates ("idioms" are templates that the ncg program expects to find somewhere in (...)!idioms relative to the current node; see the documentation for apply_idiom() elsewhere in this document) from within a template, and how to pass arguments to these other templates.
In addition to the standard Ruby library classes and methods, there are a handful of "helper" methods available for use within ncg files.
Looks for a node named node[(...)!idioms!idiom] (i.e., checks node and each of its ancestor nodes in turn for a sub-node named "idioms" which itself has a sub-sub-node named "idiom"), and applies it with optional vars passed as variables.
Variables to pass are specified as a Ruby hash, with the following syntax:
{ "@name" => @var [, ...] }
So, for example, each of the following would be a valid vars argument to
apply_idiom() (assuming the referenced variables exist):
{"@vlan" => @vlan}
{"@active" => @vlan["active"]}
{"@target" => @target, "@vlan" => @vlan}
Returns a key built by combining all the partN arguments, using "!" as a separator. For example:
buildkey("a", "b", "c")
returns
"a!b!c"
Compares two interface- or version-style names, and determines what order they should sort in. This is similar to the Ruby core String#<=> operator, but it works in a way that is more useful for comparing multi-part strings such as interface and subinterface names, version numbers, and so forth.
Returns:
To compare the arguments a and b, they are first broken into parts. Each part, in turn, is the longest-possible string of either:
Then, the corresponding parts of each argument are compared in turn, until an answer is determined, subject to the following rules:
If the corresponding parts of both arguments are equivalent by these rules, then the next pair of corresponding parts is considered, and so forth, until an answer is determined.
For example, consider a list of interfaces; sorted normally (not using compare_parts, their order would be:
compare_parts would break each of these down into the following parts (shown by spaces) for comparison:
So, sorted using compare_parts for the comparison, the list would be:
This is a more "natural" order for a list of interfaces and subinterfaces.
Returns a string that is a multi-line header suitable for placing as a comment at the beginning of a generated config file, describing what tool was used to generate the config, what target key it was generated for, what date it was generated on, what user, hostname, and directory name it was generated for, and what arguments the generating program was invoked with.
prefix, if defined, is prepended to every line of the generated header. It should be whatever marks the rest of the line as a comment in the generated config file.
before, if defined, is used as the very first line of the generated header. It should be whatever marks the beginning of a multi-line comment in the generated config file. prefix is not applied to before, so before should include prefix if necessary.
after, if defined, is used as the very last line of the generated header. It should be whatever marks the end of a multi-line comment in the generated config file. prefix is not applied to after, so after should include prefix if necessary.
For example, to generate headers suitable for a shell script, you would do
emit_header("# ", nil, nil)
which would return a header of the form
# line 1 # line 2 # ...
To generate headers for a C-style config, you would do
emit_header(" * ", "/*", " */")
which would return a header of the form
/* * line 1 * line 2 * ... */
Converts filename to a key, by
filename_to_key("../a/b/c/./d")
returns
"(..)!a!b!c!(.)!d"
ip_a, ip_b, and the result are all IP addresses represented as strings. The result is the bitwise OR of the two arguments ip_a and ip_b. For example:
ip_union("10.5.0.0", "0.0.16.34") => "10.5.16.34"
ip_union("10.5.1.0", "0.0.16.34") => "10.5.17.34"
Expands file name filename relative to another file or directory name basename, returning the expanded filename. For example:
relative_filename("/a/b/c", "d") => "/a/b/d"
relative_filename("/a/b/c", "d/e") => "/a/b/d/e"
Note: as a special case, if filename begins with "/", it is treated as an absolute filename and returned as-is, not relative to basename. For example:
relative_filename("/a/b/c", "/d/e") => "/d/e"
This method can be used at the beginning of a template to check whether a needed argument has been passed to the template as an instance variable (see the section elsewhere in this document on Passing Data to Templates). Raises a Ruby ArgumentError (which typically aborts the program) if name (which is passed to this method as a quoted string, i.e. "@interface") doesn't exist. Also raises a Ruby ArgumentError if the variable exists, but isn't of the expected Ruby class (Netomata::Node, by default).
For example, the following would check that a node named "@interfaces" had been passed into a template, and raise an error if it hadn't:
<%
template_arg("@interfaces")
-%>
This method can be used at the beginning of a template to check whether a needed argument key is defined within a node that has been passed to the template as an instance variable (see the section elsewhere in this document on Passing Data to Templates). Raises a Ruby ArgumentError (which typically aborts the program) if any of the following tests fail:
For example, the following would check that a node named "@vlan" had been passed into a template, and that it had a key named "id" of Ruby class String, raising an error if it hadn't:
<%
template_arg_node_key("@vlan", "id")
-%>
Ruby class Netomata::IPAddr is an extension of the standard Ruby IPAddr class. In addition to all the methods defined in the Ruby IPAddr class, the Netomata::IPAddr class adds a set of methods for obtaining IP netmasks in various formats.
Returns ipaddr's netmask as a string in canonical format (dotted-quad for IPv4, and ':'-separated hex for IPv6).
For example:
Returns the number of significant bits in the netmask of ipaddr.
For example:
Returns the number of significant bits in netmask, which is expressed in any of the following forms:
For example:
Returns the netmask of ipaddr as a string in CIDR notation.
For example:
Returns a netmask as a string in CIDR notation, from input netmask, which is expressed in any of the following forms:
For example:
Returns the netmask of ipaddr as a string in "dotted quad" (IPv4) notation.
For example:
Returns a netmask as a string in CIDR notation, from input netmask, which is expressed in any of the following forms:
netmask must be an IPv4 netmask (i.e., 0 to 32 bits). If netmask is not a valid IPv4 netmask, then an error is raised.
For example:
foo <% 3.times do %> x <% end %> bazThis will result in the following output, with what many would consider to be extraneous newlines:
foo x x x bazTo eliminate the extraneous newlines, simply change the closing tag for the embedded Ruby blocks from '%>' to '-%>'. That will cause the ERB interpreter to suppress the newline that would otherwise immediately follow the closing tag:
foo <% 3.times do -%> x <% end -%> bazResulting in the following output, without the extraneous newlines:
foo x x x baz
Some ERB documentation speaks of a syntax whereby lines begining with '%' are also treated as Ruby code (i.e., a line '% Ruby code' is treated the same as a line '<% Ruby code %>'). This syntax is not supported in ncg files.
ncg was originally written in 2008 by Brent Chapman of Netomata, Inc.
Please report any you find by email to bugs@netomata.com.
Brent Chapman of Netomata, Inc.
Copyright (C) 2009, 2010 Netomata, Inc. All Rights Reserved.
ncg program, neto file format, neto_table file format.
This documentation is for ncg version 0.10.x.