class VrfAttributes(VrfSubAttributes): rd = Vrf.rd.copy() @rd.defaulter def rd(self): vrf = self.vrf return vrf and vrf.rd address_families = managedattribute( name='address_families', finit=typedset(AddressFamily).copy, type=typedset(AddressFamily)._from_iterable) @address_families.defaulter def address_families(self): return self.parent.address_families.copy() class AddressFamilyAttributes(AddressFamilySubAttributes): pass address_family_attr = managedattribute( name='address_family_attr', read_only=True, doc=AddressFamilySubAttributes.__doc__) @address_family_attr.initter def address_family_attr(self): return SubAttributesDict(self.AddressFamilyAttributes, parent=self) class NeighborAttributes(IPNeighborSubAttributes): address_families = managedattribute( name='address_families', finit=typedset(AddressFamily).copy, type=typedset(AddressFamily)._from_iterable) @address_families.defaulter def address_families(self): return self.parent.address_families.copy() class AddressFamilyAttributes(AddressFamilySubAttributes): pass address_family_attr = managedattribute( name='address_family_attr', read_only=True, doc=AddressFamilySubAttributes.__doc__) @address_family_attr.initter def address_family_attr(self): return SubAttributesDict(self.AddressFamilyAttributes, parent=self) neighbor_attr = managedattribute( name='neighbor_attr', read_only=True, doc=NeighborAttributes.__doc__) @neighbor_attr.initter def neighbor_attr(self): return SubAttributesDict(self.NeighborAttributes, parent=self) router_id = managedattribute( name='router_id', default=None, type=(None, IPv4Address)) neighbors = managedattribute( name='neighbors', finit=set, type=managedattribute.test_set_of(IPNeighbor), gettype=frozenset) neighbors = managedattribute( name='neighbors', finit=typedset(IPNeighbor).copy, type=typedset(IPNeighbor)._from_iterable) def add_neighbor(self, neighbor): # TODO DEPRECATE self.neighbors.add(neighbor) def remove_neighbor(self, neighbor): # TODO DEPRECATE self.neighbors.remove(neighbor)
class Vfi(ConfigurableBase): container = None # BridgeDomain device = managedattribute( name='device', read_only=True, gettype=managedattribute.auto_unref) name = managedattribute( name='name', read_only=True) # read-only hash key virtual = managedattribute( name='virtual', default=False, type=(None, managedattribute.test_istype(bool))) shutdown = managedattribute( name='shutdown', default=None, type=(None, managedattribute.test_istype(bool))) vpn_id = managedattribute( name='vpn_id', default=None, type=(None, managedattribute.test_istype(int))) class AutodiscoveryBgpAttributes(ConfigurableVfiNamespace): enabled = managedattribute( name='enabled', default=False, type=managedattribute.test_istype(bool)) control_word = managedattribute( name='control_word', default=None, type=(None, managedattribute.test_istype(bool))) rd = managedattribute( name='rd', default=None, type=(None, RouteDistinguisher, managedattribute.test_in(( 'auto', )))) export_route_policy = managedattribute( name='export_route_policy', default=None, type=(None, managedattribute.test_istype(str))) export_route_targets = managedattribute( name='export_route_targets', finit=typedset(RouteTarget.ImportExport).copy, type=typedset(RouteTarget.ImportExport)._from_iterable) import_route_targets = managedattribute( name='import_route_targets', finit=typedset(RouteTarget.ImportExport).copy, type=typedset(RouteTarget.ImportExport)._from_iterable) table_policy = managedattribute( name='table_policy', default=None, type=(None, managedattribute.test_istype(str))) class SignalingProtocolBgpAttributes(ConfigurableVfiNamespace): enabled = managedattribute( name='enabled', default=False, type=managedattribute.test_istype(bool)) ve_id = managedattribute( name='ve_id', default=None, type=(None, managedattribute.test_istype(int))) ve_range = managedattribute( name='ve_range', default=None, type=(None, managedattribute.test_istype(int), managedattribute.test_istype(str))) signaling_protocol_bgp = managedattribute( name='signaling_protocol_bgp', read_only=True, doc=SignalingProtocolBgpAttributes.__doc__) @signaling_protocol_bgp.initter def signaling_protocol_bgp(self): return self.SignalingProtocolBgpAttributes(vfi=self.vfi) class SignalingProtocolLdpAttributes(ConfigurableVfiNamespace): enabled = managedattribute( name='enabled', default=False, type=managedattribute.test_istype(bool)) vpls_id = managedattribute( name='vpls_id', default=None, type=(None, RouteTarget)) signaling_protocol_ldp = managedattribute( name='signaling_protocol_ldp', read_only=True, doc=SignalingProtocolLdpAttributes.__doc__) @signaling_protocol_ldp.initter def signaling_protocol_ldp(self): return self.SignalingProtocolLdpAttributes(vfi=self.vfi) def __init__(self, vfi): super().__init__(vfi=vfi) autodiscovery_bgp = managedattribute( name='autodiscovery_bgp', read_only=True, doc=AutodiscoveryBgpAttributes.__doc__) @autodiscovery_bgp.initter def autodiscovery_bgp(self): return self.AutodiscoveryBgpAttributes(vfi=self) class MulticastP2mpAttributes(ConfigurableVfiNamespace): class SignalingProtocolBgpAttributes(ConfigurableVfiNamespace): enabled = managedattribute( name='enabled', default=False, type=managedattribute.test_istype(bool)) signaling_protocol_bgp = managedattribute( name='signaling_protocol_bgp', read_only=True, doc=SignalingProtocolBgpAttributes.__doc__) @signaling_protocol_bgp.initter def signaling_protocol_bgp(self): return self.SignalingProtocolBgpAttributes(vfi=self.vfi) class TransportRsvpTeAttributes(ConfigurableVfiNamespace): enabled = managedattribute( name='enabled', default=False, type=managedattribute.test_istype(bool)) attribute_set_p2mp_te = managedattribute( name='attribute_set_p2mp_te', default=None, type=(None, managedattribute.test_istype(str))) transport_rsvp_te = managedattribute( name='transport_rsvp_te', read_only=True, doc=TransportRsvpTeAttributes.__doc__) @transport_rsvp_te.initter def transport_rsvp_te(self): return self.TransportRsvpTeAttributes(vfi=self.vfi) def __init__(self, vfi): super().__init__(vfi=vfi) multicast_p2mp = managedattribute( name='multicast_p2mp', read_only=True, doc=MulticastP2mpAttributes.__doc__) @multicast_p2mp.initter def multicast_p2mp(self): return self.MulticastP2mpAttributes(vfi=self) # TODO Cannot use typedset because segments need to be updated pseudowires = managedattribute( name='pseudowires', finit=set, type=managedattribute.test_set_of( managedattribute.test_isinstance(Pseudowire)), gettype=frozenset, doc='A `set` of Pseudowire associated objects') def add_pseudowire(self, pseudowire): prev_segments = self.segments self.pseudowires |= {pseudowire} self._on_segments_updated(prev_segments) def remove_pseudowire(self, pseudowire): prev_segments = self.segments self.pseudowires -= {pseudowire} self._on_segments_updated(prev_segments) @property def pseudowire_neighbors(self): for pw in self.pseudowires: for nbr in pw.neighbors: if nbr.container is self: # implied: nbr.device is self.device yield nbr def create_pseudowire_neighbor(self, **kwargs): pwnbr = PseudowireNeighbor(container=self, device=self.device, **kwargs) return pwnbr @property def segments(self): segments = [] segments += list(self.pseudowires) return frozenset(segments) def add_segment(self, segment): if isinstance(segment, Pseudowire): self.add_pseudowire(segment) else: raise ValueError(segment) def remove_segment(self, segment): if isinstance(segment, Pseudowire): self.remove_pseudowire(segment) else: raise ValueError(segment) def _on_segments_updated(self, prev_segments): pass # TODO class NeighborAttributes(PseudowireNeighborSubAttributes): # ip -> self.neighbor.ip # pw_id -> self.neighbor.pw_id dhcp_ipv4_snooping_profile = managedattribute( name='dhcp_ipv4_snooping_profile', default=None, type=(None, managedattribute.test_is(False), # False managedattribute.test_istype(str), # <profile> )) igmp_snooping_profile = managedattribute( name='igmp_snooping_profile', default=None, type=(None, managedattribute.test_is(False), # False managedattribute.test_istype(str), # <profile> )) mld_snooping_profile = managedattribute( name='mld_snooping_profile', default=None, type=(None, managedattribute.test_is(False), # False managedattribute.test_istype(str), # <profile> )) mpls_static_label = managedattribute( name='mpls_static_label', default=None, type=(None, managedattribute.test_istype(int))) pw_class = managedattribute( name='pw_class', default=None, type=(None, managedattribute.test_isinstance(PseudowireClass))) static_mac_address = managedattribute( name='static_mac_address', default=None, type=(None, MAC)) neighbor_attr = managedattribute( name='neighbor_attr', read_only=True, doc=NeighborAttributes.__doc__) @neighbor_attr.initter def neighbor_attr(self): return SubAttributesDict(self.NeighborAttributes, parent=self) def __init__(self, name, device, bridge_domain=None, *args, **kwargs): assert isinstance(name, str) self._name = name assert isinstance(device, Device) self._device = weakref.ref(device) super().__init__(*args, **kwargs) if bridge_domain is not None: bridge_domain.add_vfi(self) def __eq__(self, other): if not isinstance(other, Vfi): return NotImplemented # return (self.device, self.name, # self.container.__class__.__name__, self.container) \ # == (other.device, other.name, # other.container.__class__.__name__, other.container) return (self.name, self.device, self.container.__class__.__name__, self.container) \ == (other.name, other.device, other.container.__class__.__name__, other.container) def __lt__(self, other): if not isinstance(other, Vfi): return NotImplemented return (self.device, self.name, self.container.__class__.__name__, self.container) \ < (other.device, other.name, other.container.__class__.__name__, other.container) def __hash__(self): # return hash((self.device, self.container, self.name)) # return hash((self.name, self.device, self.container)) return hash(self.name)
class TunnelTeInterface(TunnelInterface, genie.libs.conf.interface.TunnelTeInterface): tunnel_mode = managedattribute(name='tunnel_mode', default='mpls traffic-eng', type=managedattribute.test_in( ('mpls traffic-eng', ))) destination = managedattribute(name='destination', default=None, type=(None, IPv4Address)) autoroute_announce = managedattribute(name='autoroute_announce', default=None, type=(None, bool)) forwarding_adjacency = managedattribute(name='forwarding_adjacency', default=None, type=(None, bool)) record_route = managedattribute(name='record_route', default=None, type=(None, bool)) frr = managedattribute(name='frr', default=None, type=(None, bool)) ipv4_unnumbered_interface = managedattribute( name='ipv4_unnumbered_interface', default=None, type=(None, managedattribute.test_isinstance(Interface))) priority_setup = managedattribute(name='priority_setup', default=None, type=(None, int)) priority_hold = managedattribute(name='priority_hold', default=None, type=(None, int)) affinity = managedattribute(name='affinity', default=None, type=(None, str)) te_bw = managedattribute(name='te_bw', default=None, type=(None, int, str)) te_backup_bw = managedattribute(name='te_backup_bw', default=None, type=(None, int, str)) path_options = managedattribute( name='path_options', finit=set, type=managedattribute.test_set_of( # TODO managedattribute.test_isinstance(PathOption)), managedattribute.test_istype(str)), gettype=frozenset, doc='A `set` of PathOption associated objects') def add_path_option(self, path_option): self._path_options.add(path_option) def remove_path_option(self, path_option): self._path_options.remove(path_option) class PathOptionAttributes(KeyedSubAttributes): @classmethod def _sanitize_key(cls, key): return str(key) path_option = managedattribute( name='path_option', read_only=True, # key doc='The path-option name (read-only key)') dynamic = managedattribute(name='dynamic', default=None, type=managedattribute.test_istype(bool)) explicit_name = managedattribute( name='explicit_name', default=None, type=managedattribute.test_istype(str)) def __init__(self, parent, key, **kwargs): self._path_option = key super().__init__(parent=parent, **kwargs) def build_config(self, apply=True, attributes=None, unconfig=False, **kwargs): assert not apply assert not kwargs attributes = AttributesHelper(self, attributes) configurations = CliConfigBuilder(unconfig=unconfig) # iosxe: interface tunnel1 / tunnel mpls traffic-eng path-option 1 dynamic if attributes.value('dynamic'): configurations.append_line( attributes.format( 'tunnel mpls traffic-eng path-option {path_option} dynamic' )) # iosxe: interface tunnel1 / tunnel mpls traffic-eng path-option 1 explicit name someword configurations.append_line(attributes.format\ ('tunnel mpls traffic-eng path-option {path_option} explicit name {explicit_name}')) return str(configurations) def build_unconfig(self, apply=True, attributes=None, **kwargs): return self.build_config(apply=apply, attributes=attributes, unconfig=True, **kwargs) path_option_attr = managedattribute(name='path_option_attr', read_only=True, doc=PathOptionAttributes.__doc__) @path_option_attr.initter def path_option_attr(self): return SubAttributesDict(self.PathOptionAttributes, parent=self) def __init__(self, *args, **kwargs): self.path_options # init! super().__init__(*args, **kwargs) def _build_config_interface_submode(self, configurations, attributes, unconfig): #super()._build_config_interface_submode(configurations=configurations, # attributes=attributes, # unconfig=unconfig) # Virtual interfaces can be fully unconfigured if unconfig and attributes.iswildcard: configurations.submode_unconfig() # iosxe: interface {name} / shutdown shutdown = attributes.value('shutdown') if shutdown is not None: if shutdown: configurations.append_line('shutdown', raw=True) else: configurations.append_line('no shutdown', raw=True) # iosxe: interface tunnel1 / tunnel mode mpls traffic-eng configurations.append_line( attributes.format('tunnel mode {tunnel_mode}')) # iosxe: interface tunnel1 / ip unnumbered Loopback0 configurations.append_line( attributes.format( 'ip unnumbered {ipv4_unnumbered_interface.name}')) # iosxe: interface tunnel1 / tunnel destination 1.2.3.4 configurations.append_line( attributes.format('tunnel destination {destination}')) # iosxe: interface tunnel1 / tunnel mpls traffic-eng autoroute announce if attributes.value('autoroute_announce'): configurations.append_line( 'tunnel mpls traffic-eng autoroute announce') # iosxe: interface tunnel1 / tunnel mpls traffic-eng forwarding adjacency if attributes.value('forwarding_adjacency'): configurations.append_line( 'tunnel mpls traffic-eng forwarding-adjacency') # iosxe: interface tunnel1 / tunnel mpls traffic-eng record-route if attributes.value('record_route'): configurations.append_line('tunnel mpls traffic-eng record_route') # iosxe: interface tunnel1 / tunnel mpls traffic-eng priority <0-7> <0-7> configurations.append_line( attributes.format( 'tunnel mpls traffic-eng priority {priority_setup} {priority_hold}' )) # iosxe: interface tunnel1 / tunnel mpls traffic-eng affinity 0xFFFF configurations.append_line( attributes.format('tunnel mpls traffic-eng affinity {affinity}')) # iosxe: interface tunnel1 / tunnel mpls traffic-eng bandwidth 1000 configurations.append_line( attributes.format('tunnel mpls traffic-eng affinity {te_bw}')) # iosxe: interface tunnel1 / tunnel mpls traffic-eng backup-bw 1000 configurations.append_line( attributes.format( 'tunnel mpls traffic-eng affinity {te_backup_bw}')) # iosxe: interface tunnel1 / tunnel mpls trafic-eng fast-reroute if attributes.value('frr'): configurations.append_line('tunnel mpls traffic-eng fast-reroute') # iosxe: interface tunnel-te1 / description some line data v = attributes.value('description') if v: if v is True: pass # TODO Create a usefull default description else: configurations.append_line('description {}'.format(v)) # iosxe: interface tunnel-te1 / ipv4 address 1.2.3.0/24 # ADD PATH OPTIONS for ns, attributes2 in attributes.mapping_values( 'path_option_attr', keys=self.path_options, sort=True): configurations.append_block( ns.build_config(apply=False, unconfig=unconfig, attributes=attributes2))
class Xconnect(DeviceFeature): group_name = managedattribute(name='group_name', type=managedattribute.test_istype(str)) @group_name.defaulter def group_name(self): return self.name + 'g' name = managedattribute( name='name', read_only=True, # read-only hash key doc='Bridge domain name (mandatory)') class Type(Enum): p2p = 1 mp2mp = 2 xconnect_type = managedattribute(name='xconnect_type', default=Type.p2p, type=Type) shutdown = managedattribute(name='shutdown', default=None, type=(None, bool)) link = managedattribute( name='link', read_only=True, doc='The XconnectLink instance that represents the connected interfaces' ) redundancy_predictive = managedattribute(name='redundancy_predictive', default=None, type=(None, bool)) class DeviceAutodiscoveryBgpAttributesDefaults(XconnectNamespace): enabled = managedattribute(name='enabled', default=False, type=managedattribute.test_istype(bool)) control_word = managedattribute( name='control_word', default=None, type=(None, managedattribute.test_istype(bool))) rd = managedattribute(name='rd', default=None, type=(None, RouteDistinguisher, managedattribute.test_in(('auto', )))) export_route_policy = managedattribute( name='export_route_policy', default=None, type=(None, managedattribute.test_istype(str))) export_route_targets = managedattribute( name='export_route_targets', finit=typedset(RouteTarget.ImportExport).copy, type=typedset(RouteTarget.ImportExport)._from_iterable) import_route_targets = managedattribute( name='import_route_targets', finit=typedset(RouteTarget.ImportExport).copy, type=typedset(RouteTarget.ImportExport)._from_iterable) table_policy = managedattribute( name='table_policy', default=None, type=(None, managedattribute.test_istype(str))) class DeviceSignalingProtocolBgpAttributesDefaults(XconnectNamespace): enabled = managedattribute(name='enabled', default=False, type=managedattribute.test_istype(bool)) ce_range = managedattribute( name='ce_range', default=None, type=(None, managedattribute.test_istype(int), managedattribute.test_istype(str))) signaling_protocol_bgp = managedattribute( name='signaling_protocol_bgp', read_only=True, doc=DeviceSignalingProtocolBgpAttributesDefaults.__doc__) @signaling_protocol_bgp.initter def signaling_protocol_bgp(self): return self.DeviceSignalingProtocolBgpAttributesDefaults( xconnect=self.xconnect) def __init__(self, xconnect): super().__init__(xconnect=xconnect) autodiscovery_bgp = managedattribute( name='autodiscovery_bgp', read_only=True, doc=DeviceAutodiscoveryBgpAttributesDefaults.__doc__) @autodiscovery_bgp.initter def autodiscovery_bgp(self): return self.DeviceAutodiscoveryBgpAttributesDefaults(xconnect=self) description = managedattribute(name='description', default=None, type=(None, managedattribute.test_istype(str))) # TODO Cannot use typedset because segments need to be updated interfaces = managedattribute( name='interfaces', finit=WeakList, type=managedattribute.test_set_of( managedattribute.test_isinstance(Interface)), gettype=frozenset, doc='A `set` of Interface associated objects') def add_interface(self, interface): prev_segments = self.segments self.interfaces |= {interface} self._on_segments_updated(prev_segments) def remove_interface(self, interface): prev_segments = self.segments self.interfaces -= {interface} self._on_segments_updated(prev_segments) class Interworking(Enum): ethernet = 'ethernet' ipv4 = 'ipv4' interface = managedattribute(name='interface', default=None, type=(None, Interworking)) # TODO Cannot use typedset because segments need to be updated pseudowires = managedattribute( name='pseudowires', finit=set, type=managedattribute.test_set_of( managedattribute.test_isinstance(Pseudowire)), gettype=frozenset, doc='A `set` of Pseudowire associated objects') def add_pseudowire(self, pseudowire): prev_segments = self.segments self.pseudowires |= {pseudowire} self._on_segments_updated(prev_segments) def remove_pseudowire(self, pseudowire): prev_segments = self.segments self.pseudowires -= {pseudowire} self._on_segments_updated(prev_segments) @property def pseudowire_neighbors(self): for pw in self.pseudowires: for nbr in pw.neighbors: if nbr.container is self: yield nbr @property def segments(self): segments = [] segments += list(self.interfaces) segments += list(self.pseudowires) return frozenset(segments) def add_segment(self, segment): if isinstance(segment, Interface): self.add_interface(segment) elif isinstance(segment, Pseudowire): self.add_pseudowire(segment) else: raise ValueError(segment) def remove_segment(self, segment): if isinstance(segment, Interface): self.remove_interface(segment) elif isinstance(segment, Pseudowire): self.remove_pseudowire(segment) else: raise ValueError(segment) def _on_segments_updated(self, prev_segments): # UNUSED prev_segments = frozenset(prev_segments) cur_segments = frozenset(self.segments) prev_link_interfaces = frozenset(self.link.interfaces) new_link_interfaces = frozenset( interface for segment in cur_segments for interface in self.link_interfaces_from_segment(segment)) for link_interface in prev_link_interfaces - new_link_interfaces: self.link._disconnect_interface_from_xconnect(link_interface) for link_interface in new_link_interfaces - prev_link_interfaces: self.link._connect_interface_from_xconnect(link_interface) def link_interfaces_from_segment(self, segment): link_interfaces = set() if isinstance(segment, Interface): # Links under Genie Interface object is deprecated # Placed the below workaround to bypass the Unittest from ats.datastructures import WeakList segment_links = set(WeakList()) - set([self]) # Priority to L2 virtual links... if not link_interfaces: for link in segment_links: if isinstance(link, (XconnectLink, XconnectLink)): link_interfaces.update(link.interfaces) link_interfaces.discard(segment) # ... then emulated links if not link_interfaces: for link in segment_links: if isinstance(link, EmulatedLink): link_interfaces.update(link.interfaces) link_interfaces.discard(segment) # ... finally, all links if not link_interfaces: for link in segment_links: link_interfaces.update(link.interfaces) link_interfaces.discard(segment) # For VLAN TGEN connections, the CE interface is the peer of the AC interface's parent if not link_interfaces: parent_interface = segment.parent_interface if parent_interface: # recurse link_interfaces = self.link_interfaces_from_segment( parent_interface) elif isinstance(segment, Pseudowire): pass else: raise ValueError(segment) return link_interfaces def create_pseudowire_neighbor(self, device, **kwargs): return self.device_attr[device].create_pseudowire_neighbor(**kwargs) class DeviceAttributes(genie.conf.base.attributes.DeviceSubAttributes): class NeighborAttributes(PseudowireNeighborSubAttributes): # ip -> self.neighbor.ip # pw_id -> self.neighbor.pw_id ipv6_source = managedattribute(name='ipv6_source', default=None, type=(None, IPv6Address)) mpls_static_label = managedattribute( name='mpls_static_label', default=None, type=(None, managedattribute.test_istype(int))) pw_class = managedattribute( name='pw_class', default=None, type=(None, managedattribute.test_isinstance(PseudowireClass))) redundancy_group = managedattribute(name='redundancy_group', type=(None, str)) redundancy_priority = managedattribute(name='redundancy_priority', type=(None, int)) encapsulation = managedattribute(name='encapsulation', default=EncapsulationType.mpls, type=(None, EncapsulationType)) neighbor_attr = managedattribute(name='neighbor_attr', read_only=True, doc=NeighborAttributes.__doc__) @neighbor_attr.initter def neighbor_attr(self): return SubAttributesDict(self.NeighborAttributes, parent=self) # interfaces -- See DeviceSubAttributes class AutodiscoveryBgpAttributes(SubAttributes): export_route_targets = managedattribute( name='export_route_targets', type=typedset(RouteTarget.ImportExport)._from_iterable) @export_route_targets.defaulter def export_route_targets(self): return frozenset(self.parent.export_route_targets) import_route_targets = managedattribute( name='import_route_targets', type=typedset(RouteTarget.ImportExport)._from_iterable) @import_route_targets.defaulter def import_route_targets(self): return frozenset(self.parent.import_route_targets) @property def device_name(self): return self._device_attr.device_name @property def device(self): return self._device_attr.device class SignalingProtocolBgpAttributes(SubAttributes): ce_ids = managedattribute(name='ce_ids', finit=typedset(int).copy, type=typedset(int)._from_iterable) def add_ce_id(self, ce_id): # TODO DEPRECATE self.ce_ids.add(ce_id) def remove_ce_id(self, ce_id): # TODO DEPRECATE self.ce_ids.remove(ce_id) @property def device_name(self): return self._device_attr.device_name @property def device(self): return self._device_attr.device class CeAttributes(KeyedSubAttributes): @classmethod def _sanitize_key(cls, key): return int(key) ce_id = managedattribute(name='ce_id', read_only=True) # read-only key interfaces = managedattribute( name='interfaces', finit=typedset( managedattribute.test_isinstance(Interface)).copy, type=typedset( managedattribute.test_isinstance( Interface))._from_iterable) def add_interface(self, intf): # TODO DEPRECATE self.interfaces.add(intf) def remove_interface(self, intf): # TODO DEPRECATE self.interfaces.remove(intf) class InterfaceAttributes(InterfaceSubAttributes): remote_ce_id = None #Always only one per interface # interface GigabitEthernet0/0/1/0 remote-ce-id 2000 # !!% Invalid argument: AC already used by existing xconnect interface_attr = None # InterfaceAttributes def __init__(self, parent, key): self._ce_id = key super().__init__(parent=parent) self.interface_attr = SubAttributesDict( self.InterfaceAttributes, parent=self) ce_attr = managedattribute(name='ce_attr', read_only=True, doc=CeAttributes.__doc__) @ce_attr.initter def ce_attr(self): return SubAttributesDict(self.CeAttributes, parent=self) def __init__(self, device_attr): self._device_attr = device_attr super().__init__(parent=device_attr.parent. autodiscovery_bgp.signaling_protocol_bgp) signaling_protocol_bgp = managedattribute( name='signaling_protocol_bgp', read_only=True, doc=SignalingProtocolBgpAttributes.__doc__) @signaling_protocol_bgp.initter def signaling_protocol_bgp(self): return self.SignalingProtocolBgpAttributes( device_attr=self._device_attr) def __init__(self, device_attr): self._device_attr = device_attr super().__init__(parent=device_attr.parent.autodiscovery_bgp) autodiscovery_bgp = managedattribute( name='autodiscovery_bgp', read_only=True, doc=AutodiscoveryBgpAttributes.__doc__) @autodiscovery_bgp.initter def autodiscovery_bgp(self): return self.AutodiscoveryBgpAttributes(device_attr=self) @property def pseudowires(self): container = self.parent device = self.device for pw in container.pseudowires: for nbr in pw.neighbors: if nbr.container is container \ and nbr.device is device: yield pw break # next pw @property def pseudowire_neighbors(self): device = self.device for nbr in self.parent.pseudowire_neighbors: if nbr.device is device: yield nbr def create_pseudowire_neighbor(self, **kwargs): pwnbr = PseudowireNeighbor(container=self.parent, device=self.device, **kwargs) return pwnbr @property def segments(self): segments = [] segments += list(self.interfaces) segments += list(self.pseudowires) return frozenset(segments) def __init__(self, parent, key, **kwargs): super().__init__(parent=parent, key=key, **kwargs) device_attr = managedattribute(name='device_attr', read_only=True, doc=DeviceAttributes.__doc__) @device_attr.initter def device_attr(self): return SubAttributesDict(self.DeviceAttributes, parent=self) def __eq__(self, other): if not isinstance(other, Xconnect): return NotImplemented # return (self.group_name, self.name, self.testbed) \ # == (other.group_name, other.name, other.testbed) return (self.name, self.group_name, self.testbed) \ == (other.name, other.group_name, other.testbed) def __lt__(self, other): if not isinstance(other, Xconnect): return NotImplemented return (self.group_name, self.name, self.testbed) \ < (other.group_name, other.name, self.testbed) def __hash__(self): # return hash((self.group_name, self.name)) return hash(self.name) def __init__(self, name, *args, **kwargs): self._name = name segments = kwargs.pop('segments', ()) super().__init__(*args, **kwargs) self._link = XconnectLink(xconnect=self) # TODO support self.segments = segments for segment in set(segments): self.add_segment(segment) def build_config(self, devices=None, apply=True, attributes=None, **kwargs): cfgs = {} assert not kwargs, kwargs attributes = AttributesHelper(self, attributes) if devices is None: devices = self.devices devices = set(devices) for key, sub, attributes2 in attributes.mapping_items('device_attr', keys=devices, sort=True): cfgs[key] = sub.build_config(apply=False, attributes=attributes2) if apply: self.testbed.config_on_devices(cfgs, fail_invalid=True) else: return cfgs def build_unconfig(self, devices=None, apply=True, attributes=None, **kwargs): cfgs = {} assert not kwargs, kwargs attributes = AttributesHelper(self, attributes) if devices is None: devices = self.devices devices = set(devices) for key, sub, attributes2 in attributes.mapping_items('device_attr', keys=devices, sort=True): cfgs[key] = sub.build_unconfig(apply=False, attributes=attributes2) if apply: self.testbed.config_on_devices(cfgs, fail_invalid=True) else: return cfgs
class SegmentRouting(Routing, DeviceFeature): address_families = managedattribute( name='address_families', finit=typedset(AddressFamily, {AddressFamily.ipv4_unicast}).copy, type=typedset(AddressFamily)._from_iterable) shutdown = managedattribute( name='shutdown', default=None, type=(None, managedattribute.test_istype(bool))) global_block = managedattribute( name='global_block', default=None, type=(None, managedattribute.test_istype(range))) sr_label_preferred = managedattribute( name='sr_label_preferred', default=None, type=(None, managedattribute.test_istype(bool))) explicit_null = managedattribute( name='explicit_null', default=None, type=(None, managedattribute.test_istype(bool))) mapping_server = managedattribute( name='mapping_server', default=None, type=(None, managedattribute.test_istype(bool))) connected_prefix_sid_map = managedattribute( name='connected_prefix_sid_map', finit=set, type=managedattribute.test_set_of( managedattribute.test_isinstance(PrefixSidMapEntry)), gettype=frozenset, doc='A `set` of connected_prefix_sid_map entries') prefix_sid_map = managedattribute( name='prefix_sid_map', finit=set, type=managedattribute.test_set_of( managedattribute.test_isinstance(PrefixSidMapEntry)), gettype=frozenset, doc='A `set` of prefix_sid_map entries') class DeviceAttributes(genie.conf.base.attributes.DeviceSubAttributes): address_families = managedattribute( name='address_families', type=typedset(AddressFamily)._from_iterable) @address_families.initter def address_families(self): return frozenset(self.parent.address_families) class AddressFamilyAttributes(AddressFamilySubAttributes): def __init__(self, parent, key): super().__init__(parent, key) def add_prefix_sid_map_entry(self,entry): self.prefix_sid_map |= {entry} def add_connected_prefix_sid_map_entry(self,entry): self.connected_prefix_sid_map |= {entry} def remove_prefix_sid_map_entry(self,entry): self.prefix_sid_map.remove(entry) def remove_connected_prefix_sid_map_entry(self,entry): self.connected_prefix_sid_map.remove(entry) address_family_attr = managedattribute( name='address_family_attr', read_only=True, doc=AddressFamilyAttributes.__doc__) @address_family_attr.initter def address_family_attr(self): return SubAttributesDict(self.AddressFamilyAttributes, parent=self) def __init__(self, parent, key): super().__init__(parent, key) device_attr = managedattribute( name='device_attr', read_only=True, doc=DeviceAttributes.__doc__) @device_attr.initter def device_attr(self): return SubAttributesDict(self.DeviceAttributes, parent=self) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def build_config(self, devices=None, apply=True, attributes=None, **kwargs): cfgs = {} assert not kwargs, kwargs attributes = AttributesHelper(self, attributes) if devices is None: devices = self.devices devices = set(devices) for key, sub, attributes2 in attributes.mapping_items( 'device_attr', keys=devices, sort=True): cfgs[key] = sub.build_config(apply=False, attributes=attributes2) if apply: self.testbed.config_on_devices(cfgs, fail_invalid=True) else: return cfgs def build_unconfig(self, devices=None, apply=True, attributes=None, **kwargs): cfgs = {} assert not kwargs, kwargs attributes = AttributesHelper(self, attributes) if devices is None: devices = self.devices devices = set(devices) for key, sub, attributes2 in attributes.mapping_items( 'device_attr', keys=devices, sort=True): cfgs[key] = sub.build_unconfig(apply=False, attributes=attributes2) if apply: self.testbed.config_on_devices(cfgs, fail_invalid=True) else: return cfgs
class BridgeDomain(DeviceFeature): group_name = managedattribute(name='group_name', type=managedattribute.test_istype(str)) @group_name.defaulter def group_name(self): return self.name + 'g' name = managedattribute( name='name', read_only=True, # read-only hash key doc='Bridge domain name (mandatory)') link = managedattribute( name='link', read_only=True, doc= 'The BridgeDomainLink instance that represents the connected interfaces' ) # TODO Cannot use typedset because segments need to be updated evis = managedattribute(name='evis', finit=set, type=managedattribute.test_set_of( managedattribute.test_isinstance(Evi)), gettype=frozenset, doc='A `set` of Evi associated objects') def add_evi(self, evi): prev_segments = self.segments self.evis |= {evi} self._on_segments_updated(prev_segments) def remove_evi(self, evi): prev_segments = self.segments self.evis -= {evi} self._on_segments_updated(prev_segments) class DefaultDeviceAndInterfaceMacAttributes(object): pass mac = managedattribute(name='mac', read_only=True, finit=DefaultDeviceAndInterfaceMacAttributes, doc=DefaultDeviceAndInterfaceMacAttributes.__doc__) # TODO Cannot use typedset because segments need to be updated interfaces = managedattribute( name='interfaces', finit=WeakList, type=managedattribute.test_set_of( managedattribute.test_isinstance(Interface)), gettype=frozenset, doc='A `set` of Interface associated objects') def add_interface(self, interface): if isinstance(interface, Vni): self.add_vni(interface) return prev_segments = self.segments self.interfaces |= {interface} self._on_segments_updated(prev_segments) def remove_interface(self, interface): if isinstance(interface, Vni): self.remove_vni(interface) return prev_segments = self.segments self.interfaces -= {interface} self._on_segments_updated(prev_segments) aging_time = managedattribute(name='aging_time', default=None, type=(None, managedattribute.test_istype(int))) learning_disable = managedattribute( name='learning_disable', default=None, type=(None, managedattribute.test_istype(bool))) split_horizon_group = managedattribute( name='split_horizon_group', default=None, type=(None, managedattribute.test_istype(bool))) split_horizon_group_core = managedattribute( name='split_horizon_group_core', default=None, type=(None, managedattribute.test_istype(bool))) # TODO Cannot use typedset because segments need to be updated pseudowires = managedattribute( name='pseudowires', finit=set, type=managedattribute.test_set_of( managedattribute.test_isinstance(Pseudowire)), gettype=frozenset, doc='A `set` of Pseudowire associated objects') def add_pseudowire(self, pseudowire): prev_segments = self.segments self.pseudowires |= {pseudowire} self._on_segments_updated(prev_segments) def remove_pseudowire(self, pseudowire): prev_segments = self.segments self.pseudowires -= {pseudowire} self._on_segments_updated(prev_segments) @property def pseudowire_neighbors(self): for pw in self.pseudowires: for nbr in pw.neighbors: if nbr.container is self: yield nbr # TODO Cannot use typedset because segments need to be updated vnis = managedattribute(name='vnis', finit=set, type=managedattribute.test_set_of( managedattribute.test_isinstance(Vni)), gettype=frozenset, doc='A `set` of Vni associated objects') def add_vni(self, vni): prev_segments = self.segments self.vnis |= {vni} self._on_segments_updated(prev_segments) def remove_vni(self, vni): prev_segments = self.segments self.vnis -= {vni} self._on_segments_updated(prev_segments) # TODO Cannot use typedset because segments need to be updated vfis = managedattribute(name='vfis', finit=set, type=managedattribute.test_set_of( managedattribute.test_isinstance(Vfi)), gettype=frozenset, doc='A `set` of Vfi associated objects') def add_vfi(self, vfi): assert isinstance(vfi, Vfi) if vfi.container is not None: raise ValueError('%r is already assigned to %r' % (vfi, vfi.container)) prev_segments = self.segments self.vfis |= {vfi} vfi.container = self self._on_segments_updated(prev_segments) def remove_vfi(self, vfi): assert isinstance(vfi, Vfi) if vfi.container is not None and vfi.container is not self: raise ValueError('%r is assigned to %r, not %r' % (vfi, vfi.container, self)) prev_segments = self.segments self.vfis -= {vfi} vfi.container = None self._on_segments_updated(prev_segments) shutdown = managedattribute(name='shutdown', default=None, type=(None, managedattribute.test_istype(bool))) @property def segments(self): segments = set() segments |= self.interfaces segments |= self.pseudowires segments |= self.vnis segments |= self.vfis segments |= self.evis return frozenset(segments) def add_segment(self, segment): if isinstance(segment, Evi): self.add_evi(segment) elif isinstance(segment, Vni): self.add_vni(segment) elif isinstance(segment, Interface): self.add_interface(segment) elif isinstance(segment, Pseudowire): self.add_pseudowire(segment) elif isinstance(segment, Vfi): self.add_vfi(segment) else: raise ValueError(segment) def remove_segment(self, segment): if isinstance(segment, Evi): self.remove_evi(segment) elif isinstance(segment, Vni): self.remove_vni(segment) elif isinstance(segment, Interface): self.remove_interface(segment) elif isinstance(segment, Pseudowire): self.remove_pseudowire(segment) elif isinstance(segment, Vfi): self.remove_vfi(segment) else: raise ValueError(segment) def _on_segments_updated(self, prev_segments): # UNUSED prev_segments = frozenset(prev_segments) cur_segments = frozenset(self.segments) prev_link_interfaces = frozenset(self.link.interfaces) new_link_interfaces = frozenset( interface for segment in cur_segments for interface in self.link_interfaces_from_segment(segment)) for link_interface in prev_link_interfaces - new_link_interfaces: self.link._disconnect_interface_from_bridge_domain(link_interface) for link_interface in new_link_interfaces - prev_link_interfaces: self.link._connect_interface_from_bridge_domain(link_interface) def link_interfaces_from_segment(self, segment): link_interfaces = set() if isinstance(segment, Evi): pass elif isinstance(segment, Vni): pass elif isinstance(segment, Interface): if isinstance(segment, BviInterface): link_interfaces.add(segment) else: # Links under Genie Interface object is deprecated # Placed the below workaround to bypass the Unittest from ats.datastructures import WeakList segment_links = set(WeakList()) - set([self.link]) # Priority to L2 virtual links... if not link_interfaces: for link in segment_links: if isinstance(link, (BridgeDomainLink, genie.libs.conf.l2vpn.XconnectLink)): link_interfaces.update(link.interfaces) link_interfaces.discard(segment) # ... then emulated links if not link_interfaces: for link in segment_links: if isinstance(link, EmulatedLink): link_interfaces.update(link.interfaces) link_interfaces.discard(segment) # ... finally, all links if not link_interfaces: for link in segment_links: link_interfaces.update(link.interfaces) link_interfaces.discard(segment) # For VLAN TGEN connections, the CE interface is the peer of # the AC interface's parent if not link_interfaces: parent_interface = segment.parent_interface if parent_interface: # recurse link_interfaces = self.link_interfaces_from_segment( parent_interface) elif isinstance(segment, Pseudowire): pass elif isinstance(segment, Vfi): pass else: raise ValueError(segment) return link_interfaces def create_pseudowire_neighbor(self, device, **kwargs): return self.device_attr[device].create_pseudowire_neighbor(**kwargs) class DeviceAttributes(genie.conf.base.attributes.DeviceSubAttributes): class InterfaceAttributes( genie.conf.base.attributes.InterfaceSubAttributes): class MacAttributes(SubAttributes): def __init__(self, _interface_attr): self._interface_attr = _interface_attr super().__init__( # BridgeDomain.device_attr[].mac parent=_interface_attr.parent.mac) @property def interface_name(self): return self._interface_attr.interface_name @property def interface(self): return self._interface_attr.interface mac = managedattribute(name='mac', read_only=True, doc=MacAttributes.__doc__) @mac.initter def mac(self): return self.MacAttributes(_interface_attr=self) static_mac_address = managedattribute(name='static_mac_address', default=None, type=(None, MAC)) def __init__(self, parent, key): super().__init__(parent, key) interface_attr = managedattribute(name='interface_attr', read_only=True, doc=InterfaceAttributes.__doc__) @interface_attr.initter def interface_attr(self): return SubAttributesDict(self.InterfaceAttributes, parent=self) class NeighborAttributes(PseudowireNeighborSubAttributes): # ip -> self.neighbor.ip # pw_id -> self.neighbor.pw_id # evi -> self.neighbor.evi # ac_id -> self.neighbor.ac_id # source_ac_id -> self.neighbor.source_ac_id dhcp_ipv4_snooping_profile = managedattribute( name='dhcp_ipv4_snooping_profile', default=None, type=( None, managedattribute.test_is(False), # False managedattribute.test_istype(str), # <profile> )) igmp_snooping_profile = managedattribute( name='igmp_snooping_profile', default=None, type=( None, managedattribute.test_is(False), # False managedattribute.test_istype(str), # <profile> )) mld_snooping_profile = managedattribute( name='mld_snooping_profile', default=None, type=( None, managedattribute.test_is(False), # False managedattribute.test_istype(str), # <profile> )) mpls_static_label = managedattribute( name='mpls_static_label', default=None, type=(None, managedattribute.test_istype(int))) pw_class = managedattribute( name='pw_class', default=None, type=(None, managedattribute.test_isinstance(PseudowireClass))) split_horizon = managedattribute( name='split_horizon', default=None, type=(None, managedattribute.test_istype(bool))) static_mac_address = managedattribute(name='static_mac_address', default=None, type=(None, MAC)) neighbor_attr = managedattribute(name='neighbor_attr', read_only=True, doc=NeighborAttributes.__doc__) @neighbor_attr.initter def neighbor_attr(self): return SubAttributesDict(self.NeighborAttributes, parent=self) class EviAttributes(EviSubAttributes): vlan = managedattribute(name='vlan', default=None, type=(None, int)) def __init__(self, parent, key): super().__init__(parent=parent, key=key) evi_attr = managedattribute(name='evi_attr', read_only=True, doc=EviAttributes.__doc__) @evi_attr.initter def evi_attr(self): return SubAttributesDict(self.EviAttributes, parent=self) class VniAttributes(VniSubAttributes): def __init__(self, parent, key): super().__init__(parent, key) vni_attr = managedattribute(name='vni_attr', read_only=True, doc=VniAttributes.__doc__) @vni_attr.initter def vni_attr(self): return SubAttributesDict(self.VniAttributes, parent=self) class MacAttributes(SubAttributes): def __init__(self, _device_attr): self._device_attr = _device_attr super().__init__( # BridgeDomain.mac parent=_device_attr.parent.mac) @property def device_name(self): return self._device_attr.device_name @property def device(self): return self._device_attr.device @property def testbed(self): return self._device_attr.testbed mac = managedattribute(name='mac', read_only=True, doc=MacAttributes.__doc__) @mac.initter def mac(self): return self.MacAttributes(_device_attr=self) @property def evis(self): device = self.device for evi in self.parent.evis: if evi.device is device: yield evi # interfaces -- See DeviceSubAttributes @property def vnis(self): device = self.device for vni in self.parent.vnis: if vni.device is device: yield vni @property def pseudowires(self): container = self.parent device = self.device for pw in container.pseudowires: for nbr in pw.neighbors: if nbr.container is container \ and nbr.device is device: yield pw break # next pw @property def pseudowire_neighbors(self): device = self.device for nbr in self.parent.pseudowire_neighbors: if nbr.device is device: yield nbr @property def vfis(self): device = self.device for vfi in self.parent.vfis: if vfi.device is device: yield vfi @property def segments(self): yield from self.interfaces yield from self.pseudowires yield from self.vnis yield from self.vfis yield from self.evis def create_pseudowire_neighbor(self, **kwargs): pwnbr = PseudowireNeighbor(container=self.parent, device=self.device, **kwargs) return pwnbr def __init__(self, parent, key): super().__init__(parent, key) device_attr = managedattribute(name='device_attr', read_only=True, doc=DeviceAttributes.__doc__) @device_attr.initter def device_attr(self): return SubAttributesDict(self.DeviceAttributes, parent=self) def __eq__(self, other): if not isinstance(other, BridgeDomain): return NotImplemented # return (self.group_name, self.name) == (other.group_name, other.name) return (self.name, self.group_name, self.testbed) \ == (other.name, other.group_name, other.testbed) def __lt__(self, other): if not isinstance(other, BridgeDomain): return NotImplemented return (self.group_name, self.name, self.testbed) \ < (other.group_name, other.name, other.testbed) def __hash__(self): # return hash((self.group_name, self.name)) return hash(self.name) def __init__(self, name, *args, **kwargs): self._name = name super().__init__(*args, **kwargs) self._link = BridgeDomainLink(bridge_domain=self) def build_config(self, devices=None, apply=True, attributes=None, **kwargs): cfgs = {} assert not kwargs, kwargs attributes = AttributesHelper(self, attributes) if devices is None: devices = self.devices devices = set(devices) for key, sub, attributes2 in attributes.mapping_items('device_attr', keys=devices, sort=True): cfgs[key] = sub.build_config(apply=False, attributes=attributes2) if apply: self.testbed.config_on_devices(cfgs, fail_invalid=True) else: return cfgs def build_unconfig(self, devices=None, apply=True, attributes=None, **kwargs): cfgs = {} assert not kwargs, kwargs attributes = AttributesHelper(self, attributes) if devices is None: devices = self.devices devices = set(devices) for key, sub, attributes2 in attributes.mapping_items('device_attr', keys=devices, sort=True): cfgs[key] = sub.build_unconfig(apply=False, attributes=attributes2) if apply: self.testbed.config_on_devices(cfgs, fail_invalid=True) else: return cfgs
class DeviceAttributes(genie.conf.base.attributes.DeviceSubAttributes): address_families = managedattribute( name='address_families', type=typedset(AddressFamily)._from_iterable) @address_families.defaulter def address_families(self): return frozenset(self.parent.address_families) area_addresses = managedattribute( name='area_addresses', type=managedattribute.test_set_of(IsisAreaAddress), doc='''Set of area address part of Network Entity Title (NET). Default value is taken from parent Isis object or, if None, a single area address unique value based on device name. ''') @area_addresses.defaulter def area_addresses(self): area_addresses = self.parent.area_addresses if area_addresses is None: unique_int = binascii.crc32(self.device_name.encode()) area_addresses = [ IsisAreaAddress('47.{:04X}.{:04X}'.format( (unique_int >> 16) & 0xFFFF, unique_int & 0xFFFF, )) ] return frozenset(area_addresses) @property def area_address(self): '''The area address part of the Network Entity Title (NET). `area_address` can be assigned to and will set `area_addresses` to a single item. `area_address`'s value is a single area address, or None. Use `area_addresses` to retrieve all the area addresses. Assign `area_addresses` to support multiple area addresses. ''' for area_address in sorted(self.area_addresses): return area_address return None @area_address.setter def area_address(self, value): self.area_addresses = {value} @area_address.deleter def area_address(self): del self.area_addresses system_id = managedattribute( name='system_id', type=IsisSystemID, doc='The system ID. Default is a unique value per device name.') @system_id.defaulter def system_id(self): system_id = self.parent.system_id if system_id is None: unique_int = binascii.crc32(self.device_name.encode()) system_id = IsisSystemID('FFFF.{:04X}.{:04X}'.format( (unique_int >> 16) & 0xFFFF, unique_int & 0xFFFF, )) return system_id @property def net_ids(self): '''The set of Network Entity Titles (NETs). Please assign using `system_id`, `area_addresses` or `net_id`. ''' system_id = self.system_id return frozenset([ IsisNET(area_address=area_address, system_id=system_id) for area_address in self.area_addresses ]) @property def net_id(self): '''The Network Entity Title (NET). The NET is formatted as `{area_address}.{system_id}.00` There can be only 1 `system_id` but there can be multiple areas (`area_addresses`). `net_id` can be assigned to and will set `area_addresses` to a single item as well as `system_id` to the desired value. `net_id`'s value is a single NET, or None. Use `net_ids` to retrieve all the NETs. Assign `area_addresses` and `system_id` to support multiple NETs. ''' for net_id in sorted(self.net_ids): return net_id return None @net_id.setter def net_id(self, value): if value is None: self.area_addresses = () else: net_id = IsisNET(value) self.system_id = net_id.system_id self.area_address = net_id.area_address @net_id.deleter def net_id(self): try: del self.area_address except AttributeError: pass try: del self.system_id except AttributeError: pass class AddressFamilyAttributes(AddressFamilySubAttributes): def __init__(self, parent, key): super().__init__(parent, key) address_family_attr = managedattribute( name='address_family_attr', read_only=True, doc=AddressFamilyAttributes.__doc__) @address_family_attr.initter def address_family_attr(self): return SubAttributesDict(self.AddressFamilyAttributes, parent=self) class InterfaceAttributes( genie.conf.base.attributes.InterfaceSubAttributes): address_families = managedattribute( name='address_families', type=typedset(AddressFamily)._from_iterable) @address_families.defaulter def address_families(self): return frozenset(self.parent.address_families) class AddressFamilyAttributes(AddressFamilySubAttributes): def __init__(self, parent, key): super().__init__(parent, key) address_family_attr = managedattribute( name='address_family_attr', read_only=True, doc=AddressFamilyAttributes.__doc__) @address_family_attr.initter def address_family_attr(self): return SubAttributesDict(self.AddressFamilyAttributes, parent=self) def __init__(self, parent, key): super().__init__(parent, key) interface_attr = managedattribute(name='interface_attr', read_only=True, doc=InterfaceAttributes.__doc__) @interface_attr.initter def interface_attr(self): return SubAttributesDict(self.InterfaceAttributes, parent=self) def __init__(self, parent, key): super().__init__(parent, key)
class Isis(Routing, DeviceFeature, InterfaceFeature, LinkFeature): pid = managedattribute(name='pid', type=str, doc='Process ID (mandatory)') address_families = managedattribute( name='address_families', finit=typedset(AddressFamily, {AddressFamily.ipv4_unicast}).copy, type=typedset(AddressFamily)._from_iterable) class MetricStyle(Enum): narrow = 'narrow' wide = 'wide' transition = 'transition' narrow_transition = 'narrow transition' wide_transition = 'wide transition' metric_style = managedattribute(name='metric_style', default=None, type=(None, MetricStyle)) metric = managedattribute(name='metric', default=None, type=(None, int, str)) class IsType(Enum): level_1 = 'level 1' level_1_2 = 'level 1 and 2' level_2 = 'level 2' is_type = managedattribute(name='is_type', default=None, type=(None, IsType)) ispf_type = managedattribute(name='ispf_type', default=None, type=(None, IsType)) circuit_type = managedattribute(name='circuit_type', default=None, type=(None, IsType)) maximum_paths = managedattribute(name='maximum_paths', default=None, type=(None, int)) ldp_auto_config = managedattribute(name='ldp_auto_config', default=None, type=(None, bool)) ldp_sync = managedattribute(name='ldp_sync', default=None, type=(None, bool)) ldp_sync_shortcut = managedattribute(name='ldp_sync_shortcut', default=None, type=(None, bool)) ldp_auto_config_shortcut = managedattribute( name='ldp_auto_config_shortcut', default=None, type=(None, bool)) distribute_link_state = managedattribute(name='distribute_link_state', default=None, type=(None, bool)) mpls_te_level = managedattribute(name='mpls_te_level', default=None, type=(None, IsType)) mpls_te_rtrid = managedattribute( name='mpls_te_rtrid', default=None, type=(None, managedattribute.test_isinstance(Interface))) net_id = managedattribute( name='net_id', read_only=True, doc='''Single Network Entity Title (NET). Only meaningful per device.''' ) net_ids = managedattribute( name='net_ids', read_only=True, doc='''Set of Network Entity Title (NET). Only meaningful per device.''' ) area_addresses = managedattribute( name='area_addresses', type=(None, managedattribute.test_set_of(IsisAreaAddress)), doc='''Set of area address part of Network Entity Title (NET). Default value is a single area address unique value based on ISIS process ID. Set to None to trigger each device to have a unique value based on individual device name. ''') @area_addresses.defaulter def area_addresses(self): unique_int = binascii.crc32(self.pid.encode()) return frozenset([ IsisAreaAddress('47.{:04X}.{:04X}'.format( (unique_int >> 16) & 0xFFFF, unique_int & 0xFFFF, )) ]) @property def area_address(self): '''The area address part of the Network Entity Title (NET). `area_address` can be assigned to and will set `area_addresses` to a single item. `area_address`'s value is a single area address, or None. Use `area_addresses` to retrieve all the area addresses. Assign `area_addresses` to support multiple area addresses. ''' area_addresses = self.area_addresses if area_addresses: for area_address in sorted(self.area_addresses): return area_address return None @area_address.setter def area_address(self, value): if value is None: self.area_addresses = None else: self.area_addresses = {value} @area_address.deleter def area_address(self): del self.area_addresses system_id = managedattribute( name='system_id', default=None, type=(None, IsisSystemID), doc= '''System ID. Assign to make all devices use the same System ID for level 1 operation.''' ) class Nsf(Enum): cisco = 'cisco' ietf = 'ietf' nsf = managedattribute(name='nsf', default=None, type=(None, Nsf)) nsf_lifetime = managedattribute(name='nsf_lifetime', default=None, type=(None, int)) nsr = managedattribute(name='nsr', default=None, type=(None, managedattribute.test_istype(bool))) redistribute_connected = managedattribute( name='redistribute_connected', default=None, type=(None, managedattribute.test_istype(bool))) passive = managedattribute(name='passive', default=None, type=(None, managedattribute.test_istype(bool))) point_to_point = managedattribute( name='point_to_point', default=None, type=(None, managedattribute.test_istype(bool))) shutdown = managedattribute(name='shutdown', default=None, type=(None, managedattribute.test_istype(bool))) nsf_lifetime = managedattribute(name='lsp_mtu', default=None, type=(None, int)) segment_routing_mpls = managedattribute( name='segment_routing_mpls', default=None, type=(None, managedattribute.test_istype(bool))) segment_routing_mpls_sr_prefer = managedattribute( name='segment_routing_mpls_sr_prefer', default=None, type=(None, managedattribute.test_istype(bool))) segment_routing_prefix_sid_map_advertise_local = managedattribute( name='segment_routing_prefix_sid_map_advertise_local', default=None, type=(None, managedattribute.test_istype(bool))) segment_routing_prefix_sid_map_receive = managedattribute( name='segment_routing_prefix_sid_map_receive', default=None, type=(None, managedattribute.test_istype(bool))) # NOTE: prefix_sid and prefix_sid_index are mutually exclusive prefix_sid = managedattribute(name='prefix_sid', default=None, type=(None, managedattribute.test_istype(int))) # NOTE: prefix_sid and prefix_sid_index are mutually exclusive prefix_sid_index = managedattribute( name='prefix_sid_index', default=None, type=(None, managedattribute.test_istype(int))) prefix_sid_explicit_null = managedattribute( name='prefix_sid_explicit_null', default=None, type=(None, managedattribute.test_istype(bool))) prefix_sid_n_flag_clear = managedattribute( name='prefix_sid_n_flag_clear', default=None, type=(None, managedattribute.test_istype(bool))) class DeviceAttributes(genie.conf.base.attributes.DeviceSubAttributes): address_families = managedattribute( name='address_families', type=typedset(AddressFamily)._from_iterable) @address_families.defaulter def address_families(self): return frozenset(self.parent.address_families) area_addresses = managedattribute( name='area_addresses', type=managedattribute.test_set_of(IsisAreaAddress), doc='''Set of area address part of Network Entity Title (NET). Default value is taken from parent Isis object or, if None, a single area address unique value based on device name. ''') @area_addresses.defaulter def area_addresses(self): area_addresses = self.parent.area_addresses if area_addresses is None: unique_int = binascii.crc32(self.device_name.encode()) area_addresses = [ IsisAreaAddress('47.{:04X}.{:04X}'.format( (unique_int >> 16) & 0xFFFF, unique_int & 0xFFFF, )) ] return frozenset(area_addresses) @property def area_address(self): '''The area address part of the Network Entity Title (NET). `area_address` can be assigned to and will set `area_addresses` to a single item. `area_address`'s value is a single area address, or None. Use `area_addresses` to retrieve all the area addresses. Assign `area_addresses` to support multiple area addresses. ''' for area_address in sorted(self.area_addresses): return area_address return None @area_address.setter def area_address(self, value): self.area_addresses = {value} @area_address.deleter def area_address(self): del self.area_addresses system_id = managedattribute( name='system_id', type=IsisSystemID, doc='The system ID. Default is a unique value per device name.') @system_id.defaulter def system_id(self): system_id = self.parent.system_id if system_id is None: unique_int = binascii.crc32(self.device_name.encode()) system_id = IsisSystemID('FFFF.{:04X}.{:04X}'.format( (unique_int >> 16) & 0xFFFF, unique_int & 0xFFFF, )) return system_id @property def net_ids(self): '''The set of Network Entity Titles (NETs). Please assign using `system_id`, `area_addresses` or `net_id`. ''' system_id = self.system_id return frozenset([ IsisNET(area_address=area_address, system_id=system_id) for area_address in self.area_addresses ]) @property def net_id(self): '''The Network Entity Title (NET). The NET is formatted as `{area_address}.{system_id}.00` There can be only 1 `system_id` but there can be multiple areas (`area_addresses`). `net_id` can be assigned to and will set `area_addresses` to a single item as well as `system_id` to the desired value. `net_id`'s value is a single NET, or None. Use `net_ids` to retrieve all the NETs. Assign `area_addresses` and `system_id` to support multiple NETs. ''' for net_id in sorted(self.net_ids): return net_id return None @net_id.setter def net_id(self, value): if value is None: self.area_addresses = () else: net_id = IsisNET(value) self.system_id = net_id.system_id self.area_address = net_id.area_address @net_id.deleter def net_id(self): try: del self.area_address except AttributeError: pass try: del self.system_id except AttributeError: pass class AddressFamilyAttributes(AddressFamilySubAttributes): def __init__(self, parent, key): super().__init__(parent, key) address_family_attr = managedattribute( name='address_family_attr', read_only=True, doc=AddressFamilyAttributes.__doc__) @address_family_attr.initter def address_family_attr(self): return SubAttributesDict(self.AddressFamilyAttributes, parent=self) class InterfaceAttributes( genie.conf.base.attributes.InterfaceSubAttributes): address_families = managedattribute( name='address_families', type=typedset(AddressFamily)._from_iterable) @address_families.defaulter def address_families(self): return frozenset(self.parent.address_families) class AddressFamilyAttributes(AddressFamilySubAttributes): def __init__(self, parent, key): super().__init__(parent, key) address_family_attr = managedattribute( name='address_family_attr', read_only=True, doc=AddressFamilyAttributes.__doc__) @address_family_attr.initter def address_family_attr(self): return SubAttributesDict(self.AddressFamilyAttributes, parent=self) def __init__(self, parent, key): super().__init__(parent, key) interface_attr = managedattribute(name='interface_attr', read_only=True, doc=InterfaceAttributes.__doc__) @interface_attr.initter def interface_attr(self): return SubAttributesDict(self.InterfaceAttributes, parent=self) def __init__(self, parent, key): super().__init__(parent, key) device_attr = managedattribute(name='device_attr', read_only=True, doc=DeviceAttributes.__doc__) @device_attr.initter def device_attr(self): return SubAttributesDict(self.DeviceAttributes, parent=self) def __init__(self, pid, *args, **kwargs): self.pid = pid super().__init__(*args, **kwargs) def build_config(self, devices=None, apply=True, attributes=None, **kwargs): cfgs = {} attributes = AttributesHelper(self, attributes) if devices is None: devices = self.devices devices = set(devices) for key, sub, attributes2 in attributes.mapping_items('device_attr', keys=devices, sort=True): cfgs[key] = sub.build_config(apply=False, attributes=attributes2) if apply: self.testbed.config_on_devices(cfgs, fail_invalid=True) else: return cfgs def build_unconfig(self, devices=None, apply=True, attributes=None, **kwargs): cfgs = {} attributes = AttributesHelper(self, attributes) if devices is None: devices = self.devices devices = set(devices) for key, sub, attributes2 in attributes.mapping_items('device_attr', keys=devices, sort=True): cfgs[key] = sub.build_unconfig(apply=False, attributes=attributes2) if apply: self.testbed.config_on_devices(cfgs, fail_invalid=True) else: return cfgs