def test_update(): handle, path = tempfile.mkstemp() orig = open(path, "r+") orig.write("HEADER\n\n;" + SLAM_HDR1 + ";" + SLAM_HDR2 + "useless content\n;"+ SLAM_FTR + "FOOTER\n") orig.flush() orig.seek(0) conf = generator.BindConfig.create(outputfile=None) conf.output = orig host1 = models.Host(name="host1") host2 = models.Host(name="host2") addr1 = models.Address(addr="addr", pool=models.Pool(dns_record="A")) addr2 = models.Address(addr="rdda", pool=models.Pool(dns_record="A")) addr3 = models.Address(addr="addr2", pool=models.Pool(dns_record="AAAA")) conf.updateconf([(None, [(host1, addr1, [], ""), (host1, addr2, [], ""), (host2, addr3, [], "")])]) orig.seek(0) res = orig.read() assert(res == "HEADER\n\n;" + SLAM_HDR1 + ";" + SLAM_HDR2 + "host1\t1D\tIN\tA\taddr\n" + "host1\t1D\tIN\tA\trdda\n" + "host2\t1D\tIN\tAAAA\taddr2\n" + ";" + SLAM_FTR + "FOOTER\n") orig.close() os.unlink(path)
def test_bind(): hdr = _strstream("stuff\n@ 1D IN SOA foo bar " + datetime.date.today().strftime("%Y%m%d") + "02 a b c d\n") out = StringIO.StringIO() conf = generator.BindConfig.create(outputfile=None) conf.output = out conf.header = hdr conf.footer = None host1 = models.Host(name="host1") host2 = models.Host(name="host2") addr1 = models.Address(addr="addr", pool=models.Pool(dns_record="A")) addr2 = models.Address(addr="rdda", pool=models.Pool(dns_record="A")) addr3 = models.Address(addr="addr2", pool=models.Pool(dns_record="AAAA")) conf.createconf([(models.Pool.create(name="tstp", definition="1.2.3.0/24"), [(host1, addr1, [], ""), (host1, addr2, [], ""), (host2, addr3, [], "")])]) assert(out.getvalue() == "stuff\n@ 1D IN SOA foo bar " + datetime.date.today().strftime("%Y%m%d") + "03 a b c d\n\n;" + SLAM_HDR1 + ";" + SLAM_HDR2 + "; Pool tstp (range: 1.2.3.0/24)\n" + "host1\t1D\tIN\tA\taddr\n" + "host1\t1D\tIN\tA\trdda\n" + "host2\t1D\tIN\tAAAA\taddr2\n" + ";" + SLAM_FTR)
def test_checkfile(): handle, path1 = tempfile.mkstemp() checkf1 = open(path1, "w") handle, path2 = tempfile.mkstemp() checkf2 = open(path2, "w") checkf1.write("host1\t1d\tin\ta\taddr\n" + "host1\t1d\tin\ta\trdda\n" + "host2\t1d\tin\taaaa\taddr2\n") checkf2.write("host142\t1d\tin\ta\taddr\n" + "42host1\t1d\tin\ta\trdda\n" + "host\t1d\tin\taaaa\taddr2\n") checkf1.close() checkf2.close() host1 = models.Host(name="host1") host2 = models.Host(name="host2") addr1 = models.Address(addr="addr", pool=models.Pool(dns_record="A")) addr2 = models.Address(addr="rdda", pool=models.Pool(dns_record="A")) addr3 = models.Address(addr="addr42", pool=models.Pool(dns_record="A")) addr4 = models.Address(addr="rdda42", pool=models.Pool(dns_record="A")) conf = generator.BindConfig.create(outputfile="-") conf.createconf([(None, [(host1, addr1, [], ""), (host2, addr2, [], "")])]) conf = generator.BindConfig.create(outputfile="-", checkfile=[path2]) dup = conf.createconf([(None, [(host1, addr3, [], ""), (host2, addr4, [], "")])]) assert len(dup) == 0 conf = generator.BindConfig.create(outputfile="-", checkfile=[path1]) dup = conf.createconf([(None, [(host1, addr1, [], ""), (host2, addr2, [], "")])]) assert len(dup) == 4 conf = generator.BindConfig.create(outputfile="-", checkfile=[path1, path2]) dup = conf.createconf([(None, [(host1, addr1, [], ""), (host2, addr2, [], "")])]) assert len(dup) == 6 os.unlink(path1) os.unlink(path2) # other generators _generator_checkfile(generator.RevBindConfig, "117.103.168.192.in-addr.arpa. 1D IN PTR test.domain.\n" + "118.103.168.192.in-addr.arpa. 1D IN PTR host1.domain.") _generator_checkfile(generator.DhcpdConfig, "host test { fixed-address test; }\n" + "host host1 { fixed-address host1; }") _generator_checkfile(generator.QuattorConfig, "escape(\"test\"),\"1.2.3.4\"\n" + "escape(\"host2\"),\"1.2.2.2\"")
def test_quattor(): conf = generator.QuattorConfig.create(outputfile=None) out = StringIO.StringIO() conf.output = out host1 = models.Host(name="host1") host2 = models.Host(name="host2") addr1 = models.Address(addr="192.168.50.30", macaddr="01:12:34:56:78:9a") addr2 = models.Address(addr="192.168.42.137") conf.createconf([(None, [(host1, addr1, [], ""), (host2, addr2, [], "")])]) assert(out.getvalue() == "\n#" + SLAM_HDR1 + "#" + SLAM_HDR2 + 'escape("host1"),"192.168.50.30",\n' + 'escape("host2"),"192.168.42.137",\n' + "#" + SLAM_FTR)
def pool_map(request, pool_name): """Make a map of the allocation of addresses inside a pool.""" addrs = [] poolobj = get_object_or_404(models.Pool, name=pool_name) poolobj._update() addr_used = models.Address.objects.filter(pool=poolobj).count() addr_avail = poolobj.len() if addr_avail == 0: addr_avail = 1 pool_addrs = models.Address.objects.filter(pool=poolobj) i = POOL_MAP_LIMIT for addr in poolobj.addr_range: if i == 0: break if poolobj.isallocated(addr): addrs.append(pool_addrs.get(addr=addr)) else: addrs.append(models.Address(addr=addr, pool=None, host=None)) i -= 1 templ_values = { "request": request, "pool": poolobj, "addrs": addrs, "addr_used": addr_used, "addr_avail": addr_avail, "addr_perc": addr_used * 100 / addr_avail, "overflow": addr_avail > POOL_MAP_LIMIT } return render_to_response("pool_map.html", templ_values)
def test_dhcp(): conf = generator.DhcpdConfig.create(outputfile=None, domain="foo.example") out = StringIO.StringIO() conf.output = out host1 = models.Host(name="host1") host2 = models.Host(name="host2") addr1 = models.Address(addr="192.168.50.30", macaddr="01:12:34:56:78:9a") addr2 = models.Address(addr="192.168.42.137") conf.createconf([(None, [(host1, addr1, [], ""), (host2, addr2, [], "")])]) assert(out.getvalue() == "\n#" + SLAM_HDR1 + "#" + SLAM_HDR2 + "option domain-name \"foo.example\";\n" + "host host1 { hardware ethernet 01:12:34:56:78:9a; " + "fixed-address host1; }\n" + "#" + SLAM_FTR)
def test_revbind(): conf = generator.RevBindConfig.create(outputfile=None, timeout="6H") out = StringIO.StringIO() conf.output = out conf.header = None conf.footer = None host1 = models.Host(name="host1") host2 = models.Host(name="host2") addr1 = models.Address(addr="192.168.50.30", pool=models.Pool(addr_range_type="ip4", dns_record="A")) addr2 = models.Address(addr="fe80:1234:5678:9abc:def0:1234:5678:9abc", pool=models.Pool(addr_range_type="ip6", dns_record="AAAA")) conf.createconf([(None, [(host1, addr1, [], ""), (host2, addr2, [], "")])]) print("@@@" + out.getvalue() + "@@@") assert(out.getvalue() == "\n;" + SLAM_HDR1 + ";" + SLAM_HDR2 + "30.50.168.192.in-addr.arpa.\t6H\tIN\tPTR\thost1\n" + "c.b.a.9.8.7.6.5.4.3.2.1.0.f.e.d.c.b.a.9.8.7.6.5.4.3.2.1.0.8.e.f" + ".ip6.arpa.\t6H\tIN\tPTR\thost2\n" + ";" + SLAM_FTR)
def _generator_checkfile(cls, content): handle, path = tempfile.mkstemp() checkf = open(path, "w") checkf.write(content) checkf.close() host1 = models.Host(name="host1") host2 = models.Host(name="host2") addr1 = models.Address(addr="addr", pool=models.Pool(dns_record="A")) addr2 = models.Address(addr="rdda", pool=models.Pool(dns_record="A")) conf = cls.create(outputfile="-") dup = conf.createconf([(None, [(host1, addr1, [], ""), (host2, addr2, [], "")])]) assert len(dup) == 0 conf = cls.create(outputfile="-", checkfile=[path]) dup = conf.createconf([(None, [(host1, addr1, [], ""), (host2, addr2, [], "")])]) assert len(dup) == 1 os.unlink(path)
def delete(pool=None, addresses=None, hosts=None): """Delete objects from the database: address, host or pool.""" if addresses: for addr in addresses: if not models.Address.objects.filter(addr=addr): raise InexistantObjectError("The addresse \"" + addr + "\" was not found in the database") else: if pool is None: pool = models.Address.objects.get(addr=addr).pool addrobj = models.Address.objects.get(addr=addr) if addrobj.macaddr: newaddr = models.Address(macaddr=addrobj.macaddr, host=addrobj.host, allocated=False) newaddr.save() LOGGER.info("Delete address " + str(addr) + " from pool " + str(pool.name)) pool.free(addr) elif hosts: for host in hosts: hostobj = models.Host.objects.get(name=host) # addresses are automatically deleted = considered as free addrs = [] for addr in models.Address.objects.filter(host=hostobj): if addr.addr: addrs.append(addr.addr) LOGGER.info("Delete host " + str(hostobj) + ", releasing addresses: " + ", ".join(addrs)) hostobj.delete() elif pool: # addresses are automatically deleted LOGGER.info("Delete pool " + str(pool)) pool.delete()
def modify(pools=None, host=None, category=None, address=None, mac=None, newname=None, alias=None, serial="", inventory="", duration=None, lastuse=None, nodns=False, comment="", clearalias=False): """Modify the name of an object in the database.""" poolobjs = [] if not alias: alias = [] if pools: for pool in pools: poolobjs.append(get_pool(pool)) hostobj = get_host(host) addrobj = None if models.Address.objects.filter(addr=address): addrobj = models.Address.objects.get(addr=address) if address and addrobj and (mac or duration or lastuse or comment): if mac: addrobj.macaddr = mac LOGGER.info("Modify address " + str(addrobj) + ": assign MAC " + mac) if duration: addrobj.duration = (datetime.datetime.now() + datetime.timedelta(days=duration)) LOGGER.info("Modify address " + str(addrobj) + ": new duration untill: " + str(addrobj.duration)) if lastuse: addrobj.lastuse = datetime.datetime.fromtimestamp(lastuse) if comment: addrobj.comment = comment addrobj.save() elif host and hostobj: if not (newname or mac or alias or serial or inventory or nodns or clearalias): raise MissingParameterError("Please provide the new name " + "or a new information for the host " + hostobj.name) if mac: addrs = hostobj.address_set.all() LOGGER.info("Assign new MAC address " + mac + " to host " + host) if addrs: addrs[0].macaddr = mac else: addrs = [models.Address(macaddr=mac, host=hostobj)] addrs[0].save() if serial: hostobj.serial = serial LOGGER.info("Changed host " + hostobj.name + ": new serial: " + serial) hostobj.save() if inventory: hostobj.inventory = inventory LOGGER.info("Changed host " + hostobj.name + ": new inventory number: " + inventory) hostobj.save() if newname: #anomalie de hostname avec espace if not isValidHostname(hostname=newname): raise PropertyFormatError( "You must provide a valid name (without space, special character) for the new host." ) #anomalie9 #verifier si le new hostname a le meme alias dans les nouveaux alias et ancienne liste de alias. #la nouvelle liste if alias: for alia in alias: if alia[0] != '-' and alia[0] != '%': if (alia == newname): raise DuplicateObjectError( "Host [" + newname + "] is the same as the new alias.") #le nouveau hostname ne faut pas existe dans la liste de tous les alias de tous les host if models.Alias.objects.filter(name=newname): raise DuplicateObjectError( "Host [" + newname + "] already exists in the list of alias.") #le nouveau hostname ne faut pas existe dans la liste tous les host if models.Host.objects.filter(name=newname): raise DuplicateObjectError("Host [" + newname + "] already exists.") #fin anomalie9 LOGGER.info("Changed name of host " + hostobj.name + " to " + newname) hostobj.name = newname hostobj.save() if category: category = category[0] LOGGER.info("Changed category of host " + hostobj.name + " to " + category) hostobj.category = category hostobj.save() if nodns: LOGGER.info("Changed NODNS setting of host " + hostobj.name) hostobj.nodns = not hostobj.nodns hostobj.save() if clearalias: models.Alias.objects.filter(host=hostobj).delete() LOGGER.info("Cleared all aliases for host " + host) elif alias: for alia in alias: # % was introduced because of argparse, which think some # argument beginning by - is an option... # http://bugs.python.org/issue9334 if alia[0] == '-' or alia[0] == '%': alia = alia[1:] if models.Alias.objects.filter(name=alia, host=hostobj): models.Alias.objects.filter(name=alia, host=hostobj).delete() LOGGER.info("Deleted alias \"" + alia + "\" for host " + host) else: if not isValidHostname(hostname=alia): raise PropertyFormatError( "You must provide a valid name (without space, special character) for the new host." ) #le nouveau alias exist pas dans la liste de alias if models.Alias.objects.filter(name=alia): raise DuplicateObjectError("Alias [" + alia + "] already exists.") #anomalie9 #le nouveau alias exist pas dans la liste de host elif models.Host.objects.filter(name=alia): raise DuplicateObjectError( "Host already exists as alias [" + alia + "]") #le nouveau alias n'est pas identique que le nouveau hostname elif newname and (alia == newname): raise DuplicateObjectError( "The new alias [" + alia + "] is the same as the new host name.") #fin anomalie9 else: LOGGER.info("New alias " + alia + " for host " + host) aliasobj = models.Alias(name=alia, host=hostobj) aliasobj.save() elif pools and poolobjs: poolobj = poolobjs[0] if not category and not newname: raise MissingParameterError("Please provide the new name or a " + "category for the pool " + poolobj.name) if category: category = ",".join(category) LOGGER.info("Changed category of pool " + poolobj.name + " to " + category) poolobj.category = category if newname: LOGGER.info("Changed namme of pool " + poolobj.name + " to " + newname) poolobj.name = newname poolobj.save() else: raise InexistantObjectError( "Could not find the object to modify or wrong action.")
def create_host(host, pool=None, address=None, mac=None, random=False, alias=None, category=None, serial="", inventory="", duration=None, nodns=False): """Create a new host and assign it the first element of addesses or automatically one from the given pool, eventually random.""" #validation if not host: raise MissingParameterError( "You must provide a name for the new host.") if not isValidHostname(hostname=host): raise PropertyFormatError( "You must provide a valid name (without space, special character) for the new host." ) if models.Host.objects.filter(name=host): raise DuplicateObjectError("Host as the host name [" + host + "] already exists.") #anomalie9 if models.Alias.objects.filter(name=host): raise DuplicateObjectError("A alias as the host name [" + host + "] already exists.") if alias: for alia in alias: if not isValidHostname(hostname=alia): raise PropertyFormatError( "You must provide a valid alias name (without space, special character) for the new host." ) if models.Alias.objects.filter(name=alia): raise DuplicateObjectError("A alias as alias name [" + str(alia) + "] already exists.") if models.Host.objects.filter(name=alia): raise DuplicateObjectError("A Host as alias name [" + str(alia) + "] already exists.") if host == alia: raise DuplicateObjectError( "Host should not be equel to a alias name [" + str(alia) + "].") #fin anomalie9 hostobj = models.Host(name=host) if not alias: alias = [] logmac = "" if mac: logmac = " (mac: " + str(mac) + ")" LOGGER.info("Create new host \"" + str(host) + logmac + "\".") if category: hostobj.category = category if serial: hostobj.serial = serial if inventory: hostobj.inventory = inventory if nodns: hostobj.nodns = True hostobj.save() for alia in alias: if models.Alias.objects.filter(name=alia): LOGGER.warn("Alias " + str(alia) + " already exists and refers to " + models.Alias.objects.get(name=alia).host.name) else: aliasobj = models.Alias(name=alia, host=hostobj) aliasobj.save() if pool or category or address: addrobj = allocate_address(pool, hostobj, address, random, category) pool = addrobj.pool addrres = str(addrobj) if duration: addrobj.duration = (addrobj.date + datetime.timedelta(days=duration)) addrobj.save() if mac: if addrobj: addrobj.macaddr = mac addrobj.save() elif hostobj.address_set.all(): first_addr = hostobj.address_set.all()[0] first_addr.macaddr = mac first_addr.save() LOGGER.info("Assigned address " + addrres + " to " + str(host) + " from pool " + pool.name) return str(hostobj), addrres else: if mac: addrobj = models.Address(macaddr=mac, host=hostobj) addrobj.save() return str(hostobj), None