Пример #1
0
def test_attributes():
    """
    Test that attributes should just be added to the nodes on the same line
    """
    topology = """
    [attr=value] hs1 hs3
    hs2
    """

    actual = parse_txtmeta(topology)

    expected = {
        'environment':
        OrderedDict(),
        'nodes': [
            {
                'attributes': OrderedDict([('attr', 'value')]),
                'nodes': ['hs1']
            },
            {
                'attributes': OrderedDict([('attr', 'value')]),
                'nodes': ['hs3']
            },
            {
                'attributes': OrderedDict(),
                'nodes': ['hs2']
            },
        ],
        'ports': [],
        'links': []
    }

    assert not DeepDiff(actual, expected)
Пример #2
0
def test_multiline():
    """
    Test the support for multiline attributes
    """
    topology = """
    # Environment
    [
        virtual=none
        awesomeness=medium
        float=1.0
        list=(
            1,
            3.14,
            True
        )
    ]
    """
    actual = parse_txtmeta(topology)

    expected = {
        'environment':
        OrderedDict([('virtual', 'none'), ('awesomeness', 'medium'),
                     ('float', 1.0), ('list', [1, 3.14, True])]),
        'nodes': [],
        'ports': [],
        'links': []
    }

    assert not DeepDiff(actual, expected)
Пример #3
0
def test_autonode():
    """
    Test the automatic creation of implicit nodes
    """

    topology = """
    sw1:port1
    """

    actual = parse_txtmeta(topology)

    expected = {
        'environment': OrderedDict(),
        'nodes': [{
            'attributes': OrderedDict(),
            'nodes': ['sw1']
        }],
        'ports': [{
            'ports': [('sw1', 'port1')],
            'attributes': OrderedDict()
        }],
        'links': []
    }

    assert not DeepDiff(actual, expected)
Пример #4
0
    def parse(self, txtmeta, load=True, inject=None):
        """
        Parse a textual topology meta-description.

        For a description of the textual format see pyszn package
        documentation.

        :param str txtmeta: The textual meta-description of the topology.
        :param bool load: If ``True`` (the default) call :meth:`load`
         immediately after parse.
        :param dict inject: An attributes injection sub-dictionary as defined
         by :func:`parse_attribute_injection`.
        """
        data = parse_txtmeta(txtmeta)
        if load:
            self.load(data, inject=inject)
        return data
Пример #5
0
def test_single():
    """
    Test that a single line string (no new lines '\\n') is parsed
    """
    topology = """[attr=value] hs1"""

    actual = parse_txtmeta(topology)

    expected = {
        'environment':
        OrderedDict(),
        'nodes': [
            {
                'attributes': OrderedDict([('attr', 'value')]),
                'nodes': ['hs1']
            },
        ],
        'ports': [],
        'links': []
    }

    assert not DeepDiff(actual, expected)
Пример #6
0
def _expand_links(filename, links_definitions, szn_dir):
    """
    Expands a list of links definitions into the matching link names.

    A link definition is a string that can match none, one or more nodes
    (by using wildcards). It can be an expression for link name matching, or
    for matching all links that have an specific attribute value. For example:

    ::

        'nodea:1 -- nodeb:1'
        'node*:1 -- nodeb:12*'
        'attr=2'

    :param str filename: A filename in which to look for matching links.
    :param list link_definitions: A list of link definitions.
    :param list szn_dir: List of paths to directories where *.szn files 
     are located.
    :return: A list of matching links.
    """

    expanded_links = []

    # Grab the topology definition from a file that contains one
    log.debug('Trying to expand links in {}'.format(filename))
    if filename.endswith('.py'):
        topology = find_topology_in_python(filename, szn_dir=szn_dir)
        if topology is None:
            log.warning(
                ('Skipping link expansion for attribute injection in filename '
                 '{} in the lookup path as it does not contain a TOPOLOGY or TOPOLOGY_ID '
                 'definition.').format(filename))
            return []
    else:
        with open(filename, 'r') as fd:
            topology = fd.read().strip()
    log.debug('Found:\n{}'.format(topology))

    # Parse content
    try:
        parsed_topology = parse_txtmeta(topology)
    except Exception:
        log.error(
            ('Skipping link expansion for attribute injection in filename '
             '{} in the lookup path as SZN format parsing failed.'
             ).format(filename))
        log.debug(format_exc())
        return []

    for link_definition in links_definitions:

        # Check if definition is for attribute matching
        if type(link_definition) is not tuple:
            expanded_links.extend(
                _match_by_attr(link_definition, parsed_topology, 'links'))
            continue

        # The definition is not attribute matching, but name matching
        for link_group in parsed_topology['links']:
            link = link_group['endpoints']
            if fnmatch(link[0][0], link_definition[0][0]) and fnmatch(
                    link[0][1], link_definition[0][1]) and fnmatch(
                        link[1][0], link_definition[1][0]) and fnmatch(
                            link[1][1], link_definition[1]
                            [1]) and link not in expanded_links:
                expanded_links.append(link)

    return expanded_links
