def test_multiple_wildcards(self):
        n = Node()

        # add a wildcard mapping
        n.put(WILD1, ADDR1, TAG1)
        n.put(WILD1, ADDR2, TAG2)
        res = n.get('xyz.foo.com')
        self.assertEquals(res[0], (ADDR1, TAG1))
        self.assertEquals(res[1], (ADDR2, TAG2))

        # remove the wildcard mapping for one tagged node
        n.remove(WILD1, TAG2)
        res = n.get('abc.foo.com')
        self.assertEquals(res, [(ADDR1, TAG1)])

        # remove the remaining wildcard mapping
        n.remove(WILD1, TAG1)
        res = n.get('abc.foo.com')
        self.assertEquals(res, None)
Example #2
0
    def test_multiple_addresses(self):
        n = Node()

        # add a normal domain mapping for 2 nodes
        n.put(HOST1, ADDR1, TAG1)
        n.put(HOST1, ADDR2, TAG2)
        res = n.get(HOST1)
        self.assertEquals(res[0], (ADDR1, TAG1))
        self.assertEquals(res[1], (ADDR2, TAG2))

        # remove one tag
        n.remove(HOST1, TAG1)
        res = n.get(HOST1)
        self.assertEquals(res, [(ADDR2, TAG2)])
    def test_multiple_addresses(self):
        n = Node()

        # add a normal domain mapping for 2 nodes
        n.put(HOST1, ADDR1, TAG1)
        n.put(HOST1, ADDR2, TAG2)
        res = n.get(HOST1)
        self.assertEquals(res[0], (ADDR1, TAG1))
        self.assertEquals(res[1], (ADDR2, TAG2))

        # remove one tag
        n.remove(HOST1, TAG1)
        res = n.get(HOST1)
        self.assertEquals(res, [(ADDR2, TAG2)])
Example #4
0
 def __init__(self):
     self._mappings = {}
     self._active = {}
     self._domains = Node()
     self._lock = threading.Lock()
Example #5
0
class Registry(object):
    ''''
    Maps a container by id/name to a list of domain names and addresses.
    When the container is started, the list of domain names can be activated,
    and when the container is stopped the list of domain names can be
    deactivated.
    '''
    def __init__(self):
        self._mappings = {}
        self._active = {}
        self._domains = Node()
        self._lock = threading.Lock()

    def add(self, key, names):
        ''''
        Adds a mapping from the given key to a list of names. The names
        will be registered when the container is activated (running) and
        unregistered when the container is deactivated (stopped).
        '''
        # first, remove the old names, if any
        self.remove(key)

        with self._lock:
            # persist the mappings
            self._mappings[key] = Mapping(names, key)

            # check if these pertain to any already-active containers and
            # activate the domain names
            activate = []
            for container in self._active.itervalues():
                if key in ('name:/' + container.name, 'id:/' + container.id):
                    desc = self._desc(container)
                    self._activate(names, container.addr, tag=key)

    def get(self, key):
        with self._lock:
            mapping = self._mappings.get(key)
            if mapping:
                return [n.idna().rstrip('.') for n in mapping.names]
            return []

    def remove(self, key):
        with self._lock:
            old_mapping = self._mappings.get(key)
            if old_mapping:
                self._deactivate(old_mapping.names, tag=old_mapping.key)
                del self._mappings[old_mapping.key]

    def activate_static(self, domain, addr):
        with self._lock:
            self._activate([domain], addr, tag='domain:/%s' % domain)

    def deactivate_static(self, domain):
        with self._lock:
            self._deactivate([domain], tag='domain:/%s' % domain)

    def activate(self, container):
        'Activate all rules associated with this container'
        desc = self._desc(container)
        with self._lock:
            self._active[container.id] = container
            mapping = self._get_mapping_by_container(container)
            if mapping:
                log.info('setting %s as active' % desc)
                key, names = mapping.key, mapping.names
                self._activate(names, container.addr, tag=key)

    def deactivate(self, container):
        'Deactivate all rules associated with this container'
        with self._lock:
            old_container = self._active.get(container.id)
            if old_container is None:
                return
            del self._active[container.id]

            # since this container is active, get the old address so we can log
            # exactly which names/addresses are being deactivated
            desc = self._desc(container)
            mapping = self._get_mapping_by_container(container)
            if mapping:
                log.info('setting %s as inactive' % desc)
                self._deactivate(mapping.names, tag=mapping.key)

    def resolve(self, name):
        'Resolves the address for this name, if any'
        with self._lock:
            res = self._domains.get(name)
            if res:
                addrs = [a for a, _ in res]
                log.debug('resolved %s -> %s' % (name, ', '.join(addrs)))
                return addrs
            else:
                log.debug('no mapping for %s' % name)

    def dump(self):
        return json.dumps(self._domains.to_dict(), indent=4, sort_keys=1)

    def _activate(self, names, addr, tag=None):
        for name in names:
            self._domains.put(name, addr, tag)
            log.info('added %s -> %s key=%s', name.idna(), addr, tag)
        #log.debug('tree %s' % self.dump())

    def _deactivate(self, names, tag=None):
        for name in names:
            if self._domains.get(name):
                addrs = self._domains.remove(name, tag)
                if addrs:
                    for addr in addrs:
                        log.info('removed %s -> %s', name.idna(), addr)
        #log.debug('tree %s', self.dump())

    def _get_mapping_by_container(self, container):
        # try name and id-based keys
        res = self._mappings.get('name:/%s' % container.name)
        if not res:
            res = self._mappings.get('id:/%s' % container.id)
        return res

    def _desc(self, container):
        return '%s (%s)' % (container.name, container.id[:10])
 def test_tagging(self):
     n = Node()
     n.put(HOST1, ADDR1, TAG1)
     res = n.get(HOST1)
     self.assertEquals(res, [(ADDR1, TAG1)])
Example #7
0
 def __init__(self):
     self._mappings = {}
     self._active = {}
     self._domains = Node()
     self._lock = threading.Lock()
Example #8
0
class Registry(object):

    ''''
    Maps a container by id/name to a list of domain names and addresses.
    When the container is started, the list of domain names can be activated,
    and when the container is stopped the list of domain names can be
    deactivated.
    '''

    def __init__(self):
        self._mappings = {}
        self._active = {}
        self._domains = Node()
        self._lock = threading.Lock()

    def add(self, key, names):
        ''''
        Adds a mapping from the given key to a list of names. The names
        will be registered when the container is activated (running) and
        unregistered when the container is deactivated (stopped).
        '''
        # first, remove the old names, if any
        self.remove(key)

        with self._lock:
            # persist the mappings
            self._mappings[key] = Mapping(names, key)

            # check if these pertain to any already-active containers and
            # activate the domain names
            activate = []
            for container in self._active.itervalues():
                if key in ('name:/' + container.name, 'id:/' + container.id):
                    desc = self._desc(container)
                    self._activate(names, container.addr, tag=key)

    def get(self, key):
        with self._lock:
            mapping = self._mappings.get(key)
            if mapping:
                return [n.idna().rstrip('.') for n in mapping.names]
            return []

    def remove(self, key):
        with self._lock:
            old_mapping = self._mappings.get(key)
            if old_mapping:
                self._deactivate(old_mapping.names, tag=old_mapping.key)
                del self._mappings[old_mapping.key]

    def activate_static(self, domain, addr):
        with self._lock:
            self._activate([domain], addr, tag='domain:/%s' % domain)

    def deactivate_static(self, domain):
        with self._lock:
            self._deactivate([domain], tag='domain:/%s' % domain)

    def activate(self, container):
        'Activate all rules associated with this container'
        desc = self._desc(container)
        with self._lock:
            self._active[container.id] = container
            mapping = self._get_mapping_by_container(container)
            if mapping:
                log.info('setting %s as active' % desc)
                key, names = mapping.key, mapping.names
                self._activate(names, container.addr, tag=key)

    def deactivate(self, container):
        'Deactivate all rules associated with this container'
        with self._lock:
            old_container = self._active.get(container.id)
            if old_container is None:
                return
            del self._active[container.id]

            # since this container is active, get the old address so we can log
            # exactly which names/addresses are being deactivated
            desc = self._desc(container)
            mapping = self._get_mapping_by_container(container)
            if mapping:
                log.info('setting %s as inactive' % desc)
                self._deactivate(mapping.names, tag=mapping.key)

    def resolve(self, name):
        'Resolves the address for this name, if any'
        with self._lock:
            res = self._domains.get(name)
            if res:
                addrs = [a for a, _ in res]
                log.debug('resolved %s -> %s' % (name, ', '.join(addrs)))
                return addrs
            else:
                log.debug('no mapping for %s' % name)

    def dump(self):
        return json.dumps(self._domains.to_dict(), indent=4, sort_keys=1)

    def _activate(self, names, addr, tag=None):
        for name in names:
            self._domains.put(name, addr, tag)
            log.info('added %s -> %s key=%s', name.idna(), addr, tag)
        #log.debug('tree %s' % self.dump())

    def _deactivate(self, names, tag=None):
        for name in names:
            if self._domains.get(name):
                addrs = self._domains.remove(name, tag)
                if addrs:
                    for addr in addrs:
                        log.info('removed %s -> %s', name.idna(), addr)
        #log.debug('tree %s', self.dump())

    def _get_mapping_by_container(self, container):
        # try name and id-based keys
        res = self._mappings.get('name:/%s' % container.name)
        if not res:
            res = self._mappings.get('id:/%s' % container.id)
        return res

    def _desc(self, container):
        return '%s (%s)' % (container.name, container.id[:10])
Example #9
0
 def __init__(self, domain=None):
     self._mappings = defaultdict(set)
     self._active = defaultdict()
     self._domains = Node()
     self._lock = threading.Lock()
     self._domain = domain.lstrip('.') if domain else None
Example #10
0
class Registry(object):
    """
    Maps a container by id/name to a list of domain names and addresses.
    When the container is started, the list of domain names can be activated,
    and when the container is stopped the list of domain names can be
    deactivated.
    """

    def __init__(self, domain=None):
        self._mappings = defaultdict(set)
        self._active = defaultdict()
        self._domains = Node()
        self._lock = threading.Lock()
        self._domain = domain.lstrip('.') if domain else None

    def __str__(self):
        return json.dumps(self._domains.to_dict(), indent=4, sort_keys=1)

    def dump(self):
        return str(self)

    def _activate(self, names, addr, tag=None):
        # ensure that is a list of addr
        addrs = [addr] if not isinstance(addr, list) else addr

        for name in names:
            for addr in addrs:
                log.info('[registry] activate DNS record \n\t\t\t\t\t\t\t\t\t\t\t\t\t- %s -> %s key=%s', name.idna(), addr, tag)
                self._domains.put(name, addr, tag)
#        log.debug('tree %s' % self.dump())

    def _deactivate(self, names, addr=None, tag=None):
        # ensure that is a list of addr
        addrs = [addr] if not isinstance(addr, list) and addr is not None else addr

        for name in names:
            if self._domains.get(name):
                addrs = self._domains.remove(name, tag, addrs)
                log.info('[registry] deactivate DNS record \n\t\t\t\t\t\t\t\t\t\t\t\t\t- %s -> %s key = %s', name.idna(), addrs, tag)
#        log.debug('tree %s', self.dump())

    def get_mapping_key(self, key=None, name=None, id=None):
        if name:
            key = '%s%s' % (PREFIX_NAME, name)
        elif id:
            key = '%s%s' % (PREFIX_ID, id)

        if key and key.startswith(PREFIX_NAME):
            key = key.lstrip('/')

            if self._domain:
                key = '.'.join((key, self._domain))

        return key

    def _get_mapping_by_container(self, container):
        """
        try name and id-based keys
        :param Container container:
        :return:
        """

        # try matching by name
        res = self._mappings.get(self.get_mapping_key(name=container.name))

        if not res:
            # try matching by id
            res = self._mappings.get(self.get_mapping_key(id=container.id))

        return res

    def remove(self, key):
        with self._lock:
            old_mapping = self._mappings.get(self.get_mapping_key(key))

            if old_mapping:
                log.debug('[registry] table.remove map \n\t\t\t\t\t\t\t\t\t\t\t\t\t- %s', old_mapping)
                self._deactivate(old_mapping.names, tag=old_mapping.key)
                self._mappings.pop(old_mapping.key)

    def add(self, key, names):
        """
        Adds a mapping from the given key to a list of names. The names
        will be registered when the container is activated (running) and
        unregistered when the container is deactivated (stopped).
        """

        # first, remove the old names, if any
        self.remove(key)

        with self._lock:

            new_mapping = Mapping(key, names)

            # persist the mappings
            log.debug('[registry] table.add map \n\t\t\t\t\t\t\t\t\t\t\t\t\t- %s', new_mapping)
            self._mappings[self.get_mapping_key(key)] = new_mapping

            # check if these pertain to any already active
            # container and activate the domain names
            for container in list(self._active.values()):
                """
                :var Container container
                """
                if key in (self.get_mapping_key(name=container.name), self.get_mapping_key(id=container.id)):
                    for addr in container.addrs:
                        self._activate(names, addr, tag=key)

    def get(self, key):
        with self._lock:
            mapping = self._mappings.get(self.get_mapping_key(key))

            if not mapping:
                log.debug('[registry] table.get %s with NoneType', key)
            else:
                log.debug('[registry] table.get %s with %s', key, [addr.idna() for addr in mapping.names])

            if mapping:
                return [n.idna().rstrip('.') for n in mapping.names]

            return []

    def activate_static(self, domain, addr):
        """
        :param domain: DNSLabel
        :param addr: string
        """

        if not (domain is DNSLabel):
            domain = DNSLabel(domain)

        with self._lock:
            log.debug('[registry] table.activate %s with %s', domain.idna(), addr)
            self._activate([domain], addr, tag='%s%s' % (PREFIX_DOMAIN, domain))

    def deactivate_static(self, domain, addr):
        """
        :param domain: DNSLabel
        :param addr: string
        """

        if not (domain is DNSLabel):
            domain = DNSLabel(domain)

        with self._lock:
            log.debug('[registry] table.deactivate %s with %s', domain.idna(), addr)
            self._deactivate([domain], addr, tag='%s%s' % (PREFIX_DOMAIN, domain))

    def activate(self, container):
        """
        Activate all rules associated with this container
        :param Container container:
        :return:
        """
        with self._lock:
            self._active[container.id] = container

            mapping = self._get_mapping_by_container(container)
            if mapping:
                log.debug('[registry] activating map for container %s \n%s', container, '\n'.join(
                    ["\t\t\t\t\t\t\t\t\t\t\t\t\t- %s -> %s" % (r.idna(), container.name) for r in mapping.names]))

                key, names = mapping.key, mapping.names
                for addr in container.addrs:
                    self._activate(names, addr, tag=key)

    def deactivate(self, container):
        """
        Deactivate all rules associated with this container
        :param Container container:
        :return:
        """
        with self._lock:
            old_container = self._active.get(container.id)

            if old_container is not None:
                del self._active[container.id]

            # since this container is active, get the old address
            # so we can log exactly which names/addresses
            # are being deactivated
            mapping = self._get_mapping_by_container(container)
            if mapping:
                log.debug('[registry] deactivating map for container %s \n%s', container, '\n'.join(
                    ["\t\t\t\t\t\t\t\t\t\t\t\t\t- %s -> %s" % (r.idna(), container.name) for r in mapping.names]))
                self._deactivate(mapping.names, tag=mapping.key)

    def resolve(self, name):
        """
        Resolves the address for this name, if any
        :param name:
        :return:
        """
        with self._lock:
            res = self._domains.get(name)
            if res:
                addrs = [a for a, _ in res]
                addrs = list(set(addrs))
                log.debug('[registry] resolved %s -> %s', name, ', '.join(addrs))
                return addrs
            else:
                log.debug('[registry] no mapping for %s', name)

    #
    # Support container renames, newer Docker API versions.
    #

    def rename(self, old_name, new_name):
        if not old_name or not new_name:
            return

        old_key = self.get_mapping_key(name=old_name)
        new_key = self.get_mapping_key(name=new_name)

        with self._lock:
            try:
                mapping = self._mappings.pop(old_key)
            except KeyError:
                pass
            else:
                if mapping:
                    mapping.key = new_key
                    self._mappings[new_key] = mapping
                    log.debug('[registry] renamed (%s -> %s) == %s', old_name, new_name, mapping)
Example #11
0
    def test_multiple_wildcards(self):
        n = Node()

        # add a wildcard mapping
        n.put(WILD1, ADDR1, TAG1)
        n.put(WILD1, ADDR2, TAG2)
        res = n.get('xyz.foo.com')
        self.assertEquals(res[0], (ADDR1, TAG1))
        self.assertEquals(res[1], (ADDR2, TAG2))

        # remove the wildcard mapping for one tagged node
        n.remove(WILD1, TAG2)
        res = n.get('abc.foo.com')
        self.assertEquals(res, [(ADDR1, TAG1)])

        # remove the remaining wildcard mapping
        n.remove(WILD1, TAG1)
        res = n.get('abc.foo.com')
        self.assertEquals(res, None)
Example #12
0
 def test_tagging(self):
     n = Node()
     n.put(HOST1, ADDR1, TAG1)
     res = n.get(HOST1)
     self.assertEquals(res, [(ADDR1, TAG1)])