custom function error undefined local variable

540 views
Skip to first unread message

Mark Rosedale

unread,
Oct 2, 2014, 1:23:25 PM10/2/14
to puppet...@googlegroups.com
I have the following custom function that I'm trying to write. 

require 'resolv'

module Puppet::Parser::Functions
  newfunction(:getIpAddr, :type => :rvalue) do |arguments|
    Resolv::DNS.open do |dns|
      ress = dns.getresources(arguments[0], Resolv::DNS::Resource::IN::A)
      if ress.any?
        dns.getaddress(arguments[0])
        #break
      else
        raise(Puppet::ParseError, "No valid A Record found for host #{aguments[0]}")
      end
    end
    #return value
  end
end

I'm getting the following error when I run this function. 

Error: Could not retrieve catalog from remote server: Error 400 on SERVER: undefined local variable or method `dns' for #<Puppet::Parser::Scope:0x7f5054f07110> at 


Mike Skint

unread,
Oct 2, 2014, 2:35:58 PM10/2/14
to puppet...@googlegroups.com

just guessing, is this a typo: " if ress.any?"

Wil Cooley

unread,
Oct 3, 2014, 2:00:27 AM10/3/14
to puppet-users group


On Oct 2, 2014 10:23 AM, "Mark Rosedale" <mros...@vivox.com> wrote:
>
> I have the following custom function that I'm trying to write. 
>

Sorry this isn't an answer to your question, but I recently published a module of functions wrapping the standard system get*by* functions (well, wrapping Ruby's interfaces to the standard system functions):  https://forge.puppetlabs.com/wcooley/name_service_lookups

This includes `gethostbyname` and `gethostbyaddr`; the main benefit over querying DNS directly is that it understands nsswitch, so /etc/hosts works and any other host database you might want to use.

But assuming you want to implement this anyway an exercise in learning Ruby & Puppet extensions, you might start by removing all the Puppet stuff and just get the lookups working as a simple standalone Ruby script.

Wil

> --
> You received this message because you are subscribed to the Google Groups "Puppet Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/02de838d-6cb2-495a-883d-98fb15782df9%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Mark Rosedale

unread,
Oct 3, 2014, 3:41:57 PM10/3/14
to puppet...@googlegroups.com
Wil, 

Thanks for the reply. I will look up the module functions you reference. Though, part  of this was writing the custom function as a learning exercise. 

So if I have a file with the following in it and run it through ruby it works. 

require 'resolv'
Resolv::DNS.open do |dns|
  ress = dns.getresources "google.com", Resolv::DNS::Resource::IN::A
  if ress.any?
    puts dns.getaddress("google.com")
  end
end

To reference Mike's question. What I found was that 'if ress.any?' works and that is what allows me to protect against malformed host names or a failure to find an A record. 

So I've already chopped out the puppet stuff, and this code works. So I'm thinking that it must be something with the require statement, where it isn't finding the library I need. But I'm not sure what I can do from here. 

Mark Rosedale

unread,
Oct 6, 2014, 12:07:46 PM10/6/14
to puppet...@googlegroups.com
Still haven't been able to hunt down the cause of this issue. Is there a way to test the code with the puppet wrapping on the cli? 

José Luis Ledesma

unread,
Oct 6, 2014, 1:07:45 PM10/6/14
to puppet...@googlegroups.com

Credits go to Nan Liu:

If you are developing facts, it's much easier to just drop into IRB and get everything working there rather than doing round trip debugging between puppet and facter:

irb(main):001:0> require 'facter'

=> true

irb(main):002:0> Facter.value("hostname")

=> "demo-1"

irb(main):003:0> Facter.value("hostname").split('-')

=> ["demo", "1"]

irb(main):006:0>  Facter.add('network_geo') do

irb(main):007:1*   setcode do

irb(main):008:2*     hostname_array =  Facter.value(:hostname).split('-')

irb(main):009:2>

irb(main):010:2*     # debug info

irb(main):011:2*     puts "My network is #{hostname_array}"

irb(main):012:2>     hostname_array.first

irb(main):013:2>   end

irb(main):014:1> end

irb(main):015:0> Facter.value(:network_geo)

My network is ["demo", "1"]

=> "demo"

If you run your existing fact in irb, you'll see the output is nil instead:

Facter.value(:network_geo)

My network is ["demo", "1"]

=> nil

Hth,

Sebastiaan van Steenis

unread,
Oct 6, 2014, 1:47:06 PM10/6/14
to puppet...@googlegroups.com
What version are you running? And what is the output if you try to call the function as you have it now?

Message has been deleted

Mark Rosedale

unread,
Oct 9, 2014, 4:10:33 PM10/9/14
to puppet...@googlegroups.com, pup...@superseb.nl
Puppet 3.5.1
ruby 1.8.7

Output is:

Error: Could not retrieve catalog from remote server: Error 400 on SERVER: undefined local variable or method `dns' for #<Puppet::Parser::Scope:0x7f5055562988> at /etc/puppet/modules/vivox/manifests/init.pp:69 on node xxx
Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run

Sebastiaan van Steenis

unread,
Oct 10, 2014, 2:10:52 AM10/10/14
to puppet...@googlegroups.com
I cannot reproduce your error, but your function does conflict with some internals I guess. I have some other modules failing when I use your function. If I simplify your function (https://gist.github.com/superseb/fdb443e86a8470a276a5) it works just fine. What other modules and/or custom functions are in your module path? Could you try using only the module with this custom function and see how that goes? Don’t forget to restart the Puppetmaster if you are changing functions.

Sebastiaan van Steenis

unread,
Oct 10, 2014, 2:12:27 AM10/10/14
to puppet...@googlegroups.com
Second thought, could you show the init.pp file in vivox/manifests ? Or just the relevant parts around line 69?

jcbollinger

unread,
Oct 10, 2014, 10:38:37 AM10/10/14
to puppet...@googlegroups.com


On Monday, October 6, 2014 11:07:46 AM UTC-5, Mark Rosedale wrote:
Still haven't been able to hunt down the cause of this issue. Is there a way to test the code with the puppet wrapping on the cli? 



As Jose suggested, use irb to test the generic parts.

As far as I can tell, however, your error does not correspond to the code you presented.  I am therefore inclined to guess that the master is using something different -- possibly an unfinished version somehow made its way into your master.  (In particular, be aware that the master does not use plugin code directly from your modules; plugins need to be synced into your master's appropriate directory before they can be used.)  You may need to restart the master afterward, too, as it only loads each plugin once, the first time it has need for it.


John

Mark Rosedale

unread,
Oct 10, 2014, 11:46:13 AM10/10/14
to puppet...@googlegroups.com, pup...@superseb.nl
<<Don’t forget to restart the Puppetmaster if you are changing functions >>

This turned out to be the issue.  I don't typically restart the puppet master when I'm doing other fast fire development so it slipped my mind, but in this case it is absolutely required. I did some testing, and if you change code, even remove all the code, but don't restart the puppetmaster it will continue to spit out the same error as if nothing has changed. But yes the function works as written above. So thanks for that...figures it would be something so simple. 

<<but your function does conflict with some internals I guess. I have some other modules failing when I use your function.>>

Interesting. Do you have any idea why? At the moment I'm just happy to know that it works. I looked at your version and it is simpler, which I like, but I would be curious how this could be causing issues elsewhere. 

Thanks for the help. 
Reply all
Reply to author
Forward
0 new messages