title: Using mako for Cisco config generation. Is it possible to use the netaddr module (or any module) in templates?
body: <p>I am very new to python and mako and I may be having trouble with basic concepts.  I have working templates but my CSV input could be cleaned up considerably if I could use the netaddr module to work with IP addresses in the template.  What I would like to do is pass an interface IP variable like:
  LAN_IP = '192.168.1.1/24' (I am doing this from a CSV) to the template and then somehow use the netaddr module to fill in the IP, subnet mask (in dotted decimal and inverse mask) and the network address so I can use that one CSV variable for bgp network statements, eigrp masks and ACLs, etc in the same configuration.  I can do the following from a Python shell:</p>
  
  <pre><code>&gt;&gt;&gt; from netaddr import *
  &gt;&gt;&gt; LAN_IP = '192.168.1.1/24'
  &gt;&gt;&gt; IP = IPNetwork(LAN_IP)
  &gt;&gt;&gt; print(IP.ip)
  192.168.1.1
  &gt;&gt;&gt; print(IP.network)
  192.168.1.0
  &gt;&gt;&gt; print(IP.netmask)
  255.255.255.0
  &gt;&gt;&gt; print(IP.hostmask)
  0.0.0.255
  </code></pre>
  
  <p>EDIT.  I was told to try the ipaddress built in fuction.  Trying this from a Python prompt shows that it can work:</p>
  
  <pre><code>MAKO_TEMPLATE_STRING = """\
  &lt;%def name="get_netmask(ip_string)"&gt;&lt;%
      import ipaddress
      return ipaddress.IPv4Interface(ip_string).netmask
  %&gt;&lt;/%def&gt;
  &lt;%def name="get_address(ip_string)"&gt;&lt;%
      import ipaddress
      return ipaddress.IPv4Interface(ip_string).ip
  %&gt;&lt;/%def&gt;
  &lt;%def name="get_subnet(ip_string)"&gt;&lt;%
      import ipaddress
      return ipaddress.IPv4Interface(ip_string).network
  %&gt;&lt;/%def&gt;
  &lt;%def name="get_hostmask(ip_string)"&gt;&lt;%
      import ipaddress
      return ipaddress.IPv4Interface(ip_string).hostmask
  %&gt;&lt;/%def&gt;
  ! Variable Input: ${data}
  ${get_address(data)} ${get_netmask(data)} ${get_subnet(data)} ${get_hostmask(data)}
  """
  print(Template(MAKO_TEMPLATE_STRING).render(data="192.168.1.1/25"))
  </code></pre>
  
  <p>This gives me the following output:
  ! Variable Input: 192.168.1.1/25
  192.168.1.1 255.255.255.128 192.168.1.0/25 0.0.0.127</p>
  
  <p>Now, a new problem is that the ipaddress.IPv4Interface(ip_string).network definition returns the network PLUS the subnet "192.168.1.0/25" which netaddr did not do.  I have not found any way to get ipaddress to return ONLY the subnet portion.</p>
  
  <p>So for the template build I got a bit farther.... If I put ONLY this into the template, it validates:</p>
  
  <pre><code>&lt;%def name="get_netmask(ip_string)"&gt;&lt;%
      import ipaddress
      return ipaddress.IPv4Interface(ip_string).netmask
  %&gt;&lt;/%def&gt;
  &lt;%def name="get_address(ip_string)"&gt;&lt;%
      import ipaddress
      return ipaddress.IPv4Interface(ip_string).ip
  %&gt;&lt;/%def&gt;
  &lt;%def name="get_network(ip_string)"&gt;&lt;%
      import ipaddress
      return ipaddress.IPv4Interface(ip_string).network
  %&gt;&lt;/%def&gt;
  </code></pre>
  
  <p>But when I try any type of reference, I get an error.</p>
  
  <pre><code>! Variable Input: ${LAN_IP}  &lt;--I tried with and without this line
  ${get_address(LAN_IP)}  &lt;--The template does not seem to like these references.
  ${get_netmask(LAN_IP)}
  ${get_subnet(LAN_IP)}
  </code></pre>
  
  <p>It seems to me that I am missing something really simple here but maybe I am approaching the problem the wrong way.  Any help would be greatly appreciated as the Mako docs and Google have turned up little to illustrate how to do something like this.</p>