Пример #7
0
def _expand_nodes(filename, nodes_definitions, szn_dir):
    """
    Expands a list of node definitions into the matching node names.

    A node definition is a string that can match none, one or more nodes
    (by using wildcards). It can be an expression for node name matching, or
    for matching all nodes that have an specific attribute value. For example:

    ::

        'nodea'
        'hs*'
        'type=host'

    :param str filename: A filename in which to look for matching nodes.
    :param list nodes_definitions: A list of node definitions.
    :param list szn_dir: List of paths to directories where *.szn files 
     are located.
    :return: A list of matching nodes.
    """

    expanded_nodes = []

    # Grab the topology definition from a file that contains one
    log.debug('Trying to expand nodes in {}'.format(filename))
    if filename.endswith('.py'):
        topology = find_topology_in_python(filename, szn_dir=szn_dir)
        if topology is None:
            log.warning(
                ('Skipping node expansion for attribute injection in filename '
                 '{} in the lookup path as it does not contain a TOPOLOGY or TOPOLOGY_ID '
                 'definition.').format(filename))
            return []
    else:
        with open(filename, 'r') as fd:
            topology = fd.read().strip()
    log.debug('Found:\n{}'.format(topology))

    # Parse content
    try:
        parsed_topology = parse_txtmeta(topology)
    except Exception:
        log.error(
            ('Skipping node expansion for attribute injection in filename '
             '{} in the lookup path as SZN format parsing failed.'
             ).format(filename))
        log.debug(format_exc())
        return []

    for node_definition in nodes_definitions:

        # Check if definition is for attribute matching
        if match(r'(.*)=(.*)', node_definition):
            expanded_nodes.extend(
                _match_by_attr(node_definition, parsed_topology, 'nodes'))
            continue

        # The definition is not attribute matching, but name matching
        for nodes_group in parsed_topology['nodes']:
            for node in nodes_group['nodes']:
                if fnmatch(node, node_definition) and \
                        node not in expanded_nodes:
                    expanded_nodes.append(node)

    return expanded_nodes
Пример #8
0
def test_parse():
    """
    Tests parsing of a complete SZN
    """

    topology = """
    # Environment
    [virtual=none awesomeness=medium]

    # Nodes
    [shell=vtysh] sw1 sw2
    [type=host] hs1
    hs2

    # Links
    sw1:1 -- hs1:1
    [attr1=2.1e2 attr2=-2.7e-1] sw1:a -- hs1:a
    [attr1=1 attr2="lorem ipsum" attr3=(1, 3.0, "B")] sw1:4 -- hs2:a
    """

    actual = parse_txtmeta(topology)

    expected = {
        'environment':
        OrderedDict([('virtual', 'none'), ('awesomeness', 'medium')]),
        'nodes': [
            {
                'attributes': OrderedDict([('shell', 'vtysh')]),
                'nodes': ['sw1']
            },
            {
                'attributes': OrderedDict([('type', 'host')]),
                'nodes': ['hs1']
            },
            {
                'attributes': OrderedDict(),
                'nodes': ['hs2']
            },
            {
                'attributes': OrderedDict([('shell', 'vtysh')]),
                'nodes': ['sw2']
            },
        ],
        'ports': [
            {
                'ports': [('sw1', '1')],
                'attributes': OrderedDict()
            },
            {
                'ports': [('hs1', '1')],
                'attributes': OrderedDict()
            },
            {
                'ports': [('sw1', 'a')],
                'attributes': OrderedDict()
            },
            {
                'ports': [('hs1', 'a')],
                'attributes': OrderedDict()
            },
            {
                'ports': [('sw1', '4')],
                'attributes': OrderedDict()
            },
            {
                'ports': [('hs2', 'a')],
                'attributes': OrderedDict()
            },
        ],
        'links': [{
            'attributes': OrderedDict(),
            'endpoints': (('sw1', '1'), ('hs1', '1'))
        }, {
            'attributes':
            OrderedDict([('attr1', 210.0), ('attr2', -0.27)]),
            'endpoints': (('sw1', 'a'), ('hs1', 'a'))
        }, {
            'attributes':
            OrderedDict([('attr1', 1), ('attr2', 'lorem ipsum'),
                         ('attr3', [1, 3.0, 'B'])]),
            'endpoints': (('sw1', '4'), ('hs2', 'a'))
        }]
    }

    assert not DeepDiff(actual, expected)
Пример #9
0
def _expand_ports(filename, ports_definitions):
    """
    Expands a list of port definitions into the matching port names.

    A port definition is a string that can match none, one or more ports
    (by using wildcards). It can be an expression for port name matching, or
    for matching all ports that have an specific attribute value. For example:

    ::

        'nodea:1'
        'hs*:1*'
        'attr=1'

    :param str filename: A filename in which to look for matching ports.
    :param list ports_definitions: A list of port definitions.
    :return: A list of matching ports.
    """
    expanded_ports = []

    # Grab the topology definition from a file that contains one
    log.debug('Trying to expand ports in {}'.format(filename))
    if filename.endswith('.py'):
        topology = find_topology_in_python(filename)
        if topology is None:
            log.warning(
                ('Skipping port expansion for attribute injection in filename '
                 '{} in the lookup path as it does not contain a TOPOLOGY '
                 'definition.').format(filename))
            return []
    else:
        with open(filename, 'r') as fd:
            topology = fd.read().strip()
    log.debug('Found:\n{}'.format(topology))

    # Parse content
    try:
        parsed_topology = parse_txtmeta(topology)
    except Exception:
        log.error(
            ('Skipping port expansion for attribute injection in filename '
             '{} in the lookup path as SZN format parsing failed.'
             ).format(filename))
        log.debug(format_exc())
        return []

    for port_definition in ports_definitions:

        # Check if definition is for attribute matching
        if type(port_definition) is not tuple:
            expanded_ports.extend(
                _match_by_attr(port_definition, parsed_topology, 'ports'))
            continue

        # The definition is not attribute matching, but name matching
        for port_group in parsed_topology['ports']:
            for port in port_group['ports']:
                if fnmatch(port[0], port_definition[0]) and fnmatch(
                        port[1],
                        port_definition[1]) and port not in expanded_ports:
                    expanded_ports.append(port)

    return expanded_ports