From 4c245819ce91f0ac8ac686c79b1d69e5b667e475 Mon Sep 17 00:00:00 2001 From: Justin Riley Date: Wed, 28 Sep 2016 11:18:14 -0400 Subject: [PATCH] server: implement tiebreaker for VMs with same name/IP The tiebreaker is first-come first serve - ie whichever VM had the name or IP first wins (based on VM id). The sync() method now sorts the VM list by id in order to evaluate the tiebreaker correctly (VM list comes that way from ONED but just in case...). --- onedns/exception.py | 8 ++++++++ onedns/server.py | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/onedns/exception.py b/onedns/exception.py index eac61f0..06b5f16 100644 --- a/onedns/exception.py +++ b/onedns/exception.py @@ -36,3 +36,11 @@ class RecordDoesNotExist(OneDnsException): self.msg = "Record Does Not Exist: {}".format(key) if val is not None: self.msg += " -> {}".format(val) + + +class DuplicateVMError(OneDnsException): + """ + Raised when two or more VMs share a name or IP + """ + def __init__(self, vmid, key, val): + self.msg = "VM one-{} has a duplicate: {} -> {}".format(vmid, key, val) diff --git a/onedns/server.py b/onedns/server.py index e504d92..70defaa 100644 --- a/onedns/server.py +++ b/onedns/server.py @@ -31,10 +31,24 @@ class OneDNS(resolver.DynamicResolver): entries[nicname] = nic.ip return entries + def _check_for_duplicates(self, vm_id, name, ip, zone=None): + z = zone or self.zone + try: + f = z.get_forward(name) + raise exception.DuplicateVMError(vm_id, f, ip) + except exception.RecordDoesNotExist: + pass + try: + r = z.get_reverse(ip) + raise exception.DuplicateVMError(vm_id, ip, r) + except exception.RecordDoesNotExist: + pass + def add_vm(self, vm, zone=None): dns_entries = self._get_vm_dns_entries(vm) log.info("Adding VM {id}: {vm}".format(id=vm.id, vm=vm.name)) for name, ip in dns_entries.items(): + self._check_for_duplicates(vm.id, name, ip, zone=zone) self.add_host(name, ip, zone=zone) def remove_vm(self, vm, zone=None): @@ -54,9 +68,12 @@ class OneDNS(resolver.DynamicResolver): def sync(self, vms=None): z = zone.Zone(self.domain) vms = vms or self._one.vms() + vms.sort(key=lambda x: x.id) for vm in vms: try: self.add_vm(vm, zone=z) except exception.NoNetworksError as e: e.log(warn=True) + except exception.DuplicateVMError as e: + e.log(warn=True) self.load(z)