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

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')
}
主站蜘蛛池模板: 兴义市| 河东区| 莒南县| 明光市| 虎林市| 土默特右旗| 昌图县| 西贡区| 加查县| 鄱阳县| 武乡县| 绥中县| 琼结县| 德江县| 巫山县| 准格尔旗| 蒙阴县| 古蔺县| 襄城县| 红桥区| 江津市| 屏东市| 汤原县| 会宁县| 台江县| 阆中市| 牟定县| 连城县| 延庆县| 赤峰市| 伊金霍洛旗| 崇阳县| 洛阳市| 和平区| 香格里拉县| 邢台市| 克什克腾旗| 凤冈县| 龙江县| 霸州市| 石林|