Commit 9344ec7a authored by Anders Blomdell's avatar Anders Blomdell
Browse files

Version 2013-10-14 20:39

M  src/hostinfo/dhcpd.py
M  src/hostinfo/dhcpd_ipv6.py
M  src/hostinfo/ifconfig.py
M  src/hostinfo/named.py
M  src/hostinfo/util.py
parent a6360f87
import sys
import os
from hostinfo.util import ntoa, aton
import hostinfo.util as util
CLASS_PXECLIENT = """
class "pxeclient" {
match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
next-server %(next_server)s;
if option arch = 00:06 {
filename "pxelinux/bootia32.efi";
} else if option arch = 00:07 {
filename "pxelinux/bootx64.efi";
} else {
filename "pxelinux.0";
}
}
}
"""
def MacOS_NETBOOT(dhcphost):
if not os.path.exists('/local/macos'):
return ''
......@@ -86,59 +101,58 @@ def generate(tree, dhcphost, kickstart, next_server=None):
address.append(ip.address[0])
pass
pass
result += 'shared-network "MAC(%s)" {\n\n' % i.ethernet[0]
result += emit_network(tree, dhcphost, address, kickstart,
i.ethernet[0], next_server=next_server)
interface=i, next_server=next_server)
result += "}\n"
for v in vlan:
result += emit_network(tree, dhcphost, [ v ], kickstart,
None, next_server=next_server)
next_server=next_server)
pass
pass
return result
def emit_network(tree, dhcphost, addr, kickstart, ethernet=None,
next_server=None):
def emit_network(tree, dhcphost, addr, kickstart,
interface=None, next_server=None):
result = ""
network = {}
for n in tree._subnet_:
if not n.network[0]:
continue
netmask = aton(n.netmask[0])
subnet = aton(n.network[0]) & netmask
subnet = {}
for s in filter(util.network, tree._subnet_):
n = util.network(s)
for a in addr:
if aton(a) & netmask == subnet:
network[ntoa(subnet)] = n
if len(network.keys()) > 1:
# Multiple networks served on this interface
result += 'shared-network "MAC(%s)" {\n\n' % ethernet
for n in network.values():
for l in emit_subnet(tree, n, dhcphost, kickstart,
next_server=next_server).split("\n"):
result += " %s\n" % l
result += "}\n"
else:
result += emit_subnet(tree, network.values()[0], dhcphost, kickstart,
next_server=next_server)
if util.address(a) in n:
subnet[n] = s
pass
pass
pass
for n in sorted(subnet):
for l in emit_subnet(tree, subnet[n], dhcphost, kickstart,
interface=interface,
next_server=next_server).split("\n"):
result += " %s\n" % l
pass
pass
return result
def emit_subnet(tree, n, dhcphost, kickstart, next_server=None):
def emit_subnet(tree, subnet, dhcphost, kickstart,
interface=None, next_server=None):
result = ""
net = util.network(subnet)
if next_server == None:
next_server = dhcphost
pass
netmask = aton(n.netmask[0])
subnet = aton(n.network[0]) & netmask
static = {}
dynamic = {}
dynamic = set()
never = []
for ip in tree._host_._interface_._ip_:
# Find all hosts that belong to this network
if ip.address[0]:
net = aton(ip.address[0]) & netmask
if net == subnet:
a = util.address(ip)
if a:
a = util.address(ip)
if a in net:
if ip.dynamic[0] == dhcphost:
# Dynamic address served by this host
dynamic[aton(ip.address[0])] = ip
dynamic.add(a)
pass
else:
static[ip.name[0:]] = ip
......@@ -146,53 +160,55 @@ def emit_subnet(tree, n, dhcphost, kickstart, next_server=None):
pass
pass
if ip.never[0]:
net = aton(ip.never[0]) & netmask
if net == subnet:
a = util.address(ip.never[0])
if a in net:
never.append(ip.ethernet[0:])
pass
pass
pass
result += "subnet %s netmask %s {\n" % (n.network[0], n.netmask[0])
result += " option subnet-mask %s;\n" % n.netmask[0]
if n.broadcast[0]:
result += " option broadcast-address %s;\n" % n.broadcast[0]
pass
if n.gateway[0]:
result += " option routers %s;\n" % n.gateway[0]
result += "subnet %s netmask %s {\n" % (net.network, net.netmask)
result += " option subnet-mask %s;\n" % net.netmask
result += " option broadcast-address %s;\n" % net.broadcast
if subnet.gateway[0]:
result += " option routers %s;\n" % subnet.gateway[0]
pass
if n.domain[0]:
result += " option domain-name \"%s\";\n" % n.domain[0]
if subnet.domain[0]:
result += " option domain-name \"%s\";\n" % subnet.domain[0]
pass
if n.name_servers[0]:
result += " option domain-name-servers %s;\n" % n.name_servers[0]
if subnet.name_servers[0]:
result += " option domain-name-servers %s;\n" % subnet.name_servers[0]
pass
if n.ntp_servers[0]:
result += " option ntp-servers %s;\n" % (n.ntp_servers[0])
if subnet.ntp_servers[0]:
result += " option ntp-servers %s;\n" % (subnet.ntp_servers[0])
pass
#
# Emit dynamic hosts
#
result += " default-lease-time 14400; # 4 hours\n"
result += " max-lease-time 86400; # 1 day\n"
dk = dynamic.keys()
dk.sort()
for s in interface_subnets_matching(interface, net):
if s.first[0] and s.last[0]:
result += " range %s %s;\n" % (util.address(s.first[0]),
util.address(s.last[0]))
pass
pass
# FIXME: Old style dynamic...
min = 0
max = 0
for d in dk:
for d in sorted(dynamic):
if d == max + 1:
max = d
pass
else:
if min:
result += " range %s %s;\n" % (ntoa(min), ntoa(max))
result += " range %s %s;\n" % (min, max)
pass
min = d
max = d
pass
pass
if min:
result += " range %s %s;\n" % (ntoa(min), ntoa(max))
result += " range %s %s;\n" % (min, max)
pass
result += " get-lease-hostnames true;\n"
result += " use-host-decl-names on;\n"
......@@ -211,7 +227,7 @@ def emit_subnet(tree, n, dhcphost, kickstart, next_server=None):
ip = i.address[0]
if ether:
assert ether.lower() == ether, "%s is not lower-case" % ether
result += " host %s.%s {\n"% (i.name[0:], n.domain[0])
result += " host %s.%s {\n"% (i.name[0:], subnet.domain[0])
result += " hardware ethernet %s;\n" % ether
result += " fixed-address %s;\n" % ip
result += " option host-name \"%s\";\n" % i.name[0:]
......@@ -241,8 +257,52 @@ def emit_subnet(tree, n, dhcphost, kickstart, next_server=None):
result += " ignore booting;\n"
result += " }\n"
pass
# result += CLASS_PXECLIENT % { 'next_server': next_server }
for s in interface_subnets_matching(interface, net):
if s.kickstart[0] != 'any':
continue
else:
continue
for i in filter(lambda i: i.ethernet[0] and i._kickstart_,
tree._host_._interface_):
e = i.ethernet[0]
assert e.lower() == e, "%s not lower-case" % e
result += " host %s {\n"% (i.name[0:])
result += " hardware ethernet %s;\n" % e
result += " option host-name \"%s\";\n" % i.name[0:]
if not kickstart:
raise Exception("--kickstart needed for %s" % i.name[0:])
kf = i._kickstart_[0].file[0]
result += " server-name \"%s\";\n" % dhcphost
result += " next-server %s;\n" % next_server
result += " if substring(option vendor-class-identifier, "
result += "0, 20) = \n"
result += " \"PXEClient:Arch:00000\" {\n"
result += " filename \"pxelinux.0\";\n"
result += " } else {\n"
result += " filename \"%s/%s\";\n" % (kickstart, kf)
result += " }\n"
result += " }\n"
pass
result += " if substring(option vendor-class-identifier, "
result += "0, 20) = \n"
result += " \"PXEClient:Arch:00000\" {\n"
result += " filename \"pxelinux.0\";\n"
result += " } else {\n"
result += " filename \"%s/default\";\n" % (kickstart)
result += " }\n"
break
result += " }\n"
result += "}\n"
return result
def interface_subnets_matching(interface, net):
if not interface:
return
for s in filter(lambda s: util.network(s) == net, interface._subnet_):
yield s
pass
pass
......@@ -53,14 +53,14 @@ def emit_interface_ipv6(tree, interface, options):
subnet = set()
for ip in [ ip for ip in interface._ipv6_ if ip.address[0] ]:
a = ipaddr.IPAddress(ip.address[0])
subnet.update([ (s.prefix[0], s) for s in tree._subnet_ipv6_
subnet.update([ (s.prefix[0], s) for s in tree._subnet_
if (s.prefix[0] and a in ipaddr.IPNetwork(s.prefix[0]))
])
pass
for k,s in sorted(subnet):
result = StringArray()
dynamic = [ map(ipaddr.IPAddress, (r.first[0], r.last[0]))
for r in interface._dhcpserver_._subnet_ipv6_
for r in interface._dhcpserver_._subnet_
if r.first[0] and r.last[0] and r.prefix[0] == s.prefix[0] ]
result.append('subnet6 %s {' % ipaddr.IPNetwork(s.prefix[0]) )
result.extend(emit_subnet_ipv6(tree, s, dynamic, options).indent())
......
from hostinfo.util import aton
import hostinfo.util as util
import subprocess
import re
import ipaddr
......@@ -113,11 +114,9 @@ def generate_ifcfgv6(tree, interface):
pass
else:
address = []
for ipv6 in interface._ipv6_:
if not ipv6.address[0]:
continue
a = ipaddr.IPAddress(ipv6.address[0])
for s in [ ipaddr.IPNetwork(s.prefix[0]) for s in tree._subnet_ipv6_ ]:
for ipv6 in filter(util.address, interface._ipv6_):
a = util.address(ipv6)
for s in map(util.network, filter(util.network, tree._subnet_ )):
if a in s:
address.append('%s/%d' % (a, s.prefixlen))
pass
......
import copy
import hostinfo.parser
from hostinfo.util import ntoa, aton, fqn, by_ip
from hostinfo.util import fqn, by_ip, network, address
import ipaddr
import itertools
def reverse_addr(addr):
if addr == None:
return None
if addr.version == 4:
def join(l):
return '.'.join(reversed(l))+'.in-addr.arpa'
if isinstance(addr, ipaddr._BaseNet):
assert addr.prefixlen % 8 == 0
n = addr.prefixlen / 8
return join(addr.exploded.split('.')[0:n])
else:
return join(addr.exploded.split('.'))
pass
elif addr.version == 6:
def join(l):
return '.'.join(reversed(l))+'.ip6.arpa'
if isinstance(addr, ipaddr._BaseNet):
assert addr.prefixlen % 4 == 0
n = addr.prefixlen / 4
return join(map(None, addr.exploded.replace(':', ''))[0:n])
else:
return join(map(None, addr.exploded.replace(':', '')))
else:
raise Exception('Unknown address version %s' % addr)
def generate(tree, host):
#
......@@ -40,33 +66,41 @@ def generate(tree, host):
conf += ' file "0.0.127.in-addr.arpa";\n'
conf += '};\n'
result.append(("named/%s" % rzone, reverse_local(tree, host)))
forward = {}
reverse = {}
for s in tree._subnet_:
fzone = s.domain[0]
if not done.has_key(fzone):
if forward(tree, s):
conf += "zone \"%s\" { \n" % fzone
conf += " type master; file \"hosts-%s\"; \n" % fzone
conf += "};\n"
result.append(("named/hosts-%s" % fzone, forward(tree, s)))
pass
done[fzone] = 1
if not s.domain[0] in forward:
forward[s.domain[0]] = generate_forward(tree, s)
pass
if s.network[0]:
t = s.network[0].split(".")[0:3]
t.reverse()
rzone = ".".join(t) + ".in-addr.arpa"
if not done.has_key(rzone):
if reverse(tree, s):
conf += "zone \"%s\" { \n" % rzone
conf += " type master; file \"%s\"; \n" % rzone
conf += "};\n"
result.append(("named/%s" % rzone, reverse(tree, s)))
pass
done[rzone] = 1
pass
r = reverse_addr(network(s))
if r and not r in reverse:
reverse[r] = generate_reverse(tree, s)
pass
for s in tree._subnet_ipv6_:
if not s.domain[0] in forward:
forward[s.domain[0]] = generate_forward(tree, s)
pass
r = reverse_addr(network(s))
if r and not r in reverse:
reverse[r] = generate_reverse(tree, s)
pass
pass
for f in filter(lambda f: forward[f], sorted(forward)):
conf += "zone \"%s\" { \n" % f
conf += " type master; file \"hosts-%s\"; \n" % f
conf += "};\n"
result.append(("named/hosts-%s" % f, forward[f]))
pass
for r in filter(lambda r: reverse[r], sorted(reverse)):
conf += "zone \"%s\" { \n" % r
conf += " type master; file \"%s\"; \n" % r
conf += "};\n"
result.append(("named/%s" % r, reverse[r]))
pass
result.append(("named.conf", conf))
return result
......@@ -113,20 +147,14 @@ def header(tree, domain, origin=None):
result += ";\n"
return result
def forward(tree, domain):
def generate_forward(tree, domain):
result = header(tree, domain.domain[0], domain.domain[0])
if not result:
return None
net = []
for s in tree._subnet_:
if s.network[0] and s.domain[0] == domain.domain[0]:
net.append((aton(s.network[0]), aton(s.netmask[0])))
pass
pass
net_ipv6 = []
for s in tree._subnet_ipv6_:
if s.prefix[0] and s.domain[0] == domain.domain[0]:
net_ipv6.append(ipaddr.IPNetwork(s.prefix[0]))
if network(s) and s.domain[0] == domain.domain[0]:
net.append(network(s))
pass
pass
......@@ -161,15 +189,17 @@ def forward(tree, domain):
if not name in host:
host[name] = []
pass
host[name].append((kind, value))
if not (kind, value) in host[name]:
host[name].append((kind, value))
pass
pass
for i in tree._host_._interface_._ip_:
for i in filter(address, tree._host_._interface_._ip_):
# Find all hosts that belong to this network
for (n, m) in net:
if i.address[0] and aton(i.address[0]) & m == n:
for n in net:
if address(i) in n:
add_entry(i.name[1:], 'A', '%s' % i.address[0])
for a in i._alias_:
add_entry(a.name[0], 'CNAME', '%s' % i.name[1:])
add_entry(a.name[0], 'A', '%s' % i.address[0])
pass
for s in i._srv_:
port = int(s.port[0] or 0)
......@@ -182,13 +212,17 @@ def forward(tree, domain):
pass
pass
for i in tree._host_._interface_._ipv6_:
for p in net_ipv6:
if ipaddr.IPAddress(i.address[0]) in p:
for i in filter(address, tree._host_._interface_._ipv6_):
for n in net:
if address(i) in n:
add_entry(i.name[1:], 'AAAA', '%s' % i.address[0])
for a in i._alias_:
add_entry(a.name[0], 'AAAA', '%s' % i.address[0])
pass
pass
pass
pass
for c in domain._cname_:
# Emit cnames defined in subnet
add_entry(c.alias[0], 'CNAME', '%s' % c.name[0])
......@@ -203,26 +237,31 @@ def forward(tree, domain):
return result
def reverse(tree, net):
t = net.network[0].split(".")[0:3]
t.reverse()
origin = ".".join(t) + ".in-addr.arpa"
result = header(tree, net.domain[0], origin)
def generate_reverse(tree, subnet):
net = network(subnet)
origin = reverse_addr(net)
result = header(tree, subnet.domain[0], origin)
if not result:
return None
host = {}
m = aton(net.netmask[0])
n = aton(net.network[0])
for i in tree._host_._interface_._ip_:
for i in itertools.chain(tree._host_._interface_._ip_,
tree._host_._interface_._ipv6_):
# Find all hosts that belong to this network
if i.address[0] and aton(i.address[0]) & m == n:
addr = aton(i.address[0]) & ~m
host[addr] = "PTR %s" % fqn(tree, i)
hk = host.keys()
hk.sort()
for h in hk:
result += "%-16dIN %s\n" % (h, host[h])
a = address(i)
if not a:
continue
if a in net:
r = reverse_addr(a).replace('.%s' % origin, '')
host[r] = "PTR %s" % fqn(tree, i)
pass
pass
def order(a, b):
def int16(v):
return int(v, 16)
return cmp(map(int16, a.split('.')),
map(int16, b.split('.')))
for h in sorted(host, order):
result += "%-15s IN %s\n" % (h, host[h])
pass
return result
......@@ -263,5 +302,5 @@ def reverse_local(tree, nameserver):
t._add(h)
break
pass
return reverse(t, net)
return generate_reverse(t, net)
import ipaddr
import itertools
import types
def network(s):
if s.network[0] and s.netmask[0]:
return ipaddr.IPNetwork('%s/%s' % (s.network[0], s.netmask[0]))
elif s.prefix[0]:
return ipaddr.IPNetwork(s.prefix[0])
else:
return None
def address(ip):
if isinstance(ip, types.StringTypes):
return ipaddr.IPAddress(ip)
elif ip.address[0]:
return ipaddr.IPAddress(ip.address[0])
else:
return None
def aton(addr):
result = long(0)
for s in addr.split('.'):
......@@ -12,14 +32,14 @@ def fqn(tree, host):
name of host"""
if host.name[0:].endswith('.'):
return host.name[0:]
if host._tag == 'ip':
ip_addr = host.address[0]
if host._tag in [ 'ip', 'ipv6' ]:
ip_addr = address(host)
elif host._tag == 'interface':
for ip in host._ip_:
if ip.alias[0] or ip.vlan[0]:
continue
if ip.address[0]:
ip_addr = ip.address[0]
ip_addr = address(ip)
break
pass
pass
......@@ -28,9 +48,9 @@ def fqn(tree, host):
if ip_addr:
for s in tree._subnet_:
if (s.network[0] and
aton(ip_addr) & aton(s.netmask[0]) == aton(s.network[0])):
return "%s.%s." % (host.name[1:],s.domain[0])
net = network(s)
if net and ip_addr in net:
return "%s.%s." % (host.name[1:], s.domain[0])
pass
raise Exception("No subnet declaration for '%s' (%s)" %
(host.name[0:], ip_addr))
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment