Getting IP address of red interface in template

v7

(Dan) #1

I’m wanting to build a nethserver-acme-dns module to (hopefully) greatly simplify this process: https://wiki.nethserver.org/doku.php?id=userguide:let_s_encrypt_acme-dns. The bulk of the job, I think, is going to be templating the config.cfg file. I think I have a fairly clear idea of how I’ll get most of it in place, but I’m stuck at figuring out the external IP address.

The config file needs to specify the external IP address in a few places. If I made the user specify the address directly in a config db entry, that would be simple for me, but a pain for the user. If I made the user specify the red interface name, that would be slightly less simple for me (though still quite do-able), but still a bit of a pain for the user (and everything the user needs to do manually is an opportunity for them to get it wrong). But I can’t wrap my head around how a template might figure out the (or “a”) red IP address on its own. Any thoughts?


(Giacomo Sanchietti) #2

You can get the IP addess only if the red interface is configured as static:

my $ndb = esmith::NetworksDB->open_ro() || die "Can't open networks database: $!\n";

foreach ($ndb->red()) {
    my $ip = $_>prop('ipaddr') || next;
    print "$ip\n";
}

Take a look at this: https://github.com/NethServer/nethserver-dnsmasq/blob/fd3818f3c2cc7d556e4d0069dc02a7a17ec9048a/root/etc/e-smith/templates/etc/dnsmasq.conf/40bind

Also, bear in mind that this the IP address of the red interface, it could be private one and not the public one.


(Dan) #3

Sure. So I should probably allow for a property for the external IP, to allow users to set that directly if needed, but default to the IP of the red interface. But I’m getting an error with that code:

ERROR in /etc/e-smith/templates-custom//etc/test/10global: Program fragment delivered error <<Can't locate object method "open_ro" via package "esmith::NetworksDB" (perhaps you forgot to load "esmith::NetworksDB"?) at /etc/e-smith/templates-custom//etc/test/10global line 3.>> at template line 1
ERROR: Template processing failed for //etc/test: 1 fragment generated errors
 at /sbin/e-smith/expand-template line 45.

(Giacomo Sanchietti) #4

You need to import required libraries:

use esmith::NetworksDB;

More info with:

perldoc esmith::NetworksDB

It’s advised to use:

use strict;

(Dan) #5

Well, that would make sense. I’m now running into a different issue, and it has me scratching my head because, as far as I can tell, I’m doing the same thing in a different template and it’s working. I need to deal with a number of variations of the system’s domain name, so I’m doing things like:

my $domain = "acme.".$DomainName;
my $nsname = "ns1.acme.".$DomainName;
my $nsadmin = "admin.".$DomainName;
my $domaindot = "acme.".$DomainName.".";
my $nsnamedot = "ns1.acme.".$DomainName.".";
my $ns2namedot = "ns2.acme.".$DomainName.".";

This same usage is present in the automx config.cfg template, and it works as expected. Here, though, I get:

WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 15.
ERROR in /etc/e-smith/templates//etc/test/10global: Program fragment delivered error <<Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 10.

(repeated for each time I use $DomainName)


(Markus Neuberger) #6

Just an idea: You may try to use ${DomainName} instead.

http://docs.nethserver.org/projects/nethserver-devel/en/v7/templates.html#the-text-template-module


(Giacomo Sanchietti) #7

Looking at the code, I can’t see any error. That variable should be already defined.
Can you post your code on GitHub so I can try it?


(Dan) #8

Unfortunately, no dice–I get the same result with that.

I think it’s a little premature to put anything up there at this point, but here’s the fragment I’m working with:

