HomeSysadmin › Calling custom functions from other custom functions in Puppet

Calling custom functions from other custom functions in Puppet

This post probably describes a bug, but I haven’t had the time yet to determine if this still exists in Puppet 2.6.x. Instead, here’s a post that will hopefully help out someone else having the same problem.

The other day, I was writing some custom parser functions for our Puppet 0.25.x install. In the interest of reusability, the idea was to keep the functions small and composable, and have them call each other in a nice, maintainable way in order to prevent code duplication.

As per the Puppet documentation, Puppet functions are called from Ruby by prefixing the function name with function_:

module Puppet::Parser::Functions
    newfunction(:my_function) do |args|
        # Puppet functions expect an array containing all of the arguments,
        # so we have to wrap our single string argument
        function_notice(["Called notice() from my_function()"])
    end
end

This worked great for calling built-in functions, but when I tried to call one of my own functions from another of my own functions, Puppet would just hang:

my_function.rb:

module Puppet::Parser::Functions
    newfunction(:my_function) do |args|
        function_my_other_function(args)
    end
end

my_other_function.rb:

module Puppet::Parser::Functions
    newfunction(:my_other_function)
        # Never get here
    end
end

After a bunch of debugging, I found that the Puppet autoloader seemed to be spinning itself into an infinite loop trying to locate and load my_other_function when it was called from my_function.rb. The solution was to manually require the file containing that function:

require File.join([File.expand_path(File.dirname(__FILE__)), 'my_other_function.rb'])
 
module Puppet::Parser::Functions
    newfunction(:my_function) do |args|
        function_my_other_function(args)
    end
end

The above assumes, of course, that the functions are in the same directory as one another.

With the dependency loaded, the custom function should work the same as any other parser function.

6 Comments.[ Leave a comment ]

  1. This an existing issue, #4549. I also wasted a bunch of time and independently found it as #5587 with 2.6. The later issue has some other workarounds that will still use the autoloader.

  2. Also related to #2930. Your work around actually got me past the issue, thank you very much! Sadly, It just led to my next stumbling block, but each step is one step closer to success.

  3. So once again my search for things brings me to your page (thank you!).

    Unfortunately, what you says works for you is giving me an error. Using the function_notice you have above I was getting this error:

    undefined method `join' for "Call notice() from my_function":String at /etc/puppet/manifests/template.pp:8 on node

    After a little bit of not understanding why it was throwing a join error I just wrapped the string in [] and it started working.

    module Puppet::Parser::Functions
        newfunction(:my_function) do |args|
            function_notice(["Called notice() from my_function()"])
        end
    end

    Then had the ‘ah duh’ understanding that all of these functions require a list input when called from inside other functions. I had run into this first time around with just the chaining of functions in general, and you show it above because you are passing the args list to the other functions.

Leave a Comment

NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">