Example #1
0
File: cib.py Project: karlgrin/neat
    def expand_rows(self, apply_extended=True):
        """Generate CIB rows by expanding all CIBs pointing to current CIB """
        paths = self.resolve_graph()

        # for storing expanded rows
        rows = []

        for path in paths:
            expanded_properties = (self.cib[uid].expand() for uid in path)
            for pas in itertools.product(*expanded_properties):
                chain = ChainMap(*pas)

                # For debugging purposes, add the path list to the chain.
                # Store as string to preserve path order (NEAT properties are not ordered).
                dbg_path = '<<'.join(uid for uid in path)

                # insert at position 0 to override any existing entries
                # chain.maps.insert(0, PropertyArray(NEATProperty(('cib_uids', dbg_path))))

                # convert back to normal PropertyArrays
                row = PropertyArray(*(p for p in chain.values()))
                row.meta['cib_uids'] = dbg_path
                rows.append(row)

        if not apply_extended:
            return rows

        if not self.cib.extenders:
            # no extender CIB nodes loaded
            return rows

        # TODO optimize
        extended_rows = rows.copy()
        for entry in rows:
            # TODO take priorities into account
            # iterate extender cib_nodes
            for uid, xs in self.cib.extenders.items():
                for pa in xs.expand():
                    if xs.match_entry(entry):
                        entry_copy = copy.deepcopy(entry)
                        chain = ChainMap(pa, entry_copy)
                        new_pa = PropertyArray(*(p for p in chain.values()))
                        try:
                            del new_pa['uid']
                        except KeyError:
                            pass
                        extended_rows.append(new_pa)

        return extended_rows
Example #2
0
File: cib.py Project: karlgrin/neat
    def lookup(self, input_properties, candidate_num=5):
        """CIB lookup logic implementation

        Return CIB rows that include *all* required properties from the request PropertyArray
        """
        assert isinstance(input_properties, PropertyArray)
        candidates = [input_properties]
        for e in self.rows:
            try:
                # FIXME better check whether all input properties are included in row - improve matching
                # ignore optional properties in input request
                required_pa = PropertyArray(
                    *(p for p in input_properties.values() if p.precedence == NEATProperty.IMMUTABLE))
                if len(required_pa & e) != len(required_pa):
                    continue
            except ImmutablePropertyError:
                continue
            try:
                candidate = e + input_properties
                candidate.cib_node = e.cib_node
                candidates.append(candidate)
            except ImmutablePropertyError:
                pass

        return sorted(candidates, key=operator.attrgetter('score'), reverse=True)[:candidate_num]
Example #3
0
File: cib.py Project: karlgrin/neat
    def __init__(self, node_dict=None):

        if node_dict is None:
            node_dict = dict()

        if not isinstance(node_dict, dict):
            raise CIBEntryError("invalid CIB object")

        self.root = node_dict.get('root', False)
        # otherwise chain matched CIBs
        self.link = node_dict.get('link', False)
        self.priority = node_dict.get('priority', 0)
        # TTL for the CIB node: the node is considered invalid after the time specified
        self.expire = node_dict.get('expire', None) or node_dict.get('expires', None)  # FIXME expires is deprecated
        self.filename = node_dict.get('filename', None)
        self.description = node_dict.get('description', '')

        # convert to PropertyMultiArray with NEATProperties
        properties = node_dict.get('properties', [])

        if not isinstance(properties, list):
            # properties should be in a list. The list elements are expanded when generating the CIB rows.
            properties = [properties]

        self.properties = PropertyMultiArray()
        for p in properties:
            if isinstance(p, list):
                self.properties.add([PropertyArray.from_dict(ps) for ps in p])
            else:
                self.properties.add(PropertyArray.from_dict(p))

        self.match = []
        # FIXME better error handling if match undefined
        for l in node_dict.get('match', []):
            # convert to NEATProperties
            self.match.append(PropertyArray.from_dict(l))

        self.linked = set()
        if self.link and not self.match:
            logging.warning('link attribute set but no match field!')

        self.uid = node_dict.get('uid')
        if self.uid is None:
            self.uid = self._gen_uid()