{
use esmith::NetworksDB;
use strict;
my $ndb = esmith::NetworksDB->open_ro() || die "Can't open networks database: $!\n";

foreach ($ndb->red()) {
    my $ip = $_>prop('ipaddr') || next;
}

my $domain = "acme.".${DomainName};
my $nsname = "ns1.acme.".${DomainName};
my $nsadmin = "admin.".${DomainName};
my $domaindot = "acme.".${DomainName}.".";
my $nsnamedot = "ns1.acme.".${DomainName}.".";
my $ns2namedot = "ns2.acme.".${DomainName}.".";

 $OUT .= <<EOF

[general]
# dns interface
listen = "$ip:1053"
# protocol, "udp", "udp4", "udp6" or "tcp", "tcp4", "tcp6"
protocol = "udp"
# domain name to serve the requests off of
domain = "$domain"
# zone name server
nsname = "$nsname"
# admin email address, where @ is substituted with .
nsadmin = "$nsadmin"
# predefined records served in addition to the TXT
records = [
    # default A
    "$domaindot A $ip",
    # A
    "$nsnamedot A $ip",
    "$ns2namedot A $ip",
    # NS
    "$domaindot NS $nsnamedot",
    "$domaindot NS $ns2namedot",
]
# debug messages from CORS etc
debug = false
EOF
}

What I’ve been doing to test it, since I need a machine with a red interface, is put this fragment on my production box at /etc/e-smith/templates-custom/etc/test/10global, and then run expand-template /etc/test. When I do, I get this:

[root@neth test]# expand-template /etc/test
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 10.
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 11.
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 12.
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 13.
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 14.
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 15.
ERROR in /etc/e-smith/templates//etc/test/10global: Program fragment delivered error <<Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 10.
Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 11.
Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 12.
Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 13.
Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 14.
Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 15.
Global symbol "$ip" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 17.
Global symbol "$ip" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 17.
Global symbol "$ip" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 17.
Global symbol "$ip" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 17.>> at template line 1
ERROR: Template processing failed for //etc/test: 6 fragments generated warnings, 1 fragment generated errors
 at /sbin/e-smith/expand-template line 45.

(Marc) #9

Maybe adding:

use esmith::ConfigDB;

(Markus Neuberger) #10

https://wiki.nethserver.org/doku.php?id=esmith:configdb


(Dan) #11

Simply adding this at the beginning doesn’t appear to change the output at all. Making a few edits suggested by the page @mrmarkuz linked, I end up with this at the beginning:

