Source code for pyNTM.node

"""A class to represent a layer 3 device in the Model"""

from .exceptions import ModelException
from .srlg import SRLG


[docs]class Node(object): """ A class to represent a layer 3 device in the model. Attribute lat, lon can be used as y, x values, respectively for graphing purposes. """ def __init__(self, name, lat=0, lon=0): self.name = name self._failed = False self._lat = lat self._lon = lon self._srlgs = set() self._igp_shortcuts_enabled = False # Validate lat, lon values if not (isinstance(lat, float)) and not (isinstance(lat, int)): raise ValueError("lat must be a float value") if not (isinstance(lon, float)) and not (isinstance(lon, int)): raise ValueError("lon must be a float value") def __repr__(self): return "Node(%r)" % self.name # Modify __eq__ and __hash__ default behavior for Node class # to allow us to easily determine if a Node instance is equivalent to another. # By default, equivalency test is 1) id, 2) hash, 3) equality. The id test will # fail and so it will move to hash and then equality. Modifying the __eq__ to # focus on the Node.name equivalency and and __hash__ to focus on the # hash of the Node.name will make equivalency testing possible def __eq__(self, other_node): return self.__dict__ == other_node.__dict__ def __hash__(self): # return hash(tuple(sorted(self.__dict__.items()))) return hash(self.name) def _key(self): return self.name @property def failed(self): """ Is node failed? Boolean. It is NOT recommended to directly modify this property. Rather, Model methods fail_node(node_name) and unfail_node(node_name) :return: Boolean - is node failed? """ return self._failed @failed.setter def failed(self, status): if not isinstance(status, bool): raise ModelException("must be boolean") if status is False: # False means Node would not be failed # Check for any SRLGs with self as a member and get status # of each SRLG failed_srlgs = [srlg for srlg in self.srlgs if srlg.failed is True] if len(failed_srlgs) > 0: self._failed = True raise ModelException( "Node must be failed since it is a member of one or more SRLGs that are failed" ) else: self._failed = False else: self._failed = True @property def lat(self): """Latitude or y-coordinate of Node on a plot""" return self._lat @lat.setter def lat(self, status): if isinstance(status, float) or isinstance(status, int): self._lat = status else: raise ValueError("lat attribute must be integer or float.") @property def lon(self): """Longitude or x-coordinate of Node on a plot""" return self._lon @lon.setter def lon(self, status): if isinstance(status, float) or isinstance(status, int): self._lon = status else: raise ValueError("lon attribute must be integer or float.") @property def igp_shortcuts_enabled(self): """Are IGP shortcuts enabled for RSVP LSPs on this Node? This is only applicable in the FlexModel; PerformanceModel subclass ignores this attribute """ return self._igp_shortcuts_enabled @igp_shortcuts_enabled.setter def igp_shortcuts_enabled(self, status): if isinstance(status, bool): self._igp_shortcuts_enabled = status elif status == "True": self.igp_shortcuts_enabled = True elif status == "False": self.igp_shortcuts_enabled = False else: raise ValueError("igp_shortcuts must be boolean")
[docs] def interfaces(self, model): """ Returns interfaces for a given node :param model: model structure :return adjacency_list: (list) list of interfaces on the given node """ adjacency_list = [] interface_iterator = (interface for interface in model.interface_objects) for interface in interface_iterator: if interface.node_object.name == self.name: adjacency_list.append(interface) return adjacency_list
[docs] def adjacent_nodes(self, model): """ Returns a list of adjacent nodes :param model: model Object :return: List of adjacent Nodes in model """ adjacencies = self.interfaces(model) adjacent_nodes = set() for adjacency in adjacencies: adjacent_nodes.add(adjacency.remote_node_object) return adjacent_nodes
[docs] def add_to_srlg(self, srlg_name, model, create_if_not_present=False): """ Adds self to an SRLG with name=srlg_name in model. :param srlg_name: name of srlg :param model: Model object :param create_if_not_present: Boolean. Create the SRLG if it does not exist in model already. True will create SRLG in model; False will raise ModelException # noqa E501 :return: None """ # See if model has existing SRLG with name='srlg_name' # get_srlg will be the SRLG object with name=srlg_name in model # or it will be False if the SRLG with name=srlg_name does not # exist in model try: get_srlg = model.get_srlg_object(srlg_name) except ModelException: get_srlg = False if get_srlg is False: # SRLG does not exist if create_if_not_present is True: new_srlg = SRLG(srlg_name, model) model.srlg_objects.add(new_srlg) self._srlgs.add(new_srlg) else: msg = "An SRLG with name {} does not exist in the Model".format( srlg_name ) raise ModelException(msg) else: # SRLG does exist in model; add self to that SRLG get_srlg.node_objects.add(self) self._srlgs.add(get_srlg)
[docs] def remove_from_srlg(self, srlg_name, model): """ Removes self from SRLG with srlg_name in model :param srlg_name: name of SRLG :param model: Model object :return: none """ # See if model has existing SRLG with name='srlg_name' # get_srlg will be the SRLG object with name=srlg_name in model # or it will be False if the SRLG with name=srlg_name does not # exist in model try: get_srlg = model.get_srlg_object(srlg_name) except ModelException: get_srlg = False if get_srlg is False: msg = "An SRLG with name {} does not exist in the Model".format(srlg_name) raise ModelException(msg) else: # Remove self from SRLG get_srlg.node_objects.remove(self) self._srlgs.remove(get_srlg) # If SRLG was failed, change self.failed = False when removed. If # setting self.failed = False generates a ModelException, pass. The # ModelException would happen if the Node was part of a different SRLG # that was still failed # if get_srlg.failed: # try: # self.failed = False # except ModelException: # pass self.failed = False
@property def srlgs(self): return self._srlgs
# TODO add node.fail and node.unfail - low priority - not really # necessary since Model has fail_/unfail_node