Example #4
0
    def __init__(self, policy_dict=None, uid=None):
        # set default values

        if policy_dict is None:
            policy_dict = dict()

        if uid is not None:
            policy_dict['uid'] = uid

        # TODO do we need to handle unknown attributes?
        for k, v in policy_dict.items():
            if isinstance(v, str):
                setattr(self, k, v)

        self.priority = int(policy_dict.get('priority', 0))
        self.replace_matched = policy_dict.get('replace_matched', False)

        self.filename = None
        self.time = time.time()

        # parse match fields
        match = policy_dict.get('match', {})
        self.match = PropertyArray()
        self.match.add(*dict_to_properties(match))

        # parse augment properties
        properties = policy_dict.get('properties', [])
        if not isinstance(properties, list):
            # properties should be in a list.
            properties = [properties]
        self.properties = PropertyMultiArray()
        for p in properties:
            if isinstance(p, list):
                self.properties.add([PropertyArray.from_dict(ps) for ps in p])
            else:
                self.properties.add(PropertyArray.from_dict(p))

        # set UID
        self.uid = policy_dict.get('uid')
        if self.uid is None:
            self.uid = self.__gen_uid()
        else:
            self.uid = str(self.uid).lower()
Example #5
0
    def __init__(self, policy_dict=None, uid=None):
        # set default values

        if policy_dict is None:
            policy_dict = dict()

        if uid is not None:
            policy_dict['uid'] = uid

        # TODO do we need to handle unknown attributes?
        for k, v in policy_dict.items():
            if isinstance(v, str):
                setattr(self, k, v)

        self.priority = int(policy_dict.get('priority', 0))
        self.replace_matched = policy_dict.get('replace_matched', False)

        self.filename = None
        self.time = time.time()

        # parse match fields
        match = policy_dict.get('match', {})
        self.match = PropertyArray()
        self.match.add(*dict_to_properties(match))

        # parse augment properties
        properties = policy_dict.get('properties', [])
        if not isinstance(properties, list):
            # properties should be in a list.
            properties = [properties]
        self.properties = PropertyMultiArray()
        for p in properties:
            if isinstance(p, list):
                self.properties.add([PropertyArray.from_dict(ps) for ps in p])
            else:
                self.properties.add(PropertyArray.from_dict(p))

        # set UID
        self.uid = policy_dict.get('uid')
        if self.uid is None:
            self.uid = self.__gen_uid()
        else:
            self.uid = str(self.uid).lower()
Example #6
0
def gen_cibs():
    for en in netifaces.interfaces():
        c = cib.CIBNode()
        c.uid = en
        c.description = "autogenerated CIB node for local interface %s" % en
        c.root = True
        c.filename = en + '.cib'
        c.expire = -1

        pa = PropertyArray()
        pa.add(
            NEATProperty(('interface', en), precedence=NEATProperty.IMMUTABLE))
        pa.add(
            NEATProperty(('local_interface', True),
                         precedence=NEATProperty.IMMUTABLE))
        c.properties.add(pa)

        addr_list = []

        for af, addresses in netifaces.ifaddresses(en).items():
            if af == netifaces.AF_INET:
                af_prop = NEATProperty(('ip_version', 4),
                                       precedence=NEATProperty.IMMUTABLE)
            elif af == netifaces.AF_INET6:
                af_prop = NEATProperty(('ip_version', 6),
                                       precedence=NEATProperty.IMMUTABLE)
            else:
                continue

            for addr in addresses:
                pa = PropertyArray()
                pa.add(
                    NEATProperty(('local_ip', addr.get('addr', 0)),
                                 precedence=NEATProperty.IMMUTABLE))
                pa.add(af_prop)
                addr_list.append(pa)

        if addr_list:
            c.properties.add(addr_list)
            yield c.json()
