Error: Function does not return a value

752 views
Skip to first unread message

iamauser

unread,
Jan 17, 2013, 8:40:11 PM1/17/13
to puppet...@googlegroups.com
My custom function looks like this :

module Puppet::Parser::Functions
        newfunction(:pattern_in_file, :type => :rvalue) do |args|
                filename = args[0]
                pattern = args[1]
                value = false
                File.open(filename) do |f|
                        f.each_line do |line|
                                return true if line.match(pattern)
                        end
                end
                false
        end
end

ruby -rpuppet and irb tests to see if the function is seen by puppet end successfully without any error.

Inside the manifests callings 
pattern_in_file('/etc/fstab', '/usr') 
don't complain or print anything, 

If I use :

$getval = pattern_in_file('/etc/fstab', '/usr')

It complains the following :

Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Function 'pattern_in_file' does not return a value at /etc/puppet/modules/mname/manifests/datavers.pp:3 on node node_name

Any suggestion why the return doesn't work ?

iamauser

unread,
Jan 18, 2013, 9:35:30 AM1/18/13
to puppet...@googlegroups.com
Any words/thoughts/suggestions/hints/ideas/pointers ?

jcbollinger

unread,
Jan 18, 2013, 10:22:35 AM1/18/13
to puppet...@googlegroups.com


Basically, it doesn't work because the Ruby block defining your function's behavior (do |args| ... end) is exactly that -- a block.  The 'return' statement does not set the value of the block; instead, it attempts to return from the method that evaluates the block.  Without knowing any details about that method's implementation, it is very dangerous to make your block attempt to return from it.  Indeed, it appears that doing so is the wrong thing in this case.

You must instead ensure that the block evaluates to the desired value.  For example:

module Puppet::Parser::Functions
  newfunction(:pattern_in_file, :type => :rvalue) do |args|
    filename = args[0]
    pattern = args[1]
    File.open(filename) do |f|
      f.lines.any? { |line| line.match(pattern) }
    end or false
    # The "or false" converts nil to false for safety, in
    # the event that the specified file does not exist.
  end
end


That's cleaner and clearer anyway, at least for this example.


John

iamauser

unread,
Jan 18, 2013, 11:08:49 AM1/18/13
to puppet...@googlegroups.com
Hi John,

Thanks for the reply. Your corrections made it work. As you pointed out about the implementation of this code. I wrote it keeping in mind 'def' of ruby where one can return a value evaluating a block. Syntactically it didn't have a problem with Ruby, but it failed to return a value in puppet's case.

I am trying to implement this code to check pattern in a file, e.g. (/etc/fstab) before puppet tries to edit it. In other words, trying to find an equivalent of "BeginGroupIfNoLineContaining" of cfengine. This may not be the best method though.

Cheers

jcbollinger

unread,
Jan 18, 2013, 2:44:56 PM1/18/13
to puppet...@googlegroups.com


On Friday, January 18, 2013 10:08:49 AM UTC-6, iamauser wrote:
Hi John,

Thanks for the reply. Your corrections made it work. As you pointed out about the implementation of this code. I wrote it keeping in mind 'def' of ruby where one can return a value evaluating a block. Syntactically it didn't have a problem with Ruby, but it failed to return a value in puppet's case.

I am trying to implement this code to check pattern in a file, e.g. (/etc/fstab) before puppet tries to edit it. In other words, trying to find an equivalent of "BeginGroupIfNoLineContaining" of cfengine. This may not be the best method though.


Not only is it not the best method, it is not a viable method.  Puppet functions are evaluated on the master, with no visibility on client details other than anything passed as arguments.  You need something that runs on the client.

You might want to look into augeas for editing the file.  Alternatively, it would be closer to your current design to implement and use a custom fact.  If you are modifying the file via an Exec, then use grep in its 'onlyif' or 'unless' parameter.  There are other alternatives, too.


John

Reply all
Reply to author
Forward
0 new messages