1 # Copyright (c) 2019 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """Path utilities library for nodes in the topology."""
16 from resources.libraries.python.topology import Topology
20 """Path utilities for nodes in the topology.
24 node1--link1-->node2--link2-->node3--link3-->node2--link4-->node1
26 | Library | resources/libraries/python/NodePath.py
29 | | [Arguments] | ${node1} | ${node2} | ${node3}
30 | | Append Node | ${nodes1}
31 | | Append Node | ${nodes2}
32 | | Append Nodes | ${nodes3} | ${nodes2}
33 | | Append Node | ${nodes1}
34 | | Compute Path | ${FALSE}
35 | | ${first_int} | ${node}= | First Interface
36 | | ${last_int} | ${node}= | Last Interface
37 | | ${first_ingress} | ${node}= | First Ingress Interface
38 | | ${last_egress} | ${node}= | Last Egress Interface
39 | | ${next} | ${node}= | Next Interface
42 >>> from NodePath import NodePath
44 >>> path.append_node(node1)
45 >>> path.append_node(node2)
46 >>> path.append_nodes(node3, node2)
47 >>> path.append_node(node1)
48 >>> path.compute_path()
49 >>> (interface, node) = path.first_interface()
50 >>> (interface, node) = path.last_interface()
51 >>> (interface, node) = path.first_ingress_interface()
52 >>> (interface, node) = path.last_egress_interface()
53 >>> (interface, node) = path.next_interface()
58 self._nodes_filter = []
63 def append_node(self, node, filter_list=None):
64 """Append node to the path.
66 :param node: Node to append to the path.
67 :param filter_list: Filter criteria list.
69 :type filter_list: list of strings
71 self._nodes_filter.append(filter_list)
72 self._nodes.append(node)
74 def append_nodes(self, *nodes):
75 """Append nodes to the path.
77 :param nodes: Nodes to append to the path.
80 .. note:: Node order does matter.
83 self.append_node(node)
88 self._nodes_filter = []
93 def compute_path(self, always_same_link=True):
94 """Compute path for added nodes.
96 .. note:: First add at least two nodes to the topology.
98 :param always_same_link: If True use always same link between two nodes
99 in path. If False use different link (if available)
100 between two nodes if one link was used before.
101 :type always_same_link: bool
102 :raises RuntimeError: If not enough nodes for path.
106 raise RuntimeError(u"Not enough nodes to compute path")
108 for idx in range(0, len(nodes) - 1):
111 node2 = nodes[idx + 1]
112 n1_list = self._nodes_filter[idx]
113 n2_list = self._nodes_filter[idx + 1]
114 links = topo.get_active_connecting_links(
115 node1, node2, filter_list_node1=n1_list,
116 filter_list_node2=n2_list
120 f"No link between {node1[u'host']} and {node2[u'host']}"
124 l_set = set(links).intersection(self._links)
126 l_set = set(links).difference(self._links)
129 f"No free link between {node1[u'host']} and "
130 f"{node2[u'host']}, all links already used"
138 self._links.append(link)
139 interface1 = topo.get_interface_by_link_name(node1, link)
140 interface2 = topo.get_interface_by_link_name(node2, link)
141 self._path.append((interface1, node1))
142 self._path.append((interface2, node2))
144 self._path_iter.extend(self._path)
145 self._path_iter.reverse()
147 def next_interface(self):
148 """Path interface iterator.
150 :returns: Interface and node or None if not next interface.
151 :rtype: tuple (str, dict)
153 .. note:: Call compute_path before.
155 if not self._path_iter:
157 return self._path_iter.pop()
159 def first_interface(self):
160 """Return first interface on the path.
162 :returns: Interface and node.
163 :rtype: tuple (str, dict)
165 .. note:: Call compute_path before.
168 raise RuntimeError(u"No path for topology")
171 def last_interface(self):
172 """Return last interface on the path.
174 :returns: Interface and node.
175 :rtype: tuple (str, dict)
177 .. note:: Call compute_path before.
180 raise RuntimeError(u"No path for topology")
181 return self._path[-1]
183 def first_ingress_interface(self):
184 """Return first ingress interface on the path.
186 :returns: Interface and node.
187 :rtype: tuple (str, dict)
189 .. note:: Call compute_path before.
192 raise RuntimeError(u"No path for topology")
195 def last_egress_interface(self):
196 """Return last egress interface on the path.
198 :returns: Interface and node.
199 :rtype: tuple (str, dict)
201 .. note:: Call compute_path before.
204 raise RuntimeError(u"No path for topology")
205 return self._path[-2]