Example #7
0
File: cib.py Project: karlgrin/neat
        print(term_separator("CIB END"))

    def __repr__(self):
        return 'CIB<%d>' % (len(self.nodes))


if __name__ == "__main__":
    cib = CIB('./cib/example/')
    b = cib['B']
    c = cib['C']

    cib.dump()
    import code

    code.interact(local=locals(), banner='CIB')

    for uid in cib.roots:
        z = cib[uid].resolve_links([])
        print(z)

    query = PropertyArray()
    test_request_str = '{"MTU": {"value": [1500, Infinity]}, "low_latency": {"precedence": 2, "value": true}, "remote_ip": {"precedence": 2, "value": "10:54:1.23"}, "transport": {"value": "TCP"}}'
    test = json.loads(test_request_str)
    for k, v in test.items():
        query.add(NEATProperty((k, v['value']), precedence=v.get('precedence', 1)))

    candidates = cib.lookup(query)
    for i in candidates:
        print(i)
        # print(i, i.cib_node, i.score)
Example #8
0
class NEATPolicy(object):
    """NEAT policy representation"""

    def __init__(self, policy_dict=None, uid=None):
        # set default values

        if policy_dict is None:
            policy_dict = dict()

        if uid is not None:
            policy_dict['uid'] = uid

        # TODO do we need to handle unknown attributes?
        for k, v in policy_dict.items():
            if isinstance(v, str):
                setattr(self, k, v)

        self.priority = int(policy_dict.get('priority', 0))
        self.replace_matched = policy_dict.get('replace_matched', False)

        self.filename = None
        self.time = time.time()

        # parse match fields
        match = policy_dict.get('match', {})
        self.match = PropertyArray()
        self.match.add(*dict_to_properties(match))

        # parse augment properties
        properties = policy_dict.get('properties', [])
        if not isinstance(properties, list):
            # properties should be in a list.
            properties = [properties]
        self.properties = PropertyMultiArray()
        for p in properties:
            if isinstance(p, list):
                self.properties.add([PropertyArray.from_dict(ps) for ps in p])
            else:
                self.properties.add(PropertyArray.from_dict(p))

        # set UID
        self.uid = policy_dict.get('uid')
        if self.uid is None:
            self.uid = self.__gen_uid()
        else:
            self.uid = str(self.uid).lower()

    def __gen_uid(self):
        # TODO make UID immutable?
        s = str(id(self))
        return hashlib.md5(s.encode('utf-8')).hexdigest()

    def dict(self):
        d = {}
        for attr in ['uid', 'priority', 'replace_matched', 'filename', 'time']:
            try:
                d[attr] = getattr(self, attr)
            except AttributeError:
                logging.warning("Policy doesn't contain attribute %s" % attr)

        d['match'] = self.match.dict()
        d['properties'] = self.properties.list()

        return d

    def json(self):
        return json.dumps(self.dict(), indent=4, sort_keys=True)

    def match_len(self):
        """Use the number of match elements to sort the entries in the PIB.
        Entries with the smallest number of elements are matched first."""
        return len(self.match)

    def match_query(self, input_properties, strict=False):
        """Check if the match properties are completely covered by the properties of a query.

        If strict flag is set match only properties with precedences that are higher or equal to the precedence
        of the corresponding match property.
        """

        # always return True if the match field is empty (wildcard)
        if not self.match:
            return True

        # TODO check
        # find full overlap?
        if not self.match.items() <= input_properties.items():
            return

        # find intersection
        matching_props = self.match.items() & input_properties.items()

        if strict:
            # ignore properties with a lower precedence than the associated match property
            return bool({k for k, v in matching_props if input_properties[k].precedence >= self.match[k].precedence})
        else:
            return bool(matching_props)

    def apply(self, properties: PropertyArray):
        """Apply policy properties to a set of candidate properties."""
        for p in self.properties.values():
            logging.info("applying property %s" % p)
            properties.add(*p)

    def __str__(self):
        return '%3s. %-8s %s  %s  %s' % (self.priority, self.uid, self.match, PM.CHARS.RIGHT_ARROW, self.properties)

    def __repr__(self):
        return repr({a: getattr(self, a) for a in ['uid', 'match', 'properties', 'priority']})
