Commit a6360f87 authored by Anders Blomdell's avatar Anders Blomdell
Browse files

Version 2013-10-07 19:01

M  src/hostinfo.py
M  src/hostinfo/__init__.py
M  src/hostinfo/dhcpd.py
A  src/hostinfo/dhcpd_ipv6.py
M  src/hostinfo/ifconfig.py
M  src/hostinfo/named.py
M  src/hostinfo/util.py
parent 92143960
#!/usr/bin/python
import copy
import hostinfo
import hostinfo.automount
import hostinfo.dhcpd
import hostinfo.ifconfig
import hostinfo.macosx_auto
import hostinfo.mio
......@@ -12,7 +12,7 @@ import hostinfo.pxelinux
import hostinfo.samba
import hostinfo.yp
import hostinfo.role
import optparse
import argparse
import os
import sys
......@@ -73,11 +73,6 @@ if not hasattr(__builtins__, "True"):
__builtins__["True"] = 1
__builtins__["False"] = 0
class VerboseOptionParser(optparse.OptionParser):
def error(self, msg):
self.print_help()
optparse.OptionParser.error(self, msg)
attr_weight = {
('host', 'name') : 1,
('interface', 'ip') : 1,
......@@ -98,6 +93,9 @@ attr_weight = {
# else:
# return 1
class AttributeDict(dict):
__getattr__ = dict.__getitem__
def host_order(a,b):
def at_top(n):
# Place hosts without ethernet or ip address at top
......@@ -206,78 +204,79 @@ def tag_sort(parent, a, b):
return None
if __name__ == '__main__':
optParser = VerboseOptionParser(usage="%prog [options] [hostinfo]")
optParser.add_option("--host",
action="store",
help="The host to generate information for")
optParser.add_option("--automount",
action="store", metavar="DIR",
help="generate automount maps in DIR")
optParser.add_option("--auto_domain",
action="store", metavar="DOMAIN",
help="DOMAIN name for automount maps")
optParser.add_option("--dfs",
action="store", metavar="DIR",
help="generate DIR/*/(dfslink|autolink)")
optParser.add_option("--dhcpd",
action="store", metavar="DIR",
help="generate DIR/dhcpd.conf file")
optParser.add_option("--ethers",
action="store", metavar="FILE",
help="Generate ethers FILE")
optParser.add_option("--ifconfig",
action="store", metavar="DIR",
help="Generate DIR/ifcfg-eth*")
optParser.add_option("--kickstart",
action="store", metavar="DIR",
help="kickstart files should be fetched from DIR")
optParser.add_option("--macosx_auto",
action="store", metavar="DIR",
help="Generate MacOSX autmount maps")
optParser.add_option("--mio",
action="store_true", default=False,
help="output mio tree")
optParser.add_option("--named",
action="store", metavar="DIR",
help="Generate DIR/named.conf and DIR/named/*")
optParser.add_option("--netgroup",
action="store", metavar="FILE",
help="Generate netgroup FILE")
optParser.add_option("--next_server",
action="store", metavar="HOST",
help="Use HOST as DHCP next-server")
optParser.add_option("--pretty",
action="store_true", default=False,
help="pretty-print XML tree")
optParser.add_option("--pxelinux",
action="store", metavar="DIR",
help="symlink DIR/<ethernet> to <kickstart>")
optParser.add_option("--role",
default=[],
action="append", metavar="ROLE",
help="check if machine has ROLE")
optParser.add_option("--samba",
action="store", metavar="FILE",
help="generate samba share FILE")
optParser.add_option("--yp",
action="store", metavar="DIR",
help="generate DIR/{hosts,ethers,etc} information")
optParser.add_option("--yp_auto_domain",
action="store", metavar="DOMAIN",
help="DOMAIN name for yp automounter maps")
(options, args) = optParser.parse_args(sys.argv[1:])
optParser = argparse.ArgumentParser(usage="%(prog)s [options] [hostinfo]")
optParser.add_argument("hostinfo_xml", nargs='?',
default="/etc/hostinfo.xml",
help="hostinfo file")
optParser.add_argument("--host",
default=os.uname()[1].split('.')[0],
action="store",
help="The host to generate information for")
optParser.add_argument("--automount",
action="store", metavar="DIR",
help="generate automount maps in DIR")
optParser.add_argument("--auto_domain",
action="store", metavar="DOMAIN",
help="DOMAIN name for automount maps")
optParser.add_argument("--dfs",
action="store", metavar="DIR",
help="generate DIR/*/(dfslink|autolink)")
optParser.add_argument("--dhcpd",
action="store", metavar="DIR",
help="generate DIR/dhcpd.conf file")
optParser.add_argument("--dhcpd6",
action="store", metavar="DIR",
help="generate DIR/dhcpd6.conf file")
optParser.add_argument("--ethers",
action="store", metavar="FILE",
help="Generate ethers FILE")
optParser.add_argument("--ifconfig",
action="store", metavar="DIR",
help="Generate DIR/ifcfg-eth*")
optParser.add_argument("--kickstart",
action="store", metavar="DIR",
help="kickstart files should be fetched from DIR")
optParser.add_argument("--macosx_auto",
action="store", metavar="DIR",
help="Generate MacOSX autmount maps")
optParser.add_argument("--mio",
action="store_true", default=False,
help="output mio tree")
optParser.add_argument("--named",
action="store", metavar="DIR",
help="Generate DIR/named.conf and DIR/named/*")
optParser.add_argument("--netgroup",
action="store", metavar="FILE",
help="Generate netgroup FILE")
optParser.add_argument("--next_server",
action="store", metavar="HOST",
help="Use HOST as DHCP next-server")
optParser.add_argument("--pretty",
action="store_true", default=False,
help="pretty-print XML tree")
optParser.add_argument("--pxelinux",
action="store", metavar="DIR",
help="symlink DIR/<ethernet> to <kickstart>")
optParser.add_argument("--role",
default=[],
action="append", metavar="ROLE",
help="check if machine has ROLE")
optParser.add_argument("--samba",
action="store", metavar="FILE",
help="generate samba share FILE")
optParser.add_argument("--yp",
action="store", metavar="DIR",
help="generate DIR/{hosts,ethers,etc} information")
optParser.add_argument("--yp_auto_domain",
action="store", metavar="DOMAIN",
help="DOMAIN name for yp automounter maps")
host = options.host or os.uname()[1].split('.')[0]
options = optParser.parse_args(sys.argv[1:])
hostinfo.options = options
tree = hostinfo.parser.parse(options.hostinfo_xml)
host = options.host
if not args:
tree = hostinfo.parser.parse("/etc/hostinfo.xml")
elif len(args) == 1:
tree = hostinfo.parser.parse(args[0])
else:
raise Exception("Only one hostinfo file allowed")
file = {}
symlink = {}
if options.dfs:
......@@ -289,14 +288,20 @@ if __name__ == '__main__':
file["%s/%s" % (options.automount, f)] = c
if options.dhcpd:
name = "%s/dhcpd.conf" % options.dhcpd
if options.kickstart:
kickstart = os.path.abspath(options.kickstart)
else:
kickstart = None
pass
file[name] = hostinfo.dhcpd.conf(tree, host, kickstart,
next_server=options.next_server)
file["%s/dhcpd.conf" % options.dhcpd] = hostinfo.dhcpd.generate(
tree, host, kickstart, next_server=options.next_server)
pass
if options.dhcpd6:
file["%s/dhcpd6.conf" % options.dhcpd6] = hostinfo.dhcpd_ipv6.generate(
tree, options)
pass
if options.ethers:
file[options.ethers] = hostinfo.yp.ethers(tree)
......
......@@ -46,7 +46,7 @@ class "AppleNBI-ppc" {
""" % (dhcphost, dhcphost)
def conf(tree, dhcphost, kickstart, next_server=None):
def generate(tree, dhcphost, kickstart, next_server=None):
#
# A. Get interfaces to serve
#
......
import sys
import os
import re
import ipaddr
class AttributeDict(dict):
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
class StringArray(list):
def append_lines(self, lines, sep='|'):
for l in map(lambda s: s.strip(), lines.split('\n')):
if not l:
continue
if not l.startswith(sep):
raise Exception('%s do not start with "%s"' % (l, pattern))
self.append(l[len(sep):])
pass
def indent(self):
for l in self:
yield ' %s' % l
pass
pass
pass
def generate(tree, options):
result = StringArray()
interface = dict([ (h.name[0], [ i for i in h._interface_ ])
for h in tree._host_ if h._interface_ ])
host = [ h for h in tree._host_ if h.name[0] == options.host ][0]
with_dhcp = list([ i for i in host._interface_ if i._dhcpserver_ ])
if not with_dhcp:
raise Exception("%s is not a dhcpserver" % options.host)
with_ipv6 = [ i for i in with_dhcp if i._ipv6_ ]
if not with_ipv6:
return ""
result.append_lines("""
|ddns-update-style none;
|authoritative;
|allow leasequery;
""")
for i in with_ipv6:
result.append('shared-network "MAC(%s)" {' % i.ethernet[0])
result.extend(emit_interface_ipv6(tree, i, options).indent())
result.append('}')
return '\n'.join(result) + '\n'
def emit_interface_ipv6(tree, interface, options):
result = StringArray()
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_
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_
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())
result.append('}' )
pass
return result
def emit_subnet_ipv6(tree, subnet, dynamic, options):
result = StringArray()
for first,last in dynamic:
result.append('range6 %s %s;' % (first, last))
pass
for name,ip in sorted([ (ip.name[0:], ip)
for ip in tree._host_._interface_._ipv6_
if ip.address[0]]):
result.append('host %s.%s {' % (name, subnet.domain[0]))
result.append(' fixed-address6 %s;' % ip.address[0])
result.append(' hardware ethernet %s;' % ip.ethernet[0:].upper())
result.append('}')
return result
def ignore():
"""
default-lease-time 2592000;
preferred-lifetime 604800;
option dhcp-renewal-time 3600;
option dhcp-rebinding-time 7200;
# Enable RFC 5007 support (same than for DHCPv4)
allow leasequery;
# Global definitions for name server address(es) and domain search list
#
#
option dhcp6.name-servers 3ffe:501:ffff:100:200:ff:fe00:3f3e;
option dhcp6.domain-search "test.example.com","example.com";
option dhcp6.info-refresh-time 21600;
# The subnet where the server is attached
subnet6 2001:ed8:77b5::/64 {
range6 2001:ed8:77b5::1 2001:ed8:77b5::ffff:ffff;
}
"""
from hostinfo.util import aton
import subprocess
import re
import ipaddr
def get_uuid(device):
try:
......@@ -26,7 +27,7 @@ def is_static(interface):
pass
return True
def generate_ifcfg(tree, interface):
def generate_ifcfgv4(tree, interface):
config = []
static_config = []
search = []
......@@ -98,8 +99,49 @@ def generate_ifcfg(tree, interface):
config.insert(0, 'BOOTPROTO=none')
config.extend(static_config)
pass
return '\n'.join(config) + '\n'
return config
def generate_ifcfgv6(tree, interface):
config = []
if not is_static(interface):
config.append('IPV6INIT=yes')
config.append('IPV6_AUTOCONF=yes')
config.append('IPV6_DEFROUTE=yes')
config.append('IPV6_PEERDNS=yes')
config.append('IPV6_PEERROUTES=yes')
config.append('IPV6_FAILURE_FATAL=no')
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_ ]:
if a in s:
address.append('%s/%d' % (a, s.prefixlen))
pass
pass
pass
if len(address):
config.append('IPV6INIT=yes')
config.append('IPV6_AUTOCONF=no')
config.append('IPV6_DEFROUTE=yes')
config.append('IPV6_FAILURE_FATAL=no')
config.append('IPV6ADDR=%s' % address[0])
pass
if len(address) > 1:
config.append('IPV6ADDR_SECONDARIES="%s"' %
' '.join(address[2:]))
pass
pass
return config
def generate_ifcfg(tree, interface):
config = []
config.extend(generate_ifcfgv4(tree, interface))
config.extend(generate_ifcfgv6(tree, interface))
return '\n'.join(config) + '\n'
def generate(tree, host):
......
import copy
import hostinfo.parser
from hostinfo.util import ntoa, aton, fqn, by_ip
import ipaddr
def generate(tree, host):
#
......@@ -18,42 +19,26 @@ def generate(tree, host):
raise Exception("%s is not a nameserver" % host)
#
# B. Read named header
# B. Read named.conf header
#
for h in tree._named_header_:
header = h.get_char()
print header
raise Exception("Is this ever used")
for h in tree._nameserver_:
conf = h.conf[0].strip() + '\n'
conf = conf.replace('{ ', '{\n')
conf = conf.replace('; ', ';\n')
pass
#
# C. Generate named.conf and named/* files
# C. Append to named.conf and create named/* files
#
result = []
conf = "include \"/etc/rndc.key\";\n"
conf += "options {\n"
conf += " directory \"/etc/named\"; notify no;\n"
conf += " allow-recursion {\n"
conf += " 127.0.0.0/8;\n"
conf += " 192.168.0.0/16;\n"
conf += " 130.235.83.0/24;\n"
conf += " };\n"
conf += " forward first;\n"
conf += " forwarders {\n"
conf += " 130.235.20.3;\n"
conf += " 130.235.132.90;\n"
conf += " };\n"
conf += "};\n"
conf += "zone \".\" {\n"
conf += " type hint; file \"root.hints\"; \n"
conf += "};\n"
conf += "zone \"0.0.127.in-addr.arpa\" {\n"
conf += " type master; file \"0.0.127.in-addr.arpa\";\n"
conf += "};\n"
done = {}
rzone = "0.0.127.in-addr.arpa"
done[rzone] = 1
conf += 'zone "0.0.127.in-addr.arpa" {\n'
conf += ' type master;\n'
conf += ' file "0.0.127.in-addr.arpa";\n'
conf += '};\n'
result.append(("named/%s" % rzone, reverse_local(tree, host)))
for s in tree._subnet_:
fzone = s.domain[0]
......@@ -141,12 +126,17 @@ def forward(tree, domain):
net_ipv6 = []
for s in tree._subnet_ipv6_:
if s.prefix[0] and s.domain[0] == domain.domain[0]:
net_ipv6.append(s.prefix[0])
net_ipv6.append(ipaddr.IPNetwork(s.prefix[0]))
pass
pass
for m in tree._host_._interface_._mailhost_:
if m.domain[0] == domain.domain[0]:
pri = int(m.priority[0] or 0)
result += "%-16sIN MX %d %s\n" % ("", pri ,fqn(tree, m._parent))
result += "%-16sIN MX %d %s\n" % ("", pri,
fqn(tree, m._parent))
pass
pass
result += ";\n"
# Add domain TXT entries
......@@ -194,7 +184,7 @@ def forward(tree, domain):
for i in tree._host_._interface_._ipv6_:
for p in net_ipv6:
if i.address[0] and i.address[0].startswith(p):
if ipaddr.IPAddress(i.address[0]) in p:
add_entry(i.name[1:], 'AAAA', '%s' % i.address[0])
pass
pass
......
......@@ -12,14 +12,20 @@ def fqn(tree, host):
name of host"""
if host.name[0:].endswith('.'):
return host.name[0:]
ip_addr = host.address[0]
if not ip_addr:
if host._tag == 'ip':
ip_addr = host.address[0]
elif host._tag == 'interface':
for ip in host._ip_:
if not ip.alias[0] and not ip.vlan[0]:
if ip.alias[0] or ip.vlan[0]:
continue
if ip.address[0]:
ip_addr = ip.address[0]
break
pass
pass
else:
raise Exception('Unexpected tag: %s', host._tag)
if ip_addr:
for s in tree._subnet_:
if (s.network[0] and
......
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