{
use esmith::ConfigDB;
use esmith::NetworksDB;
use strict;
my $db = esmith::ConfigDB->open_ro;
my $ndb = esmith::NetworksDB->open_ro() || die "Can't open networks database: $!\n";

foreach ($ndb->red()) {
    my $ip = $_>prop('ipaddr') || next;
}

my $DomainName = $DomainName->value;
my $domain = "acme.".${DomainName};
my $nsname = "ns1.acme.".${DomainName};
my $nsadmin = "admin.".${DomainName};
my $domaindot = "acme.".${DomainName}.".";
my $nsnamedot = "ns1.acme.".${DomainName}.".";
my $ns2namedot = "ns2.acme.".${DomainName}.".";

 $OUT .= <<EOF

[general]

(the rest unchanged). Output is different, but still looks like I’m running into the same error:

[root@neth test]# expand-template /etc/test
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 12.
ERROR in /etc/e-smith/templates//etc/test/10global: Program fragment delivered error <<Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 12.
Global symbol "$ip" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 20.
Global symbol "$ip" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 20.
Global symbol "$ip" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 20.
Global symbol "$ip" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 20.>> at template line 1
ERROR: Template processing failed for //etc/test: 1 fragment generated warnings, 1 fragment generated errors
 at /sbin/e-smith/expand-template line 45.

Even changing it further, to my $DomainName = $db->get_value($DomainName);, doesn’t change the results. And yes, DomainName is set:

[root@neth test]# config show DomainName
DomainName=familybrown.org

(Marc) #12

Not familiar with Perl, but for this error it could be the variable scope. Try declaring the my $ip outside the foreach loop.


(Marc) #13

you can try removing that line, and commenting the foreach loop to see if $DomainName works.

Could be a typo here?


(Dan) #14

Still no dice. The fragment now begins:

{
use esmith::ConfigDB;
use esmith::NetworksDB;
use strict;
my $db = esmith::ConfigDB->open_ro;

my $ip = "1.2.3.4";
my $domain = "acme.".${DomainName};
my $nsname = "ns1.acme.".${DomainName};
my $nsadmin = "admin.".${DomainName};
my $domaindot = "acme.".${DomainName}.".";
my $nsnamedot = "ns1.acme.".${DomainName}.".";
my $ns2namedot = "ns2.acme.".${DomainName}.".";

 $OUT .= <<EOF

[general]

…and the output from trying to expand it is:

[root@neth test]# expand-template /etc/test
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 8.
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 9.
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 10.
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 11.
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 12.
WARNING in /etc/e-smith/templates//etc/test/10global: Variable "$DomainName" is not imported at /etc/e-smith/templates//etc/test/10global line 13.
ERROR in /etc/e-smith/templates//etc/test/10global: Program fragment delivered error <<Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 8.
Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 9.
Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 10.
Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 11.
Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 12.
Global symbol "$DomainName" requires explicit package name at /etc/e-smith/templates//etc/test/10global line 13.>> at template line 1
ERROR: Template processing failed for //etc/test: 6 fragments generated warnings, 1 fragment generated errors
 at /sbin/e-smith/expand-template line 45.

There’s got to be something fundamental I’m missing. This should work. The docs say it should work, and it works in other templates. And I’ll probably feel kind of dumb when I find out what it is.


(Giacomo Sanchietti) #15

The use strict keyword was causing the issue. Also, you have an invalid syntax inside the for loop.
This is a working extract:

{
  use esmith::NetworksDB;
  my $ndb = esmith::NetworksDB->open_ro() || die "Can't open networks database: $!\n";

  foreach ($ndb->red()) {
    my $ip = $_->prop('ipaddr') || next;
  }

  my $domain = "acme.".${DomainName};
  my $nsname = "ns1.acme.".${DomainName};
  my $nsadmin = "admin.".${DomainName};
  my $domaindot = "acme.".${DomainName}.".";
  my $nsnamedot = "ns1.acme.".${DomainName}.".";
  my $ns2namedot = "ns2.acme.".${DomainName}.".";

}


(Dan) #16

Ah, much better. Yes, the $DomainName variable is now working as expected, and processing completes without errors (warnings yes, errors no):

[root@neth test]# expand-template /etc/test
WARNING in /etc/e-smith/templates//etc/test/10global: Use of uninitialized value $esmith::__TEMPLATE__::1::ip in concatenation (.) or string at /etc/e-smith/templates//etc/test/10global line 16.
WARNING in /etc/e-smith/templates//etc/test/10global: Use of uninitialized value $esmith::__TEMPLATE__::1::ip in concatenation (.) or string at /etc/e-smith/templates//etc/test/10global line 16.
WARNING in /etc/e-smith/templates//etc/test/10global: Use of uninitialized value $esmith::__TEMPLATE__::1::ip in concatenation (.) or string at /etc/e-smith/templates//etc/test/10global line 16.
WARNING in /etc/e-smith/templates//etc/test/10global: Use of uninitialized value $esmith::__TEMPLATE__::1::ip in concatenation (.) or string at /etc/e-smith/templates//etc/test/10global line 16.
WARNING: Template processing succeeded for //etc/test: 4 fragments generated warnings
 at /sbin/e-smith/expand-template line 45.

There’s no complaint at all about $ip any more, but $ip still isn’t working–any place in the template fragment that I use $ip, I get nothing. So

listen = "$ip:1053"

expands to

listen = ":1053"

If I add print $ip; inside the foreach loop, it does print the red IP address of the system, so that does seem to be working correctly.


(Giacomo Sanchietti) #17

Because you declared the variable as local.

I think you need to learn a little bit of perl :smiley:
http://mkweb.bcgsc.ca/intranet/perlbook/prog/ch04_08.htm


(Dan) #18

Yeah, probably so–I’m kind of bumbling around here.