Example #9
0
 def apply(self, properties: PropertyArray):
     """Apply policy properties to a set of candidate properties."""
     for p in self.properties.values():
         logging.info("applying property %s" % p)
         properties.add(*p)
Example #10
0
class NEATPolicy(object):
    """NEAT policy representation"""
    def __init__(self, policy_dict=None, uid=None):
        # set default values

        if policy_dict is None:
            policy_dict = dict()

        if uid is not None:
            policy_dict['uid'] = uid

        # TODO do we need to handle unknown attributes?
        for k, v in policy_dict.items():
            if isinstance(v, str):
                setattr(self, k, v)

        self.priority = int(policy_dict.get('priority', 0))
        self.replace_matched = policy_dict.get('replace_matched', False)

        self.filename = None
        self.time = time.time()

        # parse match fields
        match = policy_dict.get('match', {})
        self.match = PropertyArray()
        self.match.add(*dict_to_properties(match))

        # parse augment properties
        properties = policy_dict.get('properties', [])
        if not isinstance(properties, list):
            # properties should be in a list.
            properties = [properties]
        self.properties = PropertyMultiArray()
        for p in properties:
            if isinstance(p, list):
                self.properties.add([PropertyArray.from_dict(ps) for ps in p])
            else:
                self.properties.add(PropertyArray.from_dict(p))

        # set UID
        self.uid = policy_dict.get('uid')
        if self.uid is None:
            self.uid = self.__gen_uid()
        else:
            self.uid = str(self.uid).lower()

    def __gen_uid(self):
        # TODO make UID immutable?
        s = str(id(self))
        return hashlib.md5(s.encode('utf-8')).hexdigest()

    def dict(self):
        d = {}
        for attr in ['uid', 'priority', 'replace_matched', 'filename', 'time']:
            try:
                d[attr] = getattr(self, attr)
            except AttributeError:
                logging.warning("Policy doesn't contain attribute %s" % attr)

        d['match'] = self.match.dict()
        d['properties'] = self.properties.list()

        return d

    def json(self):
        return json.dumps(self.dict(), indent=4, sort_keys=True)

    def match_len(self):
        """Use the number of match elements to sort the entries in the PIB.
        Entries with the smallest number of elements are matched first."""
        return len(self.match)

    def match_query(self, input_properties, strict=False):
        """Check if the match properties are completely covered by the properties of a query.

        If strict flag is set match only properties with precedences that are higher or equal to the precedence
        of the corresponding match property.
        """

        # always return True if the match field is empty (wildcard)
        if not self.match:
            return True

        # TODO check
        # find full overlap?
        if not self.match.items() <= input_properties.items():
            return

        # find intersection
        matching_props = self.match.items() & input_properties.items()

        if strict:
            # ignore properties with a lower precedence than the associated match property
            return bool({
                k
                for k, v in matching_props
                if input_properties[k].precedence >= self.match[k].precedence
            })
        else:
            return bool(matching_props)

    def apply(self, properties: PropertyArray):
        """Apply policy properties to a set of candidate properties."""
        for p in self.properties.values():
            logging.info("applying property %s" % p)
            properties.add(*p)

    def __str__(self):
        return '%3s. %-8s %s  %s  %s' % (self.priority, self.uid, self.match,
                                         PM.CHARS.RIGHT_ARROW, self.properties)

    def __repr__(self):
        return repr({
            a: getattr(self, a)
            for a in ['uid', 'match', 'properties', 'priority']
        })
Example #11
0
 def apply(self, properties: PropertyArray):
     """Apply policy properties to a set of candidate properties."""
     for p in self.properties.values():
         logging.info("applying property %s" % p)
         properties.add(*p)