From c0a03c32b56a69f1183988d8e3e03a135fa7c437 Mon Sep 17 00:00:00 2001 From: Anders Blomdell <anders.blomdell@control.lth.se> Date: Wed, 13 Nov 2013 12:33:59 +0100 Subject: [PATCH] Version 2013-11-13 12:33 M src/hostinfo.py M src/hostinfo/dhcpd.py M src/hostinfo/named.py M src/hostinfo/parser.py M src/hostinfo/role.py --- src/hostinfo.py | 146 ++++++++++++++++++++++------------------- src/hostinfo/dhcpd.py | 7 ++ src/hostinfo/named.py | 5 +- src/hostinfo/parser.py | 6 +- src/hostinfo/role.py | 31 +++++---- 5 files changed, 111 insertions(+), 84 deletions(-) diff --git a/src/hostinfo.py b/src/hostinfo.py index 772f031..122710e 100755 --- a/src/hostinfo.py +++ b/src/hostinfo.py @@ -12,6 +12,7 @@ import hostinfo.pxelinux import hostinfo.samba import hostinfo.yp import hostinfo.role +import hostinfo.util import argparse import os import sys @@ -78,6 +79,7 @@ attr_weight = { ('interface', 'ip') : 1, ('interface', 'ether') : 2, ('subnet', 'network') : 1, + ('subnet', 'prefix') : 1, ('subnet', 'domain') : 2, ('subnet', 'broadcast') : 3, ('subnet', 'netmask') : 4, @@ -85,79 +87,81 @@ attr_weight = { ('subnet', 'name_servers') : 6, } -#def cmp(a,b): -# if a < b: -# return -1 -# elif a == b: -# return 0 -# else: -# return 1 - class AttributeDict(dict): __getattr__ = dict.__getitem__ +def network_order(a, b): + a_net = hostinfo.util.network(a) + b_net = hostinfo.util.network(b) + if not a_net or not b_net: + return cmp(a,b) + if a_net.version == b_net.version: + return cmp(a_net, b_net) + return cmp(a_net.version, b_net.version) + def host_order(a,b): - def at_top(n): - # Place hosts without ethernet or ip address at top - for i1 in n._interface_: - if i1.ethernet[0]: - return False - for i2 in i1._ip_: - if i2.address[0]: - return False - pass - pass - return True - def at_bottom(n): - # Place hosts with ethernet but without ip address at bottom - result = False - for i1 in n._interface_: - if i1.ethernet[0]: - result = True - for i2 in i1._ip_: - if i2.address[0]: - return False - pass - pass - return result - if (at_top(a) == at_top(b) and at_bottom(a) == at_bottom(b)): - return cmp(a.name[0], b.name[0]) - elif at_top(a): - return -1 - elif at_top(b): - return 1 - elif at_bottom(a): - return 1 - elif at_bottom(b): - return -1 - else: - raise Exception('Should never happen') + def fqn(host): + n = host.name[0] + return n and n.endswith('.') + def select(f, c): + return [ f(e) for e in c if f(e) ] + def ether(host): + return select(lambda i: i.ethernet[0], host._interface_) + def ip(host): + ipv4 = select(hostinfo.util.address, host._interface_._ip_) + ipv6 = select(hostinfo.util.address, host._interface_._ipv6_) + return ipv4 + ipv6 + def no_addr(host): + return not ether(host) and not ip(host) + def all_addr(host): + return ether(host) and ip(host) + + # Fully qualified names + if fqn(a) or fqn(b): + if fqn(a) and fqn(b): return cmp(a.name[0], b.name[0]) + if fqn(a): return -1 + if fqn(b): return 1 + pass + + # Hosts without ether an ip address (reusable names) + if no_addr(a) or no_addr(b): + if no_addr(a) and no_addr(b): return cmp(a.name[0], b.name[0]) + if no_addr(a): return -1 + if no_addr(b): return 1 + pass + + # Hosts with ip and ether (active machines) + if all_addr(a) or all_addr(b): + if all_addr(a) and all_addr(b): return cmp(a.name[0], b.name[0]) + if all_addr(a): return -1 + if all_addr(b): return 1 + pass + # This should be machines with ether but no ip (decommissioned) + if ip(a): + raise hostinfo.util.HostinfoException('Unexpected ip address %s' % + a.name[0], where=a) + if ip(b): + raise hostinfo.util.HostinfoException('Unexpected ip address %s' % + b.name[0], where=b) + return cmp(a.name[0], b.name[0]) tag_weight = { - ('hostinfo', 'soa') : (1, - None), - ('hostinfo', 'subnet') : (2, - lambda a,b: cmp(a.network[0],b.network[0])), - ('hostinfo', 'netgroup') : (3, + ('hostinfo', 'soa') : (1, None), + ('hostinfo', 'subnet') : (2, network_order), +# lambda a,b: cmp(a.network[0],b.network[0])), + ('hostinfo', 'nameserver') : (3, None), + ('hostinfo', 'netgroup') : (4, lambda a,b: cmp(a.name[0],b.name[0])), - ('hostinfo', 'host') : (4, - host_order), - ('host', 'automount') : (1, - lambda a,b: cmp(a.host[0],b.host[0])), - ('host', 'mio') : (2, - None), - ('interface', 'kickstart') : (1, - None), - ('interface', 'ip') : (2, - None), - ('interface', 'alias') : (3, - None), - ('interface', 'dhcpserver') : (4, - None), - ('interface', 'nameserver') : (5, - None), - ('automount', 'entry') : (1, - lambda a,b: cmp(a.key[0],b.key[0])), + ('hostinfo', 'host') : (5, host_order), + ('host', 'role') : (1, None), + ('host', 'automount') : (2, lambda a,b: cmp(a.host[0],b.host[0])), + ('host', 'mio') : (3, None), + ('interface', 'kickstart') : (1, None), + ('interface', 'ip') : (2, None), + ('interface', 'alias') : (3, None), + ('interface', 'dhcpserver') : (4, None), + ('interface', 'nameserver') : (5, None), + ('automount', 'entry') : (1, lambda a,b: cmp(a.key[0],b.key[0])), } def attr_sort(node, a, b): @@ -261,6 +265,10 @@ if __name__ == '__main__': default=[], action="append", metavar="ROLE", help="check if machine has ROLE") + optParser.add_argument("--role-holder", + default=[], + action="store", metavar="ROLE", + help="check which machine currently holding ROLE") optParser.add_argument("--samba", action="store", metavar="FILE", help="generate samba share FILE") @@ -331,12 +339,18 @@ if __name__ == '__main__': result = "<?xml version='1.0' encoding='utf-8'?>\n\n" result += tree._xml(attr_sort=attr_sort, tag_sort=tag_sort) print result.encode("utf-8") + sys.exit(0) if options.role: roles = hostinfo.role.generate(tree, host, options.role) # print "Roles:",",".join(roles) sys.exit(len(roles) != len(options.role)) + if options.role_holder: + who = hostinfo.role.holder(tree, options.role_holder) + print who + pass + if options.yp: for (f, c) in hostinfo.yp.generate(tree, options.yp_auto_domain): file["%s/%s" % (options.yp, f)] = c diff --git a/src/hostinfo/dhcpd.py b/src/hostinfo/dhcpd.py index 529e192..766c513 100755 --- a/src/hostinfo/dhcpd.py +++ b/src/hostinfo/dhcpd.py @@ -90,6 +90,10 @@ class "pxeclient" { } else { filename "pxelinux.0"; } +} +class "non-pxeclient" { + match if substring (option vendor-class-identifier, 0, 9) != "PXEClient"; + ignore booting; }""" PXE_DENY=""" @@ -154,6 +158,9 @@ def generate(tree, options): |ddns-update-style none; |get-lease-hostnames true; |use-host-decl-names on; + |# Windows proxy server/WPAD URL (Stops DHCPINFORM) + |option url-252 code 252 = text; + |option url-252 "\\n\\000"; """) if get_pxeboot(dhcp) == 'only': if not options.next_server: diff --git a/src/hostinfo/named.py b/src/hostinfo/named.py index a17a33f..2a90372 100755 --- a/src/hostinfo/named.py +++ b/src/hostinfo/named.py @@ -25,10 +25,7 @@ def generate(tree, options): conf = util.StringArray() for h in tree._nameserver_: - for l in re.sub('([{;]\s)', '\g<1>\n', h.conf[0]).split('\n'): - if l[0] == ' ': - l = l[1:] - pass + for l in h._char: conf.append(l) pass pass diff --git a/src/hostinfo/parser.py b/src/hostinfo/parser.py index 4bd8330..3d6dc24 100755 --- a/src/hostinfo/parser.py +++ b/src/hostinfo/parser.py @@ -382,7 +382,11 @@ class Node: result += "%s/>\n" % line else: result += "%s>\n" % line - result += xml_escape("".join(self._char)) + #result += xml_escape('\n'.join(self._char)) + if self._char: + result += '\n'.join(self._char) + result += '\n' + pass child = self._children child.sort(TagSortWrapper(self, tag_sort)) for c in child: diff --git a/src/hostinfo/role.py b/src/hostinfo/role.py index b70a512..ebcb336 100755 --- a/src/hostinfo/role.py +++ b/src/hostinfo/role.py @@ -1,19 +1,24 @@ +import hostinfo.util as util + def generate(tree, host, roles): - result = [] - by_role = {} - for r in tree._host_._role_: - role = r.name[0] - if host == r.name[1] and role in roles: - result.append(role) - pass - if role in by_role: - raise Exception("Duplicate roles '%s' on %s, %s" % - (role, host, by_role[role]) ) - by_role[role] = r.name[1] - pass + by_role = get_all(tree) for r in roles: if not r in by_role: raise Exception("Role '%s' not found in %s" % (r, by_role.keys())) - + return filter(lambda (k,v): k in roles and v == host, + by_role.iteritems()) + +def holder(tree, role): + return get_all(tree)[role] + +def get_all(tree): + result = {} + for r in tree._host_._role_: + name = r.name[0] + if name in result: + raise util.HostinfoException('Duplicate role holders %s' % name, + where=[result[name], r]) + result[name] = r.name[1] + pass return result -- GitLab