官术网_书友最值得收藏!

Creating Puppet 4 functions

The Puppet 3 functions API has some limitations and is missing features. The new function API in Puppet 4 improves upon that substantially.

Some of the limitations of the old functions are as follows:

  • The functions had no automatic type checking
  • These functions had to have a unique name due to a flat namespace
  • These functions were not private and hence could be used anywhere
  • The documentation could not be retrieved without running the Ruby code

Running on Puppet 3 requires functions to be in a module in the lib/puppet/parser/functions directory. Therefore, people referred to these functions as parser functions. But this name is misleading. Functions are unrelated to the Puppet parser.

In Puppet 4, functions have to be put into a module in path lib/puppet/functions.

This is how you create a function that will return the hostname of the Puppet Master:

# modules/utils/lib/puppet/functions/resolver.rb
require 'socket'
Puppet::Functions.create_function(:resolver) do
  def resolver()
    Socket.gethostname
  end
end

Using dispatch adds type checking for attributes. Depending on desired functionality, one might have multiple dispatch blocks (checking for different data types). Each dispatch can refer to another defined Ruby method inside the function. This reference is possible by using the same names for dispatch and the Ruby method.

The following example code should get additional functionality; depending on the type of argument, the function should either return the hostname of the local system, or use DNS to get the hostname from an IPv4 address or the ipaddress for a given hostname:

require 'resolv'
require 'socket'
Puppet::Functions.create_function(:resolver) do
  dispatch :ip_param do
     param 'Pattern[/^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/]', :ip
  end
  dispatch :fqdn_param do
     param 'Pattern[/^([a-z0-9\.].*$/]', :fdqn
  end
  dispatch :no_param do
  end

  def no_param
    Socket.gethostname
  end
  def ip_param(ip)
    Resolv.getname(ip)
  end
  def fqdn_param(fqdn)
    Resolv.getaddress(fqdn)
  end
end

At the beginning of the file, we have to load some Ruby modules to allow the DNS name resolution and finding the local hostname.

The first two dispatch sections check for the data type of the parameter value and set a unique symbol. The last dispatch section does not check for data types, which matches when no parameter was given.

Each defined Ruby method uses the name of the according dispatch and executes Ruby code depending on the parameter type.

Now the resolver function can be used from inside the Puppet manifest code in three different ways:

class resolver {
  $localname = resolver()
  notify { "Without argument resolver returns local hostname: ${localname}": }

  $remotename = resolver('puppetlabs.com')
  notify { "With argument puppetlabs.com: ${remotename}": }

  $remoteip = resolver('8.8.8.8')
  notify { "With argument 8.8.8.8: ${remoteip}": }
}

When declaring this class, the following output will show up:

puppet apply -e 'include resolver'
Notice: Compiled catalog for puppetmaster.example.net in environment production in 0.35 seconds
...
Notice: Without argument resolver returns local hostname: puppetmaster

Notice: With argument puppetlabs.com: 52.10.10.141

Notice: With argument 8.8.8.8: google-public-dns-a.google.com

Notice: Applied catalog in 0.04 seconds

With Puppet 3 functions, it was impossible to have two functions of the same name. One always had to check whether duplicate functions appeared when making use of a new module.

The Puppet 4 functions now offer the possibility of using namespacing just like classes.

Let's migrate our function into the class namespace:

# modules/utils/lib/puppet/functions/resolver/resolve.rb
require 'resolv'
require 'socket'
Puppet::Functions.create_function(:'resolver::resolve') do
  # the rest of the function is identical to the example given # above
end

In the example, the code needs to be in resolver/lib/puppet/functions/resolver/resolve.rb which corresponds to function name: 'resolver::resolve'.

Functions with namespaces are invoked as usual:

class resolver {
  $localname = resolver::resolve()

  $remotename = resolver::resolve('puppetlabs.com')

  $remoteip = resolver::resolve('8.8.8.8')
}
主站蜘蛛池模板: 遂溪县| 同心县| 周宁县| 凤翔县| 航空| 新田县| 钦州市| 十堰市| 方城县| 上栗县| 柳河县| 西乌珠穆沁旗| 丘北县| 兴国县| 七台河市| 克山县| 锡林浩特市| 任丘市| 额济纳旗| 嘉义县| 新源县| 石阡县| 容城县| 犍为县| 武城县| 徐汇区| 固安县| 乐昌市| 铜陵市| 霍城县| 南漳县| 吉林省| 大邑县| 涞水县| 沈丘县| 电白县| 城固县| 安宁市| 兴海县| 额尔古纳市| 翁源县|